Go Down

Topic: simple LED chaser without delay (Read 957 times) previous topic - next topic

pm1066

Standard semi newbie disclaimer....

I'm trying to do something relatively simple, and getting stuck.  My goal is to have a simple 1-2-3-1-2-3-1-2-3... chaser of 3 LEDs.  I can do this using a delay function easily, but want to use a millis() type solution like Blink Without Delay.  So, in short;

All LEDs off
Turn on LED 1,
check to see if fixed interval passed
if true, turn off LED 1, turn LED 2 on
Check timer
if true, turn off LED 1, 2, turn LED 3  on

My current code example only turns on the fisrt LED constantly:
Code: [Select]
/*This sketch borrows the array setup from the 5 random blink
without sketch


*/
const int numberOfBlades = 3;
int ledPin[] = { 6, 7, 9}; // LED pins to use.
int ledState[3];
long interval = 83;
long previousMillis = 0;        // will store last time LED was updated
int i = 0;

void setup() {
for(int i = 0; i<numberOfBlades; i++){
   pinMode(ledPin[i],OUTPUT);
   ledState[i] = LOW;
   digitalWrite(ledPin[i], LOW); // all LEDs off
}

}

void loop() {
  unsigned long currentMillis = millis();   
  if(currentMillis - previousMillis > interval) {             // Arduino run time - changeTime value greater then ledDelay variable? Yes then
    previousMillis = currentMillis;
    changeLED();       // Go to changeLED routine.
    i = i++ % 2;       //i is either 0, 1 or 2
  }

 
void changeLED(){
for(; ;){
  if (i % 0 == 0){
    ledState[0] = HIGH;
    ledState[1] = LOW;   
    ledState[2] = LOW; 
    digitalWrite(ledPin[i],ledState[i]);
  }
  else if (i % 1 == 0){
    ledState[0] = LOW;
    ledState[1] = HIGH;   
    ledState[2] = LOW; 
    digitalWrite(ledPin[i],ledState[i]);
  }
  else (i % 2 == 0);  {
    ledState[0] = LOW;
    ledState[1] = LOW;   
    ledState[2] = HIGH; 
    digitalWrite(ledPin[i],ledState[i]);
  }

}
}


Any help appreciated!

Jack Christensen

for (;;) { } is an infinite loop. So the first time that the changeLed() function is called, it just executes the for loop forever, i never gets changed, etc.

Maybe just taking the for loop out is all that is needed.

Oh one more thing, should  i = i++ % 2;  instead be  i = i++ % 3;  ?
MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

marco_c

#2
Nov 24, 2013, 01:51 am Last Edit: Nov 24, 2013, 04:38 am by marco_c Reason: 1
Check out my MultiBlink sketch in the code repository (linked below) for ideas on how this is done. You can also use the sketch directly if you want.
Arduino libraries http://arduinocode.codeplex.com
Parola for Arduino http://parola.codeplex.com

pm1066


for (;;) { } is an infinite loop. So the first time that the changeLed() function is called, it just executes the for loop forever, i never gets changed, etc.

Maybe just taking the for loop out is all that is needed.

Oh one more thing, should  i = i++ % 2;  instead be  i = i++ % 3;  ?

Removing the  for loop helped somewhat, now all three LEDs turn on.  The problem is they turn on very solely, and semi randomly blink.

That tells  me that the lighting isn't working on the 0.083 seconds cycle.

Jack Christensen

#4
Nov 24, 2013, 04:42 am Last Edit: Nov 24, 2013, 04:48 am by Jack Christensen Reason: 1
Couple more things.

Code: [Select]
i = i++ % 3;

is probably not doing what you want. It's an odd construct, the right side modifies i  by incrementing it then of course the assignment changes i  too. I'd have to research what the expected behavior would be. It might be better to break it down into two statements. I might just increment i then test if it's 3 or greater, in which case set it back to 0. Simpler, easier to read and understand.

The if clauses in changeLed() are incorrect. The modulo operator is not needed. Just test for 0, 1, and 2. Simpler.
Each if only does one digitalWrite... at least two will always be needed, one to turn off the current LED, one to turn on the next.

The last else is missing an if. Either that, or the condition clause in parens isn't needed.

Keep at it!
MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

CrossRoads

You could simplify it a bit:
Code: [Select]

/*
This sketch borrows the array setup from the 5 random blink without sketch
*/
const int numberOfBlades = 3;
int ledPin[] = {
  6, 7, 9}; // LED pins to use.
int ledState[3];
unsigned long currentMillis;
unsigned long interval = 83;
unsigned long previousMillis = 0;        // will store last time LED was updated
int i = 0;

void setup() {
  for(int i = 0; i<numberOfBlades; i++){
    pinMode(ledPin[i],OUTPUT);
    ledState[i] = LOW;
    digitalWrite(ledPin[i], LOW); // all LEDs off
  }

}

void loop() {
  currentMillis = millis();   
  if( (currentMillis - previousMillis) >= interval) {    // Arduino run time - changeTime value greater then ledDelay variable? Yes then
    previousMillis = previousMillis + interval;

    i = i+1;       //i is either 0, 1 or 2
    if (i==3){
      i = 0;
    }
    switch(i){
    case 0:
      digitalWrite (ledState[0], HIGH);
      digitalWrite (ledState[1], LOW);   
      digitalWrite (ledState[2], LOW); 
      break;
    case 1:
      digitalWrite (ledState[0], LOW);
      digitalWrite (ledState[1], HIGH);   
      digitalWrite (ledState[2], LOW); 
      break;
    case 2:
      digitalWrite (ledState[0], LOW);
      digitalWrite (ledState[1], LOW);   
      digitalWrite (ledState[2], HIGH); 
      break;
    }
  }

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

nilton61

One way is to use my state machine library found here: http://playground.arduino.cc/Code/SMlib
Its very easy to use and give clean readable code. Here is an example of what u are requesting

Code: [Select]
#include <SM.h>

SM ledChaser(Display, Wait);

const int numberOfBlades = 3;
int ledPin[numberOfBlades] = { 6, 7, 9}; // LED pins to use.
int currentLed;
long interval = 83;

void setup() {
for(int i = 0; i<numberOfBlades; i++){
   pinMode(ledPin[i],OUTPUT);
   digitalWrite(ledPin[i], LOW); // all LEDs off
}//for(i)
}//setup()

void loop(){
  EXEC(ledChaser);
}//loop()

State Display(){
  digitalWrite(ledPin[currentLed++], 0);//turn last led off
  currentLed %= numberOfBlades;//limit count
  digitalWrite(ledPin[currentLed], 1);//turn new led on
}//Display()

State Wait(){
  if(ledChaser.Timeout(interval)) ledChaser.Restart();
}//Wait()

pm1066


You could simplify it a bit:
Code: [Select]

/*
This sketch borrows the array setup from the 5 random blink without sketch
*/
const int numberOfBlades = 3;
int ledPin[] = {
  6, 7, 9}; // LED pins to use.
int ledState[3];
unsigned long currentMillis;
unsigned long interval = 83;
unsigned long previousMillis = 0;        // will store last time LED was updated
int i = 0;

void setup() {
  for(int i = 0; i<numberOfBlades; i++){
    pinMode(ledPin[i],OUTPUT);
    ledState[i] = LOW;
    digitalWrite(ledPin[i], LOW); // all LEDs off
  }

}

void loop() {
  currentMillis = millis();   
  if( (currentMillis - previousMillis) >= interval) {    // Arduino run time - changeTime value greater then ledDelay variable? Yes then
    previousMillis = previousMillis + interval;

    i = i+1;       //i is either 0, 1 or 2
    if (i==3){
      i = 0;
    }
    switch(i){
    case 0:
      digitalWrite (ledState[0], HIGH);
      digitalWrite (ledState[1], LOW);   
      digitalWrite (ledState[2], LOW); 
      break;
    case 1:
      digitalWrite (ledState[0], LOW);
      digitalWrite (ledState[1], HIGH);   
      digitalWrite (ledState[2], LOW); 
      break;
    case 2:
      digitalWrite (ledState[0], LOW);
      digitalWrite (ledState[1], LOW);   
      digitalWrite (ledState[2], HIGH); 
      break;
    }
  }




Thanks, I'll have to peel this apart a bit more.  Currently it shuts all LEDs off.

pm1066


One way is to use my state machine library found here: http://playground.arduino.cc/Code/SMlib
Its very easy to use and give clean readable code. Here is an example of what u are requesting

Code: [Select]
#include <SM.h>

This is very interesting.  I wasn't able to figure out from that page how/where the state machine library is  installed on my PC so it compiles with the rest of the code.

UKHeliBob

It should be installed in a folder named SM under the libraries folder in the place where your programs are normally stored.  Stop and restart the IDE after you install the library.  You can check that it is available from the IDE by doing Sketch/Import Library
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Jimmy60

Once you have advanced i (I would have named it ptr) you can just display all the leds based on it. You could display the leds every time through loop or just when i changes. To display all the leds just cycle through them with a for loop.

Code: [Select]
/*
This sketch borrows the array setup from the 5 random blink without sketch
*/
const int numberOfBlades = 3;
int ledPin[numberOfBlades] = {
  6, 7, 9}; // LED pins to use.
unsigned long currentMillis;
unsigned long interval = 83;
unsigned long previousMillis = 0;        // will store last time LED was updated
int i = 0;

void setup() {
  for(int i = 0; i< numberOfBlades; i++)
  {
    pinMode(ledPin[i],OUTPUT);
    digitalWrite(ledPin[i], LOW); // all LEDs off
  }
}

void loop() {
  currentMillis = millis();   
  if( currentMillis - previousMillis >= interval) // Arduino run time - changeTime value greater then ledDelay variable? Yes then
  { 
    previousMillis = currentMillis;  // remember the time now
    i = ++i % (numberOfBlades - 1);        // advance i handle rollover
    for (int n = 0; n < numberOfBlades; n++) // display with new i
    {
      if ( n == i ) digitalWrite(ledPin[n], HIGH);
      else digitalWrite(ledPin[n], LOW);
    }
  }
}


pm1066

Jimmy60, Thanks!  That was the ultimate direction I was planning to go, but with the LED lighting sub not working I backed off the more complete full array setup.

I did test my counter routine, which was working:
Code: [Select]
void loop() {
  unsigned long currentMillis = millis();   
  if(currentMillis - previousMillis > interval) {             // Arduino run time - changeTime value greater then ledDelay variable? Yes then
    previousMillis = currentMillis;

    i = i++;       
    i= i%3;            //i is either 0, 1 or 2
      Serial.println("on");
      Serial.print("i:  ");
      Serial.println(i);

This produced a series of 0, 1, 2, 0, 1, 2, 0,... which I read on the serial monitor.

When I ran you code as is, the third LED (pin 9) wasn't lighting.  I modified the code from:
Code: [Select]
    i = ++i % (numberOfBlades - 1);        // advance i handle rollover
which as modulo 2 of numbers was producing 1, 0, 1, 1, 0, 1... To:
Code: [Select]
    i = ++i % (numberOfBlades);        // advance i handle rollover
so the pointers would go though 0, 1 and 2.  That completely fixed it.

I also see how ++i versus i++ makes the i = i++ % 3 not work, while i = ++i % 3 works.

nilton61

#12
Nov 25, 2013, 04:16 am Last Edit: Nov 25, 2013, 02:54 pm by nilton61 Reason: 1
http://arduino.cc/en/Guide/Libraries

Modulo arithmetic is a little tricky but very useful:

++i %= numberOfBlades works..

westfw

modularity is your friend.  I would do somthing like:
Code: [Select]
boolean delay_without_delaying(unsigned long time) {
// return false if we're still "delaying", true if time ms has passed.
// this should look a lot like "blink without delay"
  static unsigned long previousmillis = 0;
  unsigned long currentmillis = millis();
  if (currentmillis - previousmillis >= time) {
    previousmillis = currentmillis;
    return true;
  }
  return false;
}

void loop() {
  if (delay_without_delaying(1000)) {
    led_off(i++);
    if (i >= 3)
      i = 0;
    led_on(i);
  }
  // Other code.   


Hmm.  I like that idea.  You could actually use some c++ and do delay_without_delaying(unsigned long &since, unsigned long time) as well, if you want different start times for different things.  (oohh.  I'm learning something from my c++ class!)

Go Up