Collection of basic functionilities how do I [stub]

Hi everybody,

from time to time I enjoy writing basic demo-codes with intensive explanations.
This thread shall be a collection for such basic functionalities.

This first posting will act as a table of content with links to the examples.

post #2 how to code a non-blocking short time action on a stateCHANGE of an IO-pin

best regards Stefan

make a short non-blocking "action" through a state-CHANGE

// MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START *
// Take it for granted at the moment scroll down to void setup
// start of macros dbg and dbgi
#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);
// usage: dbg("1:my fixed text",myVariable);
// myVariable can be any variable or expression that is defined in scope

#define dbgi(myFixedText, variableName,timeInterval) \
  do { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  } while (false);
// usage: dbgi("2:my fixed text",myVariable,1000);
// myVariable can be any variable or expression that is defined in scope
// third parameter is the time in milliseconds that must pass by until the next time a
// Serial.print is executed
// end of macros dbg and dbgi
// MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END *


const byte SIGNAL_Pin = 4;      

void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println( F(__FILE__) );
  Serial.print( F("  compiled ") );
  Serial.print( F(__DATE__) );
  Serial.print( F(" ") );
  Serial.println( F(__TIME__) );
}


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

unsigned long MyTestTimer =  0; // Timer-variables MUST be of type unsigned long
const byte    OnBoard_LED = 13;

byte actualSignalState;
byte lastSignalState;


// to make your code easy to understand
// rename this variable that the new name describes 
// SPOT-ON what the PURPOSE of the variable is
boolean ActionShallBeActive = false; // software-switch for switching on/off pulse-creation



// to make your code easy to understand
// rename this variable that the new name describes 
// SPOT-ON what the PURPOSE of the variable is
unsigned long actionTimer = 0; // variable used for non-blockingtiming MUST be of type unsigned long


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


// to make your code easy to understand
// rename this function that the new name describes 
// SPOT-ON what the code does
void actionOn_low_HIGH_change() {      
  dbg("actionOn_low_HIGH_change",111);
  // add your code here 
}

// to make your code easy to understand
// rename this function that the new name describes 
// SPOT-ON what the code does
void actionOn_HIGH_low_change() {     

  dbg("actionOn_HIGH_low_change()",222);
  // add your code here 
}


// to make your code easy to understand
// rename this function that the new name describes 
// SPOT-ON what the code does
void actionFinalisingAfterChange() { 
  dbg("actionFinalisingAfterChange()",999);
  // add your code here 
}

void setup() {
  Serial.begin(115200);
  Serial.println( F("/n Setup-Start /n") );
  PrintFileNameDateTime();
  pinMode(SIGNAL_Pin, INPUT);
  // eventually on startup execute finalising code
  // example switch OFF IO-pins 
  //actionFinalisingAfterChange()

  // initialise actualSignalState and lastSignalState to be equal on power-on
  actualSignalState = digitalRead(SIGNAL_Pin);
  lastSignalState = actualSignalState;      
}


void loop() {
  BlinkHeartBeatLED(OnBoard_LED, 250);

  actualSignalState = digitalRead(SIGNAL_Pin);
  //dbgi("0:",actualSignalState,1000);

  if (actualSignalState != lastSignalState) { // check if a state-CHANGE has occurred
    // if a state-CHANGE has REALLY occured
    dbg("state-CHANGE detected",actualSignalState);
    // update lastSignalState because we HAVE detected the state-CHANGE
    lastSignalState = actualSignalState;      

    ActionShallBeActive = true;  // set flag-variable to true

    // store actual time in Timer-variable as initialisation
    actionTimer = millis();    
    
    if (actualSignalState == HIGH) {
      actionOn_low_HIGH_change(); 
    }

    if (actualSignalState == LOW) {
      actionOn_HIGH_low_change();
    }
  } // END OF if (actualSignalState != lastSignalState)

  if (ActionShallBeActive) {
    if ( TimePeriodIsOver(actionTimer,1000) ) { // check if more than 1000 milliseconds of time have passed by
       // if 1000 milliseconds of time HAVE passed by
      dbg("actiontime is over",actualSignalState);
      ActionShallBeActive = false; // RE-set flag-variable to stop action
      actionFinalisingAfterChange();    
    }
  }
}

best regards Stefan

making code fast responsive to whatever

in most projects multiple functions are needed.
And very often it is required that the code is always fast responsive to

  • incoming data
  • button-presses
  • state-changes of switches like limit-switches
  • etc.

This requires to write code in a consequent NON-blocking way
consequence:

NOWHERE use delay()

NOWHERE use while-loops or do-while-loops

because delay and while-loops are blocking

But how shall repetetive actions be coded then ?
how shall delayed actions be coded then ?

The most important thing is let do

all looping by void loop()

in combination with non-blocking functions that get repeatedly called through the - guess what

looping by void loop()

taking action only from time to time is done by non-blocking timing based on millis()
this means: let do void loop() looping fast all the time and repeatedly check how much time has passed by through comparing a snapshot of time with actual time

work through a sequence of steps is done by state-machines
this means: let do void loop() looping fast all the time and repeatedly call a function that "works through" a sequence of multiple steps".
If changing to a new step shall be done after a certain time it is done by non-blocking timing like described above

1 Like

reply 4

reply 5

reply 6

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.