Bar graph animation

I was playing with a 28 segment LED bar graph the other night and started wondering: What animations do people use for their bar graphs?

I have coded three that I see quite often:

What other animations do people like to use? I would like to see if I can get them to work with this.

For those who are curious: I am using a straight from China 28 segment 30mm bar graph (brand name Barmeter on ebay) that is multiplexed using a MAX7219. Three pins from an Arduino control the MAX7219 which in turn uses eleven pins to control the bar graph.

Berg

Really digging LED work there. I struggled trying to figure out a better way to code my Arduino for my all in one pack lights and sound setup. I’d be interested in how these sequences are coded as I don’t have much experience with the MAX7219. My electronics are in my pack build thread.

Great work there!

Thanks for the kind words!

I’m currently working on an all in one solution too. So far I have switch/button inputs, sounds and the bar graph working. It is fairly simplistic as it has no changing animation rates or overheat functions, but those can be added later. I’m still fairly new at coding, so it isn’t the prettiest or most efficient.

For the bar graph that I am using I need to use the MAX7219 to multiplex. The bar graph has twenty eight LEDs, but only eleven pins to control it with. Essentially the LEDs are set up in an array format. If you think of it like an excel spreadsheet there are seven columns and four rows and each cell in this matrix is an LED. If a column supplies the voltage and the row connects to ground the LED will light up. So to light up the first LED the first column (zero in Arduino) is taken to supply voltage and the first row (again zero) is brought to ground. Then next LED is the next one down in the column so the second row (row 1 in Arduino) is brought to ground. The first four LEDs can be lit this way. Where thing get tricky is lighting the first five. This requires that column zero supplies power while rows zero through three supply ground. The fifth LED gets power from column one, but because all the rows are already grounded this would light up all the LEDs in that column. The MAX7219 switches the powers and grounds on and off very quickly so that all the LEDs that need to be lit up blink. It is quick enough that the LEDs appear to be on solid. All of the complex blinking calculations are done automatically by the MAX7219. The Arduino simply tells it which LEDs in the matrix should be on and which ones should be off. There is a library written for this chip so all of the hard work is already done. Another big advantage is the fact that I only need to one resister to limit the current to all the LEDs. When it comes time to make up some printed boards this will save a lot of space.

As for the Arduino code, here is the bar graph filling and emptying part:

<i>
</i>if (updown = 1)			//Positive value of "updown" means filling the bar graph
{
  int col = 0;			//Start at the first LED
  int row = 0;			//Start at the first LED
  while(col<7) 			//There are only seven columns, 0 - 6
  {
    while(row<4) 		//There are only four rows, 0 - 3
	{



      unsigned long currentMillisbar = millis();			//Get current program time
      lc.setLed(0,row,col,true);							//Set the LED at row and col to on
      if(currentMillisbar - previousMillisbar > interval1) 	//Check to see if the interval time has passed
	  {														//If enough time has passed:
      previousMillisbar = currentMillisbar;  				//Store current program time
      row++;												//Increase row number by one
	  }
    }														//row has passed 3, exit while loop
    row = 0;												//Reset row to zero
    col++;													//Increase column number by one
  }															//col value has passed 6, bargraph is full
  updown -= updown;											//updown changes from positive to negative value
}															//updown no longer positive, exit if loop

if (updown = -1)		//Negative value of "updown" means emptying the bar graph
{
  int col = 7;			//Start at last LED
  int row = 4;			//Start at last LED
  while(col>0) 			//This prevents this loop from doing anything with the first column
  {						//The first four LEDs will always be lit.  Change this to -1 to empty completely
    while(row>-1)		//Count the rows down to zero
	{
      unsigned long currentMillisbar = millis();			//Get current program time
      lc.setLed(0,row,col,false);							//Set the LED at row and col to off
      if(currentMillisbar - previousMillisbar > interval1) 	//Check to see if the interval time has passed
	  {														//If enough time has passed:
      previousMillisbar = currentMillisbar;  				//Store current program time
      row--;												//Decrease row number by one
	  }
    }														//row has passed 0, exit while loop
    row = 4;												//Reset row to 4
    col--;													//Decrease column number by one
  }															//col value has passed 1
  updown -= updown; 										//updown changes from negative to positive value
}															//updown no longer negative, exit if loop

And for the two LEDs moving from the middle to the ends and back:

<i>
</i>/*Define the bytes that I will use for moving two LEDs on
the bar graph.  These are matrices with five bytes each*/

byte a[5]={B00000000,B00000001,B00000010,B00000100,B00001000};
byte b[5]={B00010000,B00100000,B01000000,B10000000,B00000000};

{
  unsigned long currentMillisbar2 = millis();				//Get program time
  if(currentMillisbar2 - previousMillisbar2 > interval1)	//If enough time has passed
  {
    previousMillisbar2 = currentMillisbar2;					//Record current time
    firepos = firepos + updown2;							//Increment firepos by updown2 (+1)
  }

  if(firepos == 0)		//All the following ifs set the rows of the matrix bar graph
  {						//using values from the bytes defined near the beginning of
  lc.setRow(0,0,a[0]);	//the program
  lc.setRow(0,1,b[0]);
  lc.setRow(0,2,b[0]);
  lc.setRow(0,3,a[0]);
  }
  else if(firepos == 1)
  {
  lc.setRow(0,0,b[0]);
  lc.setRow(0,1,a[0]);
  lc.setRow(0,2,a[0]);
  lc.setRow(0,3,b[0]);
  }
  else if(firepos == 2)
  {
  lc.setRow(0,0,a[4]);
  lc.setRow(0,1,a[0]);
  lc.setRow(0,2,a[0]);
  lc.setRow(0,3,b[1]);
  }
  else if(firepos == 3)
  {
  lc.setRow(0,0,a[0]);
  lc.setRow(0,1,a[4]);
  lc.setRow(0,2,b[1]);
  lc.setRow(0,3,a[0]);
  }
  else if(firepos == 4)
  {
  lc.setRow(0,0,a[0]);
  lc.setRow(0,1,b[1]);
  lc.setRow(0,2,a[4]);
  lc.setRow(0,3,a[0]);
  }
  else if(firepos == 5)
  {
  lc.setRow(0,0,b[1]);
  lc.setRow(0,1,a[0]);
  lc.setRow(0,2,a[0]);
  lc.setRow(0,3,a[4]);
  }
  else if(firepos == 6)
  {
  lc.setRow(0,0,a[3]);
  lc.setRow(0,1,a[0]);
  lc.setRow(0,2,a[0]);
  lc.setRow(0,3,b[2]);
  }
  else if(firepos == 7)
  {
  lc.setRow(0,0,a[0]);
  lc.setRow(0,1,a[3]);
  lc.setRow(0,2,b[2]);
  lc.setRow(0,3,a[0]);
  }
  else if(firepos == 8)
  {
  lc.setRow(0,0,a[0]);
  lc.setRow(0,1,b[2]);
  lc.setRow(0,2,a[3]);
  lc.setRow(0,3,a[0]);
  }
  else if(firepos == 9)
  {
  lc.setRow(0,0,b[2]);
  lc.setRow(0,1,a[0]);
  lc.setRow(0,2,a[0]);
  lc.setRow(0,3,a[3]);
  }
  else if(firepos == 10)
  {
  lc.setRow(0,0,a[2]);
  lc.setRow(0,1,a[0]);
  lc.setRow(0,2,a[0]);
  lc.setRow(0,3,b[3]);
  }
  else if(firepos == 11)
  {
  lc.setRow(0,0,a[0]);
  lc.setRow(0,1,a[2]);
  lc.setRow(0,2,b[3]);
  lc.setRow(0,3,a[0]);
  }
  else if(firepos == 12)
  {
  lc.setRow(0,0,a[0]);
  lc.setRow(0,1,b[3]);
  lc.setRow(0,2,a[2]);
  lc.setRow(0,3,a[0]);
  }
  else if(firepos == 13)
  {
  lc.setRow(0,0,b[3]);
  lc.setRow(0,1,a[0]);
  lc.setRow(0,2,a[0]);
  lc.setRow(0,3,a[2]);
  }

  if (firepos > 13)		//There are thirteen steps through this animation, if firepos passes 13
  {
    updown2 = -1;		//Set updown2 to -1 to which causes animation to run backwards
  }

  if (firepos < 0)		//Animation has run all the way backwards to the start
  {
    updown2 = 1;		//Set updown2 to +1 to start again
  }

}

Please note that these are copy and pastes, so some of the setup and library information is missing. I’m sure that there is much room for improvement in my code. This was simply to try and get it working. The more things I want my Arduino to do the more I have to slim down the code.

I will try to get another video of what I have running so far soon.

Cheers,

Berg

I took a look through your thread propcicle, I only hope that one day my project will look half as good as yours!

Well, this is as far as I have got so far. It isn’t movie accurate. There are three switches and two buttons. Plan is to have the bottom switch as the “power on”, next one up is the “ready to fire” or Activate switch, the third switch up simply turns off the hum sound while is power on mode. The button to the left will be the Intensify or “fire” button. The last button will be on the ear on the front of the barrel. Holding this button while flipping the power switch puts it into music mode. Every press of the barrel button after that changes the track selection, which is displayed on the bar graph. Flipping the Activate switch and then pressing the barrel button counts down instead of up. The Intensify button starts the selected track.

In either mode, turning the power switch off reverts it back to the initial state.

I’m still working on other things and combinations I can get the inputs doing. I also need to get some PWM LED drivers to complete all the lighting effects. Lets be honest, I’ve barely started.

Cheers,

Berg

I don’t seem to be able to edit my posts. I do have something I think is neat that I didn’t show in the video:

I use the third switch in the music mode to do something special. While playing a song I can flip this switch on then turn the power switch off. The current song will be put on a loop and continue to play while the pack is in “off” mode. I can then flip the power switch on and have the song continue to play in the back ground while playing all the sound effects as well until I turn off the power switch again. This is the “soundtrack” mode.

https://www.youtube.com/watch?v=i9pdV3XV8Co&feature=youtu.be

This is made possible by using the Sparkfun Wav Trigger. It can play up to fourteen tracks at once. I only need to use one wire to send it information from the Arduino (so long as they have a common ground). This guy uses .wav files loaded onto a Micro SD card. The files are numbered and the Arduino will tell it to play/stop/loop various file numbers. I use file numbers below 100 for sound effects and above 100 for music. When it is music mode I exit by flipping the power switch off. If the third switch is off the exit function includes a “stop all tracks” command. With the switch on it instead uses a “loop current track” command. Since there is no call in the non music code for any tracks above 100 it leaves it playing on a loop until the power switch is turned off. The shutdown function here includes a “stop all tracks”.

Unfortunately there doesn’t yet seem to be a way to get information from the Wav Trigger to the Arduino so I can’t get it to indicate that it has finished playing a song so the Arduino can tell it to play the next one.

Okay, I’ll stop posting now.

Cheers,

Berg

Cool idea with the track selection using the bar graph as an indicator. Your last YouTube video is set to private, so I couldn’t watch that one. I need to look at your graph code a little closer. I saw those bar graphs on eBay, but hadn’t figured out the best way to blink the lights from a matrix. Thanks for sharing!

Sorry about that. Try again, I changed the video setting to public.

Berg

And for anyone curious, here’s my (very incomplete) code:

<i>
</i>//////////////////////////////////////////////////////////////////////////////////////
//This is a work in progress program for a proton pack
//Created by by Berg9987 (KLB)
//Currently using an Arduino Pro Mini 5v, single MAX7219, and a SparkFun Wav Trigger
//Several parts of this code uses examples found online
//Feel free to use it or change it as you wish
//If you do make it better, please post your changes where you found this sketch
//Last updated December 10th, 2015
//////////////////////////////////////////////////////////////////////////////////////

//Include the necessary libraries
#include "LedControl.h"       //MAX7219 library for the bar graph
#include <AltSoftSerial.h>    //Used to create a software serial TX on pin 9 for the wav trigger
#include <wavTrigger.h>       //Wav Trigger Library

#define DEBOUNCE 25  // Button debouncer, how many ms to debounce after button state change

// Define the buttons
byte buttons[] = {14, 15, 16, 17, 2}; // the analog 0-5 pins are also known as 14-19
//  14 = A0 = 0 = INTENSIFY
//  15 = A1 = 1 = ACTIVATE
//  16 = A2 = 2 = POWERON
//  17 = A3 = 3 = EXTRA
//   2 = D2 = 4 = BARREL

// Checks the size of the above button array
#define NUMBUTTONS sizeof(buttons)
// Track if a button is just pressed, just released, or 'currently pressed'
volatile byte pressed[NUMBUTTONS], justpressed[NUMBUTTONS], justreleased[NUMBUTTONS];

//States for state machine
enum operatingState { OFF = 0, STANDBY, POWERUP, HUM, SAFETYOFF, FIRE, POWERDOWN, MUSIC };
operatingState opState = OFF;

/*
 Setup MAX7219 control
 pin 12 is connected to the DataIn
 pin 11 is connected to the CLK
 pin 10 is connected to LOAD
 There is only 1 MAX7219
 */
LedControl lc=LedControl(12,11,10,1);
wavTrigger wTrig;             //WAV Trigger object

int interval1 = 20;     //Timing for the bar graph
int updown = 1;         //Bar graph direction in poweron mode
int updown2 = 1;        //Bar graph direction in fire mode
int firepos = 0;        //Initial bargraph fire animation position
int songnum = 101;      //Initial song number (101 is the first song)
int songplaying = 1;    //Song number that is playing (will be 101 to 120 when started), used for serial print
int songcount = 1;      //Determinrs if song increases or decreases with barrel button press
int fade = 0;           //Used in hum mode to indicate whether the hum sound should be playing 0=yes, 1=no
int soundtrack = 0;     //Switch bit to put into soundtrack mode

unsigned long previousMillisbar = 0;    //used for bar graph animation timing
unsigned long previousMillisbar2 = 0;    //used for bar graph animation timing

/*
 * bytes below used for animating bar graph by "writing" them to different rows
 */
byte a[5]={B00000000,B00000001,B00000010,B00000100,B00001000};
byte b[5]={B00010000,B00100000,B01000000,B10000000,B00000000};

void setup()
{
  byte i;   //used to initialize the switches

   //Set up serial port for debugging
   //Print what the program is and how many buttons
   //were found in the size of button array above.
  Serial.begin(9600);
  Serial.print("GB Control with ");
  Serial.print(NUMBUTTONS, DEC);
  Serial.println(" buttons, bar graph and sound.");
  Serial.println("Wait");   //Indicate that setup has begun, wait for it to finish

   //Make input & enable pull-up resistors on switch pins
  for (i=0; i < NUMBUTTONS; i++)
  {
    pinMode(buttons[i], INPUT);     //Buttons are inputs
    digitalWrite(buttons[i], HIGH); //Enable pull up resistors
  }

  /*
  The MAX72XX is in power-saving mode on startup,
  we have to do a wakeup call
  */
  lc.shutdown(0,false);
  /* Set the brightness to a medium values */
  lc.setIntensity(0,8);
  /* and clear the display */
  lc.clearDisplay(0);

  // WAV Trigger startup at 57600
  wTrig.start();

  // Wait for the WAV Trigger to finish reset before trying to send commands.
  delay(1000);

  wTrig.stopAllTracks();  //Stop anything the WAV Trigger might be playing
  wTrig.masterGain(0);    //Set master gain.  Both these commands "reset" the wav trigger in case it was doing something strange

  Serial.println("Ready");  //Indicate that the setup is done
}

/*
 * Track any changes in the switch states.  This function was taken from an online example.
 * I would like to try and get it to work on an interrupt timer again (used it before in the
 * example that I found), but until I have all the other functions running I won't and interrupt
 * timers can mess up PWMs on pins.
 */
void check_switches()
{
  static byte previousstate[NUMBUTTONS];
  static byte currentstate[NUMBUTTONS];
  static long lasttime;
  byte index;

  if (millis() < lasttime)  // we wrapped around, lets just try again
  {
     lasttime = millis();
  }

  if ((lasttime + DEBOUNCE) > millis())
  {
    // not enough time has passed to debounce
    return;
  }
  // ok we have waited DEBOUNCE milliseconds, lets reset the timer
  lasttime = millis();

  for (index = 0; index < NUMBUTTONS; index++)
  {
    currentstate[index] = digitalRead(buttons[index]);   // read the button

    if (currentstate[index] == previousstate[index])
    {
      if ((pressed[index] == LOW) && (currentstate[index] == LOW))
      {
          // just pressed
          justpressed[index] = 1;
      }
      else if ((pressed[index] == HIGH) && (currentstate[index] == HIGH))
      {
          // just released
          justreleased[index] = 1;
      }
      pressed[index] = !currentstate[index];  // remember, digital HIGH means NOT pressed
    }
    //Serial.println(pressed[index], DEC);
    previousstate[index] = currentstate[index];   // keep a running tally of the buttons
  }
}

void loop()
{
  check_switches();   //Call the check switches every time through the loop

  switch (opState)    //Switch part of the switch/case state machine
  {
    case OFF:         //Off.  The initial state
      off();
      break;
    case STANDBY:     //Standby.  Like off but the barrel button is pressed
      standby();
      break;
    case POWERUP:     //State between off and hum (Power switch flipped on)
      wTrig.trackPlayPoly(1);   //Play powerup sound
      powerup();
      break;
    case HUM:         //Hum, power switch is on, pack is "idle"
      wTrig.trackLoop(2, 1);    //If hum sound is playing, put it on a loop
      hum();
      break;
    case SAFETYOFF:   //Like hum, but now ready to fire (Activate switch flipped on)
      safetyoff();
      break;
    case FIRE:        //Fire animations and sounds (Intensify button pressed)
      fire();
      break;
    case POWERDOWN:     //Powerdown animation and sound (Power switch flipped off)
      powerdown();
      break;
    case MUSIC:         //Power switch flipped on while in standby
      music();
      break;
  }
}

void off()
{
  lc.clearDisplay(0);   //Turn off bar graph

  if (justpressed[2])  //The "power" switch on
  {
    justpressed[2] = 0; //reset justpressed 2
    Serial.println("Power On");
    opState = POWERUP;    //Go to powerup mode
    return;
  }

  if ((justpressed[4]) || (pressed[4])) //Barrel button is pressed or held
  {
    justpressed[4] = 0; //reset justpressed 2
    Serial.println("Button Pressed");
    opState = STANDBY;    //Go to standby mode
    return;
  }
}

void standby()
{
  if (justpressed[2])  //the "power" switch on
  {
    justpressed[2] = 0; //reset justpressed 2
    Serial.println("Music");
    opState = MUSIC;    //Go to music mode
    return;
  }

  if (justreleased[4])  //the "barrel" button off
  {
    justreleased[4] = 0; //reset justpressed 4
    Serial.println("Off");
    opState = OFF;    //Go to off mode
    return;
  }
}

void powerup()     //Start bar graph at empty and fill it.
{
  int col = 0;    //Start at the first LED
  int row = 0;    //Start at the first LED
  while(col<7)    //There are only seven columns, 0 - 6
  {
    while(row<4)  //There are only four rows, 0 - 3
    {
      unsigned long currentMillisbar = millis();      //Get current program time
      lc.setLed(0,row,col,true);                      //Set the LED at row and col to on
      if(currentMillisbar - previousMillisbar > 50)   //Check to see if the interval time has passed
      {                                               //50 is used as it causes the bar graph to fill in abot the time it takes to play the startup sound
      previousMillisbar = currentMillisbar;           //If enough time has passed: store current program time
      row++;                                          //Increase row number by one
      }
    }           //row has passed 3, exit while loop
    row = 0;    //Reset row to zero
    col++;      //Increase column number by one
  }             //col value has passed 6, bargraph is full

  Serial.println("Hum");    //Print next state
  wTrig.trackPlayPoly(2);   //Start the hum sound
  opState = HUM;            //Go to hum mode
  return;
}

void hum()
{
  if (updown = 1)   //Positive value of "updown" means filling the bar graph
  {
    int col = 0;          //Start at the first LED
    int row = 0;          //Start at the first LED
    while(col<7)          //There are only seven columns, 0 - 6
    {
      while(row<4)          //There are only four rows, 0 - 3
      {

        check_switches();  //In the while loop the program wont run the check switches function
                           //so I'm calling it here.  This way I don't have to wait until the
                           //bargraph is eighther completely full or empty to respond to button presses
                           //This can hopefully be removed when I have the switches called by a
                           //timer interrupt

        if (pressed[3])   //If the extra switch it flipped on
        {
          fade = 1;       //Set fade to 1
        }
        else              //Otherwise...
        {
          fade = 0;       //Leave it at zero.
        }

         if (fade == 1)          //If the extra switch is flipped on
        {
          wTrig.trackStop(2);   //stop playing the hum sounc
                                //I wanted this to fade out, but it wouldn't work.
                                //I suspect I can fix it by playing with justpressed instead of pressed
        }

        /*
         * I discovered that if I pressed the Intesify button while in hum
         * that the justpressed bit was held and when the activate switch
         * was flipped the system started the fire and then immediately
         * played the wind down sound.  This is here just to prevent that
         */

        if (justpressed[0])
        {
          justpressed[0] = 0; //reset justpressed
        }

        if (justreleased[2])  //the "power" switch off
        {
          justreleased[2] = 0;  //reset justreleased 2
          Serial.println("Shutting Down");  //Print next state
          opState = POWERDOWN;  //Go to shutdown mode
          return;
        }

        if ((justpressed[1]) || (pressed[1])) //if the "activate" switch is switched on, in this case I'm using it as a safety
        {
          justpressed[1] = 0;   //reset justpressed[1]
          Serial.println("Safety Off!");  //Print next state
          opState = SAFETYOFF;  //Go to safety off
          return;
        }

        /*
        * Now that the buttons have been checked and any button state changes handled
        * update the bar graph
        * NOTE:  at the moment the barrel and intensify buttons don't do anything in this state
        */
        unsigned long currentMillisbar = millis();    //Get current program time
        lc.setLed(0,row,col,true);                    //Set the LED at row and col to on
        if(currentMillisbar - previousMillisbar > interval1)  //Check to see if the interval time has passed
        {                                               //If enough time has passed:
          previousMillisbar = currentMillisbar;           //Store current program time
          row++;        //Increase row number by one
        }
      }     //row has passed 3, exit while loop
      row = 0;    //Reset row to zero
      col++;   //Increase column number by one
    }       //col value has passed 6, bargraph is full
    updown -= updown; //updown changes from positive to negative value
  }

  if (updown = -1)    //Negative value of "updown" means emptying the bar graph
  {
    int col = 7;      //Start at last LED
    int row = 4;      //Start at last LED
    while(col>0)      //This prevents this loop from doing anything with the first column
    {                 //The first four LEDs will always be lit.  Change this to -1 to empty completely
      while(row>-1)   //Count the rows down to zero
      {

        check_switches();  //In the while loop the program wont run the check switches function
                           //so I'm calling it here.  This way I don't have to wait until the
                           //bargraph is eighther completely full or empty to respond to button presses
                           //This can hopefully be removed when I have the switches called by a
                           //timer interrupt

        if (pressed[3])   //If the extra switch it flipped on
        {
          fade = 1;       //Set fade to 1
        }
        else              //Otherwise...
        {
          fade = 0;       //Leave it at zero.
        }

         if (fade == 1)          //If the extra switch is flipped on
        {
          wTrig.trackStop(2);   //stop playing the hum sounc
                                //I wanted this to fade out, but it wouldn't work.
                                //I suspect I can fix it by playing with justpressed instead of pressed
        }

        if (justreleased[2])  //the "power" switch off
        {
          justreleased[2] = 0;  //reset justreleased 2
          Serial.println("Shutting Down");  //Print next state
          opState = POWERDOWN;  //Go to shutdown mode
          return;
        }

        if ((justpressed[1]) || (pressed[1])) //if the "activate" switch is switched on, in this case I'm using it as a safety
        {
          justpressed[1] = 0;   //reset justpressed[1]
          Serial.println("Safety Off!");  //Print next state
          opState = SAFETYOFF;  //Go to safety off
          return;
        }

        /*
        * Now that the buttons have been checked and any button state changes handled
        * update the bar graph
        * NOTE:  at the moment the barrel and intensify buttons don't do anything
        */
        unsigned long currentMillisbar = millis();      //Get current program time
        lc.setLed(0,row,col,false);                     //Set the LED at row and col to off
        if(currentMillisbar - previousMillisbar > interval1) //Check to see if the interval time has passed
        {                                       //If enough time has passed:
          previousMillisbar = currentMillisbar;  //Store current program time
          row--;                              //Decrease row number by one
        }                                       //Decrease row number by one
      }
      row = 4;              //Reset row to 4
      col--;                //Decrease column number by one
  }
  updown -= updown;     //updown changes from negative to positive value
  }                   //updown no longer negative, exit if loop
}

void safetyoff()    //System is ready to fire
{
  justreleased[0] = 0;  //sometimes the wind down sound plays first when the intensify button is pressed
                        //this seems to prevent that.
  /*
   * The below code is very similar to the hum code.  Please see hum section for
   * comments.  I will note differences here
   */
  if (updown = 1)
  {
    int col = 0;
    int row = 0;
    while(col<7)
    {
      while(row<4)
      {
        check_switches();

        if (pressed[0])  //the "intensify" switch on
        {

          Serial.println("Fire");  //Print next state
          wTrig.trackPlayPoly(3);  //Start to play firing sound
          opState = FIRE;      //Go to fire
          return;
        }

        if (justreleased[1])  //the "activate" switch off
        {
          justreleased[1] = 0;  //reset justreleased 1
          Serial.println("Safety On"); //Print next state
          opState = HUM;     //Go to hum
          return;
        }

        if (justreleased[2])  //the "power" switch off
        {
          justreleased[2] = 0;  //reset justreleased 2
          Serial.println("Shutting Down");  //Print next state
          opState = POWERDOWN;    //Go to powerdown
          return;
        }
        lc.setLed(0,row,col,true);
        row++;
      }
      row = 0;
      col++;
      /*
       * NOTE THAT TEHRE IS NO TIMING HERE, THIS WILL GIVE THE APPEARANCE
       * OF THE BAR GRAPH FILLING UP INSTANTANEOUSLY
       */
    }
  updown -= updown;
  }

  long barstop = random(1, 4);  //This is a random number between one and three that will be used
                                //to keep the bar graph mostly lit but animated
  if (updown = -1)
  {
    int col = 7;
    int row = 4;
    while(col>barstop)
    {
      while(row>-1)
      {
        check_switches();
        if ((justpressed[0]) || (pressed[0]))  //the "intensify" switch off
        {
          justpressed[0] = 0;  //reset justreleased 0
          Serial.println("Fire"); //Print next state
          wTrig.trackPlayPoly(3); //Play the firing sound
          wTrig.trackLoop(3, 1);  //Put firing sound on a loop
          opState = FIRE; //Go to fire
          return;
        }

        if (justreleased[1])  //the "activate" switch off
        {
          justreleased[1] = 0;  //reset justreleased 1
          Serial.println("Safety On");
          opState = HUM;
          return;
        }

        if (justreleased[2])  //the "power" switch off
        {
          justreleased[2] = 0;  //reset justreleased 2
          Serial.println("Shutting Down");
          opState = POWERDOWN;
          return;
        }

        unsigned long currentMillisbar = millis();
        lc.setLed(0,row,col,false);
        if(currentMillisbar - previousMillisbar > 10)
        {
          previousMillisbar = currentMillisbar;
          row--;
        }
      }
      row = 4;
      col--;
    }
    updown -= updown;
  }
}

void fire()
{
  unsigned long currentMillisbar2 = millis();           //Get program time
  if(currentMillisbar2 - previousMillisbar2 > interval1)  //If enough time has passed
  {
    check_switches();

    if (justreleased[0])  //the "intensify" switch off
    {
      justreleased[0] = 0;  //reset justreleased 0
      Serial.println("Cease Fire - Still armed");
      wTrig.trackStop(3); //stop firing sound
      wTrig.trackPlayPoly(4); //play wind down sound
      opState = SAFETYOFF;    //Go to safety off
      return;
    }

    if (justreleased[1])  //the "activate" switch off
    {
      justreleased[1] = 0;  //reset justreleased 1
      Serial.println("Cease Fire - Unarmed");
      wTrig.trackStop(3);  //stop firing sound
      wTrig.trackPlayPoly(4); //play wind down sound
      opState = HUM;    //Go to hum
      return;
    }

    if (justreleased[2])  //the "power" switch off
    {
      justreleased[2] = 0;  //reset justreleased 2
      Serial.println("Shutting Down");  //Pring next state
      opState = POWERDOWN;  //Go to powerdown (don't worry about stopping the sounds, powerdown takes care of that
      return;
    }

    previousMillisbar2 = currentMillisbar2; //Record current time
    firepos = firepos + updown2;    //Increment firepos by updown2 (+/-1)
  }

  if(firepos == 0)        //All the following ifs set the rows of the matrix bar graph
  {                       //using values from the bytes defined near the beginning of
  lc.setRow(0,0,a[0]);    //the program
  lc.setRow(0,1,b[0]);
  lc.setRow(0,2,b[0]);
  lc.setRow(0,3,a[0]);
  }
  else if(firepos == 1)
  {
  lc.setRow(0,0,b[0]);
  lc.setRow(0,1,a[0]);
  lc.setRow(0,2,a[0]);
  lc.setRow(0,3,b[0]);
  }
  else if(firepos == 2)
  {
  lc.setRow(0,0,a[4]);
  lc.setRow(0,1,a[0]);
  lc.setRow(0,2,a[0]);
  lc.setRow(0,3,b[1]);
  }
  else if(firepos == 3)
  {
  lc.setRow(0,0,a[0]);
  lc.setRow(0,1,a[4]);
  lc.setRow(0,2,b[1]);
  lc.setRow(0,3,a[0]);
  }
  else if(firepos == 4)
  {
  lc.setRow(0,0,a[0]);
  lc.setRow(0,1,b[1]);
  lc.setRow(0,2,a[4]);
  lc.setRow(0,3,a[0]);
  }
  else if(firepos == 5)
  {
  lc.setRow(0,0,b[1]);
  lc.setRow(0,1,a[0]);
  lc.setRow(0,2,a[0]);
  lc.setRow(0,3,a[4]);
  }
  else if(firepos == 6)
  {
  lc.setRow(0,0,a[3]);
  lc.setRow(0,1,a[0]);
  lc.setRow(0,2,a[0]);
  lc.setRow(0,3,b[2]);
  }
  else if(firepos == 7)
  {
  lc.setRow(0,0,a[0]);
  lc.setRow(0,1,a[3]);
  lc.setRow(0,2,b[2]);
  lc.setRow(0,3,a[0]);
  }
  else if(firepos == 8)
  {
  lc.setRow(0,0,a[0]);
  lc.setRow(0,1,b[2]);
  lc.setRow(0,2,a[3]);
  lc.setRow(0,3,a[0]);
  }
  else if(firepos == 9)
  {
  lc.setRow(0,0,b[2]);
  lc.setRow(0,1,a[0]);
  lc.setRow(0,2,a[0]);
  lc.setRow(0,3,a[3]);
  }
  else if(firepos == 10)
  {
  lc.setRow(0,0,a[2]);
  lc.setRow(0,1,a[0]);
  lc.setRow(0,2,a[0]);
  lc.setRow(0,3,b[3]);
  }
  else if(firepos == 11)
  {
  lc.setRow(0,0,a[0]);
  lc.setRow(0,1,a[2]);
  lc.setRow(0,2,b[3]);
  lc.setRow(0,3,a[0]);
  }
  else if(firepos == 12)
  {
  lc.setRow(0,0,a[0]);
  lc.setRow(0,1,b[3]);
  lc.setRow(0,2,a[2]);
  lc.setRow(0,3,a[0]);
  }
  else if(firepos == 13)
  {
  lc.setRow(0,0,b[3]);
  lc.setRow(0,1,a[0]);
  lc.setRow(0,2,a[0]);
  lc.setRow(0,3,a[2]);
  }

  if (firepos > 13) //There are thirteen steps through this animation, if firepos passes 13
  {
    updown2 = -1;   //Set updown2 to -1 to which causes animation to run backwards
  }

  if (firepos < 0)  //Animation has run all the way backwards to the start
  {
    updown2 = 1;    //Set updown2 to +1 to start again
  }
}

void powerdown()
{
  wTrig.stopAllTracks();    //Stop all sounds/music
  wTrig.trackPlayPoly(5);   //Play power off sound
  /*
   * The below code should be familiar now.  This time it just empties the
   * bar graph at a rate such taht the end of the animation roughly lines up
   * with the end of the power off sound.
   */
  int col = 7;
  int row = 4;
  while(col>-1)
  {
    while(row>-1)
    {
      unsigned long currentMillisbar = millis();
      lc.setLed(0,row,col,false);
      if(currentMillisbar - previousMillisbar > 50)
      {
        previousMillisbar = currentMillisbar;
        row--;
      }
    }
    row = 4;
    col--;
  }

  Serial.println("Off");    //print the next state
  opState = OFF;    //Go to off
  return;
}

void music()    //Music mode
{
  /*
   *   Since there ins't any timing to worry about here the check switches
   *   function call in the main loop is good enough for button/switch tracking
   *
   *   So far I am only using the soundtracks for the first and second movies
   *   Each on has ten songs.
   */
  if (pressed[1]) //Activate switch is flipped on
  {
    songcount = -1; //count down through the songs
  }
  else
  {
    songcount = 1;  //count up through the songs
  }

  if (pressed[3])   //if the extra switch if flipped up
  {
    soundtrack = 1; //Indicate soundtrack mode desired
  }
  else
  {
    soundtrack = 0; //No soundtrack mode
  }

  if (justpressed[4]) //barrel button pressed
  {
    justpressed[4] = 0; //reset justpressed[4]
    songnum = songnum + songcount;  //increment the song number by 1 if activate is off and -1 if activate is on
      if(songnum < 101) //Lower than the firest song
      {
        songnum = 120;  //Set to highest song
      }
      if(songnum > 120) //Higher than last song
      {
        songnum = 101;  //Set to lowest song
      }
      Serial.print("Next song cued ");  //Print the selected song number
      Serial.print(songnum);
      Serial.println();
  }

  /*
   * The below bar graph code lights up one LED for the corresponding song
   */
  if (songnum == 101)
  {
      lc.setRow(0,0,b[3]);
      lc.setRow(0,1,a[0]);
      lc.setRow(0,2,a[0]);
      lc.setRow(0,3,a[0]);
    }
    if (songnum == 102)
    {
      lc.setRow(0,0,a[0]);
      lc.setRow(0,1,b[3]);
      lc.setRow(0,2,a[0]);
      lc.setRow(0,3,a[0]);
    }
    if (songnum == 103)
    {
      lc.setRow(0,0,a[0]);
      lc.setRow(0,1,a[0]);
      lc.setRow(0,2,b[3]);
      lc.setRow(0,3,a[0]);
    }
    if (songnum == 104)
    {
      lc.setRow(0,0,a[0]);
      lc.setRow(0,1,a[0]);
      lc.setRow(0,2,a[0]);
      lc.setRow(0,3,b[3]);
    }
    if (songnum == 105)
    {
      lc.setRow(0,0,b[2]);
      lc.setRow(0,1,a[0]);
      lc.setRow(0,2,a[0]);
      lc.setRow(0,3,a[0]);
    }
    if (songnum == 106)
    {
      lc.setRow(0,0,a[0]);
      lc.setRow(0,1,b[2]);
      lc.setRow(0,2,a[0]);
      lc.setRow(0,3,a[0]);
    }
    if (songnum == 107)
    {
      lc.setRow(0,0,a[0]);
      lc.setRow(0,1,a[0]);
      lc.setRow(0,2,b[2]);
      lc.setRow(0,3,a[0]);
    }
    if (songnum == 108)
    {
      lc.setRow(0,0,a[0]);
      lc.setRow(0,1,a[0]);
      lc.setRow(0,2,a[0]);
      lc.setRow(0,3,b[2]);
    }
    if (songnum == 109)
    {
      lc.setRow(0,0,b[1]);
      lc.setRow(0,1,a[0]);
      lc.setRow(0,2,a[0]);
      lc.setRow(0,3,a[0]);
    }
    if (songnum == 110)
    {
      lc.setRow(0,0,a[0]);
      lc.setRow(0,1,b[1]);
      lc.setRow(0,2,a[0]);
      lc.setRow(0,3,a[0]);
    }
    if (songnum == 111)
    {
      lc.setRow(0,0,a[0]);
      lc.setRow(0,1,a[0]);
      lc.setRow(0,2,b[1]);
      lc.setRow(0,3,a[0]);
    }
    if (songnum == 112)
    {
      lc.setRow(0,0,a[0]);
      lc.setRow(0,1,a[0]);
      lc.setRow(0,2,a[0]);
      lc.setRow(0,3,b[1]);
    }
    if (songnum == 113)
    {
      lc.setRow(0,0,b[0]);
      lc.setRow(0,1,a[0]);
      lc.setRow(0,2,a[0]);
      lc.setRow(0,3,a[0]);
    }
    if (songnum == 114)
    {
      lc.setRow(0,0,a[0]);
      lc.setRow(0,1,b[0]);
      lc.setRow(0,2,a[0]);
      lc.setRow(0,3,a[0]);
    }
    if (songnum == 115)
    {
      lc.setRow(0,0,a[0]);
      lc.setRow(0,1,a[0]);
      lc.setRow(0,2,b[0]);
      lc.setRow(0,3,a[0]);
    }
    if (songnum == 116)
    {
      lc.setRow(0,0,a[0]);
      lc.setRow(0,1,a[0]);
      lc.setRow(0,2,a[0]);
      lc.setRow(0,3,b[0]);
    }
    if (songnum == 117)
    {
      lc.setRow(0,0,a[4]);
      lc.setRow(0,1,a[0]);
      lc.setRow(0,2,a[0]);
      lc.setRow(0,3,a[0]);
    }
    if (songnum == 118)
    {
      lc.setRow(0,0,a[0]);
      lc.setRow(0,1,a[4]);
      lc.setRow(0,2,a[0]);
      lc.setRow(0,3,a[0]);
    }
    if (songnum == 119)
    {
      lc.setRow(0,0,a[0]);
      lc.setRow(0,1,a[0]);
      lc.setRow(0,2,a[4]);
      lc.setRow(0,3,a[0]);
    }
    if (songnum == 120)
    {
      lc.setRow(0,0,a[0]);
      lc.setRow(0,1,a[0]);
      lc.setRow(0,2,a[0]);
      lc.setRow(0,3,a[4]);
    }

  if (justpressed[0]) //Intensify is pressed
  {
    justpressed[0] = 0; //reset justpressed[0]
    songplaying = songnum;  //selected song now equals playing song
    wTrig.stopAllTracks();  //stop all sounds/songs
    wTrig.trackPlayPoly(songnum); //start playing selected song
    Serial.print("Now Playing: ");  //Print the playing song
    Serial.print(songplaying);
    Serial.println();
  }
  if (justreleased[2])  //the "power" switch off
  {
    justreleased[2] = 0;  //reset justreleased 2
    if (soundtrack == 0)  //Extra switch is flipped off
    {
      wTrig.stopAllTracks();  //stop all sounds/music
    }
    else if (soundtrack == 1) //Soundtrack mode called for
    {
      wTrig.trackLoop(songplaying, 1);  //Loop the song that is playing
    }
    songnum = 101;  //Reset the song select counter for next time entering music mode
    Serial.println("Off");  //Print next state
    opState = OFF;  //Go to off
    return;
  }
}

Please forgive any spelling mistakes in my comments.

Cheers,

Berg

Hi i know that this is a really old post but i need some help. Can you share your electric schema please? I bouth same bargraph.

Thanks,

Ciro

Hi Ciro, sorry for the late reply. I do not have a schematic for this, but I can describe how I got is working. Sorry in advance for the length of this post.

This bar graph takes a little bit of thinking to get working, but once figured out should be fairly straightforward. The first thing that needs to be understood is multiplexing.

In this case multiplexing is a method of driving multiple LEDs in a matrix. The trick with multiplexing is that the LEDs are not fully “on” while being displayed. Instead they “flash” very quickly. Because the human eye has persistence of vision that lasts longer than each LED is off for it appears to be on full time. This is how old movie film works, instead of seeing individual frames we see a motion picture.

LEDs only turn on when a current flows through it when the anode is connected to a positive voltage and the cathode is connected to ground. Typically you will need a current limiting resistor in series to prevent too much current going through the LED and burning it out.

Now for multiplexing look at this LED matrix (image from this page: http://lednique.com/display-technology/multiplexed-display/);

In the above image the switch S2 is providing voltage to the second row. By itself this would do nothing, but since switch S6 is also closed it provides a path for current to ground LED L7 will now light up.

Now if we wanted LED L6 to also light up the switch S5 would need to be closed as well. Now both L6 and L7 will be on, but depending on the driving source this might provide problems with current supply. So instead, for multiplexing, the switches S5 and S6 will alternate being closed. This happens fast enough that the LEDs appear to be on a full brightness. If we wanted L12 to also turn on then S2 would be closed, S5 closed, then S5 opened, then S6 closed, then S2 and S6 opened, and finally S3 and S7 closed. Then the whole sequence repeats for as long as these three LEDs are desired to be on.

Now take a look as some of the information provided by the manufacturer of the bargraph:

As can be seen by the image with the grey background this is already set up for multiplexing. There are four positive connections (L1, L2, L3, L4) and seven connections to ground (C1, C2, C3, C4, C5, C6, C7). An Arduino can be used by itself to multiplex, but it would be resource heaving requiring eleven pins to switch on and off and precise timing. For this reason I instead used an LED display driver, the MAX7219. This received serial commands from the Arduino with instructions of what to turn on and handles the rest. Even better, there is already a library written for this chip using SPI. This is usually used to run seven segment displays with an extra dot (essentially eight segment).

This image is handy because it lists how the MAX7219 connects to the display. The MAX7219 has a positive (anode connection) listed as SEG A through SEG G and a SEG DP. The ground (cathode connection) are listed as DIG 0 through DIG 7. So the chip is designed to drive an eight digit display of eight segment characters. The datasheet describing the connections can be viewed here:

https://datasheets.maximintegrated.com/en/ds/MAX7219-MAX7221.pdf

So, to connect it all together I have the Arduino connected to the MAX7219 using three connections (not including power and ground), Data In (DIN) pin 1 on MAX7219, Clock (CLK) pin 13 on MAX7219, and Chip Select (CS) pin 12 on MAX7219.

The MAX7219 is connected to the bargraph like this:

  • SEG A (pin 14) to L1

  • SEG B (pin 16) to L2

  • SEG C (pin 20) to L3

  • SEG D (pin 23) to L4

  • DIG 0 (pin 2) to C1

  • DIG 1 (pin 11) to C2

  • DIG 2 (pin 6) to C3

  • DIG 3 (pin 7) to C4

  • DIG 4 (pin 3) to C5

  • DIG 5 (pin 10) to C6

  • DIG 6 (pin 5) to C7

Beyond that you just need to write some code to drive the chip. Remember when writing your code that you need to only use the first four segments (SEGs) and first seven digits (DIGs) and then either reverse the pattern or repeat the pattern.

Hope this helps!

Cheers,

Berg