Pages: [1]   Go Down
Author Topic: simple LED chaser without delay  (Read 861 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
/*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!
Logged

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 95
Posts: 4089
CODE is a mass noun and should not be used in the plural or with an indefinite article.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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;  ?
Logged

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

Sydney, Australia
Offline Offline
Edison Member
*
Karma: 33
Posts: 1283
Big things come in large packages
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
« Last Edit: November 23, 2013, 10:38:56 pm by marco_c » Logged

Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

for (;smiley-wink { } 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.
Logged

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 95
Posts: 4089
CODE is a mass noun and should not be used in the plural or with an indefinite article.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Couple more things.

Code:
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!
« Last Edit: November 23, 2013, 10:48:57 pm by Jack Christensen » Logged

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

Global Moderator
Boston area, metrowest
Offline Offline
Brattain Member
*****
Karma: 545
Posts: 27352
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You could simplify it a bit:
Code:
/*
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;
    }
  }

Logged

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.

Helsingborg, Sweden
Offline Offline
God Member
*****
Karma: 24
Posts: 556
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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()
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You could simplify it a bit:
Code:
/*
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.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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.
Logged

East Anglia (UK)
Offline Offline
Faraday Member
**
Karma: 116
Posts: 4312
May all of your blinks be without delay()
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Saskatchewan
Offline Offline
Sr. Member
****
Karma: 19
Posts: 364
When the going gets weird, the weird turn pro. - Hunter S. Thompson
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
/*
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);
    }
  }
}
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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:
    i = ++i % (numberOfBlades - 1);        // advance i handle rollover
which as modulo 2 of numbers was producing 1, 0, 1, 1, 0, 1... To:
Code:
    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.
Logged

Helsingborg, Sweden
Offline Offline
God Member
*****
Karma: 24
Posts: 556
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

http://arduino.cc/en/Guide/Libraries

Modulo arithmetic is a little tricky but very useful:

++i %= numberOfBlades works..
« Last Edit: November 25, 2013, 08:54:07 am by nilton61 » Logged

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 135
Posts: 6782
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

modularity is your friend.  I would do somthing like:
Code:
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!)
Logged

Pages: [1]   Go Up
Jump to: