top of page

Arduino Code

This project uses a modified version of Amanda Ghassaei's code for Arduino Frequency Detection in order to get frequency readings using the Arduino. Before we explain more about how the code works, please keep in mind the changes we made to Amanda's original code:

  • Changing of the LED Arduino pins to accommodate for having only 7 LEDs - this is for a common anode display, all bit values should be inverted for a common cathode display.

  • Assigning the SSEG display pins so that the note of the guitar string played is displayed. When looking at the code and Segments table above, please note that this configuration is for a common anode display, so all bit values should be inverted for a common cathode display.

Code Explanation

Overall, the Arduino code analyzes a signal coming into the Arduino's analog input and determines the frequency. The code uses a sampling rate of 38.5kHz and is generalized for arbitrary wave shapes. Follow through the explanation of each method below for a better idea of how this code works.

​

The first method, setup(), assigns all of the pins we are using on the Arduino and clear ADCSRA and ADCSRB registers.

​

The second method, ISR(ADC_vect), calculates the new signal slope, midpoint, and period whenever the new ADC value is ready. By doing so, we make sure the peaks are always located where the pulse wave toggles between its high and low states. Notice that since we are measuring the incoming signal from A0 with 8 bit precision (0-255), the midpoint (2.5V) will give a value of 127.  All of this method's code takes place in the ADC interrupt (interrupts each time a new analog in value is ready from A0).

​

Next, we have reset() that just cleans out the index, noMatch, and maxSlope variables.

​

Then, there's stringCheck(). Here, we determine the correct frequency and light up the appropriate SSEG letter according to which string is being played. Note the ranges allowed for each string to be played:

A - 70-90

B - 100-120

C - 135-155

D - 186-205

E - 235-255

F - 320-340

​

Similarly, there's also frequencyCheck() that determines how far off the string is form the ideal frequency value of that note. Base on this, we light up the appropriate LED's to show how sharp or flat the note is.

​

There's also allLEDsOff() that simply turns all the LEDs and the SSEG display off.

​

Finally, there's loop(), which is where all the magic happens. Here, we start by turning all the LEDs off. Then, we can the calculate frequency timer rate/period so we can call stringCheck() and frequencyCheck() to display the tuner. This function occurs every time a string is played on the guitar.

Code Repository

To test out the code:

  1. Make sure to have Arduino Software (IDE) downloaded first.

  2. Then, copy and paste this code into the software package OR downloadn/clone the software from the public github repository.

  3. Once the code compiles, you can connect the Arduino to your computer to program the Arduino with software.

​

/*

  Group 4- Delta Force

  Guitar Tuner Code

  This code was originally from amandaghassaei ‘s method for Frequency Detection on Instructables.

  Our team made a  few changes including adding a SSEG display to display the note, which replaced 6 of

  the LED’s. For more information, please read our how-to website at

  https://deltaforce4.wixsite.com/howtodigitaltuner

*/

 

//data storage variables

 

byte newData = 0;

byte prevData = 0;

unsigned int time = 0; //keeps time and sends vales to store in timer[] occasionally

int timer[10]; //storage for timing of events

int slope[10]; //storage for slope of events

unsigned int totalTimer; //used to calculate period

unsigned int period; //storage for period of wave

byte index = 0; //current storage index

float frequency; //storage for frequency calculations

int maxSlope = 0; //used to calculate max slope as trigger point

int newSlope; //storage for incoming slope data

 

//variables for deciding whether you have a match

 

byte noMatch = 0; //counts how many non-matches you've received to reset variables if it's been too long

byte slopeTol = 3; //slope tolerance- adjust this if you need

int timerTol = 10; //timer tolerance- adjust this if you need

 

//variables for amp detection

 

unsigned int ampTimer = 0;

byte maxAmp = 0;

byte checkMaxAmp;

byte ampThreshold = 30; //raise if you have a very noisy signal

 

//variables for tuning

 

int correctFrequency; //the correct frequency for the string being played

 

void setup()

{

 

 Serial.begin(9600);

 

 //Set all LED pins and SSEG pins as outputs

 pinMode(7, OUTPUT);

 pinMode(6, OUTPUT);

 pinMode(5, OUTPUT);

 pinMode(4, OUTPUT);

 pinMode(3, OUTPUT);

 pinMode(2, OUTPUT);

 pinMode(A3, OUTPUT);

 pinMode(A4, OUTPUT);

 pinMode(A5, OUTPUT);

 pinMode(A1, OUTPUT);

 pinMode(A2, OUTPUT);

 pinMode(8, OUTPUT);

 pinMode(9, OUTPUT);


 

 //Beginning LED sequence

 digitalWrite(7, 1);

 digitalWrite(6, 1);

 digitalWrite(5, 1);

 digitalWrite(4, 1);

 digitalWrite(3, 1);

 digitalWrite(2, 1);

 digitalWrite(8, 1);

 analogWrite(A1, 255);

 delay(500);

 digitalWrite(9, 1);

 analogWrite(A2, 255);

 delay(500);

 digitalWrite(A5, 255);

 analogWrite(A3, 255);

 delay(500);

 analogWrite(A4, 255);

 delay(500);



 

 cli(); //disable interrupts

 

 //set up continuous sampling of analog pin 0 at 38.5kHz

 

 //clear ADCSRA and ADCSRB registers

 ADCSRA = 0;

 ADCSRB = 0;

 

 ADMUX |= (1 << REFS0); //set reference voltage

 ADMUX |= (1 << ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only

 

 ADCSRA |= (1 << ADPS2) | (1 << ADPS0); //set ADC clock with 32 prescaler- 16mHz/32=500kHz

 ADCSRA |= (1 << ADATE); //enabble auto trigger

 ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete

 ADCSRA |= (1 << ADEN); //enable ADC

 ADCSRA |= (1 << ADSC); //start ADC measurements

 

 sei(); //enable interrupts

} // end of setup()

 

ISR(ADC_vect)

{

 //when new ADC value ready

 

 PORTB &= B11101111; //set pin 12 low

 prevData = newData; //store previous value

 newData = ADCH; //get value from A0

 if (prevData < 127 && newData >= 127) //if increasing and crossing midpoint

 {

   newSlope = newData - prevData; //calculate slope

   if (abs(newSlope - maxSlope) < slopeTol) //if slopes are ==

   {

     //record new data and reset time

     slope[index] = newSlope;

     timer[index] = time;

     time = 0;

     if (index == 0) //new max slope just reset

     {

       PORTB |= B00010000; //set pin 12 high

       noMatch = 0;

       index++; //increment index

     }

     else if (abs(timer[0] - timer[index]) < timerTol && abs(slope[0] - newSlope) < slopeTol) //if timer duration and slopes match

     {

       //sum timer values

       totalTimer = 0;

       for (byte i = 0; i < index; i++)

       {

         totalTimer += timer[i];

       }

       period = totalTimer; //set period

       //reset new zero index values to compare with

       timer[0] = timer[index];

       slope[0] = slope[index];

       index = 1; //set index to 1

       PORTB |= B00010000; //set pin 12 high

       noMatch = 0;

     }

     else   //crossing midpoint but not match

     {

       index++; //increment index

       if (index > 9)

       {

         reset();

       }

     }

   }

   else if (newSlope > maxSlope) //if new slope is much larger than max slope

   {

     maxSlope = newSlope;

     time = 0; //reset clock

     noMatch = 0;

     index = 0; //reset index

   }

   else //slope not steep enough

   {

     noMatch++; //increment no match counter

     if (noMatch > 9)

     {

       reset();

     }

   }

 }

 

 time++; //increment timer at rate of 38.5kHz

 

 ampTimer++; //increment amplitude timer

 if (abs(127 - ADCH) > maxAmp)

 {

   maxAmp = abs(127 - ADCH);

 }

 if (ampTimer == 1000)

 {

   ampTimer = 0;

   checkMaxAmp = maxAmp;

   maxAmp = 0;

 }

 

}

 

void reset() //clean out some variables

{

 index = 0; //reset index

 noMatch = 0; //reset match couner

 maxSlope = 0; //reset slope

} // end of reset()

 

//Determine the correct frequency and light up

//the appropriate LED for the string being played

void stringCheck()

{

 if (frequency > 70 & frequency < 90)

 {

   digitalWrite(2, 1);    //Every digitalWrite in the stringCheck()

   digitalWrite(3, 0);    //function was added

   digitalWrite(4, 0);

   digitalWrite(5, 0);

   digitalWrite(6, 0);

   digitalWrite(7, 1);

   correctFrequency = 82.4;

 }

 if (frequency > 100 & frequency < 120)

 {

   digitalWrite(2, 1);

   digitalWrite(3, 0);

   digitalWrite(4, 0);

   digitalWrite(5, 0);

   digitalWrite(6, 1);

   digitalWrite(7, 0);

   correctFrequency = 110;

 }

 if (frequency > 135 & frequency < 155)

 {

   digitalWrite(2, 1);

   digitalWrite(3, 0);

   digitalWrite(4, 1);

   digitalWrite(5, 0);

   digitalWrite(6, 0);

   digitalWrite(7, 0);

   correctFrequency = 146.8;

 }

 if (frequency > 186 & frequency < 205)

 {

   digitalWrite(2, 1);

   digitalWrite(3, 0);

   digitalWrite(4, 0);

   digitalWrite(5, 1);

   digitalWrite(6, 0);

   digitalWrite(7, 0);

   correctFrequency = 196;

 }

 if (frequency > 235 & frequency < 255)

 {

   digitalWrite(2, 1);

   digitalWrite(3, 0);

   digitalWrite(4, 0);

   digitalWrite(5, 0);

   digitalWrite(6, 0);

   digitalWrite(7, 0);

   correctFrequency = 246.9;

 }

 if (frequency > 320 & frequency < 340)

 {

   digitalWrite(2, 1);

   digitalWrite(3, 0);

   digitalWrite(4, 0);

   digitalWrite(5, 0);

   digitalWrite(6, 0);

   digitalWrite(7, 1);

   correctFrequency = 329.6;

 }

}

 

//Compare the frequency input to the correct

//frequency and light up the appropriate LEDS

void frequencyCheck()

{

 if (frequency > correctFrequency + 1)

 {

   analogWrite(A3, 255);

 }

 if (frequency > correctFrequency + 4)

 {

   analogWrite(A2, 255);

 }

 if (frequency > correctFrequency + 6)

 {

   analogWrite(A1, 255);

 }

 if (frequency < correctFrequency - 1)

 {

   analogWrite(A5, 255);

 }

 if (frequency < correctFrequency - 4)

 {

   digitalWrite(9, 1);

 }

 if (frequency < correctFrequency - 6)

 {

   digitalWrite(8, 1);

 }

 if (frequency > correctFrequency - 1 & frequency < correctFrequency + 1)

 {

   analogWrite(A4, 255);

 }

} // end of frequencyCheck()

 

void allLEDsOff()

{

 digitalWrite(2, 1);  // digitalWrite for pins 2-7 are additions to original code

 digitalWrite(3, 1);

 digitalWrite(4, 1);

 digitalWrite(5, 1);

 digitalWrite(6, 1);

 digitalWrite(7, 1);  

 digitalWrite(8, 0);

 digitalWrite(9, 0);

 analogWrite(A1, 0);

 analogWrite(A2, 0);

 analogWrite(A3, 0);

 analogWrite(A4, 0);

 analogWrite(A5, 0);

} // end of all LEDsOff()

 

void loop()

{

 

 allLEDsOff();

 

 if (checkMaxAmp > ampThreshold)

 {

   frequency = 38462 / float(period); //calculate frequency timer rate/period

 }

 

 stringCheck();

 frequencyCheck();

 

 delay(100);

 

} // end of loop()

©2017 BY ARDUINO DIGITAL GUITAR TUNER. PROUDLY CREATED WITH WIX.COM

bottom of page