Spectrum analyzer 16 bands

Hi everyone, i tried to redo a project i found on the internet. The goal is to make a spectrum sound analyzer using FFT. In the project i found, the person used 4 in 1 display. I have the same exact components except i have 2 Max712 instead of 4. I thought it was only a matter of coding as i just have to half certain values to match it.
Here's the code

#include <arduinoFFT.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include <EEPROM.h>

#define SAMPLES 32                          // Must be a power of 2
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW   // Set display type  so that  MD_MAX72xx library treets it properly
#define MAX_DEVICES  2                      // Total number display modules
#define CLK_PIN   13                        // Clock pin to communicate with display
#define DATA_PIN  11                        // Data pin to communicate with display
#define CS_PIN    10                        // Control pin to communicate with display
#define  xres 16                            // Total number of  columns in the display, must be <= SAMPLES/2
#define  yres 8                             // Total number of  rows in the display

int audio_response = 12;                                              // put a value between 10 and 80. Smaller the number, higher the audio response

int MY_ARRAY[]={0, 128, 192, 224, 240, 248, 252, 254, 255};           // default = standard pattern
int MY_MODE_1[]={0, 128, 192, 224, 240, 248, 252, 255, 255};          // standard pattern
int MY_MODE_2[]={0, 128, 64, 32, 16, 8, 4, 2, 1};                     // only peak pattern
int MY_MODE_3[]={0, 128, 192, 160, 144, 136, 132, 130, 129};          // only peak +  bottom point
int MY_MODE_4[]={0, 128, 192, 160, 208, 232, 244, 250, 253};          // one gap in the top , 3rd light onwards
int MY_MODE_5[]={0, 1, 3, 7, 15, 31, 63, 127, 255};                   // standard pattern, mirrored vertically

 
double vReal[SAMPLES];
double vImag[SAMPLES];
char data_avgs[xres];

int yvalue;
int displaycolumn , displayvalue;
int peaks[xres];
const int buttonPin = 5;             // the number of the pushbutton pin
int state = HIGH;                    // the current reading from the input pin
int previousState = LOW;             // the previous reading from the input pin
int displaymode = 1;
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers


MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);   // display object
arduinoFFT FFT = arduinoFFT();                                    // FFT object
 


void setup() {
    EEPROM.update(1,1);                                           //(memory address, value), RUN THIS FOR THE FIRST TIME
    displaymode = EEPROM.read(1);
    ADCSRA = 0b11100101;                                          // set ADC to free running mode and set pre-scalar to 32 (0xe5)
    ADMUX = 0b00000000;                                           // use pin A0 and external voltage reference
    pinMode(buttonPin, INPUT);
    mx.begin();                                                   // initialize display
    delay(50);                                                    // wait to get reference voltage stabilized
    
}
 
void loop() {
   // ++ Sampling
   for(int i=0; i<SAMPLES; i++)
    {
      while(!(ADCSRA & 0x10));                // wait for ADC to complete current conversion ie ADIF bit set
      ADCSRA = 0b11110101 ;                   // clear ADIF bit so that ADC can do next operation (0xf5)
      int value = ADC - 256 ;                 // Read from ADC and subtract DC offset caused value(ADC - SAMPLES x 8)
      vReal[i]= value/8;                      // Copy to bins after compressing
      vImag[i] = 0;                         
    }
    // -- Sampling

 
    // ++ FFT
    FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
    FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
    FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
    // -- FFT

    
    // ++ re-arrange FFT result to match with no. of columns on display ( xres )
    int step = (SAMPLES/2)/xres; 
    int c=0;
    for(int i=0; i<(SAMPLES/2); i+=step)  
    {
      data_avgs[c] = 0;
      for (int k=0 ; k< step ; k++) {
          data_avgs[c] = data_avgs[c] + vReal[i+k];
      }
      data_avgs[c] = data_avgs[c]/step; 
      c++;
    }
    // -- re-arrange FFT result to match with no. of columns on display ( xres )

    
    // ++ send to display according measured value 
    for(int i=0; i<xres; i++)
    {
      data_avgs[i] = constrain(data_avgs[i],0,80);               // set max & min values for buckets
      data_avgs[i] = map(data_avgs[i], 0, 80, 0, yres);          // remap averaged values to yres
      yvalue=data_avgs[i];

      peaks[i] = peaks[i]-1;    // decay by one light
      if (yvalue > peaks[i]) 
          peaks[i] = yvalue ;
      yvalue = peaks[i];    
      displayvalue=MY_ARRAY[yvalue];
      displaycolumn=31-i;
      mx.setColumn(displaycolumn, displayvalue);               // for left to right
     }
     // -- send to display according measured value 
     
    displayModeChange ();                                      // check if button pressed to change display mode
} 

void displayModeChange() {
  int reading = digitalRead(buttonPin);
  if (reading == HIGH && previousState == LOW && millis() - lastDebounceTime > debounceDelay) // works only when pressed
  
  {

   switch (displaymode) {
    case 1:    //       move from mode 1 to 2
      displaymode = 2;
      EEPROM.update(1,2);
      for (int i=0 ; i<=8 ; i++ ) {
        MY_ARRAY[i]=MY_MODE_2[i];
      }
      break;
    case 2:    //       move from mode 2 to 3
      displaymode = 3;
      EEPROM.update(1,3);
      for (int i=0 ; i<=8 ; i++ ) {
        MY_ARRAY[i]=MY_MODE_3[i];
      }
      break;
    case 3:    //     move from mode 3 to 4
      displaymode = 4;
      EEPROM.update(1,4);
      for (int i=0 ; i<=8 ; i++ ) {
        MY_ARRAY[i]=MY_MODE_4[i];
      }
      break;
    case 4:    //     move from mode 4 to 5
      displaymode = 5;
      EEPROM.update(1,5);
      for (int i=0 ; i<=8 ; i++ ) {
        MY_ARRAY[i]=MY_MODE_5[i];
      }
      break;
    case 5:    //      move from mode 5 to 1
      displaymode = 1;
      EEPROM.update(1,1);      
      for (int i=0 ; i<=8 ; i++ ) {
        MY_ARRAY[i]=MY_MODE_1[i];
      }
      break;
  }

    lastDebounceTime = millis();
  }
  previousState = reading;
}

But it is not really working, the leds matrix do not even light up.
I tested separately all my components and they work. Tested the microphone while adjusting the potentiometer with a simple led using the clapping project(where you make a sound and see if the led light on and off).
I do not see where the problem is, could you help me along the way please ?

Have you mastered how to use the display? For example, can you light up any individual pixel, create bars, etc.?

Does the FFT produce reasonable results? Print out the frequency and amplitude values for various test tones.

Hello no, it's the first time i've used this kind of display, it's a project for uni. Normally i would use the LCD1602 module included in the elegoo arduino pack. but i just reckoned it was the same way it worked ? And that is the reason why i wanted to start from something working and try to build from that.
As for the frequency measures and amplitude, how should i print it out ? I never coded on arduino before but i did code in C.

You have to completely understand how to use the display, and use the FFT, before you can hope to get this project working.

There are plenty of FFT tutorials to study. For something as simple as 16 bands, I recommend the OpenMusicLabs library for AVR-based Arduinos, like the Uno.

Example of generating a tone signal, transforming it, and printing out a spectrum.

/*
 fft_test_sine
 example sketch for testing the OpenMusicLabs fft library.
 This generates a simple sine wave data set consisting
 of two frequences f1 and f2, transforms it, calculates 
 and prints the amplitude of the transform.
 */

// do #defines BEFORE #includes
#define LIN_OUT 1 // use the linear output function
#define FFT_N 64 // set to 64 point fft

#include <FFT.h> // include the library

void setup() {
  Serial.begin(9600); // output on the serial port
  int i,k;
  float f1=2.0,f2=5.0;  //the two input frequencies (bin values)

  for (i = 0 ; i < FFT_N ; i++) { // create samples

    // amplitudes are 1000 for f1 and 500 for f2
    k=1000*sin(2*PI*f1*i/FFT_N)+500.*sin(2*PI*f2*i/FFT_N);

    fft_input[2*i] = k; // put real data into even bins
    fft_input[2*i+1] = 0; // set odd bins to 0
  }
  
//  fft_window();  //Try with and without this line, it smears

  fft_reorder(); // reorder the data before doing the fft
  fft_run(); // process the data using the fft
  fft_mag_lin(); // calculate the magnitude of the output

  // print the frequency index and amplitudes

  Serial.println("bin  amplitude");
  for (i=0; i<FFT_N/2; i++) {
    Serial.print(i);
    Serial.print("       ");
    Serial.println(2*fft_lin_out[i]); //*2 for "negative frequency" amplitude
  }
  Serial.println("Done");
}

void loop() {}

Thanks, i'll get into it and try to see if the FFT works, for the display, i'm pretty confident in knowing how to use it if it's the same as in C programming

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.