Check a condition all the time

Hi,

Is it a way to check a condition all the time while doing another on an Arduino uno. I mean like multitasking...
For example, I created different leds functions (blink, serie of colors...) and I want to switch between them with a push putton.
It works for small loop functions but not with big ones (I need to wait the function to be finish before it switch but what I want is to stop the actual function and start the next one..)

Is it a special command for this ?

Thanks

Alexis

Nope. The remedy, don't write function that take a lot of time :slight_smile:

For blinking, see Blink without delay
In general, see Several things at the same time.

alexisdp95:
Hi,

Is it a way to check a condition all the time while doing another on an Arduino uno. I mean like multitasking...
For example, I created different leds functions (blink, serie of colors...) and I want to switch between them with a push putton.

There are at least two ways of multitasking:

  1. preemptive multitasking
  2. cooperative multitasking

preemptive multitasking is a feature of operating systems.
Arduino boards are NOT running on an operating system like PCs and smartphones do.
Therefore you have NO preemptive multitasking with Arduino boards.

But of course you can do do cooperative multitasking on your Arduino.
It's just a matter of organizing your programming logic, consisting of non-blocking function calls, avoiding all blocking and busy-waiting functions.

If you have to wait for "function to be finish before it switch", then the programming logic of the function is WRONG FOR COOPERATIVE MULTITASKING!

Maybe the function is using some busy-waiting bullshit like "calls of delay()" function or other Busy waiting - Wikipedia shitty functions.

If you want to try preemptive multitasking with an Arduino DUE board, see this thread:

It works nicely :slight_smile:

I believe the OP is using an Uno.

Have a look at how millis() is used to manage timing without blocking in several things at a time

Notice how each function only does a little piece of its task for every iteration of loop()

…R

use the button to create an interrupt, which would set a flag...
in each of your functions check the flag occasionally and if set, clear the flag, end the function and proceed to the next lighting function.

http://playground.arduino.cc/Code/Interrupts
http://www.engblaze.com/we-interrupt-this-program-to-bring-you-a-tutorial-on-arduino-interrupts/

MarshaJ847:
use the button to create an interrupt, which would set a flag...
in each of your functions check the flag occasionally

That sounds like a lot of duplicated code when there could be one single function to check the button (without the complication of an interrupt) in every iteration of loop().

...R

alexisdp95:
Hi,

Is it a way to check a condition all the time while doing another on an Arduino uno. I mean like multitasking...
For example, I created different leds functions (blink, serie of colors...) and I want to switch between them with a push putton.
It works for small loop functions but not with big ones (I need to wait the function to be finish before it switch but what I want is to stop the actual function and start the next one..)

Is it a special command for this ?

Thanks

Alexis

What others are trying to get at is:

You dont want to keep your 'code' stuck in a loop that is doing just the animation/effects for your LED(s)..

you want to do something like:

  • check button state
  • if button state mandates a change.. (do so).. it not:
  • continue in your current LED animation cycle.. -BUT-.. only do one incremental step in this 'animation update'
    (for example if your animation is lighting 1 led in a series of say 10 leds.. you would only update/turn on the '1' led)...
  • exist your animation loop..

start at top of list.....rinse & repeat.

So instead of staying your LED animation loop.. you just want to update it incrementally, then do your button check again... if no button state change... enter LED animation loop again and update the next led...

check for button state.....etc..etc (you get the idea)

this keep the cycles free 'to do other things' (so to speak).. (like checking your button state/interaction)

Reading button with interrupt => terrible code structure.

And even if you would set a flag in the interrupt you can't handle that flag until you're not stuck in a function... You might indeed not miss it that way but you can't act on it directly.

So just don't get your Arduino to spend ages in a single function and let loop() loop as fast as possible.

One doesn't read the button in the interrupt; when the button is pressed, regardless of what the program is doing, the interrupt sets a flag.

Lets say 4 functions, CW runs LEDs clockwise, CW counter-clockwise, FL5 flashes 5 times, FLALt flashes two sets alternating.

In each of the four hypothetical functions, in whatever logic structure is doing the lighting, you check to see if the flag is set.
If the flag is set you abort out of the function and go to the next one.

The flag being set is what un-sticks the function.

Why not poll the switch in the loop as well? Interrupt is just not the right tool to check something as mega slow as a switch. Especially with all the debouncing that will cause it to call the interrupt multiple times etc.

And aborting a function? Noo, just no. The loop should loop. Just remember what stuff you want to do (in this case, remember which pastern to do) and every call to the function just update that pastern (if necessary). Making it stick in a function is a killing thing to do if you want to multitask with an uC.

Interrupts are meant for fast things. You can do the button checking in the loop, no problem. Just make all your functions fast. Which you should also do if you capture the button press in an interrupt because otherwise you can't react fast on it.

MarshaJ847:
One doesn't read the button in the interrupt; when the button is pressed, regardless of what the program is doing, the interrupt sets a flag.

Lets say 4 functions, CW runs LEDs clockwise, CW counter-clockwise, FL5 flashes 5 times, FLALt flashes two sets alternating.

In each of the four hypothetical functions, in whatever logic structure is doing the lighting, you check to see if the flag is set.
If the flag is set you abort out of the function and go to the next one.

The flag being set is what un-sticks the function.

What is the difference between needing to check the flag in every function or needing to check the pin with digitalRead in every function. I don't think you realize that your "solution" doesn't solve anything. You're left with the exact same problem. Only now you have interrupt code to deal with as well.

The original poster wanted to ‘check a condition all the time’
Therefore, using an interrupt to set a flag, that the condition has occurred, would be better than manually doing digitalRead, hoping to catch exactly when the user has pressed the button.

OP ’ I want is to stop the actual function and start the next one.’
Inside the main loop, the functions that do the lighting will use exit strategies such as ‘return’, while loops that use the flag as condition, etc.

Totally ugly code example

// Adapted from https://www.arduino.cc/en/Reference/AttachInterrupt

int clockLED12 = 12;
int clockLED3 = 3;
int clockLED6 = 6;
int clockLED9 = 9;

const byte interruptPin = 2;
volatile byte state = LOW ;

void setup() {
  pinMode(clockLED12, OUTPUT);
  pinMode(clockLED3, OUTPUT);
  pinMode(clockLED6, OUTPUT);
  pinMode(clockLED9, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, LOW);
}

void loop() {
  state = LOW;
  CW();
  delay(500);
  state = LOW;
  CCW();
  delay(500);
  state = LOW;
  FL5();
  delay(500);
  state = LOW;
  ALT();
  delay(500);
}

void blink() {
  // state = !state;
  state = HIGH;
  delay(10); // debounce
}

void CW() {
  do {
    digitalWrite(clockLED12, HIGH);
    digitalWrite(clockLED3, LOW);
    digitalWrite(clockLED6, LOW);
    digitalWrite(clockLED9, LOW);
    delay(300);
    if (state == HIGH) {
      state = LOW;
      return;
    }
    digitalWrite(clockLED12, LOW);
    digitalWrite(clockLED3, HIGH);
    digitalWrite(clockLED6, LOW);
    digitalWrite(clockLED9, LOW);
    delay(300);
    if (state == HIGH) {
      state = LOW;
      return;
    }
    digitalWrite(clockLED12, LOW);
    digitalWrite(clockLED3, LOW);
    digitalWrite(clockLED6, HIGH);
    digitalWrite(clockLED9, LOW);
    delay(300);
    if (state == HIGH) {
      state = LOW;
      return;
    }
    digitalWrite(clockLED12, LOW);
    digitalWrite(clockLED3, LOW);
    digitalWrite(clockLED6, LOW);
    digitalWrite(clockLED9, HIGH);
    delay(300);
    if (state == HIGH) {
      state = LOW;
      return;
    }
  } while (1);
}


void CCW() {
  do {
    digitalWrite(clockLED12, HIGH);
    digitalWrite(clockLED3, LOW);
    digitalWrite(clockLED6, LOW);
    digitalWrite(clockLED9, LOW);
    delay(300);
    if (state == HIGH) {
      state = LOW;
      return;
    }
    digitalWrite(clockLED12, LOW);
    digitalWrite(clockLED3, LOW);
    digitalWrite(clockLED6, LOW);
    digitalWrite(clockLED9, HIGH);
    delay(300);
    if (state == HIGH) {
      state = LOW;
      return;
    }
    digitalWrite(clockLED12, LOW);
    digitalWrite(clockLED3, LOW);
    digitalWrite(clockLED6, HIGH);
    digitalWrite(clockLED9, LOW);
    delay(300);
    if (state == HIGH) {
      state = LOW;
      return;
    }
    digitalWrite(clockLED12, LOW);
    digitalWrite(clockLED3, HIGH);
    digitalWrite(clockLED6, LOW);
    digitalWrite(clockLED9, LOW);
    delay(300);
    if (state == HIGH) {
      state = LOW;
      return;
    }
  } while (1);
}


void FL5() {
  do {
    state = LOW;
    for (int i = 0; i < 5; i++) {
      digitalWrite(clockLED12, HIGH);
      digitalWrite(clockLED3, HIGH);
      digitalWrite(clockLED6, HIGH);
      digitalWrite(clockLED9, HIGH);
      delay(250);
      if (state == HIGH) {
        i = 6;
        continue;
      }
      digitalWrite(clockLED12, LOW);
      digitalWrite(clockLED3, LOW);
      digitalWrite(clockLED6, LOW);
      digitalWrite(clockLED9, LOW);
      delay(250);
      if (state == HIGH) {
        i = 6;
        continue;
      }
    }
  } while (state == LOW);
}

void ALT() {
  do {
    state = LOW;
    for (int i = 0; i < 5; i++) {
      digitalWrite(clockLED12, HIGH);
      digitalWrite(clockLED3, LOW);
      digitalWrite(clockLED6, HIGH);
      digitalWrite(clockLED9, LOW);
      delay(250);
      if (state == HIGH) {
        i = 6;
        continue;
      }
      digitalWrite(clockLED12, LOW);
      digitalWrite(clockLED3, HIGH);
      digitalWrite(clockLED6, LOW);
      digitalWrite(clockLED9, HIGH);
      delay(250);
      if (state == HIGH) {
        i = 6;
        continue;
      }
    }
  } while (state == LOW);
}

MarshaJ847:
hoping to catch exactly when the user has pressed the button.

Humans are very slow by Arduino standards. I have never had any trouble catching a button press using digitalRead().

In fact the opposite is the bigger problem - I have to put an interval between digitalRead()s so it does not catch the same button press several times. Look for example, at the code in the demo Several Things at a Time

...R

Delta_G:
What is the difference between needing to check the flag in every function or needing to check the pin with digitalRead in every function. I don’t think you realize that your “solution” doesn’t solve anything. You’re left with the exact same problem. Only now you have interrupt code to deal with as well.

There is a difference when you check the pin in every pass through loop() as opposed to every function in loop().

And even if you would set a flag in the interrupt you can’t handle that flag until you’re not stuck in a function… You might indeed not miss it that way but you can’t act on it directly.

Exactly. It is not about when you read the pin or the flag set by the interrupt. The problem is whatever code blocks the sketch from getting that information and doing anything about it.

The entire point is to write non-blocking code if you want a smooth responsive program.

ANY function or loop that will take more than 100 micros should be viewed as something to turn into a simple state machine that does its work over a series of calls instead of all in one go.

Think of long trains on tracks vs individual cars on roads.

Put a loop() counter in your sketch. Have it print and zero the count every 1 second. With blocky code the count will be less than 10KHz and likely less than 1KHz. Non-blocking, you should be able to maintain > 20KHz.

PS – buttons pushed by humans should be low priority. Even a few millis debounce is tiny by compare to slop in finger speed. The reason to make contact switch debounce code fast is so it doesn’t slow down or rob cycles from more important things.