Arduino OLED Spectrum Analyzer

 




Today I am make an Arduino OLED Spectrum Analyzer its work with 0 to 3.3v Analog input. This is very smooth and clear Visualization of audio frequencies. This is very important to make an audio spectrum analyser for DVD Music player, IPod, MP3 player and other Music player not only its look good it also represents any kind of music. You can make a box to fit it and attached in car or anywhere you want but I make just simple in breadboard.

Here is the complete video:



Note: This project is only for simple audio device, a Real Spectrum Analyser devices are use in Microwave signal, Radar Signal, Dish Antenna Signal, Cable frequencies Signal, etc. Do not try to use for these proposes your Arduino will burn or crash and it cause permanently Damage.

In this blog you are learning about a Arduino Spectrum Analyzer which follows:

>>SSD1306 Oled Display

>>Needed Parts

>>Libraries in we need to use

>>Super Easy Breadboard connection

>>Complete Code

SSD1306 Oled Display:

This very common and simple OLED Display for Arduino that very less count of Pin to connect in arduino that called I2C two wire interface the I2C stands for (I2C=IIC=Inter-Integrated Circuit) and OLED stands for Organic Light-Emitting Diodes. The size of this oled display is 0.96 inch that make it too much small and the total pixel is 128X64 px resolution you can convert a pic to bitmap and program to show in this display. In 16X2 LCD Display We need a backlight pin but in OLED this pin not required.

This is very simple to connect an OLED to Arduino Just follow these wiring:

OLED Pins  :    Arduino Pins

Vin             |        5V     //this is power Pin

GND           |        GND //this is GND Pin

SCL             |          A5     // this is I2C Pins

SDA            |          A4     //this is I2C Pins

Varieties of Arduino Pin If you use:

 Arduino Uno: SDA (A4), SCL (A5)

Arduino Nano: SDA (A4), SCL (A5)

Arduino Leonardo: SDA (20), SCL (21)

Arduino MEGA: SDA (20), SCL (21)

Parts :

Arduino Nano or https://amzn.to/2RTdsLe

Arduino Uno https://amzn.to/3cD1hcy

128x68 I2C OLED Display https://amzn.to/35iybec

Jumper Wires https://amzn.to/3xuOaCn

Breadboard https://amzn.to/35e2Klr

Libraries Used in This Project:

If you are beginner for this project, you need to download the Adafruit SSD1306 Master zip Library From here available in Github and also need one more Adafruit GFX Library master.zip also available in Github. Open Arduino IDE Software go to the sketch tab, then here click include library and click Add Zip Library here you can add your downloaded library you can also download and install from Manage Library Option just search these library in this box.



And Now for This Project need to download FIX_FFT.h master zip from here fix_fft.git and nano_engine.h library here: nano_engine.h (if you are already installed ssd1306 then Nano engine is not necessary or if not then paste it in new tab with same name).


Breadboard Connection:

This is very simple connection for Arduino Nano and oled. Here I am using 10k variable for adjust the volume of Music it connected with A0 pin and Audio input plug for connect with audio devices.



Audio Input:

Make sure always check voltage and current level in Analog Input of Arduino Board as Music or Sound Input, some amplifiers and Sound Devices are too much high Current as Output, do not plug on it. This Device needs only 3.8 to 4V and 40mA to 300mA Max voltage and current that come from mini portable amplifier, IPod, Portable Speaker, Mp3 Players, etc.

 Complete Code:

Here you can copy and paste the in your Arduino IDE Software:
This is a copyright code from ColonelWatch Github

// Copyright [2019] [colonelwatch]

#include <fix_fft.h>                  // 8-bit FFT library modified for Arduino
#include <ssd1306.h>                  // library for OLED
#include <nano_engine.h>             

// To get this program to operate, the SDA and SCL pins must be reassigned to 0 and 2 respectively in the library header file
// The file is located in libraries\ssd1306\src\intf\i2c\ssd1306_i2c_conf.h
// Make sure to undo this if the library will be used again in the future

// These are user-adjustable
//#define LOG_OUTPUT              // Uncomment to enable logarithmic output (exchanges absolute resoluton for more readable output; may require different below params)
#define SAMPLING_FREQUENCY 15000  // Sampling frequency (Actual max measured frequency captured is half)
#define TIME_FACTOR 3             // Smoothing factor (lower is more dynamic, higher is smoother) ranging from 1 to 10+
#define SCALE_FACTOR 12           // Direct scaling factor (raise for higher bars, lower for shorter bars)

#ifdef LOG_OUTPUT
const float log_scale = 64./log(64./SCALE_FACTOR + 1.);                              // Attempts to create an equivalent to SCALE_FACTOR for log function
#endif
const float coeff = 1./TIME_FACTOR;                                                  // Time smoothing coefficients (used to factor in previous data)
const float anti_coeff = (TIME_FACTOR-1.)/TIME_FACTOR;
const unsigned int sampling_period_us = round(1000000 * (2.0 / SAMPLING_FREQUENCY)); // Sampling period (doubled to account for overclock)

int8_t data[64], buff[32];                                     // used to store FFT input/output and past data
unsigned long microseconds;                                    // used for timekeeping
int summ, avg;                                                 // used for DC bias elimination

NanoEngine<TILE_32x32_MONO> engine;                            // declares nanoengine

void setup()
{
  OSCCAL = 240; // Overclocks the MCU to around 30 MHz, set lower if this causes instability, raise if you can/want
  
  ADCSRA &= ~(bit (ADPS0) | bit (ADPS1) | bit (ADPS2));       // clear ADC prescaler bits
  ADCSRA |= bit (ADPS2);                                      // sets ADC clock in excess of 10kHz
  ADCSRA |= bit (ADPS0);

  ssd1306_128x64_i2c_init();                                  // initializes OLED
  ssd1306_clearScreen();                                      // clears OLED
  
  engine.begin();                                             // inititalizes nanoengine
};

void loop()
{
  summ = 0;
  for (int i = 0; i < 64; i++) {
    microseconds = micros();
    
    data[i] = ((analogRead(A0)) >> 2) - 128;                        // Fitting analogRead data (range:0 - 1023) to int8_t array (range:-128 - 127)
    summ += data[i];
    while (micros() < (microseconds + sampling_period_us)) {        // Timing out uC ADC to fulfill sampling frequency requirement
    }
  }

  // Eliminating remaining DC component (produces usable data in FFT bin #0, which is usually swamped by DC bias)
  avg = summ/64;
  for (int i = 0; i < 64; i++){
    data[i] -= avg;
  }
    
  fix_fftr(data, 6, 0);                             // Performing real FFT
  
  // Time smoothing by user-determined factor and user-determined scaling
  for(int count = 0; count < 32; count++){
  if(data[count] < 0) data[count] = 0;                                          // Eliminating negative output of fix_fftr
  #ifdef LOG_OUTPUT
  else data[count] = log_scale*log((float)(data[count]+1));                     // Logarithmic function equivalent to SCALING_FACTOR*log2(x+1)
  #else
  else data[count] *= SCALE_FACTOR;                                             // Linear scaling up according to SCALE_FACTOR
  #endif
  data[count] = (float)buff[count] * anti_coeff + (float)data[count] * coeff;   // Smoothing by factoring in past data
  buff[count] = data[count];                                                    // Storing current output as next frame's past data
  if(data[count] > 63) data[count] = 63;                                        // Capping output at screen height
  }
  
  // Output to SSD1306 using nanoengine canvas from library
  engine.refresh();                                               // Mark entire screen to be refreshed
  engine.canvas.clear();                                          // Clear canvas as previous data
  for(int i = 0; i < 8; i++){
    engine.canvas.drawVLine(i*4,31-(data[i]+1),31);          // Draw to canvas data for lower-leftest sector (FFT bins 0 - 7, lower half)
  }
  engine.canvas.blt(0,32);                                        // Outputs canvas to OLED with an offset (x pixels, y pixels)
  engine.canvas.clear();
  for(int i = 0; i < 8; i++){
    if(data[i] > 31) engine.canvas.drawVLine(i*4,31-(data[i]-31),31);     // Draw to canvas data for upper-leftest sector (FFT bins 0 - 7, upper half)
  }
  engine.canvas.blt(0,0);
  engine.canvas.clear();
  for(int i = 8; i < 16; i++){
    engine.canvas.drawVLine((i-8)*4,31-(data[i]+1),31);      // FFT bins 8 - 15, lower half
  }
  engine.canvas.blt(32,32);  
  engine.canvas.clear();
  for(int i = 8; i < 16; i++){
    if(data[i] > 31) engine.canvas.drawVLine((i-8)*4,31-(data[i]-31),31);   // FFT bins 9 - 15, upper half
  }
  engine.canvas.blt(32,0);
  engine.canvas.clear();
  for(int i = 16; i < 24; i++){
    engine.canvas.drawVLine((i-16)*4,31-(data[i]+1),31);     // FFT bins 16 - 23, lower half
  }
  engine.canvas.blt(64,32);
  engine.canvas.clear();
  for(int i = 16; i < 24; i++){
    if(data[i] > 31) engine.canvas.drawVLine((i-16)*4,31-(data[i]-31),31);  // FFT bins 16 - 23, upper half 
  }
  engine.canvas.blt(64,0);
  engine.canvas.clear();
  for(int i = 24; i < 32; i++){
    engine.canvas.drawVLine((i-24)*4,31-(data[i]+1),31);     // FFT bins 24 - 31, lower half
  }
  engine.canvas.blt(96,32);
  engine.canvas.clear();
  for(int i = 24; i < 32; i++){
    if(data[i] > 31) engine.canvas.drawVLine((i-24)*4,31-(data[i]-31),31);  // FFT bins 24 - 31, upper half
  }
  engine.canvas.blt(96,0);
}

Now Enjoy Music!

Comments

  1. How would be the performance if Two oleds are used ?

    ReplyDelete
    Replies
    1. Not much but change some code and divide for two OLEDs one for Left channel and second for right channel audio.

      Delete
  2. Can I use in Car Amplifier.....?

    ReplyDelete
    Replies
    1. Yes You can but make sure use resistor or check current or voltage of input audio.

      Delete

Post a Comment

Have any doubt and problem Pls Comment..