Blink without delay Macros "Simplifying the New Arduino Programmers Life"

I am suggesting several helper macros to be added to the arduino code to simplify Blink without delay().
new users struggle with this every day and are confused on how to code blink without delay especially when it comes to getting the rollover properly handled

Using for() in the macro to handle the delay:

// Run Every and Run after respond differently when confronted with a delay() somewhere else in the code both are handy
// using for to handle the delay has a huge advantage that the timer variable is hidden within the scope of the delay allowing for additional uses within the same scope
#define runEvery(t,Clock)    for (static unsigned long _ETimer = Clock; (unsigned long)(Clock - _ETimer) >= (t); _ETimer += (t))
#define runAfter(t,Clock)    for (static unsigned long _ATimer = Clock; (unsigned long)(Clock - _ATimer) >= (t); _ATimer = Clock)

Using if() in the macro to handle the delay:

// using if() requires us to create a variable in the current scope preventing us from adding additional timers within that scope
// There is a possibility that the timer could skip a cycle if the && (_ATimer = Clock)) -or-   && (_ETimer += (t))  would roll over to zero#define ifRunAfter(t,Clock) static unsigned long _ATimer = Clock; if( ((unsigned long)(Clock - _ATimer) >= (t)) && (_ATimer = Clock))
#define ifRunEvery(t,Clock) static unsigned long _ETimer = Clock; if( ((unsigned long)(Clock - _ETimer) >= (t)) && (_ETimer += (t)))
#define ifRunAfter(t,Clock) static unsigned long _ATimer = Clock; if( ((unsigned long)(Clock - _ATimer) >= (t)) && (_ATimer = Clock))

I recommend using the for() timer for all its advantages with no disadvantages I can see at this time.

I have created example and test code attached for you to test and review (attached)
Thanks,

Z

BlinkWithoutDelayMacros.ino (7.25 KB)

Thanks for sharing.

IMO if a new person cannot work their way through BWD, macros and libraries to automate the process won't be understood either.

.

so just like the F("string") helper macro don't show them let it be a magical thing :slight_smile:

Just saying those who want to really get into programming will grasp the BWD technique and run with it.
Those who don't want to get into programming write their one program to get a mark then proceed with their degree.

I use a structure:

//Blink without Delay skeleton example using a structure.
//LarryD

//======================================================================
struct timer
{
  //lastMillis = the time this "timer" was (re)started
  //waitMillis = delay time (mS) we are looking for. You can use math 60*60*1000 for 1 hour
  //restart    = do we start "this timer" again and again  
  //enableFlag = is "this timer" enabled/allowed to be accessed
  //**********************
  //For each timer object you need: 
  //Example:
  //   timer myTimer = //give the timer a name "myTimer"
  //   {
  //     0, 200UL, true, true  //lastMillis, waitMillis, restart, enableFlag 
  //   };
  // You have access to: 
  // myTimer.lastMillis, myTimer.waitMillis, myTimer.restart, myTimer.enableFlag, myTimer.CheckTime() 
  //**********************

  unsigned long lastMillis; 
  unsigned long waitMillis; 
  bool          restart; 
  bool          enableFlag;
  
  bool CheckTime() //Delay time expired function "CheckTime()"
  {
    //is the time up for this task?
    if (enableFlag && millis() - lastMillis >= waitMillis) 
    //Note: if delays of < 2 millis are needed use micros() and adjust waitMillis as needed
    {
      //should this start again? 
      if(restart)
      {
        //get ready for the next iteration
        lastMillis += waitMillis;  
      }
      //time was reached
      return true;
    }
    //time was not reached
    return false;
  } //END of CheckTime()

}; //END of structure timer
//======================================================================


//**********************************************************************
//Let's create 6 timer objects and initialize them in this sketch
//**********************************************************************
timer pin13 = //create timer pin13
{
  0, 200UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************
timer pin12 = //create timer pin12
{
  0, 3*1000UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************
timer pin11 = //create timer pin11
{
  0, 10*1000UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************
timer pin10 = //create timer pin10
{
  0, 6*1000UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************
timer Toggle10 = //create timer Toggle10
{
  0, 50UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************
timer checkSwitches = //create timer checkSwitches
{
  0, 50UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************

byte lastMySwitchState = 1; //for mySwitch on Pin 2
byte counter           = 0; 

const byte Pin13 = 13;
const byte Pin12 = 12;
const byte Pin11 = 11;
const byte Pin10 = 10;
const byte Pin9  =  9;

const byte mySwitch = 2;

//**********************************************************************

void setup()
{
  Serial.begin(9600);

  pinMode(Pin13,OUTPUT);
  pinMode(Pin12,OUTPUT);
  pinMode(Pin11,OUTPUT);
  pinMode(Pin10,OUTPUT);
  pinMode(Pin9, OUTPUT);

  digitalWrite(Pin13,LOW);
  digitalWrite(Pin12,LOW);
  digitalWrite(Pin11,LOW);
  digitalWrite(Pin10,LOW);
  digitalWrite(Pin9, LOW);

  pinMode(mySwitch,INPUT_PULLUP);


} //  >>>>>>>>>>>>>> E N D  O F  s e t u p ( ) <<<<<<<<<<<<<<<<<


void loop()
{
  //Below are examples demonstrating different timing situations 

  //***************************
  //example 1    Toggle Pin13 every 200ms
  if (pin13.CheckTime())
  {
    //Toggle Pin13
    digitalWrite(Pin13,!digitalRead(Pin13));

    //if you only want this section of code to happen once
    //uncomment the next line 
    //pin13.enableFlag = false;
  }

  //***************************
  //example 2    After 3 seconds, Pin12 goes and stays HIGH 
  if (pin12.CheckTime())
  {
    //Make Pin12 HIGH now
    digitalWrite(Pin12,HIGH);
    //disable timing section of code 
    pin12.enableFlag = false;
  }

  //***************************
  //example 3    Pin11 is HIGH for 10 seconds, then goes and stays LOW
  if (pin11.enableFlag && !pin11.CheckTime())
  {
    digitalWrite(Pin11,HIGH);
  }
  //10 seconds is now up now, leave the Pin11 LOW
  else
  {
    digitalWrite(Pin11,LOW);
    //disable timing section of code 
    pin11.enableFlag = false;
  }

  //***************************
  //example 4    For 6 seconds, toggle Pin10
  if (pin10.enableFlag && !pin10.CheckTime())
  {
    //example 5  Toggling Pin10 every 50mS
    if(Toggle10.CheckTime())
    {  
      //toggle Pin10
      digitalWrite(Pin10,!digitalRead(Pin10));    
    }
  }
  //6 seconds is now up, toggling is stopped
  else
  {
    digitalWrite(Pin10,LOW);
    //disable timing section of code 
    pin10.enableFlag = false;
  }

  //***************************
  //example 6    Is it time to check the switches?
  if (checkSwitches.CheckTime())
  {
    //time to read the switches
    Switches();      
  } 

  //**********************************
  //Put other non-blocking stuff here
  //**********************************

} //  >>>>>>>>>>>>>> E N D  O F  l o o p ( ) <<<<<<<<<<<<<<<<<


//======================================================================
//                      F U N C T I O N S
//======================================================================


//**********************************************************************
//switches are checked every checkSwitches.waitMillis milli seconds 
//no minimum switch press time is validated with this code (i.e. No glitch filter)
void Switches()  
{
  boolean thisState; //re-usable for all the switches      

  //*************************** mySwitch Pin 2 code  
  //check if this switch has changed state
  thisState = digitalRead(mySwitch); 
  if (thisState != lastMySwitchState)
  {  
    //update the switch state
    lastMySwitchState = thisState;  

    //This switch position has changed, let's do some stuff

    //"HIGH condition code"
    //switch goes from LOW to HIGH
    if(thisState == HIGH)        
    {
      //example: LED on Pin9 is Push ON, Push OFF
      digitalWrite(Pin9,!digitalRead(Pin9)); 
    }

    //"LOW condition code"
    //switch goes from HIGH to LOW
    else                          
    {
      //example: display the current switch push count 
      Serial.println(++counter);      
    }
  } //END of mySwitch Pin 2 code

  //******************************************  
  //similar code for other switches goes here 
  //******************************************  

} //END of Switches()


//======================================================================
//                        E N D  O F  C O D E
//======================================================================

.

1 Like

LarryD:
Just saying those who want to really get into programming will grasp the BWD technique and run with it.
Those who don't want to get into programming write their one program to get a mark then proceed with their degree.

I use a structure:

//Blink without Delay skeleton example using a structure.

//LarryD

//======================================================================
struct timer
{
  //lastMillis = the time this "timer" was (re)started
  //waitMillis = delay time (mS) we are looking for. You can use math 60601000 for 1 hour
  //restart    = do we start "this timer" again and again 
  //enableFlag = is "this timer" enabled/allowed to be accessed
  //**********************
  //For each timer object you need:
  //Example:
  //  timer myTimer = //give the timer a name "myTimer"
  //  {
  //    0, 200UL, true, true  //lastMillis, waitMillis, restart, enableFlag
  //  };
  // You have access to:
  // myTimer.lastMillis, myTimer.waitMillis, myTimer.restart, myTimer.enableFlag, myTimer.CheckTime()
  //**********************

unsigned long lastMillis;
  unsigned long waitMillis;
  bool          restart;
  bool          enableFlag;
 
  bool CheckTime() //Delay time expired function "CheckTime()"
  {
    //is the time up for this task?
    if (enableFlag && millis() - lastMillis >= waitMillis)
    //Note: if delays of < 2 millis are needed use micros() and adjust waitMillis as needed
    {
      //should this start again?
      if(restart)
      {
        //get ready for the next iteration
        lastMillis += waitMillis; 
      }
      //time was reached
      return true;
    }
    //time was not reached
    return false;
  } //END of CheckTime()

}; //END of structure timer
//======================================================================

//**********************************************************************
//Let's create 6 timer objects and initialize them in this sketch
//**********************************************************************
timer pin13 = //create timer pin13
{
  0, 200UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************
timer pin12 = //create timer pin12
{
  0, 31000UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//
**************************
timer pin11 = //create timer pin11
{
  0, 101000UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//
**************************
timer pin10 = //create timer pin10
{
  0, 61000UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//
**************************
timer Toggle10 = //create timer Toggle10
{
  0, 50UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************
timer checkSwitches = //create timer checkSwitches
{
  0, 50UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************

byte lastMySwitchState = 1; //for mySwitch on Pin 2
byte counter          = 0;

const byte Pin13 = 13;
const byte Pin12 = 12;
const byte Pin11 = 11;
const byte Pin10 = 10;
const byte Pin9  =  9;

const byte mySwitch = 2;

//**********************************************************************

void setup()
{
  Serial.begin(9600);

pinMode(Pin13,OUTPUT);
  pinMode(Pin12,OUTPUT);
  pinMode(Pin11,OUTPUT);
  pinMode(Pin10,OUTPUT);
  pinMode(Pin9, OUTPUT);

digitalWrite(Pin13,LOW);
  digitalWrite(Pin12,LOW);
  digitalWrite(Pin11,LOW);
  digitalWrite(Pin10,LOW);
  digitalWrite(Pin9, LOW);

pinMode(mySwitch,INPUT_PULLUP);

} //  >>>>>>>>>>>>>> E N D  O F  s e t u p ( ) <<<<<<<<<<<<<<<<<

void loop()
{
  //Below are examples demonstrating different timing situations

//***************************
  //example 1    Toggle Pin13 every 200ms
  if (pin13.CheckTime())
  {
    //Toggle Pin13
    digitalWrite(Pin13,!digitalRead(Pin13));

//if you only want this section of code to happen once
    //uncomment the next line
    //pin13.enableFlag = false;
  }

//***************************
  //example 2    After 3 seconds, Pin12 goes and stays HIGH
  if (pin12.CheckTime())
  {
    //Make Pin12 HIGH now
    digitalWrite(Pin12,HIGH);
    //disable timing section of code
    pin12.enableFlag = false;
  }

//***************************
  //example 3    Pin11 is HIGH for 10 seconds, then goes and stays LOW
  if (pin11.enableFlag && !pin11.CheckTime())
  {
    digitalWrite(Pin11,HIGH);
  }
  //10 seconds is now up now, leave the Pin11 LOW
  else
  {
    digitalWrite(Pin11,LOW);
    //disable timing section of code
    pin11.enableFlag = false;
  }

//***************************
  //example 4    For 6 seconds, toggle Pin10
  if (pin10.enableFlag && !pin10.CheckTime())
  {
    //example 5  Toggling Pin10 every 50mS
    if(Toggle10.CheckTime())
    { 
      //toggle Pin10
      digitalWrite(Pin10,!digitalRead(Pin10));   
    }
  }
  //6 seconds is now up, toggling is stopped
  else
  {
    digitalWrite(Pin10,LOW);
    //disable timing section of code
    pin10.enableFlag = false;
  }

//***************************
  //example 6    Is it time to check the switches?
  if (checkSwitches.CheckTime())
  {
    //time to read the switches
    Switches();     
  }

//**********************************
  //Put other non-blocking stuff here
  //**********************************

} //  >>>>>>>>>>>>>> E N D  O F  l o o p ( ) <<<<<<<<<<<<<<<<<

//======================================================================
//                      F U N C T I O N S
//======================================================================

//**********************************************************************
//switches are checked every checkSwitches.waitMillis milli seconds
//no minimum switch press time is validated with this code (i.e. No glitch filter)
void Switches() 
{
  boolean thisState; //re-usable for all the switches

//*************************** mySwitch Pin 2 code 
  //check if this switch has changed state
  thisState = digitalRead(mySwitch);
  if (thisState != lastMySwitchState)
  { 
    //update the switch state
    lastMySwitchState = thisState;

//This switch position has changed, let's do some stuff

//"HIGH condition code"
    //switch goes from LOW to HIGH
    if(thisState == HIGH)       
    {
      //example: LED on Pin9 is Push ON, Push OFF
      digitalWrite(Pin9,!digitalRead(Pin9));
    }

//"LOW condition code"
    //switch goes from HIGH to LOW
    else                         
    {
      //example: display the current switch push count
      Serial.println(++counter);     
    }
  } //END of mySwitch Pin 2 code

//****************************************** 
  //similar code for other switches goes here
  //******************************************

} //END of Switches()

//======================================================================
//                        E N D  O F  C O D E
//======================================================================





.

I like the restart feature and your structure is clean I'm defiantly keeping this code for further study Thanks!
My hope is for something simple Like

#define runAfter(t,Clock)    for (static unsigned long _ATimer = Clock; (unsigned long)(Clock - _ATimer) >= (t); _ATimer = Clock)
// The above line if approved would become part of the arduino IDE 's base code

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  runAfter(1000, millis()) {
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));   // Alternate LED on and off
  }
}

Z

An example where pushing a switch on pin 2 starts a timing process on pin 9:

//Blink without Delay skeleton example using a structure.
//LarryD
 
//======================================================================
struct timer
{
  //lastMillis = the time this "timer" was (re)started
  //waitMillis = delay time (mS) we are looking for. You can use math 60*60*1000 for 1 hour
  //restart    = do we start "this timer" again and again
  //enableFlag = is "this timer" enabled/allowed to be accessed
  //**********************
  //For each timer object you need:
  //Example:
  //   timer myTimer = //give the timer a name "myTimer"
  //   {
  //     0, 200UL, true, true  //lastMillis, waitMillis, restart, enableFlag
  //   };
  // You have access to:
  // myTimer.lastMillis, myTimer.waitMillis, myTimer.restart, myTimer.enableFlag, myTimer.CheckTime()
  //**********************
 
  unsigned long lastMillis;
  unsigned long waitMillis;
  bool          restart;
  bool          enableFlag;
  bool CheckTime() //Delay time expired function "CheckTime()"
  {
    //is the time up for this task?
    if (enableFlag && millis() - lastMillis >= waitMillis)
      //Note: if delays of < 2 millis are needed use micros() and adjust waitMillis as needed
    {
      //should this start again?
      if (restart)
      {
        //get ready for the next iteration
        lastMillis = millis();
      }
      //time was reached
      return true;
    }
    //time was not reached
    return false;
  } //END of CheckTime()
 
}; //END of structure timer
//======================================================================
 
 
//**********************************************************************
//Let's create 7 timer objects and initialize them in this sketch
//**********************************************************************
timer pin13 = //create timer pin13
{
  0, 200UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************
timer pin12 = //create timer pin12
{
  0, 3 * 1000UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************
timer pin11 = //create timer pin11
{
  0, 10 * 1000UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************
timer pin10 = //create timer pin10
{
  0, 6 * 1000UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************
timer Toggle10 = //create timer Toggle10
{
  0, 50UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************
timer pin9 = //create timer pin9
{
  0, 5000UL, false, false //lastMillis, waitMillis, restart, enableFlag
};
//***************************
timer checkSwitches = //create timer checkSwitches
{
  0, 50UL, true, true //lastMillis, waitMillis, restart, enableFlag
};
//***************************
 
byte lastMySwitchState = 1; //for mySwitch on Pin 2
byte counter           = 0;
 
const byte Pin13 = 13;
const byte Pin12 = 12;
const byte Pin11 = 11;
const byte Pin10 = 10;
const byte Pin9  =  9;
 
const byte mySwitch = 2;
 
//**********************************************************************
 
void setup()
{
  Serial.begin(9600);
 
  pinMode(Pin13, OUTPUT);
  pinMode(Pin12, OUTPUT);
  pinMode(Pin11, OUTPUT);
  pinMode(Pin10, OUTPUT);
  pinMode(Pin9,  OUTPUT);
 
  digitalWrite(Pin13, LOW);
  digitalWrite(Pin12, LOW);
  digitalWrite(Pin11, LOW);
  digitalWrite(Pin10, LOW);
  digitalWrite(Pin9,  LOW);
 
  pinMode(mySwitch, INPUT_PULLUP);
 
 
} //  >>>>>>>>>>>>>> E N D  O F  s e t u p ( ) <<<<<<<<<<<<<<<<<
 
 
void loop()
{
  //Below are examples demonstrating different timing situations
 
  //***************************
  //example 1    Toggle Pin13 every 200ms
  //Has the timer lapsed?
  if (pin13.CheckTime())
  {
    //Toggle Pin13
    digitalWrite(Pin13, !digitalRead(Pin13));
 
    //if you only want this section of code to happen once
    //uncomment the next line
    //pin13.enableFlag = false;
  }
 
  //***************************
  //example 2    After 3 seconds, Pin12 goes and stays HIGH
  //Has the timer lapsed?
  if (pin12.CheckTime())
  {
    //Make Pin12 HIGH now
    digitalWrite(Pin12, HIGH);
    //disable timing section of code
    pin12.enableFlag = false;
  }
 
  //***************************
  //example 3    Pin11 is HIGH for 10 seconds, then goes and stays LOW
  //Has the timer lapsed?
  if (pin11.enableFlag && !pin11.CheckTime())
  {
    digitalWrite(Pin11, HIGH);
  }
  //10 seconds is now up now, leave the Pin11 LOW
  else
  {
    digitalWrite(Pin11, LOW);
    //disable timing section of code
    pin11.enableFlag = false;
  }
 
  //***************************
  //example 4    For 6 seconds, toggle Pin10
  //Has the timer lapsed?
  if (pin10.enableFlag && !pin10.CheckTime())
  {
    //example 5  Toggling Pin10 every 50mS
    //Has the timer lapsed?
    if (Toggle10.CheckTime())
    {
      //toggle Pin10
      digitalWrite(Pin10, !digitalRead(Pin10));
    }
  }
  //6 seconds is now up, toggling is stopped
  else
  {
    digitalWrite(Pin10, LOW);
    //disable timing section of code
    pin10.enableFlag = false;
  }
 
  //***************************
  //example 6    Pin9 is HIGH for 5 seconds, once mySwitch is pushed
  //if the timer is enabled, has timer has lapsed
  if (pin9.enableFlag && pin9.CheckTime())
  {
    //it is time to turn Pin9 OFF/LOW
    digitalWrite(Pin9, LOW);
    //disable timing section of code
    pin9.enableFlag = false;
  }
 
  //***************************
  //example 7    Is it time to check the switches?
  //Has the timer lapsed?
  if (checkSwitches.CheckTime())
  {
    //time to read the switches
    Switches();
  }
 
  //**********************************
  //Put other non-blocking stuff here
  //**********************************
 
} //  >>>>>>>>>>>>>> E N D  O F  l o o p ( ) <<<<<<<<<<<<<<<<<
 
 
//======================================================================
//                      F U N C T I O N S
//======================================================================
 
 
//**********************************************************************
//switches are checked every checkSwitches.waitMillis milli seconds
//no minimum switch press time is validated with this code (i.e. No glitch filter)
void Switches()
{
  boolean thisState; //re-usable for all the switches
 
  //*************************** mySwitch Pin 2 code
  //check if this switch has changed state
  thisState = digitalRead(mySwitch);
  if (thisState != lastMySwitchState)
  {
    //update the switch state
    lastMySwitchState = thisState;
 
    //This switch position has changed, let's do some stuff
 
    //"HIGH condition code"
    //if we are not timing and switch goes from LOW to HIGH
    if (pin9.enableFlag == false && thisState == HIGH)
    {
      //LED on Pin9 goes ON/HIGH for 5 seconds once mySwitch is pressed
      digitalWrite(Pin9, HIGH);
      //initialize this timer
      pin9.lastMillis = millis();
      //enable this timer
      pin9.enableFlag = true;
    }
 
    //"LOW condition code"
    //switch goes from HIGH to LOW
    else
    {
    }
  } //END of mySwitch Pin 2 code
 
  //******************************************
  //similar code for other switches goes here
  //******************************************
 
} //END of Switches()
 
 
//======================================================================
//                        E N D  O F  C O D E
//======================================================================

If it wasn't desirable to add them to the Arduino cores, another option would be to make a library consisting of those macros. Library Manager makes it pretty easy for even beginners to install libraries.

pert:
If it wasn't desirable to add them to the Arduino cores, another option would be to make a library consisting of those macros. Library Manager makes it pretty easy for even beginners to install libraries.

yep I've got a nice library with several macros all based on timing
but sharing code with macros causes some confusion. any suggestions.
I see all the new Arduino users confused about the delay() function and how not to use it. then trying to teach someone who has little experience how to create a timer with 3 lines of code and help them understand subtraction to prevent rollover is a huge headache for many of those who contribute time. It would be nice to say use runAfter(100UL,micros()){} and watch them run off with working code!

LarryD:
An example where pushing a switch on pin 2 starts a timing process on pin 9:

//Blink without Delay skeleton example using a structure.

//LarryD

... See earlier post

I've created a macro version of your structure It isn't a perfect fit but I think I can do everything you are doing with it. i'm too tired to think tonight. Here's your first 2 examples re-worked into a macro which were pretty easy. I an looking to try to recreate all of them with macro timers. thanks again for the structure timer example It has inspired new code and I think it has uses I may not be able to do with macros.

#define timer(waitMillis, enableFlag, Clock) for (static unsigned long lastMillis = Clock; enableFlag && (unsigned long) (Clock - lastMillis) >= (waitMillis); lastMillis = Clock)
// looking to add restart later on.
void setup() {
  Serial.begin(115200);
  Serial.print(" P12 ");
  Serial.print(" P13 ");
  Serial.print("Counter");
  Serial.println();
  pinMode(13, OUTPUT);
  pinMode(12, OUTPUT);
}

void loop() {
  static bool pin12enableFlag = true;
  timer(10UL, true, millis())
  {
    static unsigned long Counter;
    Counter++;
    Serial.print(digitalRead(12) ? " On  " : " Off ");
    Serial.print(digitalRead(13) ? " On  " : " Off ");
    Serial.print(Counter * 100);
    Serial.println();
  }
  //***************************
  //example 1    Toggle Pin13 every 200ms
  //Has the timer lapsed?
  static bool pin13enableFlag = true;
  timer(200UL, pin13enableFlag, millis()) // pin13
  {
    //Toggle Pin13
    digitalWrite(13, !digitalRead(13));

    //if you only want this section of code to happen once
    //uncomment the next line
    //pin13enableFlag = false;
  }

  //***************************
  //example 2    After 3 seconds, Pin12 goes and stays HIGH
  //Has the timer lapsed?
  //Wait Millis Resetart Enable

  timer(3 * 1000UL, pin12enableFlag, millis()) //pin12
  {
    //Make Pin12 HIGH now
    digitalWrite(12, HIGH);
    //disable timing section of code
    pin12enableFlag = false;
  }
}

Z

I much prefer to show the user how to achieve something and all of my small tutorials have been aimed at making the workings very clear so that they can (hopefully) be understood and adapted and extended.

I have had problems myself, and I have seen others having problems when the "packaged solution" does not do exactly what I wanted (or what I thought it was claiming to do). It is very easy to spend more time trying to figure out what's in the package than the time that would have been required to solve the problem without the package.

IMHO the time spent developing many packages would have produced a much more useful output if it had been used to write a tutorial explaining how to do the thing without the package. Knowledge should be shared, not hidden in "black boxes".

...R
PS. None of this is intended as a personal attack on @zhomeslice

zhomeslice:
sharing code with macros causes some confusion. any suggestions.

What kind of confusion do you mean?

I prefer to use a different convention for macro names: RUN_EVERY(). This makes it more obvious it's a macro. To further avoid conflicts I append the name of the library. For example, if my library was named ZHTime: ZHTIME_RUN_EVERY(). In this case I'm not sure whether the small chance of conflict is worth changing to those less user friendly names. The Arduino core macros just use camel case like the functions but there certainly are some issues when users encounter the sometimes unexpected behavior of things like min(), max(), abs(), constrain() caused by them being macros rather than functions. However, I don't think that issue really applies to these macros since something like:

runEvery(Serial.parseInt(), millis()) {

wouldn't work even if it was a function.

DelayAsync

I've enjoyed this thread and learned so much.
Thank each of you for your contributions.
Gethub repository creation still alludes me but I may need to dig into this and finally figure it out.

I feel for the new programmer who only understands delay() and for all those who try to teach them Blink without dealy :slight_smile:

It would be great if our minds could come together to create a solution for this that could be a black box for the new to Arduino community and advanced enough with great examples for the rest of us.

I'm sharing all my macro examples for everyone to try I've used and tested most but of course some may have issues still. I'm not the best programmer. :slight_smile:

// ones I use the most:
#define runAfter(t)		    for (static unsigned long _ATimer; (unsigned long)(millis() - _ATimer) >= (t); _ATimer = millis())
#define runEvery(t)		    for (static unsigned long _ETimer; (unsigned long)(millis() -_ETimer) >= (t); _ETimer += (t))
#define runAfterClock(t,Clock)      for (static unsigned long _ATimer = Clock; (unsigned long)(Clock - _ATimer) >= (t); _ATimer = Clock)
#define runEveryClock(t,Clock)      for (static unsigned long _ETimer = Clock; (unsigned long)(Clock - _ETimer) >= (t); _ETimer += (t))

// NEW Thanks to LarryD for your structure timer I got this from:
#define timer(waitMillis, enableFlag, Clock) for (static unsigned long lastMillis = Clock; enableFlag && (unsigned long) (Clock - lastMillis) >= (waitMillis); lastMillis = Clock)

// Other Concepts
#define runEveryWithCountCycles(t)	for (static unsigned long _ETimer,Counter,Cycles; ((unsigned long)(millis() - _ETimer) >= (t)) ?   _ETimer += (t) : Cycles++ == false; Counter++)
#define runEveryWithCycles(t)		for (static unsigned long _ETimer,Cycles; ((unsigned long)(millis() - _ETimer) >= (t)) ?   _ETimer += (t) : Cycles++ == false; )
#define runEveryWithCount(t)		for (static unsigned long _ETimer,Counter; ((unsigned long)(millis() - _ETimer) >= (t)) ? Counter++ : false; _ETimer += (t))
#define runEveryWithCountAlt(t)		for (static unsigned long _ETimer,Counter; ((unsigned long)(millis() - _ETimer) >= (t)) ? _ETimer += (t) : false; Counter++)
#define runEveryWithCyclesAlt(t)	for (static unsigned long _ETimer,Counter; Cycles++ && (unsigned long)(millis() -_ETimer >= (t)); _ETimer += (t)) 
#define runEveryAlt(t)			for (static unsigned long _ETimer; ((unsigned long)(millis() - _ETimer) >= (t)) ? _ETimer += (t) : false; )
#define runEveryAltX(t)			for (static unsigned long _ETimer; ((unsigned long)(millis() - _ETimer) < (t)) ? false:_ETimer += (t); )
#define runAfterAlt(t)			for (static unsigned long _ATimer; ((unsigned long)(millis() - _ATimer) >= (t))?  _ATimer = millis() : false; )
#define runAfterAltX(t)			for (static unsigned long _ATimer,Now; ((unsigned long)((Now = millis()) - _ATimer) >= (t))?  _ATimer = Now : false; )
#define runAfterX(t)			for (static unsigned long _ATimer,Now; (unsigned long)((Now = millis()) - _ATimer) >= (t); _ATimer = Now)
#define runAt(t)			for (static unsigned long _EATimer; ((unsigned long) millis() -_ETimer) >= (t); _EATimer += (t) * (1 +((int)  (millis()- _EATimer) / (t))))

zhomeslice:
I feel for the new programmer who only understands delay() and for all those who try to teach them Blink without dealy :slight_smile:

Maybe the inability to "get" BWoD is "survival of the fittest" in action. (Programming red in tooth and claw) :slight_smile:

...R

Very much appreciate your work.
Still think a new person benefits greatly when the light comes on when they grasp BWD.

On a different topic, here are a few debug macros I use, thought you might be interested.

// DebugMacros.h

/* Example of use:
   #define DEBUG          // <-----<<<< this line must appear before the include line
   #include <DebugMacros.h>
*/

//If you comment the line:  #define DEBUG
//The Macro lines are defined as blank, thus would be ignored by the compiler.
//If the line is NOT commented, these macros will be included in the sketch.
// examples:
// This  converts to         >>>>----->         This OR a Blank Line. 
//---–----------------------------------------------------------------------------------------
// DPRINTLN("Testing123");   >>>>----->     Serial.println("Testing123"); 
// DPRINTLN(0xC0FFEEul,DEC); >>>>----->     Serial.println(0xC0FFEEul,DEC);
// DPRINTLN(12648430ul,HEX); >>>------>     Serial.println(12648430ul,HEX);
// DPRINTLNF("This text came from flash");  Serial.println(F("This text came from flash"));
// DPRINT(myVariable);       >>>>----->     Serial.print(myVariable);
// DELAY(100);               >>>>----->     delay(100);
// SERIALBEGIN(9600);        >>>>----->     Serial.begin(9600);
// PINMODE(13,OUTPUT);       >>>>----->     pinMode(13,OUTPUT);
// TOGGLEd13;                >>>>----->     PINB = 0x20;  // D13 Toggle,for UNO ONLY
 
#ifdef DEBUG
//#define DPRINT(args...)  Serial.print(args)             //OR use the following syntax:
#define SERIALBEGIN(...)   Serial.begin(__VA_ARGS__)
#define DPRINT(...)        Serial.print(__VA_ARGS__)
#define DPRINTLN(...)      Serial.println(__VA_ARGS__)
#define DRINTF(...)        Serial.print(F(__VA_ARGS__))
#define DPRINTLNF(...)     Serial.println(F(__VA_ARGS__)) //Printing text using the F macro
#define DELAY(...)         delay(__VA_ARGS__)
#define PINMODE(...)       pinMode(__VA_ARGS__)
#define TOGGLEd13          PINB = 0x20                    //For the UNO only
 
#else
#define SERIALBEGIN(...)   //blank line
#define DPRINT(...)        //blank line
#define DPRINTLN(...)      //blank line
#define DPRINTF(...)       //blank line
#define DPRINTLNF(...)     //blank line
#define DELAY(...)         //blank line
#define PINMODE(...)       //blank line
#define TOGGLEd13          //blank line 
 
#endif
//***************************************************************

Edit:
The structure example is easily replaced by using Class i.e. a library.
The reason I use a structure in sketches is for visibility.

.

1 Like

LarryD:
Very much appreciate your work.
Still think a new person benefits greatly when the light comes on when they grasp BWD.

On a different topic, here are a few debug macros I use, thought you might be interested.

Welcome and Your Debug code Is greatly appropriated! I've already added it to my code and added a macro
I had a macro created for Floats I Think you will love!!!
I works with other numbers also just convert them to floats

Modified code to match your format

#define  DPRINTLNSF(...)    {char S[30]; Serial.println(dtostrf(__VA_ARGS__ , S));}   //Variable, Width, Percision
#define  DPRINTSF(...)      {char S[30]; Serial.print(dtostrf(__VA_ARGS__ , S));}     //Variable, Width, Percision

Test Example

#define runAfter(t)          for (static unsigned long _ATimer; (unsigned long)(millis() - _ATimer) >= (t); _ATimer = millis())
#define  DPRINTLNSF(...)    {char S[30]; Serial.println(dtostrf(__VA_ARGS__ , S));}  //Variable, Width, Percision
#define  DPRINTSF(...)      {char S[30]; Serial.print(dtostrf(__VA_ARGS__ , S));}    //Variable, Width, Percision
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  delay(123);
}

void loop() {
  // put your main code here, to run repeatedly:
  runAfter(100) {
    DPRINTSF((float) micros()*-0.001, 13, 3); //Variable, Width, Percision
    DPRINTLNSF((float) micros()*0.1, 13, 1);  //Variable, Width, Percision
  }
}

Output:

-13525.001 1352521.3
-13624.329 1362454.9
-13724.681 1372490.0
-13824.009 1382422.9
-13924.360 1392457.6
-14024.713 1402492.9

The DPRINTSF & DPRINTLNSF macros converts the double value passed in into an ASCII representation that will be printed to the serial output.
Conversion is done in the format "[-]d.ddd". The minimum field width of the output string (including the possible '.' and the possible sign for negative values) is given in width,
The precision determines the number of digits after the decimal sign.
width is signed value, negative for left adjustment.

Z

Nice.
If you add this to DebugMacros.h remember to add the second part in the 'else' section.

#else
#define DPRINTLNSF(...) //
#define DPRINTSF(...) //

.

LarryD:
Nice.
If you add this to DebugMacros.h remember to add the second part in the 'else' section.

#else
#define DPRINTLNSF(...) //
#define DPRINTSF(...) //

Yep I did that and it's working great :slight_smile:
Thanks again
Z

LarryD, I want to thank you for showing me the code that helped create this incredible powerful timer It far surpasses what I was working on.
Thanks,
Z

// Thank you LarryD. This has become a great way to manage multiple timers thanks to your code you shared with me. 
struct S_TIMER {
  unsigned long waitTime;
  bool          everyTime;
  bool          micro;
  bool          restart;
  bool          enableFlag;
  unsigned long lastTime;
  unsigned long remainingTime;

  bool CheckTime() { //Delay time expired function "CheckTime()"
    unsigned long Now = S_TIMER::GetNow();
    if (enableFlag && (((unsigned long) Now - lastTime) >= (waitTime))) { // Test Timer
      if (restart) lastTime = (everyTime) ? (lastTime + waitTime) : Now; //get ready for the next iteration Every or (After) Has Different affects
      return true; // Timer Finished
    }
    return false; // Still Waiting
  } //END of CheckTime()

  void init(unsigned long wT, bool eT = false, bool m = false, bool r = true, bool eF = true) {
    waitTime = wT; // The Delay
    everyTime = eT;
    micro = m;
    restart = r;
    enableFlag = eF;
  }//END of init()

  unsigned long GetNow() {
    return ((micro) ? micros() : millis());
  }

  void stopTimer() {
    remainingTime = S_TIMER::GetNow() - lastTime;
    enableFlag = false;
  }

  void startTimer() {
    lastTime = S_TIMER::GetNow() + remainingTime;
    enableFlag = true;
  }

  void resetTimer(bool r = true) {
    lastTime = S_TIMER::GetNow();
    restart = r;
    enableFlag = true;
  }
}; //END of structure timer

#define Create_S_TIMER(ID)   S_TIMER STMR_##ID
#define Init_S_TIMER(ID,args...)     STMR_##ID.init(args)          // (waitMillis, everyTime, restart, enableFlag)  Sets the initial behavior of the timer
#define Check_S_TIME(ID)             STMR_##ID.CheckTime()         // Check Timer
#define SetTime_S_TIMER(ID,Time)     STMR_##ID.waitTime = Time     // Change the timers delay time
#define Time_S_TIMER(ID)             STMR_##ID.waitTime            // Access the timers delay time
#define SetLastTime_S_TIMER(ID,Time) STMR_##ID.lastTime  = Time    // Change the timers last time 
#define LastTime_S_TIMER(ID)         STMR_##ID.lastTime            // Access the timers last time 
#define Stop_S_TIME(ID)              STMR_##ID.stopTimer()         // Pauses Timer
#define Start_S_TIME(ID)             STMR_##ID.startTimer()        // Start Timer Where it left off << Rollover issue HELP 
#define Pause_S_TIME(ID)             STMR_##ID.restart = false     // Pauses Timer at end of timing WARNING CheckTimer() returns true at end of timing event and wont reset to false
#define Reset_S_TIME(ID,args...)     STMR_##ID.resetTimer(args)    // Reset and args (restart bool default true) timer
#define Every_S_TIME(ID)             STMR_##ID.everyTime = true    // By adding waitMillis to lastMillis timing will always shift by (waitMillis) 
#define After_S_TIME(ID)             STMR_##ID.everyTime = false   // By shifting to millis() the next time interval will always be (waitMillis) long
#define This_S_TIME(ID)              STMR_##ID                     // Get the name of the Structure for Direct Access This_S_TIME(ID).lastMillis for example

Create_S_TIMER(Spam); // Create timer object

void setup() {
  Serial.begin(115200);
  Init_S_TIMER(Spam, 100, true); // Set the timer for 100 ms and it is additive triggere every 100 ms no matter how long the other code takes in between
  SetLastTime_S_TIMER(Spam, 0); // Sets the timer to start at zero miliseconds
}

void loop() {
  if (Check_S_TIME(Spam)) {
    Serial.println(millis());
    if (LastTime_S_TIMER(Spam) == 2000) {
      Stop_S_TIME(Spam);
      delay(500);
      Start_S_TIME(Spam);
    }
  }
}

@zhomeslice
I have implemented something similar but as a C++ class. This avoids many of the problems with macros. A class is much easier to use with arrays, etc.

Please see GitHub - mikaelpatel/Arduino-Timemark: Timemark handler for Arduino and the example sketches.

Cheers!