Array based issue for VU meter code- I think! MSGEQ7 & 74HC595

Hi all. I’m making a 7 band VU meter. Using a MSGEQ7, and some 74hc595 shift registers with the shiftPWM library.

I have got it working nicely for frequency 1 band (spectrumValue[1]) scaled over 8 LED’s currently(ledPins) , but after trying to add a second band spectrumValue[2] I am having issues.

The first 8 LED’s still illuminate but very dimly and no leds from the second array (ledPinsB) illuminate. I think I have a error in the function that interprets the second frequency band, because if I comment it out the first array starts to work sensibly again :confused:

I have been through the logic time and time again and I cant work it out, I thought that adding +8 to ledLevelB and thisLed should work :frowning:

thanks in advance, and apologies for the messy code!

// Clock and data pins are pins from the hardware SPI, you cannot choose them yourself if you use the hardware SPI.
// Data pin is MOSI (Uno and earlier: 11, Leonardo: ICSP 4, Mega: 51, Teensy 2.0: 2, Teensy 2.0++: 22)
// Clock pin is SCK (Uno and earlier: 13, Leonardo: ICSP 3, Mega: 52, Teensy 2.0: 1, Teensy 2.0++: 21)

// You can choose the latch pin yourself.
const int ShiftPWM_latchPin = 8;

// ** uncomment this part to NOT use the SPI port and change the pin numbers. This is 2.5x slower **
//#define SHIFTPWM_NOSPI
//const int ShiftPWM_dataPin = 6;
//const int ShiftPWM_clockPin = 7;


// If your LED's turn on if the pin is low, set this to true, otherwise set it to false.
const bool ShiftPWM_invertOutputs = false;

// You can enable the option below to shift the PWM phase of each shift register by 8 compared to the previous.
// This will slightly increase the interrupt load, but will prevent all PWM signals from becoming high at the same time.
// This will be a bit easier on your power supply, because the current peaks are distributed.
const bool ShiftPWM_balanceLoad = false;

#include <ShiftPWM.h>   // include ShiftPWM.h after setting the pins!

// Here you set the number of brightness levels, the update frequency and the number of shift registers.
// These values affect the load of ShiftPWM.
// Choose them wisely and use the PrintInterruptLoad() function to verify your load.
// There is a calculator on my website to estimate the load.

unsigned char maxBrightness = 255;
unsigned char pwmFrequency = 75;
int numRegisters = 2;
int numRGBleds = numRegisters * 8 / 3;









int analogPin = 0;    //connects to the Output of the MSGEQ7, Measures the voltage value for each frequency band (0V-5V)
int strobePin = 2;    //connects to the Strobe Pin of the MSGEQ7, controls the Multiplexer and thus switches between the frequency bands
int resetPin = 3;     //connects to the Reset Pin of the MSGEQ7, controls the Multiplexer and let's it restart with the lowest frequency band
int spectrumValue[7]; //Integer variable to store the 10bit values of the frequency bands
int filter = 80;      //There will always be some noises which the analogpin will receive. With this filter value we can ignore the very low peaks of the output of the MSGEQ7. Fell free to adjust this value to your liking


const int ledCount = 8;    // the number of LEDs in the bar graph

int ledPins[] = {
  0, 1, 2, 3, 4, 5, 6, 7,  //correct for shift pwm pinouts
};   // an array of pin numbers to which LEDs are attached



int ledPinsB[] = {
  8, 9, 10, 11, 12, 13, 14, 15 //correct for shift pwm pinouts
};   // an array of pin numbers to which LEDs are attached


void setup() {

  Serial.begin(9600);         //needed to output the values of the frequencies bands on the serial monitor
  pinMode(analogPin, INPUT);  //defines analog pin A0 as an Input
  pinMode(strobePin, OUTPUT); //defines strobe pin 2 as Output
  pinMode(resetPin, OUTPUT);  //defines reset pin 3 as Output
  digitalWrite(resetPin, LOW);
  digitalWrite(strobePin, HIGH);




  // Sets the number of 8-bit registers that are used.
  ShiftPWM.SetAmountOfRegisters(numRegisters);
  // SetPinGrouping allows flexibility in LED setup.
  // If your LED's are connected like this: RRRRGGGGBBBBRRRRGGGGBBBB, use SetPinGrouping(4).
  ShiftPWM.SetPinGrouping(1); //This is the default, but I added here to demonstrate how to use the funtion
  ShiftPWM.Start(pwmFrequency, maxBrightness);
}

void loop() {

  digitalWrite(resetPin, HIGH);
  digitalWrite(resetPin, LOW);              //change from high to low starts the output of the mutliplexer from the beginning
  for (int i = 0; i < 7; i++) {             //for loop goes through this cycle 7 times to get the values for each frequency band
    digitalWrite(strobePin, LOW);           //puts strobe pin low to output the frequency band
    delayMicroseconds(30);                  //wait until output value of MSGEQ7 can be measured (see timing diagram in the datasheet)
    spectrumValue[i] = analogRead(analogPin); //put analog DC value in the spectrumValue variable
    if (spectrumValue[i] < filter) {
      spectrumValue[i] = 0;
    }                  //if the received value is below the filter value it will get set to 0
    Serial.print(spectrumValue[i]);         //outputs the PWM value on the serial monitor
    Serial.print(" ");
    digitalWrite(strobePin, HIGH);          //puts the strobe pin high to get ready for the next cycle
  }
  Serial.println();



  //First frequency band
  // map the result to a range from 0 to the number of LEDs:
  int ledLevel = map(spectrumValue[0], 0, 1023, 0, ledCount);  //change spectrum value for freq selection

  // loop over the LED array:
  for (int thisLed = 0; thisLed < ledCount; thisLed++) {
    // if the array element's index is less than ledLevel,
    // turn the pin for this element on:
    if (thisLed < ledLevel) {
      ShiftPWM.SetOne(ledPins[thisLed], 255);
    }
    // turn off all pins higher than the ledLevel:
    else {
      ShiftPWM.SetOne(ledPins[thisLed], 0);
    }
  }

  ///*
  //Second frequency band
  // map the result to a range from 0 to the number of LEDs:
  int ledLevelB = map(spectrumValue[1], 0, 1023, 0, ledCount);  //change spectrum value for freq selection

  ledLevelB + 8;

  // loop over the LED array:
  for (int thisLed = 8; thisLed < 15; thisLed++) {  //add 8 to led count
    // if the array element's index is less than ledLevel,
    // turn the pin for this element on:
    if (thisLed < ledLevelB) {
      ShiftPWM.SetOne(ledPinsB[thisLed], 255);
    }
    // turn off all pins higher than the ledLevel:
    else {
      ShiftPWM.SetOne(ledPinsB[thisLed], 0);
    }
  }


  //*/









  delay(10);
}
int ledPins[] = {
  0, 1, 2, 3, 4, 5, 6, 7,  //correct for shift pwm pinouts
};

  Serial.begin(9600);

Pins 0 and 1 are the hardware serial pins. You can't use them for LEDs and Serial at the same time.

  pinMode(analogPin, INPUT);  //defines analog pin A0 as an Input

The pinMode() function does nothing with analog pins. This is, uselessly, setting the digital pin that shares space with the analog pin, to INPUT. This accomplishes nothing when the pin is used as an analog pin.

You complete overshoot the array!

You try to fix the 8 led off set in two place:

  • First by making a map array ledPinsB
  • And then by creating an off set in ledLevelB and start with 8…

Just skip the arrays.

And by the way, in the comment you say “//add 8 to led count”, but you write 15 and in my book 8 + 8 = 16 :stuck_out_tongue:

And “ledLevelB + 8;” does nothing. It just adds 8 to ledLevelB but does not save it anywhere. Make it “ledLevelB =+ 8;”

And you’re filter does not actually filter… Just a start threshold/

// Clock and data pins are pins from the hardware SPI, you cannot choose them yourself if you use the hardware SPI.
// Data pin is MOSI (Uno and earlier: 11, Leonardo: ICSP 4, Mega: 51, Teensy 2.0: 2, Teensy 2.0++: 22)
// Clock pin is SCK (Uno and earlier: 13, Leonardo: ICSP 3, Mega: 52, Teensy 2.0: 1, Teensy 2.0++: 21)

// You can choose the latch pin yourself.
const int ShiftPWM_latchPin = 8;

// ** uncomment this part to NOT use the SPI port and change the pin numbers. This is 2.5x slower **
//#define SHIFTPWM_NOSPI
//const int ShiftPWM_dataPin = 6;
//const int ShiftPWM_clockPin = 7;


// If your LED's turn on if the pin is low, set this to true, otherwise set it to false.
const bool ShiftPWM_invertOutputs = false;

// You can enable the option below to shift the PWM phase of each shift register by 8 compared to the previous.
// This will slightly increase the interrupt load, but will prevent all PWM signals from becoming high at the same time.
// This will be a bit easier on your power supply, because the current peaks are distributed.
const bool ShiftPWM_balanceLoad = false;

#include <ShiftPWM.h>   // include ShiftPWM.h after setting the pins!

// Here you set the number of brightness levels, the update frequency and the number of shift registers.
// These values affect the load of ShiftPWM.
// Choose them wisely and use the PrintInterruptLoad() function to verify your load.
// There is a calculator on my website to estimate the load.

const unsigned char MaxBrightness = 255;
const unsigned char PwmFrequency = 75;
const byte numRegisters = 2;
//int numRGBleds = numRegisters * 8 / 3; //not used!









const byte Msgeq7Out = A0;    //connects to the Output of the MSGEQ7, Measures the voltage value for each frequency band (0V-5V)
const byte StrobePin = 2;    //connects to the Strobe Pin of the MSGEQ7, controls the Multiplexer and thus switches between the frequency bands
const byte ResetPin = 3;     //connects to the Reset Pin of the MSGEQ7, controls the Multiplexer and let's it restart with the lowest frequency band
byte spectrumValue[7];      //byte with number of leds to turn on in each band
const byte Filter = 80;            //There will always be some noises which the Msgeq7Out will receive. With this Filter value we can ignore the very low peaks of the output of the MSGEQ7. Fell free to adjust this value to your liking


const byte LedCount = 8;    // the number of LEDs in the bar graph BYTE WILL DO!
const byte SpectumBands = 7; //number of spectum bands




void setup() {

  Serial.begin(9600);         //needed to output the values of the frequencies bands on the serial monitor
  pinMode(StrobePin, OUTPUT); //defines strobe pin 2 as Output
  pinMode(ResetPin, OUTPUT);  //defines reset pin 3 as Output
  digitalWrite(ResetPin, LOW);
  digitalWrite(StrobePin, HIGH);




  // Sets the number of 8-bit registers that are used.
  ShiftPWM.SetAmountOfRegisters(numRegisters);
  // SetPinGrouping allows flexibility in LED setup.
  // If your LED's are connected like this: RRRRGGGGBBBBRRRRGGGGBBBB, use SetPinGrouping(4).
  ShiftPWM.SetPinGrouping(1); //This is the default, but I added here to demonstrate how to use the funtion
  ShiftPWM.Start(PwmFrequency, MaxBrightness);
}

void loop() {

  digitalWrite(ResetPin, HIGH);
  digitalWrite(ResetPin, LOW);              //change from high to low starts the output of the mutliplexer from the beginning
  for (int i = 0; i < SpectumBands; i++) {             //for loop goes through this cycle 7 times to get the values for each frequency band
    digitalWrite(StrobePin, LOW);           //puts strobe pin low to output the frequency band
    delayMicroseconds(30);                  //wait until output value of MSGEQ7 can be measured (see timing diagram in the datasheet)
    spectrumValue[i] = map(analogRead(Msgeq7Out), 0, 1023, 0, LedCount); //just save what we need => number of leds to lid
    
    /*if (spectrumValue[i] < Filter) {
      spectrumValue[i] = 0;
    }                  //if the received value is below the Filter value it will get set to 0
    */
    Serial.print(spectrumValue[i]);         //outputs the PWM value on the serial monitor NO, nothing to do with PWM!
    Serial.print(" ");
    digitalWrite(StrobePin, HIGH);          //puts the strobe pin high to get ready for the next cycle
  }
  Serial.println();
  
  //for() //WHAT IS THIS DOING HERE?


  /* ALREADY DONE!
  //First frequency band
  // map the result to a range from 0 to the number of LEDs:
  int ledLevel = map(spectrumValue[0], 0, 1023, 0, LedCount);  //change spectrum value for freq selection
  */
  
  
  // loop over the all leds
  for (byte thisLed = 0; thisLed < (LedCount * SpectumBands); thisLed++) {
    // turn the pin for this element on:
    if (thisLed < spectrumValue[thisLed / LedCount]) {
      ShiftPWM.SetOne(thisLed, 255);
    }
    // turn off all pins higher than the ledLevel:
    else {
      ShiftPWM.SetOne(thisLed, 0);
    }
  }
  
  /* DON'T NEED ALL THIS ANYMORE :)
  //
  //Second frequency band
  // map the result to a range from 0 to the number of LEDs:
  int ledLevelB = map(spectrumValue[1], 0, 1023, 0, LedCount);  //change spectrum value for freq selection

  ledLevelB + LedCount;

  // loop over the LED array:
  for (int thisLed = LedCount; thisLed < 2 * LedCount; thisLed++) {  //add 8 to led count
    // if the array element's index is less than ledLevel,
    // turn the pin for this element on:
    if (thisLed < ledLevelB) {
      ShiftPWM.SetOne(thisLed, 255);
    }
    // turn off all pins higher than the ledLevel:
    else {
      ShiftPWM.SetOne(thisLed, 0);
    }
  }


  //
  */

  delay(10);
}

Should work for all bands…

And BTW, the use of the SHiftPWM library is VERY VERY useless here. You only use 255 or 0 (on or off). It would be easier just to use the shift library or the SPI library :wink:

@Paul, he is not using pin0 and pin1 of the Arduino (other then the serial). That’s the pin’s of the shift registers :slight_smile:

Wow septillion, thanks so much! Many improvements and things I did not know there :slight_smile:

I can just about follow the logic I think, so 8 leds will be assigned to each of the 7 bands and it will assume that there are 7x8 leds in total?

And it will loop through the bands 1-7 lighting the leds in each group as it goes through?

One segment that I’m struggling to follow is this part

if (thisLed < spectrumValue[thisLed / LedCount]) {
      ShiftPWM.SetOne(thisLed, 255);
    }
    // turn off all pins higher than the ledLevel:
    else {
      ShiftPWM.SetOne(thisLed, 0);
    }

By substitution, if for example thisLed = 3 and spectrumValue = 5…

if (3 < spectrumValue[3 / 8]
if (3 < spectrumValue[0.375]

Or am I going totally mad? Can’t wait to try it out but I have to finish work first :o

Thanks again!

It will loop through bands 0 to 6, not 1 to 7 :wink: Makes sens to start @ 0 because arrays do this.

Uhm, for the logic, if thisLed = 3 and LedCount = 8 (because you have 8 leds per segment) you have 3 / 8 = 0. It’s int logic, no decimal places :wink: And this tells you that led 3 is part of band 0 (first band). Is you have for example thisLed = 20 you get 20 / 8 = 2. This will tell you led 20 is part of the graph of band 2 (third band).

And by using this outcome to select the right array member you get the number of leds you want to lid in that band (because that’s what I store in that array. Changed that bit :wink: ) spectrumValue[0] will tell the number of led lid in the first band.

But, I spoted an error of my own. The full line should be

if ((thisLed % LedCount) < spectrumValue[thisLed / LedCount]) {

thisLed % LedCount (modulus) will return which led in the bar it is. 20 % 8 = 4. So it’s led 4 (fifth led) of band 2 (third band)

Rule of thumb: If you try to copy past/make code that looks similar there is an easier way. And using array’s for similar things is the way to go :smiley:

But like I said, the use of ShiftPWM is useless. You can just skip it and use a normal shift (or SPI). ShiftPWM is only needed if you want to vary the intensity of each LED.

Full code

// Clock and data pins are pins from the hardware SPI, you cannot choose them yourself if you use the hardware SPI.
// Data pin is MOSI (Uno and earlier: 11, Leonardo: ICSP 4, Mega: 51, Teensy 2.0: 2, Teensy 2.0++: 22)
// Clock pin is SCK (Uno and earlier: 13, Leonardo: ICSP 3, Mega: 52, Teensy 2.0: 1, Teensy 2.0++: 21)

// You can choose the latch pin yourself.
const int ShiftPWM_latchPin = 8;

// ** uncomment this part to NOT use the SPI port and change the pin numbers. This is 2.5x slower **
//#define SHIFTPWM_NOSPI
//const int ShiftPWM_dataPin = 6;
//const int ShiftPWM_clockPin = 7;


// If your LED's turn on if the pin is low, set this to true, otherwise set it to false.
const bool ShiftPWM_invertOutputs = false;

// You can enable the option below to shift the PWM phase of each shift register by 8 compared to the previous.
// This will slightly increase the interrupt load, but will prevent all PWM signals from becoming high at the same time.
// This will be a bit easier on your power supply, because the current peaks are distributed.
const bool ShiftPWM_balanceLoad = false;

#include <ShiftPWM.h>   // include ShiftPWM.h after setting the pins!

// Here you set the number of brightness levels, the update frequency and the number of shift registers.
// These values affect the load of ShiftPWM.
// Choose them wisely and use the PrintInterruptLoad() function to verify your load.
// There is a calculator on my website to estimate the load.

const unsigned char MaxBrightness = 255;
const unsigned char PwmFrequency = 75;
const byte numRegisters = 2;
//int numRGBleds = numRegisters * 8 / 3; //not used!









const byte Msgeq7Out = A0;    //connects to the Output of the MSGEQ7, Measures the voltage value for each frequency band (0V-5V)
const byte StrobePin = 2;    //connects to the Strobe Pin of the MSGEQ7, controls the Multiplexer and thus switches between the frequency bands
const byte ResetPin = 3;     //connects to the Reset Pin of the MSGEQ7, controls the Multiplexer and let's it restart with the lowest frequency band
byte spectrumValue[7];      //byte with number of leds to turn on in each band
const byte Filter = 80;            //There will always be some noises which the Msgeq7Out will receive. With this Filter value we can ignore the very low peaks of the output of the MSGEQ7. Fell free to adjust this value to your liking


const byte LedCount = 8;    // the number of LEDs in the bar graph BYTE WILL DO!
const byte SpectumBands = 7; //number of spectum bands




void setup() {

  Serial.begin(9600);         //needed to output the values of the frequencies bands on the serial monitor
  pinMode(StrobePin, OUTPUT); //defines strobe pin 2 as Output
  pinMode(ResetPin, OUTPUT);  //defines reset pin 3 as Output
  digitalWrite(ResetPin, LOW);
  digitalWrite(StrobePin, HIGH);




  // Sets the number of 8-bit registers that are used.
  ShiftPWM.SetAmountOfRegisters(numRegisters);
  // SetPinGrouping allows flexibility in LED setup.
  // If your LED's are connected like this: RRRRGGGGBBBBRRRRGGGGBBBB, use SetPinGrouping(4).
  ShiftPWM.SetPinGrouping(1); //This is the default, but I added here to demonstrate how to use the funtion
  ShiftPWM.Start(PwmFrequency, MaxBrightness);
}

void loop() {

  digitalWrite(ResetPin, HIGH);
  digitalWrite(ResetPin, LOW);              //change from high to low starts the output of the mutliplexer from the beginning
  for (int i = 0; i < SpectumBands; i++) {             //for loop goes through this cycle 7 times to get the values for each frequency band
    digitalWrite(StrobePin, LOW);           //puts strobe pin low to output the frequency band
    delayMicroseconds(30);                  //wait until output value of MSGEQ7 can be measured (see timing diagram in the datasheet)
    spectrumValue[i] = map(analogRead(Msgeq7Out), 0, 1023, 0, LedCount); //just save what we need => number of leds to lid
    
    /*if (spectrumValue[i] < Filter) {
      spectrumValue[i] = 0;
    }                  //if the received value is below the Filter value it will get set to 0
    */
    Serial.print(spectrumValue[i]);         //outputs the PWM value on the serial monitor NO, nothing to do with PWM!
    Serial.print(" ");
    digitalWrite(StrobePin, HIGH);          //puts the strobe pin high to get ready for the next cycle
  }
  Serial.println();
  
  //for() //WHAT IS THIS DOING HERE?


  /* ALREADY DONE!
  //First frequency band
  // map the result to a range from 0 to the number of LEDs:
  int ledLevel = map(spectrumValue[0], 0, 1023, 0, LedCount);  //change spectrum value for freq selection
  */
  
  
  // loop over the all leds
  for (byte thisLed = 0; thisLed < (LedCount * SpectumBands); thisLed++) {
    // turn the pin for this element on:
    if ((thisLed % LedCount) < spectrumValue[thisLed / LedCount]) {
      ShiftPWM.SetOne(thisLed, 255);
    }
    // turn off all pins higher than the ledLevel:
    else {
      ShiftPWM.SetOne(thisLed, 0);
    }
  }
  
  /* DON'T NEED ALL THIS ANYMORE :)
  //
  //Second frequency band
  // map the result to a range from 0 to the number of LEDs:
  int ledLevelB = map(spectrumValue[1], 0, 1023, 0, LedCount);  //change spectrum value for freq selection

  ledLevelB + LedCount;

  // loop over the LED array:
  for (int thisLed = LedCount; thisLed < 2 * LedCount; thisLed++) {  //add 8 to led count
    // if the array element's index is less than ledLevel,
    // turn the pin for this element on:
    if (thisLed < ledLevelB) {
      ShiftPWM.SetOne(thisLed, 255);
    }
    // turn off all pins higher than the ledLevel:
    else {
      ShiftPWM.SetOne(thisLed, 0);
    }
  }


  //
  */

  delay(10);
}

Oh yes, of course we start at 0 :slight_smile: I think thats why I ended up with 15, 7+8? But I’m not really sure what I was doing anway:)

Thanks so much, that makes sense! That is very ingenious how you have done that, whats why I love this forum, I would never have been able to simplify it like that, no matter how much longer I spent scratching my head! lol.

Definitely makes sense to simply rather than repeat - I need to get more comfortable with using arrays :slight_smile:

I see what you mean about shiftpwm, I only used it because I have had some success with it in the past. I might look at changing it or even adding the ability to adjust the brightness of the VU meter.

Thanks again, you are a star! I can’t wait to test, STILL stuck at work though :frowning:

finally found some time to test and it works brilliantly! I’m so pleased, thanks very much! I love the way you have adjusted the code so it can be adapted easily too, I’m now thinking of using 2x shift registers per band :o lol

Now I can carry on with the build :slight_smile:

Next project is to make it work with 2 msgeq7’s and just add up all the spectrum bands to form a simple stereo VU meter :slight_smile:

Thanks again septillion :smiley: