/********************************************************** * Joel Ong (jyo2), Frank Chen (flc23), Justin Leow (jl574) * ECE 4760 Final Project * Tutor * Friday Lab **********************************************************/ #include #include #include #include #include #include #include #include "uart.h" FILE uart_str = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW); // Timeout values #define t1 50 unsigned int t2; #define t3 100 #define t4 200 // Debounce States #define NoPush 0 #define MaybePush 1 #define Pushed 2 #define MaybeNoPush 3 // Modes #define SongMode 0 #define ChordMode 1 // Limits #define maxSongs 5 #define maxLength 100 #define maxChords 100 // Tasks void debounce(void); void update(void); void read(void); void process(void); // Subroutines void initialize(void); void play(unsigned char); void light(unsigned char,unsigned char); void setTempo(void); unsigned char getKey(void); void getstr_int(void); // Starts getting a string from serial line void putstr_int(void); // Starts a send to serial line // Task scheduling timeout counters volatile unsigned char time1; volatile unsigned int time2; volatile unsigned char time3; volatile unsigned char time4; // States unsigned char debounceState; unsigned char playState; unsigned char mode; // Variables unsigned char song; unsigned char pointer; unsigned char chord; // Preset Songs and Chords unsigned char numSongs = 2; char * songNames[maxSongs] = {"Happy Birthday", "Greensleeves"}; unsigned char tempo[maxSongs] = {60,45}; unsigned char length[maxSongs] = {25,32}; unsigned char library[maxSongs][maxLength] = { {0, 0,0,0, 4,4,4, 4,4,4, 0,0,0, 0,0,0, 4,3,3, 0,0,4, 0,0,0}, {12,0,4,9, 12,12,2,2, 12,0,4,9, 12,2,12,12, 0,0,4,9, 12,12,2,2, 0,0,4,9, 12,2,12,12} }; unsigned char numChords = 14; char * chordNames[maxChords] = {"C","D","E","F","G","A","B", "Cm","Dm","Em","Fm","Gm","Am","Bm"}; unsigned char chords[maxChords][6] = {{5,3,2,0,1,0}, // 0 C major {5,5,0,2,3,2}, // 1 D major {0,2,2,1,0,0}, // 2 E major {1,3,3,2,1,1}, // 3 F major {3,2,0,0,0,3}, // 4 G major {5,0,2,2,2,0}, // 5 A major {0,0,0,0,0,0}, // 6 B major {0,3,2,0,1,0}, // 7 C minor {5,5,0,2,3,1}, // 8 D minor {0,2,2,0,0,0}, // 9 E minor {1,3,3,1,1,1}, // 10 F minor {0,0,0,0,0,0}, // 11 G minor {5,0,2,2,1,0}, // 12 A minor {0,0,0,0,0,0}};// 13 B minor // User Interface Variables char command[16]; // Command entered char arg1[20]; // Command argument 1 char arg2[10]; // Command argument 2 char newstr; // task1-->task2 handshake // RXC ISR variables volatile unsigned char r_index; //current string index volatile char r_buffer[32]; //input string volatile unsigned char r_ready; //flag for receive done volatile char r_char; //current character // TX ISR variables volatile unsigned char t_index; //current string index volatile char t_buffer[512]; //output string volatile unsigned char t_ready; //flag for transmit done volatile char t_char; //current character /********************************************************** * Timer 0 Compare Match ISR **********************************************************/ ISR (TIMER0_COMPA_vect) { if (time1) time1--; if (time2) time2--; if (time3) time3--; if (time4) time4--; } /********************************************************** * UART character-ready ISR * builds a string and signals when the string is complete * supports backspace **********************************************************/ ISR (USART0_RX_vect) { r_char = UDR0 ; //get a char UDR0 = r_char; //then print it //build the input string if (r_char != '\r') { // Is the input a ? if (r_char == '\b') { // Is the input a backspace? putchar(' '); // erase the character on the screen putchar('\b'); // backup --r_index; // wipe a character from the string } else r_buffer[r_index++] = r_char ; // add a character to the string } else { // Human pressed putchar('\n'); //use putchar to avoid overwrite r_buffer[r_index] = 0x00; //zero terminate r_ready = 1; //signal cmd processor UCSR0B ^= (1<length[song]) { playState = 0; pointer = 0; } } else if (mode==ChordMode) { for (unsigned char str=0; str< 6; str++) light(str,chords[chord][str]); } } /********************************************************** * Read Command Task **********************************************************/ void read(void) { //print and get another serial string if (r_ready) { // read string which is now ready sscanf((const char*)r_buffer,"%s %s %s", command , arg1, arg2); // set up procedure to get the next string input // and read it using receive ISR getstr_int(); newstr = 1; // signal task2 that a new string is ready } } //TODO: google avrlibc eeprom for writing to eeprom during runtime /********************************************************** * Process Command Task **********************************************************/ void process(void) { // see if there is a message from task1 and if the last transmit is done if (t_ready && newstr) { if (!strcmp(command,"mapping")) { printf("\nCode \t LEDs \t Meaning \n\r" "0 \t none \t Strum Open String \n\r" "1 \t 1 \t First fret \n\r" "2 \t 2 \t Second fret \n\r" "3 \t 3 \t Third fret \n\r" "4 \t 4 \t Fourth fret \n\r" "5 \t all \t No Strum \n\r"); } else if (!strcmp(command, "chords")) { printf("\nCHORDS\n\r"); for (unsigned char i = 0; i>"); putstr_int(); // print it using transmit ISR newstr = 0; // clear the string ready handshake from task 1 } } /********************************************************** * Decode and returns button number of pressed button **********************************************************/ unsigned char getKey(void) { if (PIND & 0x08) return 1; else if (PIND & 0x10) return 2; else if (PIND & 0x20) return 3; else return 0; } /********************************************************** * Light up appropriate LEDs for fret state **********************************************************/ void light(unsigned char str, unsigned char fret) { switch (str) { case 0: if (!fret) PORTB &= 0xf0; else if (fret==5) PORTB |= 0x0f; else PORTB = (PORTB & 0xf0) | (0x01 << (fret-1)); break; case 1: if (!fret) PORTB &= 0x0f; else if (fret==5) PORTB |= 0xf0; else PORTB = (PORTB & 0x0f) | (0x10 << (fret-1)); break; case 2: if (!fret) PORTA &= 0xf0; else if (fret==5) PORTA |= 0x0f; else PORTA = (PORTA & 0xf0) | (0x01 << (fret-1)); break; case 3: if (!fret) PORTA &= 0x0f; else if (fret==5) PORTA |= 0xf0; else PORTA = (PORTA & 0x0f) | (0x10 << (fret-1)); break; case 4: if (!fret) PORTC &= 0xf0; else if (fret==5) PORTC |= 0x0f; else PORTC = (PORTC & 0xf0) | (0x01 << (fret-1)); break; case 5: if (!fret) PORTC &= 0x0f; else if (fret==5) PORTC |= 0xf0; else PORTC = (PORTC & 0x0f) | (0x10 << (fret-1)); break; } } /********************************************************** * Set Tempo **********************************************************/ void setTempo(void) { t2 = 60000/tempo[song]; } /********************************************************** * Non-blocking keyboard input: initializes ISR-driven receive. * This routine merely sets up the ISR, which then * does all the work of getting a command. **********************************************************/ void getstr_int(void) { r_ready=0; // mark string as not ready r_index=0; // reset index // turn on receive ISR UCSR0B |= (1<0) { // if so, send one chararcter putchar(t_buffer[0]); // and turn on transmit (UDR empty) ISR UCSR0B |= (1<>"); // Timer 0 - 1 kHz OCR0A = 249; // clear after 250 counts TIMSK0 = (1<