Digital Guitar Tuner

Eric Tai | Daniel Tsui

ECE 476: Spring 2005

 

Introduction | High Level Design | Program/Hardware Design | Results | Conclusions | Appendix

 

Appendix

 

Appendix A:  Commented program listing

//time base will be 10e-4

//stuff that needs to be added in:

//

//

//PORT hookups:

//Port A: ADC  

//Port B: LED outputs

//Port D: pushbutton inputs

 

#asm

    .equ __lcd_port=0x15

#endasm

#include <lcd.h> // LCD driver routines

 

 

#include <Mega32.h>

 

#include <stdio.h>

 

#define begin {

#define end   } 

                 

//signal timer state machine

#define start 1

#define counting 2  

//pushbutton state machine

#define release 1

#define debounce 2

#define detect_t 3

#define done 4

#define still_p 5

#define debounce_r 6    

 

  

 

//guitar frequencies

#define E2 12134           // period in us.  E2 period is 12134x10^-6

#define A2 9090

#define D3 6180

#define G3 5102

#define B3 4049

#define E4 3033

 

#define STIME 2

#define BUTTONTIME 500  //ever 50ms

 

#define mult(a,b) ((char)((((long)(a))*((long)(((int)b)<<8)))>>16))  //multiply 8-bit integer by 8-bit fraction

 

//declaring functions     

 

char lcd_buffer[17];

 

void initialize(void);

void pollbuttons(void);

void dosignal(void);

void eval_timer(void);  

 

 

//variables

unsigned char x, lastx, y, lasty;        //raw A to D number           

 

float a,b;

                          

char state, buttonstate, count;                        //timing state machine    

unsigned int timer, endtime;                    //unsigned int from 0 to 65535     

char threshold, thres;

//counters

char signal_time;     

char led;

char buttons, maybe;                     //store states for pushbutton

int stringval;                                         //the string being hit

 

int time1;                          //timer1

unsigned int temp;

 

unsigned int lower2, upper2, lower1, upper1, lower0, upper0, cal;

 

//*****************************************************

//timer 0 compare ISR

interrupt [TIM0_COMP] void timer0_compare(void)

begin

   

       if (time1 > 0) --time1;   

    if (signal_time > 0) --signal_time;      

    timer++;

end                                                 

 

 

//*******************************************************

 

void initialize(void)

begin

          lcd_init(16);

 

 //init the A to D converter

   TIMSK = 2;

   OCR0 = 25;            //count up to 25  

 

   TCCR0=0b000001011;      //prescale by 64

   ADMUX = 0b01100000;          //enable ADC and set prescaler to 1/128*16MHz=125,000

                                                       //user internal vref

                                                       //and clear interupt enable

                                                       //and start a conversion

   ADCSR = 0b11000111;

  

   //initialize buttons

   DDRB = 0xff;                                 //output LED's

   PORTB = 0x00;                         //start all off  

   DDRD = 0x00;                                 //input pushbuttons      

   PORTD = 0xff;       

  

   //initialize variables                     

   time1 = BUTTONTIME;

   signal_time = STIME;   

   threshold = 127;                      //digitized value for zero ----CHANGE THIS VALUE

   thres = 0;                            // the amount of leeway on tuning

   led = 0x00;

   PORTB = ~led;      

   state = start;

 

       b=0.0305;

       a=0.9391;

  

       buttonstate = release;           

       upper0 = 0;

       upper1 = 0;

       upper2 = 0;

       lower0 = 0;

       lower1 = 0;

       lower2 = 0;

       #asm

       sei

       #endasm

       temp = 0;

       count=0;

end

 

void pollbuttons(void)              

//function: to set the correct string that is being checked.  Can occur every 30 ms.  We will have to debounce.

begin 

                                                                                                              

       time1 = BUTTONTIME;     

       buttons = PIND;

    //debounce

       switch (buttonstate)

        begin  

                case release:

                //PORTB = 0b11111111;

                        //pushbuttons not pressed

                      if (buttons != 0xff)  //if something pressed

                           begin

                           maybe = buttons;     //keep old buttonpressed number

                           buttonstate = debounce;    //change states      

                          

                        end

                break;

               

                case debounce:

                                  //is pushbuttons pressed?                           

                    if (buttons == maybe) buttonstate = still_p;           //button pressed 

                    else buttonstate = release;//button not pressed

                break;

 

                case still_p:

                //press confirmed

               

                     if (buttons == maybe)             //button IS pressed

                     begin

                        switch (buttons)               //button capture    

                        begin

                                  case 0b11111110:

                                         stringval = E2;     

                                         PORTB = 0b11111110;   

                                         lcd_clear();

                                                       lcd_gotoxy(0,0);

                                                       sprintf(lcd_buffer,"String E2");

                                                       lcd_puts(lcd_buffer);

                                         b=0.0450;

                                         a=0.9099;

                                         //passing frequency bounds

                                         upper2 = 2527;

                                         upper1 = 2498;

                                         upper0 = 2470;

                                         lower0 = 2386;

                                         lower1 = 2358;

                                         lower2 = 2331;

                                         cal=20;   

                                         threshold = 127;

                                         break;     

                                  case 0b11111101:

                                         stringval = A2;     

                                         lcd_clear();

                                                       lcd_gotoxy(0,0);

                                                       lcd_putsf("String A2");

                                         b=0.0592;

                                         a=0.8816;  

                                         //passing frequency bounds

                                         upper2 = 1893;

                                         upper1 = 1871;

                                      upper0 = 1850;

                                         lower0 = 1786;

                                         lower1 = 1766;

                                      lower2 = 1476;

                                         cal=30;

                                         threshold = 127;

                                         break;

                                  case 0b11111011:

                                         stringval = D3;     

                                         lcd_clear();

                                                       lcd_gotoxy(0,0);

                                                       lcd_putsf("String D3");   

                                         b=0.0797;

                                         a=0.8406;

                                         //passing frequency bounds

                                         upper2 =  1419;

                                         upper1 =  1402;

                                      upper0 =  1386;

                                         lower0 =  1339;

                                         lower1 =  1324;

                                      lower2 =  1308;

                                      cal=30;         

                                      threshold = 127;

                                         break;    

                                  case 0b11110111:

                                         stringval = G3;     

                                         lcd_clear();

                                                       lcd_gotoxy(0,0);

                                                       lcd_putsf("String G3");   

                                         b=0.0730;

                                         a=0.8541;

                                         //passing frequency bounds

                                         upper2 = 1062;

                                         upper1 = 1050;

                                      upper0 = 1038;

                                         lower0 = 1003;

                                         lower1 = 991;

                                      lower2 = 980;

                                      cal=10;     

                                      threshold = 80;

                                         break;

                                  case 0b11101111:

                                         stringval = B3;     

                                         lcd_clear();

                                                       lcd_gotoxy(0,0);

                                                       lcd_putsf("String B3");   

                                         b=0.1270;

                                         a=0.7459;

                                         //passing frequency bounds

                                         upper2 = 843;

                                         upper1 = 834;

                                      upper0 = 824;

                                         lower0 = 796;

                                         lower1 = 787;

                                      lower2 = 778;

                                      cal=10;    

                                      threshold = 127;

                                         break;

                                  case 0b11011111:

                                         stringval = E4;

                                         lcd_clear();

                                                       lcd_gotoxy(0,0);

                                                       lcd_putsf("String E4");   

                                         b=0.1648;

                                         a=0.6705; 

                                         //passing frequency bounds

                                         upper2 = 632;

                                         upper1 = 624;

                                      upper0 = 617;

                                         lower0 = 596;

                                         lower1 = 589;

                                      lower2 = 583;

                                      cal=10;

                                      threshold = 127;

                                         break;

                                        

                                  default:      break;

                           end

                     end

                     else buttonstate = debounce_r;          

                break;

               

                case debounce_r:

                     if (buttons == maybe) buttonstate = still_p;

                                  else buttonstate = release;

                break;

        end         //switch   */

end         //pollbuttons

 

 

void dosignal(void)                                       

//to filter then time the input frequency.  Needs to be occurring every 1 microsecond. 

begin

       signal_time = STIME;

       lastx=x;

       lasty=y;

       x=ADCH; //get signal

       ADCSR.6=1; //get next sample

       endtime=timer; //get current timer value for the period

       //digital filter

       y=((char)(b*x+b*lastx+a*lasty));

 

      

       if(lasty<threshold && y > threshold)      //cross zero from negative to positive

       begin

              count++;

              if(count==20)

              begin

                     eval_timer(); //check if timer value is in bounds

                     count=0;

                     timer=0;      //reset timer and begin measurement for next 20 periods

              end     

       end

 

end

                            

void eval_timer(void)

begin          

            endtime = endtime + cal;

            lcd_clear();             

                     lcd_gotoxy(0,0);

                     sprintf(lcd_buffer,"targ: %d-%d",lower0,upper0);

                     lcd_puts(lcd_buffer);

                     lcd_gotoxy(0,1);

                     sprintf(lcd_buffer,"%d",endtime);

                     lcd_puts(lcd_buffer);

                     if      (endtime > lower0 && endtime < upper0) PORTB = 0b11110111;   //light up middle LED

                     else if (endtime > upper0 && endtime < upper1) PORTB = 0b11111011;    //light up +30 cent

              else if (endtime > upper1 && endtime < upper2) PORTB = 0b11111101;       //light up +50 cent

              else if (endtime > upper2)                      PORTB = 0b11111110;        //light up +70cent

               else if (endtime > lower1 && endtime < lower0)    PORTB = 0b11101111;   //light up -30 cent

               else if (endtime > lower2 && endtime < lower1)    PORTB = 0b11011111;    //-50

               else if (endtime < lower2)                     PORTB = 0b10111111;       //-70

      

end

                                        

 

void main(void)

begin

       initialize();

   // measure and display loop

   while (1)

   begin  

       if(signal_time==0)   dosignal();  //get and process signal

       if(time1==0) pollbuttons();      //get input from buttons

  end

end

    

 

Appendix B:  Schematics

Figure: Flow Diagram

 

Picture: Completed Circuit

 

Appendix C:  Cost details with all part numbers and their price.

 This cost will include components supplied by the lab, including MCU and power supplies but excluding the STK500.

Item

Cost

1 x breadboard

6.00

1 x Power Supply

5.00

1 x Mega32

8.00

1 x LCD Display (16x2)

8.00

1 x Custom PC Board

5.00

11 x Resistors

0.11

2 x Capacitors

0.50

2 x 1N914 Diodes

0.02

1 x LMC7111 Op Amp

1.55

1 x Audio Jack

2.00

2 x Solder-linked breadboards

5.00

TOTAL:

41.18

 

Appendix D:  Specific Tasks

            Programming Code – ejt22, ddt7.

            Analog Op Amp – ddt7, etj22.

            Digital Filter – ddt7

            Web Site – ejt22.

            Pushbuttons and LCD – ejt22, ddt7

 

Appendix E:  References

Data sheets

LCD Display

LMC7111 Op Amp

MEGA32

 

 

Vendor sites

Radio Shack.  www.radioshack.com

 

Background sites/papers

Reeves, Galen and Dimitry Berenson.  “Digital Guitar Tuner”. Spring 2004. http://instruct1.cit.cornell.edu/courses/ee476/FinalProjects/s2004/ddb25/index.htm

 

Wolfe, Joe.  “Note Names, MIDI Numbers and Frequencies.”  http://www.phys.unsw.edu.au/~jw/notes.html