How to replace Multiple Delays in a row with millis()

Hello All,

I found this script and was wondering, what is the easiest way to replace all these delay(50) and delay(100) listed in a row, with millis() ?

Please advise
Thanks

void setup() {
 pinMode(6, OUTPUT); // RED
 pinMode(7, OUTPUT); // BLUE
 pinMode(8, OUTPUT); // RED
 pinMode(9, OUTPUT); // BLUE
 
}

void loop() {
  
 digitalWrite(6, HIGH);
 digitalWrite(7, HIGH);
 delay(50);
 
 digitalWrite(6, LOW);
 digitalWrite(7, LOW);
 delay(50);
 
 digitalWrite(6, HIGH);
 digitalWrite(7, HIGH);
 delay(50);
 
 digitalWrite(6, LOW);
 digitalWrite(7, LOW);
 delay(50);
 
 digitalWrite(6, HIGH);
 digitalWrite(7, HIGH);
 delay(50);
 
 digitalWrite(6, LOW);
 digitalWrite(7, LOW);
 delay(50);
 
 
 delay(100);
 
 
 digitalWrite(8, HIGH);
 digitalWrite(9, HIGH);
 delay(50);
 
 digitalWrite(8, LOW);
 digitalWrite(9, LOW);
 delay(50);
 
 digitalWrite(8, HIGH);
 digitalWrite(9, HIGH);
 delay(50);
 
 digitalWrite(8, LOW);
 digitalWrite(9, LOW);
 delay(50);
 
 digitalWrite(8, HIGH);
 digitalWrite(9, HIGH);
 delay(50);
 
 digitalWrite(8, LOW);
 digitalWrite(9, LOW);
 delay(50);
}

Hello
Take a view to the BWOD example of IDE.
Have a nice day and enjoy coding in C++.

Build a state machine, use a common so called millis TIMER to handle timing.

1 Like

not clear on your response what is Take a view to the BWOD example of IDE.

Looking at your code, it looks like a sequence of 13 steps of 50ms long each. I think I'd use time as the state variable:

 int mySequence  = (millis() / 50) % 13;
...
 if (mySequence ==  0) {
    digitalWrite(6, HIGH);
    digitalWrite(7, HIGH);
  }
...

Most likely the BlinkWithoutDelay example that comes with the Arduino IDE (under File->Examples->Digital).

But for a thing like you are asking for a state machine is most likely the best option like @LarryD suggested.

Something like:

unsigned long previousMillis = 0;
byte state = 0;

void setup() {
  Serial.begin(115200);
}

bool stateWait(unsigned long mill){
  if(millis() - previousMillis >= mill){
    state++;
    previousMillis = millis();
  }
}

void loop() {
  switch(state){
    case 0:
      Serial.println(F("state 0"));
      digitalWrite(6, HIGH);
      digitalWrite(7, HIGH);
      stateWait(1000);
    break;
    case 1:
      Serial.println(F("state 1"));
      digitalWrite(6, HIGH);
      digitalWrite(7, HIGH);
      stateWait(1000);
    break;
  }
}

The thing to keep in mind with this implementation is, that each case is called as often as possible during its 1s upkeep.

But we can change this by checking if it's the first time we run through a case like so:

unsigned long previousMillis = 0;
byte state = 0;
bool firstStateRun = true;

void setup() {
  Serial.begin(115200);
}

bool stateWait(unsigned long mill) {
  if (millis() - previousMillis >= mill) {
    state++;
    previousMillis = millis();
    firstStateRun = true;
  }
}

void loop() {
  switch (state) {
    case 0:
      if (firstStateRun) {
        Serial.println(F("state 0"));
        digitalWrite(6, HIGH);
        digitalWrite(7, HIGH);
        firstStateRun = false;
      }
      stateWait(1000);
      break;
    case 1:
    if (firstStateRun) {
      Serial.println(F("state 1"));
      digitalWrite(6, HIGH);
      digitalWrite(7, HIGH);
      firstStateRun = false;
    }
      stateWait(1000);
      break;
  }
}

This gives us this output:
image

1 Like

consider

#define MyHW
#ifdef MyHW
enum { P0 = 10, P1 = 11, P2 = 12, P3 = 13 };
#else
enum { P0 = 6, P1 = 7, P2 = 8, P3 = 9 };
#endif

byte LedPins [] = { P0, P1, P2, P3 };

enum { Off = HIGH, On = LOW };

struct Seq  {
    byte            pin0;
    byte            pin1;
    byte            state;
    unsigned long   period;
};

Seq seqs [] = {
    { P0, P1,   On,  50 },
    { P0, P1,  Off,  50 },
    { P0, P1,   On,  50 },
    { P0, P1,  Off,  50 },
    { P0, P1,   On,  50 },
    { P0, P1,  Off, 150 },

    { P2, P3,   On,  50 },
    { P2, P3,  Off,  50 },
    { P2, P3,   On,  50 },
    { P2, P3,  Off,  50 },
    { P2, P3,   On,  50 },
    { P2, P3,  Off,  50 },
};
#define N_SEQ   (sizeof(seqs)/sizeof(Seq))
int idx;

unsigned long msecLst;
unsigned long msec;
unsigned long period;

void loop() {
    msec = millis ();

    if ((msec - msecLst) > period)  {
        msecLst = msec;

        Seq *s = & seqs [idx++];
        digitalWrite (s->pin0, s->state);
        digitalWrite (s->pin1, s->state);
        period = s->period;

        idx = N_SEQ == idx ? 0 : idx;
    }
}

void setup() {
    for (unsigned n = 0; n < sizeof(LedPins); n++)  {
        pinMode      (LedPins [n], OUTPUT);
        digitalWrite (LedPins [n], Off);
    }
}

Looking further at your code, you could turn the pin 9,8,7,6 states into data:

...
const byte pattern[] = {
                 0b0011, 0b0000, 0b0011, 0b0000, 0b0011, 
                 0b0011, 0b0011,
                 0b1111, 0b0011, 0b1111, 0b0011, 0b1111}; 

void doPattern(void){
  const unsigned long interval = 50;
  static unsigned long last = 0;
  static int index  = 0; 
  unsigned long now = millis();
  if(now - last >= interval){
    last+= interval;
    digitalWrite(6,pattern[index] & 0b0001);  
    digitalWrite(7,pattern[index] & 0b0010);  
    digitalWrite(8,pattern[index] & 0b0100);  
    digitalWrite(9,pattern[index] & 0b1000);
    // advance state:
    index = ( index + 1 ) % sizeof(pattern);
  }
}

void loop(){
   doPattern();
 }


(Edited per How to replace Multiple Delays in a row with millis() - #9 by alto777 )

one error and another small error.

    digitalWrite(6, pattern[index] & 0b0001 ? HIGH : LOW);

Next: move the 4 bits to be on one port and use direct port manipulation…

a7

1 Like

I know it's sloppy, but I've always relied on the casting and zero versus not-zero.

To use the source, https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring_digital.c#L138 the test is LOW/zero versus not:

	if (val == LOW) {
		*out &= ~bit;
	} else {
		*out |= bit;
	}

Huh -- looking further down the code, it's int digitalRead(uint8_t pin), not a bool or uint8_t.

So much code would break if 0 and 1 didn’t work for LOW and HIGH, false and true and any I just refuse to adopt that… I just don’t think we’ll live to see it.

0 and not zero, hmm, probably also.

I still

 unsigned char flag = 1; // initial flag is set

Just stubborn if it wasn’t broken, why are you fixing it atitude.

Some of this is the making things easier for noobs Arduino moves, dunno who ever thought that up, even all the way to setup/loop, which, as you may have noticed still stymies quite a number of ppl. Daily. :expressionless:

a7

Hello stspringer
The easiest way to replace the delay()s is the design of an event controlled timer. As base the BWOD example of the IDE is used extended by a variable to control on/off. See below an example sketch, take a view, do modifications and test it.

/* BLOCK COMMENT
  ATTENTION: This Sketch contains elements of C++.
  https://www.learncpp.com/cpp-tutorial/
  Many thanks to LarryD
  https://europe1.discourse-cdn.com/arduino/original/4X/7/e/0/7e0ee1e51f1df32e30893550c85f0dd33244fb0e.jpeg
  https://forum.arduino.cc/t/how-to-replace-multiple-delays-in-a-row-with-millis/962815
*/
#define ProjectName "How to replace Multiple Delays in a row with millis()"
// HARDWARE AND TIMER SETTINGS
// YOU MAY NEED TO CHANGE THESE CONSTANTS TO YOUR HARDWARE AND NEEDS
// CONSTANT DEFINITION
constexpr byte LedPinsStages[] {5,6,7,8,9,10};  // portPin o---|220|---|LED|---GND
constexpr byte LedPinsStage1[] {5,7,9};         // portPin o---|220|---|LED|---GND
constexpr byte LedPinsStage3[] {6,8,10};        // portPin o---|220|---|LED|---GND
constexpr  int numberOfFlashs1 {3};
constexpr  int numberOfFlashs3 {5};
constexpr unsigned long delayTimeStage1 {250};
constexpr unsigned long delayTimeStage2 {1000};
constexpr unsigned long delayTimeStage3 {500};
#define OutPutTest
unsigned long OutPutTestTime {500};
// VARIABLE DECLARATION AND DEFINITION
unsigned long currentTime;
struct TIMER {              // has the following members
  unsigned long duration;   // memory for interval time
  unsigned long stamp;      // memory for actual time
  bool onOff;               // control for start/stop
};
TIMER stage1 {delayTimeStage1, 0, false};
TIMER stage2 {delayTimeStage2, 0, false};
TIMER stage3 {delayTimeStage3, 0, false};

bool timerEvent (TIMER &timer) {
  return (currentTime - timer.stamp >= timer.duration && timer.onOff);
}
void startTimer(TIMER &timer) {
  timer.stamp = currentTime;
  timer.onOff = true;
}
void resetTimer(TIMER &timer) {
  timer.stamp = currentTime;
}
void stoppTimer(TIMER &timer) {
  timer.onOff = false;
}
void toogleLedPin(int pin) {
  digitalWrite(pin, !digitalRead(pin));
}
// -------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  Serial.println(F("."));
  Serial.print(F("File   : ")), Serial.println(__FILE__);
  Serial.print(F("Date   : ")), Serial.println(__DATE__);
  Serial.print(F("Project: ")), Serial.println(ProjectName);
  pinMode (LED_BUILTIN, OUTPUT);  // used as heartbeat indicator
  //  https://www.learncpp.com/cpp-tutorial/for-each-loops/
  for (auto Output_ : LedPinsStages) pinMode(Output_, OUTPUT);
#ifdef OutPutTest
  // check outputs
  for (auto Output_ : LedPinsStages) digitalWrite(Output_, HIGH), delay(OutPutTestTime);
  for (auto Output_ : LedPinsStages) digitalWrite(Output_, LOW), delay(OutPutTestTime);
#endif
  startTimer(stage1);
}
void loop () {
  currentTime = millis();
  digitalWrite(LED_BUILTIN, (currentTime / 500) % 2);
  if (timerEvent(stage1)) {
    for (auto LedPinStage1 : LedPinsStage1) toogleLedPin(LedPinStage1);
    resetTimer(stage1);
    static int counter=0;
    if(!(++counter%=numberOfFlashs1<<1)) startTimer(stage2),stoppTimer(stage1);
  }
  if (timerEvent(stage2)) {
    startTimer(stage3),stoppTimer(stage2);
  }
  if (timerEvent(stage3)) {
    for (auto LedPinStage3 : LedPinsStage3) toogleLedPin(LedPinStage3);
    resetTimer(stage3);
    static int counter=0;
    if(!(++counter%=numberOfFlashs3<<1)) startTimer(stage1),stoppTimer(stage3);
  }
}

Have a nice day and enjoy coding in C++.

1 Like

Wow this is deep checking it out thanks

I plugged it into my script and there is one bug

My low beam fog lights are always on by default and they do not turn off in the blink sequence consistently. I think it is because of button 4 may be stuck on low at times, here is my script. Sometimes it blinks normally and sometimes it doesn't. You have to do a double-click on button 5 to run your script

if you uncomment run_police_lights(); you will see my original blink does fine but not with the fancy blink I like in your script that I edited

//call the function
//run_police_lights();
run_police_lights_2();

//Arduino forum 02_21_2022 blh64 Faraday https://forum.arduino.cc/t/onebutton-library-doubleclick/959465/30
//My_Working_OneButton_Harley_Fog_Lights_With_Police_Fine_Tuneup_1.uno
//button 4 blinks the fog lights

//Button 5 has 3 jobs short click, long press, double click
//Button 5 will have 3 jobs, a short press will toggle on or off the high beam fog lights, as you have coded.
//Button 5 the first long press will turn off all the fog lights, and a second long press will turn on just the low beam fog lights, as you have coded.
//while all the fog lights are off , no other button presses will work
//Button 5 a first double click, will turn on the police lights, and a second double click will turn off the police lights and just light the low beam fog lights, the high beams will be off.
//The low beam fog lights are always on as default.

//Declarations
#include "OneButton.h"
//===================================================================================================================================================



//=======================================================================================================================================================
//BEGIN run_police_lights_2 code
//=======================================================================================================================================================
// HARDWARE AND TIMER SETTINGS
// YOU MAY NEED TO CHANGE THESE CONSTANTS TO YOUR HARDWARE AND NEEDS
// CONSTANT DEFINITION


constexpr byte LedPinsStages[] {6,7,8,9};  // portPin o---|220|---|LED|---GND



//LED pins
constexpr byte LedPinsStage1[] {6,7};         // portPin o---|220|---|LED|---GND
constexpr byte LedPinsStage3[] {8,9};  

// portPin o---|220|---|LED|---GND

//How many flashes
constexpr  int numberOfFlashs1 {6};
constexpr  int numberOfFlashs3 {6};

//set the times
constexpr unsigned long delayTimeStage1 {50};
constexpr unsigned long delayTimeStage2 {100};
constexpr unsigned long delayTimeStage3 {50};



#define OutPutTest
unsigned long OutPutTestTime {500};
// VARIABLE DECLARATION AND DEFINITION
unsigned long currentTime;
struct TIMER {              // has the following members
unsigned long duration;   // memory for interval time
unsigned long stamp;      // memory for actual time
bool onOff;               // control for start/stop
};
TIMER stage1 {delayTimeStage1, 0, false};
TIMER stage2 {delayTimeStage2, 0, false};
TIMER stage3 {delayTimeStage3, 0, false};

bool timerEvent (TIMER &timer) {
return (currentTime - timer.stamp >= timer.duration && timer.onOff);
}
void startTimer(TIMER &timer) {
timer.stamp = currentTime;
timer.onOff = true;
}
void resetTimer(TIMER &timer) {
timer.stamp = currentTime;
}
void stoppTimer(TIMER &timer) {
timer.onOff = false;
}
void toogleLedPin(int pin) {
digitalWrite(pin, !digitalRead(pin));
}

//=======================================================================================================================================================
//END run_police_lights_2 code
//=======================================================================================================================================================
// Setup a new OneButton push buttons on pin 4 and 5

/*
Button 4 - toggle blinking on/off
Button 5 - toggle HIGH fog ligts on, long click - toggle all lights on/off
*/

//OneButton blink_button(4, true); //original
//OneButton on_off_button(5, true); //original

OneButton button_blink_the_fog_lights(4, true);
OneButton switch_turn_on_the_high_beam_fog_lights(5, true);


//define
#define DISABLED  false
#define ENABLED  true
#define LEDon  HIGH
#define LEDoff  LOW

unsigned long currentMillis;
unsigned long previousMillis;
unsigned long on_off_long_press_start_time;

const unsigned long blinkInterval = 100;
//this is not needed on a long press because of switch_turn_on_the_high_beam_fog_lights.setPressTicks(2500); // a long press will be detected after 2500 ms
const unsigned long longPressInterval = 2500;

//LED's
const int fog_light_low_beam = 6;
const int fog_light_low_beam_indicator = 7;
const int fog_light_high_beam = 8;
const int fog_light_high_beam_indicator = 9;

//bool
bool blinking = DISABLED;
bool inLongPress = false;
bool all_the_fog_lights_are_off = DISABLED;

//enum
//enum { LIGHTS_OFF, LIGHTS_LOW_BEAM, LIGHTS_BOTH };//original
enum { LIGHTS_OFF, LIGHTS_LOW_BEAM, LIGHTS_BOTH, POLICE_LIGHTS };
int lightState;


//Police lights
bool start_police_lights_now = DISABLED;
bool Short_Button_Press_Allowed = ENABLED;

const long onDuration_1 = 250;// OFF time for LED//orig 100
const long offDuration_1 = 200;// ON time for LED //orig 500 lower this number for a faster blink

const long onDuration_2 = 250;// OFF time for LED// orig 100
const long offDuration_2 = 200;// ON time for LED//orig 500 lower this number for a faster blink


int LEDState_1 = HIGH;// initial state of LED
int LEDState_2 = LOW;// initial state of LED

long rememberTime_1 = 0;// this is used by the code
long rememberTime_2 = 0;
//end Police

//END Declarations

void setup()
{

//=======================================================================================================================================================
//BEGIN run_police_lights_2 code
//=======================================================================================================================================================   
//  https://www.learncpp.com/cpp-tutorial/for-each-loops/
for (auto Output_ : LedPinsStages) pinMode(Output_, OUTPUT);
#ifdef OutPutTest
// check outputs
//for (auto Output_ : LedPinsStages) digitalWrite(Output_, HIGH), delay(OutPutTestTime);//original
//BEGIN my add edit

////this does NOT light the 4 LED's, on startup, when Output is set to LOW, uncomment it if you wish, and then "comment out"  for (auto Output_ : LedPinsStages) digitalWrite(Output_, HIGH), delay(OutPutTestTime);
//for (auto Output_ : LedPinsStages) digitalWrite(Output_, LOW), delay(OutPutTestTime);

//this lights the 4 LED's, on startup, when Output is set to HIGH, comment it out is you wish and then "uncomment" /for (auto Output_ : LedPinsStages) digitalWrite(Output_, LOW), delay(OutPutTestTime);
for (auto Output_ : LedPinsStages) digitalWrite(Output_, HIGH), delay(OutPutTestTime);

//END my add edit
for (auto Output_ : LedPinsStages) digitalWrite(Output_, LOW), delay(OutPutTestTime);
#endif
startTimer(stage1);
//=======================================================================================================================================================
//END run_police_lights_2 code
//=======================================================================================================================================================   
 
 pinMode(fog_light_low_beam, OUTPUT);
 pinMode(fog_light_low_beam_indicator, OUTPUT);
 pinMode(fog_light_high_beam, OUTPUT);
 pinMode(fog_light_high_beam_indicator, OUTPUT);

 digitalWrite(fog_light_high_beam, LEDoff);
 digitalWrite(fog_light_high_beam_indicator, LEDoff);
 digitalWrite(fog_light_low_beam, LEDon);
 digitalWrite(fog_light_low_beam_indicator, LEDon);
 
 //turns on the low beeams default
 lightState = LIGHTS_LOW_BEAM;

 // Setup the Serial port. see http://arduino.cc/en/Serial/IfSerial
 Serial.begin(115200);
 while (!Serial) 
 {
    ; // wait for serial port to connect. Needed for Leonardo only
 }

 //link your buttos here
 button_blink_the_fog_lights.attachClick(blink_click);//original this is for a "latched switch" if you want one

 //begin my add or edit
 button_blink_the_fog_lights.attachLongPressStart(blink_click);//this is for a momentary-on switch the "blinking" variable gets switched on and off in the blink_click function,  blinking = !blinking;
 button_blink_the_fog_lights.attachLongPressStop(blink_click);//this is for a momentary-on switch the "blinking" variable gets switched on and off in the blink_click function, blinking = !blinking;
 //
 button_blink_the_fog_lights.setDebounceTicks(50);
 button_blink_the_fog_lights.setPressTicks(10);//set faster click response
 //end my add or edit

 //original
 switch_turn_on_the_high_beam_fog_lights.attachClick(on_off_click);//original
 switch_turn_on_the_high_beam_fog_lights.attachLongPressStart(on_off_long_press_start);//original
 switch_turn_on_the_high_beam_fog_lights.attachDuringLongPress(on_off_long_press);//original
 switch_turn_on_the_high_beam_fog_lights.attachLongPressStop(on_off_long_press_stop);//original

 //begin my add or edit
 switch_turn_on_the_high_beam_fog_lights.setDebounceTicks(50);
 switch_turn_on_the_high_beam_fog_lights.setClickTicks(150);//this 150ms will allow the doubleclick to work, any "lower" and doubleclick will not be detected
 switch_turn_on_the_high_beam_fog_lights.setPressTicks(2500); // a long press will be detected after 2500 ms
 switch_turn_on_the_high_beam_fog_lights.attachDoubleClick(doubleclick); //will use this for police lights
 //end my add or edit

} //setup


void loop()
{
 //don't forget to set start time with millis()
 currentMillis = millis();
 
 //currentTime = millis(); used for run_police_lights_2
 currentTime = millis();
 
 
 // keep watching the push buttons:
 button_blink_the_fog_lights.tick();
 switch_turn_on_the_high_beam_fog_lights.tick();

 if (blinking)
 {
    //call the function
    blink_the_fog_lights();
 }

if(start_police_lights_now)//toggled in doubleclick
{
   lightState = POLICE_LIGHTS;//set lightState to POLICE_LIGHTS
   blinking = DISABLED;
   Short_Button_Press_Allowed = DISABLED;//don't allow short clicks
   //call the function
   //run_police_lights();
   run_police_lights_2();
} 
else//police lights are off
{
   Short_Button_Press_Allowed = ENABLED;// allow short clicks
}

}//loop

//SHORT PRESS BUTTON 4 toggle on and off the high beam fog lights
void on_off_click()//button 5 short press hereh "LIGHTS_BOTH" is doing 1 job here for a "short press" high beams are OFF low beams are ON
{
 // if the high beam fog lights are off, turn them on
 // if the high beam fog lights are on, turn them off

 if(Short_Button_Press_Allowed)
 {
    Serial.println("switch_turn_on_the_high_beam_fog_lights click.");
    switch ( lightState )
    {
       case POLICE_LIGHTS:// short press do noting
       break;
    
       case LIGHTS_OFF:  // all lights are off so ignore
       break;
         
       //this is called initally from void setup() lightState = LIGHTS_LOW_BEAM;
       case LIGHTS_LOW_BEAM: // low beam fog lights are on so switch to just high beam fog lights
          digitalWrite(fog_light_high_beam, LEDon);
          digitalWrite(fog_light_high_beam_indicator, LEDon);
          digitalWrite(fog_light_low_beam, LEDon);
          digitalWrite(fog_light_low_beam_indicator, LEDon);
          lightState = LIGHTS_BOTH;
          Serial.println("high ON");
          break;

       case LIGHTS_BOTH: // both low and high beam fog lights are on so switch high off, "LIGHTS_BOTH" is doing 1 job here for the second "short press" high beams are OFF low beams are ON
          digitalWrite(fog_light_high_beam, LEDoff);
          digitalWrite(fog_light_high_beam_indicator, LEDoff);
          digitalWrite(fog_light_low_beam, LEDon);
          digitalWrite(fog_light_low_beam_indicator, LEDon);
          lightState = LIGHTS_LOW_BEAM;
          Serial.println("high OFF");
          break;
    }//switch case
 }//if
}// end on_off_click()

//LONG PRESS BUTTON 5 on the first long press turn off all the fog lights then on the second long press turn back on just the low beam fog lights
void on_off_long_press()//button 5 long press here or doubleclick
{
 // this gets called while a long press is in progress
 // if enough time has elapsed, toggle the state
 //using millis() here
 unsigned long duration = millis() - on_off_long_press_start_time;

 if ( duration >= longPressInterval && inLongPress == true )
 {
    // if the high beam fog lights are off, turn them on
    // if the high beam fog lights are on, turn them off

    Serial.println("Button 5 on_off_longPress.");
    //lightState can be used in other functions
    switch (lightState) 
    {
       
       case LIGHTS_OFF:  // all lights are off so turn on low beam fog lights
          Serial.println("long press button 5 High Beam Fog Lights Off will call LIGHTS_BOTH on the next press");
          digitalWrite(fog_light_high_beam, LEDoff);
          digitalWrite(fog_light_high_beam_indicator, LEDoff);
          digitalWrite(fog_light_low_beam, LEDon);
          digitalWrite(fog_light_low_beam_indicator, LEDon);
          all_the_fog_lights_are_off = DISABLED;
          lightState = LIGHTS_LOW_BEAM;
          Serial.println("low ON");
          break;

       case LIGHTS_LOW_BEAM: // low beam fog lights are on so switch everything off
          
  
       case LIGHTS_BOTH: // "LIGHTS_BOTH" is doing another job here for a "long press", both low and high beam fog lights are off
          Serial.println("long press button 5 ALL Fog Lights Off will call LIGHTS_OFF on the next press");
          digitalWrite(fog_light_high_beam, LEDoff);
          digitalWrite(fog_light_high_beam_indicator, LEDoff);
          digitalWrite(fog_light_low_beam, LEDoff);
          digitalWrite(fog_light_low_beam_indicator, LEDoff);
          all_the_fog_lights_are_off = ENABLED;
          lightState = LIGHTS_OFF;
          Serial.println("all OFF");
          break;
       
       case POLICE_LIGHTS:
          lightState = POLICE_LIGHTS;
          break;
          
    }//switch case
    
    inLongPress = false;//this was set true in void on_off_long_press_start(), and set false also in void on_off_long_press_stop()
 }//if
}//on_off_long_press_stop()

void on_off_long_press_start()
{
 // record time of the long press
 //begin my add edit
 //on_off_long_press_start_time = millis();//don't need millis here because of switch_turn_on_the_high_beam_fog_lights.setPressTicks(2500); // a long press will be detected after 2500 ms
 //end my add edit
 inLongPress = true;
}  //on_off_long_press_start

void on_off_long_press_stop()
{
 inLongPress = false;
}


void blink_click()
{

 //this blinking bool variable, toggles "blinking" back and forth on each run of the blink_click() function
 blinking = !blinking;

 // if we are done blinking, make sure we leave the lights on
 if ( blinking == DISABLED )//if blinking is DISABLED do nothing
 {

    Serial.println("blinking");
    Serial.println(blinking);
   if ( lightState == LIGHTS_BOTH )
   {
      Serial.println("blinking");
      Serial.println(blinking);
      digitalWrite(fog_light_high_beam, LEDon);
      digitalWrite(fog_light_high_beam_indicator, LEDon);
   }//if

     //if the value of "lightState" equals the value of "LIGHTS_HIGH_BEAM" "OR" the value of "lightState" equals the value of "LIGHTS_BOTH"
     if ( lightState == LIGHTS_LOW_BEAM || lightState == LIGHTS_BOTH )
     {
        // toggle low beams
        digitalWrite(fog_light_low_beam, LEDon);
        digitalWrite(fog_light_low_beam_indicator, LEDon);
     }//if
 }//blinking DISABLED
}//blink_click()


void blink_the_fog_lights()
{
 //if lighrState = LIGHTS_OFF bail out, do not blink
 if ( lightState == LIGHTS_OFF )
 {
    // lights are off so nothing to do
    return;
 }//if
 //using millis() here
 if (currentMillis - previousMillis >= blinkInterval)
 {
    // enough time passed yet?
    previousMillis = currentMillis; // sets the time we wait "from"
    if ( lightState == LIGHTS_BOTH )
    {
       // toggle high beams
       digitalWrite(fog_light_high_beam, !digitalRead(fog_light_high_beam)); // shortcut to toggle the LED
       digitalWrite(fog_light_high_beam_indicator, !digitalRead(fog_light_high_beam_indicator)); // shortcut to toggle the LED
    }//if

    //if the value of "lightState" equals the value of "LIGHTS_LOW_BEAM" "OR" the value of "lightState" equals the value of "LIGHTS_BOTH"
    if ( lightState == LIGHTS_LOW_BEAM || lightState == LIGHTS_BOTH )
    {
       // toggle low beams
       digitalWrite(fog_light_low_beam, !digitalRead(fog_light_low_beam)); // shortcut to toggle the LED
       digitalWrite(fog_light_low_beam_indicator, !digitalRead(fog_light_low_beam_indicator)); // shortcut to toggle the LED
    }//if
 }//if
}//blink_the_fog_lights()

// this function will be called when the button was pressed 2 times in a short timeframe.
void doubleclick()
{
 if (!all_the_fog_lights_are_off)//all the fog lights are NOT off, so continue to run the police lights
 {
    if (!start_police_lights_now)//police lights are on
    {
       start_police_lights_now = ENABLED;
       Short_Button_Press_Allowed = DISABLED;
    }
    else//police lights are off
    {
       start_police_lights_now = DISABLED; 
       Short_Button_Press_Allowed = ENABLED;
       if (lightState = POLICE_LIGHTS)
       {
          digitalWrite(fog_light_high_beam, LEDoff);
          digitalWrite(fog_light_high_beam_indicator, LEDoff);
          digitalWrite(fog_light_low_beam, LEDon);
          digitalWrite(fog_light_low_beam_indicator, LEDon); 
          lightState = LIGHTS_LOW_BEAM;//go back to short press LIGHTS_LOW_BEAM
       } //if
    }//else
 } //all_the_fog_lights_are_off
} //end  doubleclick


//Police
void run_police_lights()
{
 if(start_police_lights_now)
 {  
    Serial.println("the police lights are on"); 
    //  LED blink with millis()

    if( LEDState_1 == HIGH )
    {
       if( (millis() - rememberTime_1) >= onDuration_1)
       {   
          LEDState_1 = LOW;// change the state of LED
          rememberTime_1 = millis();// remember Current millis() time
       }//if
 }
 else
 {   
    if( (millis()- rememberTime_1) >= offDuration_1)
    {     
       LEDState_1 = HIGH;// change the state of LED
       rememberTime_1 = millis();// remember Current millis() time
    }//if else
 }//if 

 //  LED blink with millis()
 digitalWrite(fog_light_low_beam,LEDState_1);// turn the LED ON or OFF
 digitalWrite(fog_light_low_beam_indicator,LEDState_1);// turn the LED ON or OFF

 if( LEDState_2 ==LOW )
 {
    if( (millis() - rememberTime_2) >= onDuration_2)
    {   
       LEDState_2 = HIGH;// change the state of LED
       rememberTime_2 = millis();// remember Current millis() time
    }
 
    }
    else
    {   
       if( (millis()- rememberTime_2) >= offDuration_2)
       {     
          LEDState_2 = LOW;// change the state of LED
          rememberTime_2 = millis();// remember Current millis() time
       }//if
    }//if else

    //  LED blink with millis()
    digitalWrite(fog_light_high_beam,LEDState_2);// turn the LED ON or OFF
    digitalWrite(fog_light_high_beam_indicator,LEDState_2);// turn the LED ON or OFF
 }
 else
 {
    if (!start_police_lights_now)
    {
       digitalWrite(fog_light_high_beam,LEDoff);
       digitalWrite(fog_light_high_beam_indicator,LEDoff);
       Short_Button_Press_Allowed = ENABLED;
    }//if
 }//if else

} //end void


void run_police_lights_2()
{
 
 if(start_police_lights_now)
 {  
    if (timerEvent(stage1))
    {
       for (auto LedPinStage1 : LedPinsStage1) toogleLedPin(LedPinStage1);
       resetTimer(stage1);
       static int counter=0;
       if(!(++counter%=numberOfFlashs1<<1)) startTimer(stage2),stoppTimer(stage1);
       }
          if (timerEvent(stage2))
          {
             startTimer(stage3),stoppTimer(stage2);
          }
          if (timerEvent(stage3))
          {
             for (auto LedPinStage3 : LedPinsStage3) toogleLedPin(LedPinStage3);
             resetTimer(stage3);
             static int counter=0;
             if(!(++counter%=numberOfFlashs3<<1)) startTimer(stage1),stoppTimer(stage3);
             } 
             }
             else
             {
                if (!start_police_lights_now)
                {
                   digitalWrite(fog_light_high_beam,LEDoff);
                   digitalWrite(fog_light_high_beam_indicator,LEDoff);
                   Short_Button_Press_Allowed = ENABLED;
                }//if
             }//else
 
}//run_police_lights_2

I am using the onebutton library and millis() in my script, with no delay() functions. My script is in post #13 you can run either police lights function my original or the one by paulpaulson

//call the function
//run_police_lights(); My original function
run_police_lights_2(); New one by paulpaulson.

My Police lights function works 100% of the time with a double-click firing it off. But it is not as fancy as I like.

My script does not have any delay() function in it just millis(). I wanted to find a script to run police lights with a "fancy blinking sequence and I did find one by paulpaulson.

I tried the script by paulpaulson in my script and it works except for one problem. When I fire off the police lights function with a DoubleClick, sometimes 2 of my 4 LED's are out of sync with the police lights script. It is not consistent. sometimes the LED's are fine sometimes they are not. If I run the script alone not plugged into my script it works fine with the same 4 LED's.

QUESTION:
What would cause this? a button left HIGH or LOW? How can I fix this.

I know this is a big ask, but it may be something really easy to fix. Please see post 13# If you want to run the scripts to see what I am talking about.

Thanks for any help

If no one follows up on a post we asked a question on are we to repost it? What is the correct etiquette on this site? Please see post #14 I never got a follow-up reply.

Thank you

We don't have your hardware, so it is difficult to debug on our end.

Reading "When I fire off the police lights function with a DoubleClick, sometimes 2 of my 4 LED's are out of sync with the police lights script. " indicates to me that the state-space isn't completely worked out. To keep things in sync, they should be driven by the same set of state variables.

I think a bump like you did is OK.

I haven’t looked closely at your issue, but it may be the things are not synchronized because they each have timing elements that may be started and stopped but leave over some idea of where they were.

Again, haven’t looked, but maybe when a thing is stopped, its timers shoukd be reset, or when it is started, the timers shoukd be initialized, or set taking into consideration where the other effect is.

If possible, I will try to put your code into the wokwi. Don’t hold your breath, I am off to the beach for a few in a bit.

And patience is a virtue, especially consider the world wide nature of these fora, I know either lotsa ppl have insomnia like me or are living many time zones away.

That said, sometimes interest dies, there’s no way to tell, but in the end code is code and putting your finger on it and playing real dumb as you do will usually turn up logic errors like you having.

a7

Ok thanks, I have patience, "If possible, I will try to put your code into the wokwi" I would appreciate that, I can wait , have fun at the beach :slight_smile:

OK I did put the code in #13 into the wokwi simulator and wired some things up.

I do not know if I wired all the buttons and LEDs.

I changed nothing.

Please go here and see if it is acting the same as yours is in real life.

Make your own account and save a copy you can work on and present here, a new locked copy each time you have something you want anyone to look at, so everyone will see the same thing and you won't accidently change it. New logic, new wokwi simulation.

All free, no worries.

TBH you have to see that what you started with is nothing like what you are wrestling with now, it is clear that I have no idea what it is supposed to do, and only by coming to a full understanding of the library you are using would anyone.

It's > 500 lines of code, the idea of which is not yours, so it is no surprise you are in the soup when you try to tinker with it.

It may be a very easy thing to adjust and improve and enhance, but only for the author or someone who gets on his hands and knees and takes a long crawl through it.

Your (someone's?) very_long_indentifiers_meant_to_make_the_code_Easy_to_read are in fact a serious impedement. But if they help you, I don't argue.

The use of attached handlers looks cool, but can make tracing the logic flow difficult.

So…

Please draw a chart showing all the different kinds of things the LEDs are supposed to be doing using a (google and look at images and try your best to mimic the way they communicate)

 state transition diagram

Label the lines that show hoe your device will move from one kind of display to another with the button (A or B) and the kind of action (click, doulbe clikc and long press) that should make it stop doing one thing and start doing another.

I get some things out of button 5, button 4 seems to do nothing.

And I will watch, but I can promise you I will not spend any more time on the code, and my suspicion is the general lack of attention accrues from what a "big ask", as you put it, it indeed is.

Ppl ten to walk away from things like train wrecks, or things that may appear to be.

I think your problem is trying to play the different things on one set of LEDs. Perhaps it would be easier to add a second set of 4 LEDs and get the multiple functions working separately on their own LEDs. I think they are fighting (> 40 calls to digitalWrite!) with each other over whether a given LED is to be on or off.

But I really have no clue. If I were you, I would go back to your original post, and follow the advices in the first few reponses, which will force you to learn some programming or improve it. The library is really treating you badly, I think it is hindering your progress.

Or it could be one line in there screwing the whole thing up. :expressionless:

a7

1 Like

The state machine / transition diagram / state space trick sort of turns this description around-- instead of thinking about what the buttons do, you think about the different things that can be done, or the different ways the system acts, and after that you can figure out how you change between those ways.

Maybe there's off, low beam fog lights, high beam fog lights, police lights, sometimes some are blinking, some need to be in sync, etc... How many different light configurations are there? Are low beams independent of the other modes or not? etc....

Once the all the states are well defined, then you can plan the transitions between them.