LED Timer Programming Help

Hey Guys,
I’m currently working on an LED Arduino project that will control an 8x8 led matrix display and another number of LEDs to turn on and off in certain patterns. I’m relatively new to C++ so my coding is a small bit inefficient .

I’ve had a look at the LED & Multiplexing forum but I thought the Programming section would be more appropriate.

I basically would like to split the two top rows from the 8x8 matrix and have two led sections running independently i.e. a 2 x 8 matrix and a 6 x 8 matrix and maybe another few sections to be added later. I’ve created separate voids to deal with the lighting of these leds. The end result I was hoping for each section to run “simultaneously”.

After a bit of research I see this is impossible and I could only make it appear like its simultaneous by using timers. I have looked through various tutorials(e.g. http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay) about timers and I think I understand the basics but on implementation of a timer into my code it becomes a little funky.

The led sequences are finishing one iteration before being interrupted by another sequence and it just loops.

I can’t seem to figure out whats wrong with the timers? I think it may be something in the voids themselves. If someone could point me in the right direction I’d be grateful.

Thanks in advance.

unsigned long lastEarFrame = 0;
unsigned long lastCheekFrame = 0;
unsigned long lastChinFrame = 0;
unsigned int earSpeed = 300; 
unsigned int cheekSpeed = 150;
unsigned int chinSpeed = 200; 
int k, p, n, t, m, m1;
int cheekAnimation = 1;
int count = 0;

#include "TrueRandom.h"
#include "LedControl.h" //  need the library
LedControl lc = LedControl(12, 11, 10, 1);

void setup() {
  //Set some pins as outputs for ears - 5 for 5 Leds
  Serial.begin(115200);
  // Max7219 Code
  lc.shutdown(0, false);
  lc.setIntensity(0, 15);
  lc.clearDisplay(0);
}

void loop() {

unsigned long currentTime = millis();
  
  // check to see if its time to animate the ear  
  if(currentTime > (lastEarFrame+earSpeed))
  {
    animateEar();
    lastEarFrame = currentTime;
  }
  
  // check to see if its time to animate the cheek  
  if(currentTime > (lastCheekFrame+cheekSpeed))
  {
    animateCheek();
    lastCheekFrame = currentTime;
  }
  
  
  // check to see if its time to animate the chin leds  
  if(currentTime > (lastChinFrame+chinSpeed))
  {
    animateChin();
    lastChinFrame = currentTime;
  }
  
}

void animateEar()
{
// To be created
}
void animateCheek() {
  if (count >= 4)
  {
    cheekAnimation++;
    count = 0;
  }
  if (cheekAnimation > 4)// Number should be equal to number of cases in switch below.
  {
    cheekAnimation = 1;
  }
  switch (cheekAnimation)
  {
    case 1: OneWay();             break;
    case 2: TwoWay();             break;
    case 3: OneWayReverse();         break;
    case 4: TwoWayReverse();         break;


      //default: OneWay();      break;
  }
}
void OneWay()
{
  for (m = 0; m <= 7; m++) {
    lc.setLed(0, 0, m, true);
    lc.setLed(0, 1, m, true);
    delay (cheekSpeed);
    lc.setLed(0, 0, m, false);
    lc.setLed(0, 1, m, false);

  }
  count++;
}
void TwoWay()
{
  for (m = 0; m <= 7; m++) {
    lc.setLed(0, 0, m, true);
    lc.setLed(0, 1, abs(m - 7), true);
    delay (cheekSpeed);
    lc.setLed(0, 0, m, false);
    lc.setLed(0, 1, abs(m - 7), false);
  }
  count++;
}
void OneWayReverse()
{

  for (m = 0; m <= 13; m++) {
    lc.setLed(0, 0, abs(m - 7), true);
    lc.setLed(0, 1, abs(m - 7), true);
    delay (cheekSpeed);
    lc.setLed(0, 0, abs(m - 7), false);
    lc.setLed(0, 1, abs(m - 7), false);
  }
  count++;
}
void TwoWayReverse()
{
  for (m = 0; m <= 13; m++) {
    if (m < 7) {
      m1 = m;
    }
    else {
      m1 = 14 - m;
    }

    lc.setLed(0, 0, m1, true);
    lc.setLed(0, 1, abs(m - 7), true);
    delay (cheekSpeed);
    lc.setLed(0, 0, m1, false);
    lc.setLed(0, 1, abs(m - 7), false);
  }
  count++;
}
void animateChin()
{// cant use set column and set led together. chin and cheek clash.
int randnumber = TrueRandom.random(2,8);// 2 to avoid the first two rows and 8 because (8-1 = 7) and 7 is the last row.
 //p += led_bit[k];
 for (k = 7;k >= randnumber; k--){
  lc.setLed(0, k, 0, true);
  lc.setLed(0, k, 1, true);
  lc.setLed(0, k, 2, true);
  lc.setLed(0, k, 3, true);
  lc.setLed(0, k, 4, true);
  lc.setLed(0, k, 5, true);
  lc.setLed(0, k, 6, true);
  lc.setLed(0, k, 7, true);
  delay(chinSpeed);
}
for (k = randnumber; k <= 7; k++) {
 
   // p -= led_bit[k];
 
  lc.setLed(0, k, 0, false);
  lc.setLed(0, k, 1, false);
  lc.setLed(0, k, 2, false);
  lc.setLed(0, k, 3, false);
  lc.setLed(0, k, 4, false);
  lc.setLed(0, k, 5, false);
  lc.setLed(0, k, 6, false);
  lc.setLed(0, k, 7, false);
  delay(chinSpeed);
 }
  //k = 0;
}

Here is a sketch using the timer setup you want.

/* 
  State Machine.
  
  This is a piece of code that constitutes a state machine.
  It is used to start an event, then keeping an eye on that event to see if its time slot has elapsed.
  The state machine is what you need to avoid using the "sleep-mode" function delay().
  Note that the code relies on global variables to store the STATE of the events.
  If you try calling the event functions with these variables as parameters, it wont work, as the
  parameters then will be considered local variables in the scope of the functions.
     
  In this code three events controls two blinking LEDs with individual blink intervals, using an event function for each LED.

  The code is written and explained by :
  Jasmine2501
  In this youtube video :
  https://www.youtube.com/watch?v=3VZgaJBrZD8 
  
  Modified 29-03-15 by Anders53
  
*/

// Constants defines pin numbers
const int blueLedPin = 10;             // the number of the blue LED pin
const int greenLedPin = 11;            // the number of the green LED pin
const int redLedPin = 12;              // the number of the red LED pin

// Variables will change
int blueLedState = HIGH;               // ledState for blue LED
int greenLedState = HIGH;              // ledState for green LED
int redLedState = HIGH;                // ledState for red LED
long previousMillisBlue = 0;           // last time blue LED was updated
long previousMillisGreen = 0;          // last time green LED was updated
long previousMillisRed = 0;            // last time red LED was updated

// Must be long integers to prevent overflow
long blueLedInterval = 1090;          // interval to blink blue LED (milliseconds)
long greenLedInterval = 1100;         // interval to blink green LED (milliseconds)
long redLedInterval = 1110;           // interval to blink red LED (milliseconds)
unsigned long currentMillis = 0;      // Current time (milliseconds)

void setup()
{  // Set the pins to output mode
  pinMode(blueLedPin, OUTPUT);
  pinMode(greenLedPin, OUTPUT);
  pinMode(redLedPin, OUTPUT);
  digitalWrite(blueLedPin, blueLedState);
  digitalWrite(greenLedPin, greenLedState);
  digitalWrite(redLedPin, redLedState);
}

void loop()
{ 
  currentMillis = millis(); // Capture the current time
  manageBlueLed();
  manageGreenLed();
  manageRedLed();
}

void manageBlueLed()  // function : check if it's time to change state of the blue LED yet
{
  if (currentMillis - previousMillisBlue > blueLedInterval) // state change condition
  {
    previousMillisBlue = currentMillis;  //store the time of this state change
    // next 2 lines is the event controlled
    blueLedState = (blueLedState == HIGH) ? LOW : HIGH;
    digitalWrite(blueLedPin, blueLedState);
  }
}

void manageGreenLed() // function : check if it's time to change state of the green LED yet
{
  if (currentMillis - previousMillisGreen > greenLedInterval) // state change condition
  {
    previousMillisGreen = currentMillis; //store the time of this state change
    // next 2 lines is the event controlled
    greenLedState = (greenLedState == HIGH) ? LOW : HIGH;
    digitalWrite(greenLedPin, greenLedState);
  }
}

void manageRedLed()  // function : check if it's time to change state of the red LED yet
{
  if (currentMillis - previousMillisRed > redLedInterval) // state change condition
  {
    previousMillisRed = currentMillis;  //store the time of this state change
    // next 2 lines is the event controlled
    redLedState = (redLedState == HIGH) ? LOW : HIGH;
    digitalWrite(redLedPin, redLedState);
  }
}

Stop calling them "voids". They are called functions.

A function must be declared with a return type. If the return type is void it returns no value, but it is still a function, not a void.

"void" is a keyword needed in Arduino c, telling the compiler what kind of function you have build. Not a free name.

Noted on the functions
On reviewing that material I can say that my timers are in fact fine. It seems that my using of the delay function to control the blinking of the lights in the led lighting functions is the culprit. Now I just have to figure out how to light my leds without using the delay function to control the spacing :disappointed_relieved:

Now I just have to figure out how to light my leds without using the delay function to control the spacing

Well, you could always BlinkWithoutDelay…

UKHeliBob: Well, you could always BlinkWithoutDelay....

or use the code I submitted ... which is in fact a refinement of BlinkWithoutDelay.

I seem to be missing the point I think. I have basically the same set up as Anders53 refinement of BlinkWithoutDelay and I use that make sure the functions are called at the right times but within these functions there is some form of algorithm to create a pattern for my leds. Now these patterns won't work without the delay function which is what I need to eliminate. Am i correct in saying that I need to incorporate the BlinkWithoutDelay setup into these functions as well?

In order to eliminate delay() entirely you need to rethink your program structure. My favoured way would be to use switch/case but you can also do it with if/else. The principle is to set a variable to the current state number then to have loop() containing a switch/case on the state number so that code for the current state is executed until the exit condition (or conditions) for the state are true, at which point the state variable is set to the target state and any entry conditions, such as current time from millis(), are set up.

At any time your program will be in one of many states. Let's take an example such as animating the chin. Suppose this is state 7 so the code for it is executed each time through loop() by means of the switch/case. You cannot use your current animateChin() function because of the blocking delay but you could execute part of it each time through loop when state is 7. Set the random number before exiting the previous state.

The chin function has its own states. Lets call them chinstates to differentiate them from the main program state. Set chinstate at 0 before exiting the previous main state. When the function is entered because state is 7 check chinstate using switch/case and carry out the actions for that state. Update chinstate when the actions for that chinstate are complete, break from the chinstate switch/case, break from the state switch/case and go round loop() again.

If the program is still in state 7 (chin animation not complete) execute the current chinstate actions, update chinstate and go round loop() again. Eventually every chinstate will have been satisfied so move the main state to the next state, possibly waiting for input.

Because the code in loop() outside the main switch/case, is executed frequently the program will remain responsive.

Ah i see. Thanks for that. From your explanation The only thing that remains unclear to me is how do i deal with the cases I have for different patterns? So i would have a case for turning on specific LEDs and another for turning them off and turning on new LEDs and so on until I have finished a pattern. But what then if i would like to change the pattern? Add another state and break that down into switch/cases aswell? Won't this result in a very very large quantity of switch/case?

Just wrote down a quick example of what I meant. If I'm on the right track let me know.

Void AnimateCheek()
cheekanimation++
switch(cheekanimation)
Case 1: A; break;
Case 2: B; break;
Case 3: C; break;
Case 4: D; break;

Void A
switch(Cheekstate)
Case 1: Led1 on; break; //each of these will increase the variable Cheekstate when complete.
Case 2: Led1 off; break;
Case 3: Led2 on; break;
Case 4: Led2 off; break;
Case 5: Led3 on; break;
Case 6: Led3 ooff; break;
Case 7: Led4 on; break;
Case 8: Led4 off; break;
Case 9: Led5 on; break;
Case 10: Led5 off; break;
Case 11: Led6 on; break;
Case 12: Led6 off; break;
Case 13: Led7 on; break;
Case 14: Led7 off; break;// this will reset Cheekstate to 0

Void B
//As above
Void C
//As above
Void D
//As above
Case 1: Led1 on; break; //each of these will increase the variable Cheekstate when complete.
Case 2: Led1 off; break;
Case 3: Led2 on; break;
Case 4: Led2 off; break;
Case 5: Led3 on; break;
etc
etc

Instead of switch/case put the LED pin numbers in an array and increment a variable each time you enter the cheek function, then you don't need the switch/case because you can use the variable to access the LED pin numbers directly.

Is that possible with my setup? I'm using an LEDcontrol library with a max7219 and the arduino so I need to pick an LED index rather than a pin on the Arduino. And if Increment the variable i wont be able to turn the previous LED off without a different function?

Is that possible with my setup?

Why not ? A LED index or an array index, it's just a number either way.

if Increment the variable i wont be able to turn the previous LED off

If you know the number of the current LED then you can work out what the previous one was....

I've made an array with the led column numbers and just iterate through them turning them on and off using the timer instead of the delay. LEDs all appear to be working together. Thanks for all your help, it was very educational.