Running multiple timers?

Hi all,
So I've come to a bit of a pickle... I've got the arduino Due and I'm using almost every pin available on it for a large but simple project. I've come to one major problem. I need to incorporate three separate timed events across the cycle of my main loop.

I need to be running debounce for one, I need to run blink without delay, and I need an output to stay active for 10 minutes after being triggered by a momentary switch input.

The blink without delay is also being called by the onebutton library; single click flash three times, hold flash repeatedly until input X reads low.

I cannot use delay as I need the loop to constantly run, and I cant use a for loop as it will hold everything else up until it's done.

Any ideas, thoughts, suggestions or (and this is my personal favorite) solutions?

eg of existing code

if(digitalRead(button1)==HIGH)
{
digitalWrite(led1,HIGH);
}
else
{
digitalWrite(led1,LOW)
}
if(digitalRead(button2)==HIGH)
{
digitalWrite(led2,HIGH);
}
else
{
digitalWrite(led2,LOW)
}
if(digitalRead(buttonN)==HIGH)
{
digitalWrite(ledN,HIGH);
}
else
{
digitalWrite(ledN,LOW)
}
etc.... all the way through button20, led20
The entirety of the loop is fast enough that all these can be processed and cycled without issue
What I need is, on top of all of this, to have the following three funtinos available

  1. to have a button with debounce trigger a output high for a duration of 10 minutes
  2. To have the onebutton library function on an input
  3. to (WITHOUT DELAY OR "FOR LOOP") have 750 milisec toggle of an led for 3 flashes (6 toggles) as a responce to the short
    press, and infinite toggles, until stopped by an independent trigger, for a long press.
unsigned long debounceStart;
unsigned long buttonStart;
unsigned long blinkStart;

// Then later,

   debounceStart = millis();
   // other code
   buttonStart = millis();
   // other code
   blinkStart = millis();

//Then later

   if (millis() - debounceStart >= debounceDuration ) {
      // accept the debounced button/key/whatever
   }

   if (millis() - buttonStart >= buttonDuration ) {
      // start another ten minute timer like the others here
   }

   if (millis() - blinkStart >= blinkDuration ) {
      // start another timer like the others to time the blinks themselves.
   }

The above are just examples, but the principles are there.
Do these one at a time, making sure each one does it's thing in the way you want it to do. Only after perfecting each one, combine them in the final program. There is only one millis(), but by using separate variables, you can easily time almost any number of events.

Or incorporate into a function:

//============================================================================ 
const unsigned long debounceValue = 50UL; //debounce time in milliseconds
const int startSwitch = 2; //note: pressing this switch makes i/p go LOW 
unsigned long debounceTime;
boolean lastSwitchState1;  //the last read value of switch #1
//boolean lastSwitchState2;  //the last read value of switch #2
// etc.

int counter;               //equals the number of times the switch is pressed

//============================================================================  

void setup()
{
  Serial.begin(9600);
  pinMode(startSwitch,INPUT_PULLUP); 
  // other switches here
  pinMode(13,OUTPUT);                    
  debounceTime = millis(); //initailize to the current time 
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END OF setup <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

void loop()
{
  //================== is it time to check the switches?
  if (millis() - debounceTime >= debounceValue)
  {
    debounceTime = millis(); //re-initialize to the current time 
    debounceSwitches();      //check the switches 
  } 
  //==================

  //other sketch/loop code goes here

}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END OF loop() <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

// FUNCTIONS

void debounceSwitches()  //switches are checked every debounceValue milli seconds 
                         //no minimum switch press time is validated with this code
{
  boolean thisState;     //re-usable for all the switches  

  //================== check if this switch has changed state
  thisState = digitalRead(startSwitch);
  if (thisState != lastSwitchState1)
  {  
    lastSwitchState1 = thisState;  //update the switch state

      // the switch has changed so do some stuff
      // example for the first switch
    digitalWrite(13,thisState);   //make LED 13 to follow the switch

    if(thisState == HIGH)         //HIGH condition code
    {
    }
    else                          //LOW condition code
    {
      Serial.println(++counter);  //example: display the current switch push count     
    }
  }
  //==================

  //similar code for other switches goes here 

}
//>>>>>>>>>>>>>>>>>>>>>>> END OF debounceSwitches() <<<<<<<<<<<<<<<<<<<<<<<<<<

GhiaGoGo:

if(digitalRead(button1)==HIGH)
  {
  digitalWrite(led1,HIGH);
  }
else
  {
  digitalWrite(led1,LOW)}

can be reduced to:

digitalWrite(led1,(digitalRead(button1)));

etc.... all the way through button20, led20

You are using the DUE so I think the best answer to your question is the "Scheduler" library. I wont go into much detail and re write your code but you can run several things almost simultaneously (I don't think this is exactly simultaneously seeing as this is a micro controller still but with a 85 MHz clock it's the best you are going to get)

With Scheduler you can build separate loops() and delay(); of one loop executes the next and then yield(); of that loop executes the next and it all works out pretty cleanly.

I quickly mocked up some example code to show this working on an LCD display. You can see the numbers start to get off at a rate of about 1/1000 clock cycles. Which could be a big deal but probably not.

#include <Scheduler.h>
#include <LiquidCrystal.h>	
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

int count = 0;
int count1 = 0;
int count2 = 0;
int count3 = 0;

void setup() {
  lcd.clear();
  lcd.begin(16, 2);
  Scheduler.startLoop(loop2);
  Scheduler.startLoop(loop3);
  Scheduler.startLoop(loop4);
}

void loop() {
  lcd.setCursor(0,0);
  lcd.println(count);
  delay(100);
  count++;
}
void loop2() {
  lcd.setCursor(8,0);
  lcd.println(count1);
  delay(1000);
  count1++;
  yield();
}
void loop3() {
  lcd.setCursor(0,1);
  lcd.println(count2);
  delay(10000);
  count2++;
  yield();
}
void loop4() {
  lcd.setCursor(8,1);
  lcd.println(count3);
  delay(100000);
  count3++;
  yield();
}

you can use my timer library, very simple to use. no delays, small footprint.

after you import the library, check the sample and test it.

/*
      Title: Simple Switch Timer
      Library: sstimer.ino
      Description: 
      Created Date: January 17, 2015
      Created By: Rolly Falco Villacacan
      Released into the public domain.
      http://www.mvsadnik.com/microcontrollers/
      https://www.facebook.com/groups/pinoymikrocontrollerscommunity/
      https://www.facebook.com/pages/Pinoy-Mikro-Controllers-

Community/1397572657207414
*/

#include <sstimer.h>

//WATER_PUMP SETUP
int PIN_NO1 = 13;
long unsigned OFF_DURATION = 500; //in milliseconds
long unsigned ON_DURATION = 500; //in milliseconds

//LIGHTHING SETUP
int PIN_NO2 = 12;
long unsigned OFF_DURATION2 = 1000; //in milliseconds
long unsigned ON_DURATION2 = 1000; //in milliseconds


sstimer WATER_PUMP(PIN_NO1, ON_DURATION, OFF_DURATION); //create instance for water pump
sstimer LIGHTHING(PIN_NO2, ON_DURATION2, OFF_DURATION2);//create instance for lighting

void setup(){
//...  
}


void loop(){
//...
WATER_PUMP.startsstimer();
LIGHTHING.startsstimer();
//..  
}

sorry, there is a changes i made on my functions, i change the startstimer to check to avoid confusion.

thanks, :smiley:

OLD

void loop(){
//...
WATER_PUMP.startsstimer();
LIGHTHING.startsstimer();
//..
}

NEW

void loop(){
//...
WATER_PUMP.check();
LIGHTHING.check();
//..
}