Go Down

Topic: Blink without delay Macros "Simplifying the New Arduino Programmers Life" (Read 2995 times) previous topic - next topic

zhomeslice

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:
Code: [Select]
// 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:
Code: [Select]
// 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
HC

larryd

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.


.
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

zhomeslice

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

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:
Code: [Select]

//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
//======================================================================



.
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

zhomeslice

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:
Code: [Select]

//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
//======================================================================



.
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
Code: [Select]
#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
HC

larryd

An example where pushing a switch on pin 2 starts a timing process on pin 9:
Code: [Select]

//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
//======================================================================
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

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.

zhomeslice

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!

HC

zhomeslice

An example where pushing a switch on pin 2 starts a timing process on pin 9:
Code: [Select]

//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.
Code: [Select]
#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
HC

Robin2

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
 
Two or three hours spent thinking and reading documentation solves most programming problems.

pert

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:
Code: [Select]
runEvery(Serial.parseInt(), millis()) {
wouldn't work even if it was a function.

vbextreme

Easy framework linguaggio C: https://github.com/vbextreme/EasyFramework
Hack your life: http://vbextreme.netai.net/
Unoffical Telegram group: https://telegram.me/joinchat/ALRu8ACkdTdXyz-2P7v13A

zhomeslice

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 :)

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.  :)
Code: [Select]
// 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))))


HC

Robin2

I feel for the new programmer who only understands delay() and for all those who try to teach them Blink without dealy :)
Maybe the inability to "get" BWoD is "survival of the fittest" in action. (Programming red in tooth and claw) :)

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

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.

Code: [Select]

// 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.

.
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

Go Up