Loading lab1.c +67 −269 Original line number Diff line number Diff line Loading @@ -2,9 +2,6 @@ * Georgiana Diana Ciocirdel * Proiect PM 2015 - Guitar Tuner * * I am using bits of code from a 2007 project, written by Razvan Tataroiu. His * project can be found here: * https://sites.google.com/site/razvan784/proiectproiectareacumicroprocesoare */ #include "lcd.h" Loading Loading @@ -50,8 +47,7 @@ /******************************************************************************/ /* Tuner specific stuff. */ #define PRESCALER 64 #define MAX_QUEUE_LEN 254 #define PRESCALER 256 #define E 164.81 #define A 220.00 Loading @@ -60,35 +56,19 @@ #define B 493.88 #define EH 659.26 /* Two times the standard guitar guitar tunings as per * http://en.wikipedia.org/wiki/Guitar_tunings#Standard */ float std_fr[] = {164.81, 220.00, 293.66, 391.99, 493.88, 659.26}; char *str_std_fr[] = {"E ", "A ", "D ", "G ", "B ", "EH"}; char chosen_string = 0; unsigned char queue[254], start, stop, size; /* Circular queue for samples. */ #define LOG2 log(2.0) #define S_RATE ((float) F_CPU / 64.0 / 13.0) #define S_RATEI (F_CPU / 64 / 13) #define S_MIN_MAX (S_RATE / 10) unsigned int avg; char gain; char state; char top; char bot; char tmp_top; char tmp_bot; int count; int no_of_samples; int last_sample; float freq; char started; char err_disp; char ngainchg; char havetopbot; char txt[17]; char notes[36]="dC dC#rD rD#mE fF fF#sG sG#lA lA#tB "; /******************************************************************************/ /******************************************************************************/ void timer1_init (void) { TCCR1B |= (1 << CS12) | /* Prescaler = 256 */ (1 << WGM12); /* Clear on compare, TOP = OCR1A */ TIMSK1 |= ( 1<< OCIE1A); OCR1A = 31250; /* TOP */ } void LCD_clear (void) { LCD_printAt (FST_LINE_FST_CHAR, EMPTY_LINE); Loading @@ -104,19 +84,10 @@ void button_init (void) { PORT_BTN |= (1 << BIT_BTN); } void ADC_init (void) { /* Enable interrupt on PA7. */ DDRA |= (1 << PA7); ADMUX = (1 << REFS0) | /* Set VCC as reference. */ (1 << ADLAR) | /* Left-adjust the result in the ADC data register: * this saves the result in ADCH. */ ((1 << MUX0) | (1 << MUX1) | (1 << MUX2)); /* ADC7 as input. */ ADCSRA = (1 << ADEN) | /* Enable ADC. */ (1 << ADSC) | /* Enable free running conversions. */ (1 << ADATE) | /* Enable ADC autotrigger. */ (1 << ADIE) | /* Enable interruptions. */ (1 << ADPS2) | /* Set prescaler at 64. */ (1 << ADPS1); void input_init (void) { DDRB &= ~(1 << PB7); PCICR |= (1 << PCIE1); PCMSK1 |= (1 << PCINT15); } void wait_for (int millisecs) { Loading @@ -128,7 +99,7 @@ void wait_for (int millisecs) { } void refresh_snd_line (void) { LCD_printAt (SND_LINE_FST_CHAR + 7, "|"); LCD_printAt (SND_LINE_FST_CHAR, EMPTY_LINE); } void startup_LCD (void) { Loading @@ -137,10 +108,8 @@ void startup_LCD (void) { /* Display welcome message and toggle LED.*/ LCD_printAt (FST_LINE_FST_CHAR, "Welcome to"); LCD_printAt (SND_LINE_FST_CHAR, "Guitar Tuner"); //toggle_bit (PORT_LED, BIT_LED); toggle_bit (PORT_LED, BIT_LED); wait_for (2000); //toggle_bit (PORT_LED, BIT_LED); toggle_bit (PORT_LED, BIT_LED); LCD_clear (); Loading @@ -156,6 +125,10 @@ void startup_LCD (void) { LCD_printAt (FST_LINE_FST_CHAR, ""); } int count_down_up; int sum = 0; int count = 0; void move_cursor (void) { if ((PIN_BTN & (1 << BIT_BTN)) == 0) { chosen_string = (chosen_string + 1) % 6; Loading @@ -164,201 +137,14 @@ void move_cursor (void) { toggle_bit (PORT_LED, BIT_LED); wait_for (300); toggle_bit (PORT_LED, BIT_LED); } } /* * I am hereby using parts of code from Razvan Tataroiu's project from 2007. His * project can be found here: * https://sites.google.com/site/razvan784/proiectproiectareacumicroprocesoare */ void process_sample (char curr_sample) { int x16; /* Used for computations => we need more precission. */ char x; /* Will hold current sample value, after computations. */ /* Increment number of samples. */ no_of_samples++; /* Compute signal average with 20 bits precision: * avg = (avg * 4095 + (increased precision) smp ) / 4096 */ avg = ((avg << 12) - avg + ((unsigned int) curr_sample << 12)) >> 12; /* After a gain change wait to stabilize external circuit and average. */ if (ngainchg == FALSE) { //PORTD = 0xFF;//led on if (no_of_samples == 5 * S_MIN_MAX) { no_of_samples = 0; last_sample = 1; ngainchg = TRUE; tmp_top = 0; tmp_bot = 0; } else { return; } } /* Center on zero. */ x16 = (int) curr_sample - (int) (avg >> 12); //decrease precision to 8 bits /* Saturate. */ if (x16 < -128) { x16 = -128; } if (x16 > 127) { x16 = 127; } x = x16; //convert to 8 bits /* Compute top, bottom. */ if (x > tmp_top) { tmp_top = x; } if (x < tmp_bot) { tmp_bot = x; } /* Update top, bottom every 100ms. */ if (no_of_samples % (S_RATEI / 10) == 0) { top = tmp_top; bot = tmp_bot; tmp_top = 0; tmp_bot = 0; } /* Make at least one top, bot measurement after a gain change. */ if (havetopbot == FALSE) { if (no_of_samples == S_MIN_MAX) { havetopbot = TRUE; no_of_samples = 0; //PORTD = 0x7F;//led off } return; } /* Schmitt trigger. */ if (state == 1 && x < bot / 2) { state = 0; } if (state == 0 && x > top / 2) { state = 1; count++; /* transition count, and sample number of last transition */ last_sample = no_of_samples; } /* frequency relative error = 1 / (sample number) */ if (no_of_samples == 8192) { // 8-step external agc, hysterezis // perform agc change now, as next samples may come in delayed // due to float calculations and lcd display if (top == 127 || bot == -128) { // decrease gain if (gain != 0b00000000) { err_disp = FALSE; gain -= 0b00100000; PORTA = gain; ngainchg = FALSE; havetopbot = FALSE; } } if (top < 16 && bot > -16) { // increase gain if (gain != 0b11100000) { //limit gain to e.g. 3 if it picks up too much noise through // microphone. leave at 8 if using a lower noise setup (e.g. plugging an electric guitar) gain += 0b00100000; PORTA = gain; ngainchg = 0; havetopbot = 0; } else { if(top < 8) { if (err_disp == FALSE) { LCD_clear (); LCD_printAt (SND_LINE_FST_CHAR, "ERROR NO SIGNAL"); err_disp = TRUE; return; } } else { err_disp = 0; } } } // update frequency freq = S_RATE * count / last_sample; count_down_up = 0; sum = 0; count = 0; no_of_samples = 0; last_sample = 1; state = 0; // ftoa int frq = (int) freq; char frac = (char) ((freq - (float) frq) * 100); unsigned char ptr = 4; if (frq > 6000) { frq = 9999; } do { txt[--ptr] = '0' + frq % 10; frq /= 10; } while (frq > 0); while (ptr > 0) txt[--ptr] = ' '; txt[4]='.'; txt[5]='0' + (frac / 10); txt[6]='0' + frac % 10; //freq = 440 * 2^((note-57)/12), where note = 12 * octave /0..7/ + note_in_octave /0..11/ float note = 12.0 * log(freq/440.0) / LOG2 + 57; //again, long live avrlibc math if (note < 0) note = -0.4; if (note > 95.0) note = 95.4; //out of scale unsigned char rnote = (unsigned char) (note + 0.5); //nearest note float dif = note - (float) rnote; if(dif < -0.25) txt[7]='<'; else txt[7]=' '; if(dif < -0.01) txt[8]='<'; else txt[8]=' '; if(dif > 0.01) txt[14]='>'; else txt[14]=' '; if(dif > 0.25) txt[15]='>'; else txt[15]=' '; txt[13] = '0' + rnote / 12; rnote %= 12; rnote *= 3; txt[9] = notes[rnote]; txt[9] = notes[rnote]; txt[11] = notes[rnote + 1]; txt[12] = notes[rnote + 2]; LCD_clear (); LCD_printAt (SND_LINE_FST_CHAR, txt); } } int main() { char curr_sample; no_of_samples = 0; avg = 0; ngainchg = FALSE; int main (void) { count_down_up = 0; /* Init LED. */ LED_init (); Loading @@ -370,46 +156,58 @@ int main() { LCD_init (); startup_LCD (); /* Init interrupts and ADC. */ ADC_init (); /* Init input and timer. */ input_init (); timer1_init (); sei(); /* Infinite loop to run program. */ for (;;) { move_cursor (); wait_for (500); sei (); if (size > 0) { if(size >= MAX_QUEUE_LEN) { /* Signal an error on overflow. */ toggle_bit (PORT_LED, BIT_LED); LCD_printAt (FST_LINE_FST_CHAR, EMPTY_LINE); LCD_printAt (SND_LINE_FST_CHAR, "OVERFLOW ERROR"); /* Wait indefinetely. */ for(;;); } /* Disable interrupt for the moment, to avoid races. */ cli (); curr_sample = queue[start]; start = (start + 1) % MAX_QUEUE_LEN; size--; /* Reenable interrupts. */ sei (); /* Process current sample. */ process_sample (curr_sample); } } return 0; } /* * ADC Interrupt Routine. */ ISR (ADC_vect) { if (size < MAX_QUEUE_LEN) { /* Add ADC value to the queue in order to be processed. */ queue[stop] = ADCH; stop = (stop + 1) % MAX_QUEUE_LEN; size++; char buff[10]; ISR (PCINT1_vect) { if ((PINB & (1 << PB7)) == 0) { /* If there is a low-high transition */ count_down_up++; } } /* Timer interrupt. */ ISR (TIMER1_COMPA_vect) { sum += count_down_up; count++; if (count == 3) { refresh_snd_line (); toggle_bit (PORT_LED, BIT_LED); sum /= count; int diff = sum - std_fr[chosen_string]; char c = '-'; if (diff > 0) { c = '+'; } else if (diff == 0) { c = '0'; } int abs_diff = abs (diff); float percent = (float) abs_diff / (std_fr[chosen_string] * 2) * 100; int percent_i = (int) percent; itoa (percent_i, buff, 10); int n = strlen (buff); buff[n] = '%';; buff[n + 1] = c; buff[n + 2] = '\0'; LCD_printAt (SND_LINE_FST_CHAR, buff); LCD_printAt (FST_LINE_FST_CHAR + chosen_string * 3, ""); count = 0; sum = 0; } count_down_up = 0; } Makefile +1 −1 File changed.Contains only whitespace changes. Show changes Loading
lab1.c +67 −269 Original line number Diff line number Diff line Loading @@ -2,9 +2,6 @@ * Georgiana Diana Ciocirdel * Proiect PM 2015 - Guitar Tuner * * I am using bits of code from a 2007 project, written by Razvan Tataroiu. His * project can be found here: * https://sites.google.com/site/razvan784/proiectproiectareacumicroprocesoare */ #include "lcd.h" Loading Loading @@ -50,8 +47,7 @@ /******************************************************************************/ /* Tuner specific stuff. */ #define PRESCALER 64 #define MAX_QUEUE_LEN 254 #define PRESCALER 256 #define E 164.81 #define A 220.00 Loading @@ -60,35 +56,19 @@ #define B 493.88 #define EH 659.26 /* Two times the standard guitar guitar tunings as per * http://en.wikipedia.org/wiki/Guitar_tunings#Standard */ float std_fr[] = {164.81, 220.00, 293.66, 391.99, 493.88, 659.26}; char *str_std_fr[] = {"E ", "A ", "D ", "G ", "B ", "EH"}; char chosen_string = 0; unsigned char queue[254], start, stop, size; /* Circular queue for samples. */ #define LOG2 log(2.0) #define S_RATE ((float) F_CPU / 64.0 / 13.0) #define S_RATEI (F_CPU / 64 / 13) #define S_MIN_MAX (S_RATE / 10) unsigned int avg; char gain; char state; char top; char bot; char tmp_top; char tmp_bot; int count; int no_of_samples; int last_sample; float freq; char started; char err_disp; char ngainchg; char havetopbot; char txt[17]; char notes[36]="dC dC#rD rD#mE fF fF#sG sG#lA lA#tB "; /******************************************************************************/ /******************************************************************************/ void timer1_init (void) { TCCR1B |= (1 << CS12) | /* Prescaler = 256 */ (1 << WGM12); /* Clear on compare, TOP = OCR1A */ TIMSK1 |= ( 1<< OCIE1A); OCR1A = 31250; /* TOP */ } void LCD_clear (void) { LCD_printAt (FST_LINE_FST_CHAR, EMPTY_LINE); Loading @@ -104,19 +84,10 @@ void button_init (void) { PORT_BTN |= (1 << BIT_BTN); } void ADC_init (void) { /* Enable interrupt on PA7. */ DDRA |= (1 << PA7); ADMUX = (1 << REFS0) | /* Set VCC as reference. */ (1 << ADLAR) | /* Left-adjust the result in the ADC data register: * this saves the result in ADCH. */ ((1 << MUX0) | (1 << MUX1) | (1 << MUX2)); /* ADC7 as input. */ ADCSRA = (1 << ADEN) | /* Enable ADC. */ (1 << ADSC) | /* Enable free running conversions. */ (1 << ADATE) | /* Enable ADC autotrigger. */ (1 << ADIE) | /* Enable interruptions. */ (1 << ADPS2) | /* Set prescaler at 64. */ (1 << ADPS1); void input_init (void) { DDRB &= ~(1 << PB7); PCICR |= (1 << PCIE1); PCMSK1 |= (1 << PCINT15); } void wait_for (int millisecs) { Loading @@ -128,7 +99,7 @@ void wait_for (int millisecs) { } void refresh_snd_line (void) { LCD_printAt (SND_LINE_FST_CHAR + 7, "|"); LCD_printAt (SND_LINE_FST_CHAR, EMPTY_LINE); } void startup_LCD (void) { Loading @@ -137,10 +108,8 @@ void startup_LCD (void) { /* Display welcome message and toggle LED.*/ LCD_printAt (FST_LINE_FST_CHAR, "Welcome to"); LCD_printAt (SND_LINE_FST_CHAR, "Guitar Tuner"); //toggle_bit (PORT_LED, BIT_LED); toggle_bit (PORT_LED, BIT_LED); wait_for (2000); //toggle_bit (PORT_LED, BIT_LED); toggle_bit (PORT_LED, BIT_LED); LCD_clear (); Loading @@ -156,6 +125,10 @@ void startup_LCD (void) { LCD_printAt (FST_LINE_FST_CHAR, ""); } int count_down_up; int sum = 0; int count = 0; void move_cursor (void) { if ((PIN_BTN & (1 << BIT_BTN)) == 0) { chosen_string = (chosen_string + 1) % 6; Loading @@ -164,201 +137,14 @@ void move_cursor (void) { toggle_bit (PORT_LED, BIT_LED); wait_for (300); toggle_bit (PORT_LED, BIT_LED); } } /* * I am hereby using parts of code from Razvan Tataroiu's project from 2007. His * project can be found here: * https://sites.google.com/site/razvan784/proiectproiectareacumicroprocesoare */ void process_sample (char curr_sample) { int x16; /* Used for computations => we need more precission. */ char x; /* Will hold current sample value, after computations. */ /* Increment number of samples. */ no_of_samples++; /* Compute signal average with 20 bits precision: * avg = (avg * 4095 + (increased precision) smp ) / 4096 */ avg = ((avg << 12) - avg + ((unsigned int) curr_sample << 12)) >> 12; /* After a gain change wait to stabilize external circuit and average. */ if (ngainchg == FALSE) { //PORTD = 0xFF;//led on if (no_of_samples == 5 * S_MIN_MAX) { no_of_samples = 0; last_sample = 1; ngainchg = TRUE; tmp_top = 0; tmp_bot = 0; } else { return; } } /* Center on zero. */ x16 = (int) curr_sample - (int) (avg >> 12); //decrease precision to 8 bits /* Saturate. */ if (x16 < -128) { x16 = -128; } if (x16 > 127) { x16 = 127; } x = x16; //convert to 8 bits /* Compute top, bottom. */ if (x > tmp_top) { tmp_top = x; } if (x < tmp_bot) { tmp_bot = x; } /* Update top, bottom every 100ms. */ if (no_of_samples % (S_RATEI / 10) == 0) { top = tmp_top; bot = tmp_bot; tmp_top = 0; tmp_bot = 0; } /* Make at least one top, bot measurement after a gain change. */ if (havetopbot == FALSE) { if (no_of_samples == S_MIN_MAX) { havetopbot = TRUE; no_of_samples = 0; //PORTD = 0x7F;//led off } return; } /* Schmitt trigger. */ if (state == 1 && x < bot / 2) { state = 0; } if (state == 0 && x > top / 2) { state = 1; count++; /* transition count, and sample number of last transition */ last_sample = no_of_samples; } /* frequency relative error = 1 / (sample number) */ if (no_of_samples == 8192) { // 8-step external agc, hysterezis // perform agc change now, as next samples may come in delayed // due to float calculations and lcd display if (top == 127 || bot == -128) { // decrease gain if (gain != 0b00000000) { err_disp = FALSE; gain -= 0b00100000; PORTA = gain; ngainchg = FALSE; havetopbot = FALSE; } } if (top < 16 && bot > -16) { // increase gain if (gain != 0b11100000) { //limit gain to e.g. 3 if it picks up too much noise through // microphone. leave at 8 if using a lower noise setup (e.g. plugging an electric guitar) gain += 0b00100000; PORTA = gain; ngainchg = 0; havetopbot = 0; } else { if(top < 8) { if (err_disp == FALSE) { LCD_clear (); LCD_printAt (SND_LINE_FST_CHAR, "ERROR NO SIGNAL"); err_disp = TRUE; return; } } else { err_disp = 0; } } } // update frequency freq = S_RATE * count / last_sample; count_down_up = 0; sum = 0; count = 0; no_of_samples = 0; last_sample = 1; state = 0; // ftoa int frq = (int) freq; char frac = (char) ((freq - (float) frq) * 100); unsigned char ptr = 4; if (frq > 6000) { frq = 9999; } do { txt[--ptr] = '0' + frq % 10; frq /= 10; } while (frq > 0); while (ptr > 0) txt[--ptr] = ' '; txt[4]='.'; txt[5]='0' + (frac / 10); txt[6]='0' + frac % 10; //freq = 440 * 2^((note-57)/12), where note = 12 * octave /0..7/ + note_in_octave /0..11/ float note = 12.0 * log(freq/440.0) / LOG2 + 57; //again, long live avrlibc math if (note < 0) note = -0.4; if (note > 95.0) note = 95.4; //out of scale unsigned char rnote = (unsigned char) (note + 0.5); //nearest note float dif = note - (float) rnote; if(dif < -0.25) txt[7]='<'; else txt[7]=' '; if(dif < -0.01) txt[8]='<'; else txt[8]=' '; if(dif > 0.01) txt[14]='>'; else txt[14]=' '; if(dif > 0.25) txt[15]='>'; else txt[15]=' '; txt[13] = '0' + rnote / 12; rnote %= 12; rnote *= 3; txt[9] = notes[rnote]; txt[9] = notes[rnote]; txt[11] = notes[rnote + 1]; txt[12] = notes[rnote + 2]; LCD_clear (); LCD_printAt (SND_LINE_FST_CHAR, txt); } } int main() { char curr_sample; no_of_samples = 0; avg = 0; ngainchg = FALSE; int main (void) { count_down_up = 0; /* Init LED. */ LED_init (); Loading @@ -370,46 +156,58 @@ int main() { LCD_init (); startup_LCD (); /* Init interrupts and ADC. */ ADC_init (); /* Init input and timer. */ input_init (); timer1_init (); sei(); /* Infinite loop to run program. */ for (;;) { move_cursor (); wait_for (500); sei (); if (size > 0) { if(size >= MAX_QUEUE_LEN) { /* Signal an error on overflow. */ toggle_bit (PORT_LED, BIT_LED); LCD_printAt (FST_LINE_FST_CHAR, EMPTY_LINE); LCD_printAt (SND_LINE_FST_CHAR, "OVERFLOW ERROR"); /* Wait indefinetely. */ for(;;); } /* Disable interrupt for the moment, to avoid races. */ cli (); curr_sample = queue[start]; start = (start + 1) % MAX_QUEUE_LEN; size--; /* Reenable interrupts. */ sei (); /* Process current sample. */ process_sample (curr_sample); } } return 0; } /* * ADC Interrupt Routine. */ ISR (ADC_vect) { if (size < MAX_QUEUE_LEN) { /* Add ADC value to the queue in order to be processed. */ queue[stop] = ADCH; stop = (stop + 1) % MAX_QUEUE_LEN; size++; char buff[10]; ISR (PCINT1_vect) { if ((PINB & (1 << PB7)) == 0) { /* If there is a low-high transition */ count_down_up++; } } /* Timer interrupt. */ ISR (TIMER1_COMPA_vect) { sum += count_down_up; count++; if (count == 3) { refresh_snd_line (); toggle_bit (PORT_LED, BIT_LED); sum /= count; int diff = sum - std_fr[chosen_string]; char c = '-'; if (diff > 0) { c = '+'; } else if (diff == 0) { c = '0'; } int abs_diff = abs (diff); float percent = (float) abs_diff / (std_fr[chosen_string] * 2) * 100; int percent_i = (int) percent; itoa (percent_i, buff, 10); int n = strlen (buff); buff[n] = '%';; buff[n + 1] = c; buff[n + 2] = '\0'; LCD_printAt (SND_LINE_FST_CHAR, buff); LCD_printAt (FST_LINE_FST_CHAR + chosen_string * 3, ""); count = 0; sum = 0; } count_down_up = 0; }