/********************************************************************************************************************************************* Nitin William Arduino Audio FFT with OLED Adapted from learnelectronics:https://www.youtube.com/watch?v=5RmQJtE61zE Aadapted from cbm80amiga: https://www.youtube.com/watch?v=EnvhEgjrHsw https://github.com/GadgetReboot/Arduino/blob/master/Uno/Spectrum_Analyzer/Spectrum_Analyzer.ino https://sites.google.com/site/myscratchbooks/home/projects/proejct-20-oled-spectrum-analizer-using-max9812-microphone-amplifier **********************************************************************************************************************************************/ //Libraries #include <Wire.h> //IDE Standard #include <Adafruit_GFX.h> //Adafruit GFX https://github.com/adafruit/Adafruit-GFX-Library #include <Adafruit_SSD1306.h> //Adafruit SSD1306 https://github.com/adafruit/Adafruit_SSD1306 #include <fix_fft.h> //https://www.arduinolibraries.info/libraries/fix_fft const byte audioIn = A0; //Define analog pin for FFT char re[128], im[128]; //Real and Imaginary FFT result arrays byte yaxis = 63; //OLED y-axis drawing boundary limit byte xaxis = 0; //OLED x-axis limit Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire,-1); void setup() { Wire.begin(); //I2C Master pinMode(audioIn,INPUT); //Set A0 as analog input pin analogReference(DEFAULT); display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.setTextColor(WHITE); display.clearDisplay(); display.display(); } /* The FFT real/imaginary data are stored in a char data type as a signed -128 to 127 number This allows a waveform to swing centered around a 0 reference data point The ADC returns data between 0-1023 so it is scaled to fit within a char by dividing by 4 and subtracting 128. eg (0 / 4) - 128 = -128 and (1023 / 4) - 128 = 127 */ void loop() { for (byte i = 0; i < 128; i++) //Read 128 analog input samples from ADC { int sample = analogRead(audioIn); re[i] = sample / 4 - 128; //Scale the samples to fit within a char variable im[i] = 0; //There are no imaginary samples associated with the time domain so set to 0 } fix_fft(re, im, 7, 0); //Send the samples for FFT conversion, returning the real/imaginary results in the same arrays display_spectrum(); } /* For a 16 MHz Arduino the ADC clock is set to 16 MHz/128 = 125 KHz. Each conversion in AVR takes 13 ADC clocks so 125 KHz /13 = 9615 Hz. The data array will contain frequency bin data in locations 0..127 for samples up to the sampling frequency of approx. 9 KHz Each frequency bin will represent a center frequency of approximately (9 KHz / 128 samples) = 70 Hz Due to Nyquist sampling requirements, we can only consider sampled frequency data up to (sampling rate / 2) or (9 KHz / 2) = 4.5 KHz Therefore we only acknowledge the first 64 frequency bins [0..63] = [0..4.5KHz] */ void display_spectrum() { display.clearDisplay(); for (byte i = 1; i < 64; i++) { int dat = sqrt(re[i] * re[i] + im[i] * im[i]); //Frequency magnitude is the square root of the sum of the squares of the real and imaginary parts of a vector if (dat >= 32 ) dat = 32; display.drawLine(i * 2, yaxis, i * 2, yaxis - dat, WHITE);// draw bars for each frequency bin from 70 Hz to 4.5 KHz } display.setTextSize(2); display.setCursor(16,8); display.print("SPECTRUM"); display.display(); }