Blink without "delay()" - stepping up.

This is code.

Do correct me/ shout me down if this is not the most appropriate place, or if this has so blatantly been done before, but we are forever referring people to the "Blink without delay" example when they enquire as to how to blink multiple LEDs at different rates, or monitor switches and control LEDs, or the Traffic Lights or Pedestrian Crossing exercises from the college course.

So ....

Here is the first step in the exercise; symmetric code to blink three (extensible to "N") LEDs independently. Next step is pushbutton toggles.

// Blink without "delay()" - multi!

const int led1Pin =  13;    // LED pin number
const int led2Pin =  10;
const int led3Pin =  11;
int led1State = LOW;        // initialise the LED
int led2State = LOW;
int led3State = LOW;
long count1 = 0;           // will store last time LED was updated
long count2 = 0;
long count3 = 0;

// Have we completed the interval?
char timeout(long *marker, long interval) {
  if (millis() - *marker >= interval) { 
    *marker += interval; 
    return true;       
  } 
  else return false;
}

void setup() {
  pinMode(led1Pin, OUTPUT);      
  pinMode(led2Pin, OUTPUT);      
  pinMode(led3Pin, OUTPUT);      
}

void loop() {
  if (timeout(&count1, 500)) {
    if (led1State == LOW) {
      led1State = HIGH;
    }
    else {
      led1State = LOW; 
    } 
    digitalWrite(led1Pin, led1State);
  } 

  if (timeout(&count2, 300)) {
    if (led2State == LOW) {
      led2State = HIGH;
    }
    else {
      led2State = LOW; 
    } 
    digitalWrite(led2Pin, led2State);
  } 

  if (timeout(&count3, 175)) {
    if (led3State == LOW) {
      led3State = HIGH;
    }
    else {
      led3State = LOW; 
    } 
    digitalWrite(led3Pin, led3State);
  } 
}

Due deference to David A. Mellis and Paul Stoffregen for the "Blink without delay" example from which the code was used by whoever wrote the sketch that several generations later I used for the sketches I cite for testing matrices and which it was convenient to cut and paste in order to generate this. :smiley:

That kind of mostly uncommented code does not help the newbies.

Please add more to this

// Have we completed the interval?
char timeout(long *marker, long interval) {
  if (millis() - *marker >= interval) { 
    *marker += interval; 
    return true;       
  } 
  else return false;
}

and this

if (timeout(&count1, 500)) {

I'll try it when I get home.

char timeout(long *marker, long interval) {

long? Really?

long count1 = 0;           // will store last time LED was updated
long count2 = 0;
long count3 = 0;

long? Really?

Paul__B:
Do correct me/ shout me down if this is not the most appropriate place, or if this has so blatantly been done before,

I am far too polite to shout :slight_smile:

Anyhow: http://arduino.cc/forum/index.php/topic,76140.html Unfortunatly owing to a strange misunderstanding this is not a sticky, so people who answer have to remember to have their own cut-n-paste bookmark file to refer to it. That example was the result of rather lengthy discussion amongst regular contributors where just about every line was revised to be as correct and educational as possible. * MP3 Shield * - Rogue Robotics rMP3 - #4 by bhagman - News - Arduino Forum

There have - of course - been others that have tried to do explain this "how to have several things at once". Many times. There are libraries with "timer classes" so that it hides the complexity (though how using such a library should be easier than remembering 3 lines of code... ? Ah well, we are all different) I've seen at least two attempts to make a new "framework" where loop() has been taken away and people just write sections of code which then get called at the right intervalls.

Despite all that, there will be people that will ask "The Question" - again and again. Partly beacuse it is too difficult to find the refereneces, partly because it presumes they read, think and understand the issue before willy-nilly cut-n-paste code.

CrossRoads:
That kind of mostly uncommented code does not help the newbies.

I am somewhat with Msquare and Steve Gibson, that a blizzard of comments isn't always helpful and that the code itself should be largely self-explanatory. My main purpose here is to provide functions (rather than libraries) that can be cut-and-pasted to obtain a result easily, yet are decipherable.

OK, OK, had a fiddle with that initially - now corrected to UL. I was not sure it mattered - as best I can figure it does not matter given the "correct" form of comparison until and unless you specify an interval beyond (half of) the critical four weeks or whatever. Am having significant fun getting to grips with "C"; more at home with assembler where you know what is going on. :slight_smile:

Current iteration:

// Blink without "delay()" - multi!

const int led1Pin =  13;    // LED pin number
const int led2Pin =  10;
const int led3Pin =  11;
int led1State = LOW;        // initialise the LED
int led2State = LOW;
int led3State = LOW;
unsigned long count1 = 0;   // will store last time LED was updated
unsigned long count2 = 0;
unsigned long count3 = 0;

// Have we completed the specified interval since last confirmed event?
// "marker" chooses which counter to check 
char timeout(unsigned long *marker, unsigned long interval) {
  if (millis() - *marker >= interval) { 
    *marker += interval;    // move on ready for next interval
    return true;       
  } 
  else return false;
}

void setup() {
  pinMode(led1Pin, OUTPUT);      
  pinMode(led2Pin, OUTPUT);      
  pinMode(led3Pin, OUTPUT);      
}

void loop() {
  // Act if the latter time (ms) has now passed on this particular counter,
  if (timeout(&count1, 500UL )) {
    if (led1State == LOW) {
      led1State = HIGH;
    }
    else {
      led1State = LOW; 
    } 
    digitalWrite(led1Pin, led1State);
  } 

  if (timeout(&count2, 300UL )) {
    if (led2State == LOW) {
      led2State = HIGH;
    }
    else {
      led2State = LOW; 
    } 
    digitalWrite(led2Pin, led2State);
  } 

  if (timeout(&count3, 77UL )) {
    if (led3State == LOW) {
      led3State = HIGH;
    }
    else {
      led3State = LOW; 
    } 
    digitalWrite(led3Pin, led3State);
  } 
}
char timeout(unsigned long *marker, unsigned long interval) {

timeout does not return a char. Change it to bool (or boolean).

Here is a video of your current iteration code:

raschemmel:
Here is a video of your current iteration code:

Yeah, cute - though I can't quite discern what sort of Arduino is in there - not that it matters; I happen to be using a Pro Mini and one of the LEDs I grabbed happens to be a laser!

Quite so. I found "bool" does not exist in the IDE - I was rather put off and distracted by that to start with, but "boolean" works. Done.

Now one of the intentions in my approach is to encapsulate the timing functions, so that rather than stepping the timer reference point down there later amongst the consequent actions, it happens within "timeout".

Next, the debounced button event ...

Why is this discussion here rather than in the much more popular (and thus more useful) Project Guidance or Programming Questions sections?

And to add to the fun I wrote a demo of how to manage several things at the same time in this Thread.

I suspect the problem is that there is no easy way for newbies to find the many existing useful examples without help - i.e. when they don't know what to search for.

...R

Robin2:
Why is this discussion here rather than in the much more popular (and thus more useful) Project Guidance or Programming Questions sections?

Essentially because I was not sure it fitted in "Project Guidance" and I do not follow "Programming Questions" (if only because it seems a little complex and requires more detailed attention) so when I looked at the groups available, this one seemed as good as any. :smiley: I tend to see those groups as places for questions to be asked, rather than examples to be offered. I am certainly more than happy for any moderator to re-locate the thread if they feel somewhere else more appropriate.

Robin2:
I suspect the problem is that there is no easy way for newbies to find the many existing useful examples without help - i.e. when they don't know what to search for.

This is a general problem with "forums" with innumerable "threads" streaming away and no fixed "root" structure. A Wiki (in addition) would seem more appropriate.

Paul__B:
This is a general problem with "forums" with innumerable "threads" streaming away and no fixed "root" structure. A Wiki (in addition) would seem more appropriate.

That is what the Playground is - a wiki. Top menubar of the standard Ardino webpage, Learning - Playground. In the left menu selection try "Tutorials", and therein "Protothreading, Timing & Millis", and in that section "How and Why to avoid delay".

(editing post - forgot to add ) I think it is fine to place it here. But before placing it here as a finished example, you could perhaps have let the discussion and suggestions run in Programming. Your example has at least two errors as others have pointed out.

Also I feel that we cannot forget Nicks excellent information on his site at http://www.gammon.com.au/forum/?id=11411 in regard to this issue :smiley:

Instead of:

  // Act if the latter time (ms) has now passed on this particular counter,
  if (timeout(&count1, 500UL )) {
    if (led1State == LOW) {
      led1State = HIGH;
    }
    else {
      led1State = LOW; 
    } 
    digitalWrite(led1Pin, led1State);
  }

I'd use:

if (timeout(&count1, 500UL )) { //has the timing period ended?
 led1State = !led1State;//Invert Led1State, HIGH becomes LOW and LOW becomes HIGH.
 digitalWrite(led1Pin, led1State);//turn LED on or off, as defined by led1State.
  }

I'd also add an explanation that, although this code only blinks LEDs, the principle can be use to time anything.

Henry_Best:

 led1State = !led1State;//Invert Led1State, HIGH becomes LOW and LOW becomes HIGH.

Strictly speaking that is bad - HIGH / LOW are not the same as true / false. They may map to it, but it is a different "type".

Henry_Best:
I'd also add an explanation that, although this code only blinks LEDs, the principle can be use to time anything.

Oh yes, indeed. But, I have found through reading "a few" examples and newbie question that somehow for them going from a LED example to something else is too abstract/large a leap. Many want to see an example of one LED + one stepper or two DC motors or one button scan + two LEDs or any other specific combination.

Henry_Best:
I'd use:

if (timeout(&count1, 500UL )) { //has the timing period ended?

led1State = !led1State;//Invert Led1State, HIGH becomes LOW and LOW becomes HIGH.
digitalWrite(led1Pin, led1State);//turn LED on or off, as defined by led1State.
 }

Tempting though it be to make it that concise, my bias is to provide bullet-proof code. "led1State" has been defined as an "int" instead of a boolean, as LOW and HIGH appear to be defined as such. Using the "!" operator on "int" values is particularly dangerous. Do you know what !HIGH is? Have you tried it?

Henry_Best:
I'd also add an explanation that, although this code only blinks LEDs, the principle can be use to time anything.

Indeed it can and that is most certainly the intent. The point is that people are generally referred to "Blink without delay" as the reference for performing any timed function.

My synth uses 3 state Machines.
All of them non blocking.

The main code, the sampling interrupt and the UART Midi interrupt.