Commit 5045c63f authored by Georgiana-Diana CIOCÎRDEL's avatar Georgiana-Diana CIOCÎRDEL
Browse files

Finished project

parent ccc926d2
Loading
Loading
Loading
Loading
+67 −269
Original line number Diff line number Diff line
@@ -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"
@@ -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
@@ -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);
@@ -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) {
@@ -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) {
@@ -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 ();

@@ -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;
@@ -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 ();
@@ -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;
}
+1 −1

File changed.

Contains only whitespace changes.