ECE 4180 Tuner Spring 2019
Team Members
Trent Hobbs
Adar Leibovitch
Collin Rusch
Gabriel Trevino Santos
Project Overview
The goal of this project is to build an instrument tuner which will read in a note being played and return the frequency. The frequency of the note is calculated using an FFT algorithm sampling at 4 kHz. The sampled note is then displayed on the LCD screen along with a graph to show the user how close to the desired frequency they are. The current note being tuned can also be played through a speaker so the user can tune their instrument by ear. Pushbuttons add functionality to select what note the user is trying to tune. The current code will correctly calculate frequencies up to 2 kHz and play any notes from A0 to B8.
Parts List
- mbed LPC1768 https://os.mbed.com/platforms/mbed-LPC1768/
- Electret Microphone Amplifier - MAX4466 with Adjustable Gain https://os.mbed.com/components/Electret-Microphone-MAX4466-Amplifier/
- uLCD-144-G2 128 by 128 Smart Color LCD https://os.mbed.com/users/4180_1/notebook/ulcd-144-g2-128-by-128-color-lcd/
- TPA2005D1 Class D Audio Amp https://os.mbed.com/users/4180_1/notebook/tpa2005d1-class-d-audio-amp/
- Speaker - PCB Mount https://www.sparkfun.com/products/11089
- x5 Pushbuttons https://os.mbed.com/users/4180_1/notebook/pushbuttons/
Schematic
Libraries Used
mbed - https://os.mbed.com/users/mbed_official/code/mbed/
MAX4466 - https://os.mbed.com/users/mgolino/code/MAX4466/
FFT - https://os.mbed.com/users/zchen78/code/FFT/
mbed-rtos - https://os.mbed.com/teams/ST/code/mbed-rtos/
4DGL-uLCD-SE - https://os.mbed.com/users/4180_1/code/4DGL-uLCD-SE/
Pin Detect - https://os.mbed.com/users/AjK/code/PinDetect/
Source Code
main.cpp
#include "mbed.h" #include "MAX4466.h" #include "FFT.h" #include "rtos.h" #include "uLCD_4DGL.h" #include "PinDetect.h" #include <string> #include <math.h> PinDetect pb1(p6); PinDetect pb2(p7); PinDetect pb3(p8); PinDetect pb4(p9); DigitalIn pb5 (p10); MAX4466 mic(p15); PwmOut speaker(p21); uLCD_4DGL uLCD(p28,p27,p30); Timer tim; #define MAX_NOTE 11 #define MAX_OCT 8 std::string notes[] = {"C","C#/Db","D","D#/Eb","E","F","F#/Gb","G","G#/Ab","A","A#/Bb","B"}; float notefreqs[] = {16.35,17.32,18.35,19.45,20.60,21.93,23.12,24.50,25.96,27.50,29.14,30.87}; volatile float readfreq = 0.00; volatile int octave = 0; volatile int indx = 0; void pb1_note_down(void) { if(!pb1) { indx -= 1; if (indx < 0) { indx = MAX_NOTE; } } } void pb2_note_up (void) { if(!pb2) { indx += 1; if (indx > MAX_NOTE) { indx = 0; } } } void pb3_oct_down (void) { if(!pb3) { octave -= 1; if (octave < 0) { octave = MAX_OCT; } } } void pb4_oct_up (void) { if(!pb4) { octave += 1; if (octave > MAX_OCT) { octave = 0; } } } //Plays speaker at desired frequency selected by user void playspeaker(void const *arguments) { while (1) { speaker.period(1.0/(notefreqs[indx] * pow(2.0f,octave))); speaker = 0.0; while(!pb5) { speaker = 0.5; } speaker = 0.0; Thread::wait(100); } } //Print frequencies of notes, detected freq, and circle display graphic to LCD void ulcd(void const *arguments) { int cx; int old_i = 0; int old_oct= 0; int i; int oct; while(1) { i = indx; oct = octave; if (old_oct != oct) { old_oct = oct; uLCD.locate(1,7); uLCD.printf(" "); } if (old_i != i) { old_i = i; uLCD.locate(1,7); uLCD.printf(" "); uLCD.locate(1,3); uLCD.printf(" "); } uLCD.locate(1,3); uLCD.printf("%s%D", notes[i], oct); uLCD.locate(1,7); uLCD.printf("%.2f Hz.", notefreqs[i] * pow(2.0f,oct)); uLCD.locate(1,14); uLCD.printf("%.2f Hz.", readfreq); uLCD.filled_circle(108, cx, 5, BLACK); if (readfreq <= (notefreqs[i] * pow(2.0f,oct))+ 5 && readfreq >= (notefreqs[i] * pow(2.0f,oct)) - 5) { cx = 64; uLCD.line(88, 64, 128, 64, GREEN); uLCD.filled_circle(108, cx, 5, GREEN); } else { cx = 64 + (notefreqs[i] * pow(2.0f,oct)) - readfreq; if (cx < 0) { cx = 0; } else if (cx > 128) { cx = 128; } uLCD.line(88, 64, 128, 64, RED); uLCD.filled_circle(108, cx, 5, RED); } Thread::wait(10); } } int main() { //set up pindetect pb1.mode(PullUp); pb2.mode(PullUp); pb3.mode(PullUp); pb4.mode(PullUp); pb5.mode(PullUp); wait(0.01); pb1.attach_deasserted(&pb1_note_down); pb2.attach_deasserted(&pb2_note_up); pb3.attach_deasserted(&pb3_oct_down); pb4.attach_deasserted(&pb4_oct_up); pb1.setSampleFrequency(); pb2.setSampleFrequency(); pb3.setSampleFrequency(); pb4.setSampleFrequency(); //set intial lcd values uLCD.background_color(BLACK); uLCD.baudrate(3000000); uLCD.line(88, 0, 88, 128, WHITE); uLCD.color(WHITE); uLCD.locate(1,1); uLCD.printf("Note:"); uLCD.locate(1,5); uLCD.printf("Note Freq:"); uLCD.locate(1,12); uLCD.printf("Read Freq:"); //launch threads Thread ulcd_thread(&ulcd); Thread speaker_thread(&playspeaker); //set up main thread int samples = 1024; float arr [samples+1]; arr[0] = 0; float max = 0; float loc = 0; float freq; osThreadSetPriority(osThreadGetId(), osPriorityHigh); //Loop and constantly be finding frequency of signal while (1) { tim.reset(); tim.start(); for (int i = 1; i<=samples; i++){ arr[i] = mic.instantlevel(); //Sample microphone at ~4 Khz wait(.00025); } tim.stop(); freq = samples/tim.read(); //Turn sampled array into its fourier transform vRealFFT(arr,samples); //Loop through and find most apparent frequency of sampled signal for(int i = 2; i<=samples; i++){ arr[i] *= arr[i]; if(max<arr[i]){ loc = freq/samples * i/2; //determine frequency by using sample rate,index in array max = arr[i]; } } readfreq = loc; max=0; wait(0.25); Thread::wait(100); } }
Import Program
Photos
Videos
Please log in to post comments.