My hopefully helpful code in using millis() instead of Delay()

Hello All,

Please tell me if anything you read here is incorrect, or you know a better way to code something. Thanks in advance.

I am new to electronics and new to Arduino UNO. I do know how to program in Visual Basic Pro 6, it’s old school now, but I didn’t have such a big learning curve tor the Arduino C++ code.
If I didn’t know how to code at all, it would have been a larger learning curve figuring out C++.

I am sharing my Arduino code here, a simple blinking led, using the built-in Arduino mills() function instead of the built-in Arduino Delay() function.

Delay() stops all your code until the Delay finishes. NOT Good for more complex sketches.

Note my code BEGIN: END: statements, I feel there is more clarity using them, I did it in Visual Basic all the time. Also using boolean instead of int, “when you can”, to save program size, little things that may help in your coding. Boolean is 1 byte, int is 2 to 4 bytes.

HTH

Thank You

blink_without_delay_use_millis_working_code_edit_1.txt (6.28 KB)

 if (Pedestrian_North_Red_Led_State==true) 
  {
      Pedestrian_North_Red_Led_State = !Pedestrian_North_Red_Led_State;
  }
  else
  {
    Pedestrian_North_Red_Led_State = !Pedestrian_North_Red_Led_State;
  }

It turns out that you can over comment code.
Take away the visual noise, and the code is simplyPedestrian_North_Red_Led_State = !Pedestrian_North_Red_Led_State;

/*
  https://www.arduino.cc/en/tutorial/BlinkWithoutDelay
  Blink without Delay function use millis function

  Code Edits Author:John J. Guarnieri jguarnieri@roadrunner.com
  Date:15/May/2020
  Version 1.0.0
  Description
  Working different code for my USA Traffic Light System using Millis()
  USA traffic lights go from Red to Green then from green to yellow 
  then from yellow back to red - repeat
*/

const int Pedestrian_North_Red_Led_Pin_N                    = 5;

unsigned long Previous_North_Prdestrian_Button_Pin_N        = 0;
unsigned long Pedestrian_North_Red_Led_Blink_Speed_interval = 500;
unsigned long currentMillis;

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

  pinMode(Pedestrian_North_Red_Led_Pin_N, OUTPUT);

} //END of setup()

//***************************************************************************************
void loop()
{
  //save current time
  currentMillis = millis();

  //********************************
  //time to toggle the LED ?
  if (currentMillis - Previous_North_Prdestrian_Button_Pin_N >= Pedestrian_North_Red_Led_Blink_Speed_interval)
  {
    //restart the TIMER
    Previous_North_Prdestrian_Button_Pin_N = currentMillis;

    //toggle LED
    digitalWrite(Pedestrian_North_Red_Led_Pin_N, !digitalRead(Pedestrian_North_Red_Led_Pin_N));
  }

} //END of loop()

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

I like that

But, unfortunately, 'true" is not necessarily the same as “LED on”

FYI:

You can use Flags to control code execution.

// TrafficLight.ino
//
// Version      YY/MM/DD
// 1.00         20/05/15      Running code


#define enabled                      true
#define disabled                     false

#define LEDon                        HIGH
#define LEDoff                       LOW


const byte redLED                    = 5;     //+5V----[>|]----[220R]----GND
const byte greenLED                  = 6;
const byte yellowLED                 = 7;
const byte heartbeatLED              = 13;

bool redFlag                         = true;
bool greenFlag                       = false;
bool yellowFlag                      = false;

unsigned long redMillis;
unsigned long greenMillis;
unsigned long yellowMillis;
unsigned long currentMillis;
unsigned long heartbeatMillis;

const unsigned long redInterval      = 5 * 1000ul;
const unsigned long greenInterval    = 5 * 1000ul;
const unsigned long yellowInterval   = 5 * 1000ul;


//                                 s e t u p ( )
//***************************************************************************************
void setup()
{
  Serial.begin(9600);

  pinMode(redLED, OUTPUT);
  digitalWrite(redLED, LEDon);

  pinMode(greenLED, OUTPUT);
  digitalWrite(greenLED, LEDoff);

  pinMode(yellowLED, OUTPUT);
  digitalWrite(yellowLED, LEDoff);

  pinMode(heartbeatLED, OUTPUT);

} //END of setup()

//                                  l o o p ( )
//***************************************************************************************
void loop()
{
  //save current time
  currentMillis = millis();

  //********************************
  //to help show if there is any blocking code, this LED toggles every 500ms 
  if (currentMillis - heartbeatMillis >= 500)
  {
    //restart this TIMER
    heartbeatMillis = currentMillis;

    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));

  }

  //********************************
  checkRed();

  //********************************
  checkGreen();

  //********************************
  checkYellow();

  //********************************
  // Other non blocking code goes here
  //********************************

} //END of loop()

//                              c h e c k R e d ( )
//***************************************************************************************
void checkRed()
{
  if (redFlag == enabled && currentMillis - redMillis >= redInterval)
  {
    digitalWrite(redLED, LEDoff);
    digitalWrite(greenLED, LEDon);

    redFlag = disabled;
    greenFlag = enabled;

    //restart the TIMER
    greenMillis = currentMillis;

  }

} //END of checkRed()

//                           c h e c k G r e e n ( )
//***************************************************************************************
void checkGreen()
{
  if (greenFlag == enabled && currentMillis - greenMillis >= greenInterval)
  {
    digitalWrite(greenLED, LEDoff);
    digitalWrite(yellowLED, LEDon);

    greenFlag = disabled;
    yellowFlag = enabled;

    //restart the TIMER
    yellowMillis = currentMillis;
    
  }

} //END of checkGreen()

//                           c h e c k Y e l l o w ( )
//***************************************************************************************
void checkYellow()
{
  if (yellowFlag == enabled && currentMillis - yellowMillis >= yellowInterval)
  {
    digitalWrite(yellowLED, LEDoff);
    digitalWrite(redLED, LEDon);

    yellowFlag = disabled;
    redFlag = enabled;

    //restart the TIMER
    redMillis = currentMillis;
    
  }

} //END of checkYellow()

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

You can use a State Machine to control code execution:

// TrafficLightStateMachine.ino
//
// Version      YY/MM/DD
// 1.00         20/05/15      Running code


#define LEDon                        HIGH
#define LEDoff                       LOW


const byte redLED                    = 5;     //+5V----[>|]----[220R]----GND
const byte greenLED                  = 6;
const byte yellowLED                 = 7;
const byte heartbeatLED              = 13;

unsigned long redMillis;
unsigned long greenMillis;
unsigned long yellowMillis;
unsigned long currentMillis;
unsigned long heartbeatMillis;

const unsigned long redInterval      = 5 * 1000ul;
const unsigned long greenInterval    = 5 * 1000ul;
const unsigned long yellowInterval   = 5 * 1000ul;

enum STATES {STARTUP, RED, GREEN, YELLOW};
STATES mState = STARTUP;


//                                 s e t u p ( )
//***************************************************************************************
void setup()
{
  Serial.begin(9600);

  pinMode(redLED, OUTPUT);
  pinMode(greenLED, OUTPUT);
  pinMode(yellowLED, OUTPUT);
  pinMode(heartbeatLED, OUTPUT);

} //END of setup()

//                                  l o o p ( )
//***************************************************************************************
void loop()
{
  //save current time
  currentMillis = millis();

  //********************************
  //to help show if there is any blocking code, this LED toggles every 500ms
  if (currentMillis - heartbeatMillis >= 500)
  {
    //restart this TIMER
    heartbeatMillis = currentMillis;

    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));

  }

  //********************************
  checkTrafficLight();

  //********************************
  // Other non blocking code goes here
  //********************************

} //END of loop()

//                        c h e c k T r a f f i c L i g h t ( )
//***************************************************************************************
void checkTrafficLight()
{
  switch (mState)
  {
    //*****************
    case STARTUP:
      {
        digitalWrite(redLED, LEDon);
        digitalWrite(greenLED, LEDoff);
        digitalWrite(yellowLED, LEDoff);

        //next State
        mState = RED;

        //restart the TIMER
        redMillis = currentMillis;
      }
      break;

    //*****************
    case RED:
      {
        if (currentMillis - redMillis >= redInterval)
        {
          digitalWrite(redLED, LEDoff);
          digitalWrite(greenLED, LEDon);

          //next State
          mState = GREEN;

          //restart the TIMER
          greenMillis = currentMillis;
        }
      }
      break;

    //*****************
    case GREEN:
      {
        if (currentMillis - greenMillis >= greenInterval)
        {
          digitalWrite(greenLED, LEDoff);
          digitalWrite(yellowLED, LEDon);

          //next State
          mState = YELLOW;

          //restart the TIMER
          yellowMillis = currentMillis;
        }
      }
      break;

    //*****************
    case YELLOW:
      {
        if (currentMillis - yellowMillis >= yellowInterval)
        {
          digitalWrite(yellowLED, LEDoff);
          digitalWrite(redLED, LEDon);

          //next State
          mState = RED;

          //restart the TIMER
          redMillis = currentMillis;
        }
      }
      break;

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

  } //END of switch/case

} //END of checkTrafficLight()

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

Your code doesn't handle timer overflow. Luckily, you can use a library that takes care of it for you.

Power_Broker:
Your code doesn't handle timer overflow. Luckily, you can use a library that takes care of it for you.

Can you point specifically to the code that does not handle a timer overflow properly? I didn't see that problem so I'd like to know what you spotted.

Note: That library complicates the math and is off by one in the overflow case. Once the error is corrected the more complicated expression is exactly equivalent to the simpler expression (which we all use already).

Power_Broker:
Your code doesn't handle timer overflow. Luckily, you can use a library that takes care of it for you.

Can you explain what you saw in my code?

You are okay.

Very nice I will study this code, Do you have anything with a pedestrian puts button? thank you

larryd:
FYI:

You can use Flags to control code execution.

// TrafficLight.ino

//
// Version      YY/MM/DD
// 1.00         20/05/15      Running code

#define enabled                      true
#define disabled                     false

#define LEDon                        HIGH
#define LEDoff                       LOW

const byte redLED                    = 5;     //+5V----[>|]----[220R]----GND
const byte greenLED                  = 6;
const byte yellowLED                 = 7;
const byte heartbeatLED              = 13;

bool redFlag                         = true;
bool greenFlag                       = false;
bool yellowFlag                      = false;

unsigned long redMillis;
unsigned long greenMillis;
unsigned long yellowMillis;
unsigned long currentMillis;
unsigned long heartbeatMillis;

const unsigned long redInterval      = 5 * 1000ul;
const unsigned long greenInterval    = 5 * 1000ul;
const unsigned long yellowInterval   = 5 * 1000ul;

//                                 s e t u p ( )
//***************************************************************************************
void setup()
{
 Serial.begin(9600);

pinMode(redLED, OUTPUT);
 digitalWrite(redLED, LEDon);

pinMode(greenLED, OUTPUT);
 digitalWrite(greenLED, LEDoff);

pinMode(yellowLED, OUTPUT);
 digitalWrite(yellowLED, LEDoff);

pinMode(heartbeatLED, OUTPUT);

} //END of setup()

//                                  l o o p ( )
//***************************************************************************************
void loop()
{
 //save current time
 currentMillis = millis();

//********************************
 //to help show if there is any blocking code, this LED toggles every 500ms
 if (currentMillis - heartbeatMillis >= 500)
 {
   //restart this TIMER
   heartbeatMillis = currentMillis;

digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));

}

//********************************
 checkRed();

//********************************
 checkGreen();

//********************************
 checkYellow();

//********************************
 // Other non blocking code goes here
 //********************************

} //END of loop()

//                              c h e c k R e d ( )
//***************************************************************************************
void checkRed()
{
 if (redFlag == enabled && currentMillis - redMillis >= redInterval)
 {
   digitalWrite(redLED, LEDoff);
   digitalWrite(greenLED, LEDon);

redFlag = disabled;
   greenFlag = enabled;

//restart the TIMER
   greenMillis = currentMillis;

}

} //END of checkRed()

//                           c h e c k G r e e n ( )
//***************************************************************************************
void checkGreen()
{
 if (greenFlag == enabled && currentMillis - greenMillis >= greenInterval)
 {
   digitalWrite(greenLED, LEDoff);
   digitalWrite(yellowLED, LEDon);

greenFlag = disabled;
   yellowFlag = enabled;

//restart the TIMER
   yellowMillis = currentMillis;
   
 }

} //END of checkGreen()

//                           c h e c k Y e l l o w ( )
//***************************************************************************************
void checkYellow()
{
 if (yellowFlag == enabled && currentMillis - yellowMillis >= yellowInterval)
 {
   digitalWrite(yellowLED, LEDoff);
   digitalWrite(redLED, LEDon);

yellowFlag = disabled;
   redFlag = enabled;

//restart the TIMER
   redMillis = currentMillis;
   
 }

} //END of checkYellow()

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





You can use a State Machine to control code execution:


// TrafficLightStateMachine.ino
//
// Version      YY/MM/DD
// 1.00         20/05/15      Running code

#define LEDon                        HIGH
#define LEDoff                       LOW

const byte redLED                    = 5;     //+5V----[>|]----[220R]----GND
const byte greenLED                  = 6;
const byte yellowLED                 = 7;
const byte heartbeatLED              = 13;

unsigned long redMillis;
unsigned long greenMillis;
unsigned long yellowMillis;
unsigned long currentMillis;
unsigned long heartbeatMillis;

const unsigned long redInterval      = 5 * 1000ul;
const unsigned long greenInterval    = 5 * 1000ul;
const unsigned long yellowInterval   = 5 * 1000ul;

enum STATES {STARTUP, RED, GREEN, YELLOW};
STATES mState = STARTUP;

//                                 s e t u p ( )
//***************************************************************************************
void setup()
{
 Serial.begin(9600);

pinMode(redLED, OUTPUT);
 pinMode(greenLED, OUTPUT);
 pinMode(yellowLED, OUTPUT);
 pinMode(heartbeatLED, OUTPUT);

} //END of setup()

//                                  l o o p ( )
//***************************************************************************************
void loop()
{
 //save current time
 currentMillis = millis();

//********************************
 //to help show if there is any blocking code, this LED toggles every 500ms
 if (currentMillis - heartbeatMillis >= 500)
 {
   //restart this TIMER
   heartbeatMillis = currentMillis;

digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));

}

//********************************
 checkTrafficLight();

//********************************
 // Other non blocking code goes here
 //********************************

} //END of loop()

//                        c h e c k T r a f f i c L i g h t ( )
//***************************************************************************************
void checkTrafficLight()
{
 switch (mState)
 {
   //*****************
   case STARTUP:
     {
       digitalWrite(redLED, LEDon);
       digitalWrite(greenLED, LEDoff);
       digitalWrite(yellowLED, LEDoff);

//next State
       mState = RED;

//restart the TIMER
       redMillis = currentMillis;
     }
     break;

//*****************
   case RED:
     {
       if (currentMillis - redMillis >= redInterval)
       {
         digitalWrite(redLED, LEDoff);
         digitalWrite(greenLED, LEDon);

//next State
         mState = GREEN;

//restart the TIMER
         greenMillis = currentMillis;
       }
     }
     break;

//*****************
   case GREEN:
     {
       if (currentMillis - greenMillis >= greenInterval)
       {
         digitalWrite(greenLED, LEDoff);
         digitalWrite(yellowLED, LEDon);

//next State
         mState = YELLOW;

//restart the TIMER
         yellowMillis = currentMillis;
       }
     }
     break;

//*****************
   case YELLOW:
     {
       if (currentMillis - yellowMillis >= yellowInterval)
       {
         digitalWrite(yellowLED, LEDoff);
         digitalWrite(redLED, LEDon);

//next State
         mState = RED;

//restart the TIMER
         redMillis = currentMillis;
       }
     }
     break;

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

} //END of switch/case

} //END of checkTrafficLight()

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

Adding a button for pedestrians should be an easy addition, try to do it, we can help if you run into problems.

In what way is this better than the existing "Blink Without Delay" example sketch? This one uses ridiculously long, confusing variable names, and has some overly-complicated code, but does basically exactly the same thing as the shorter, simpler, example sketch.

Regards,
Ray L.

larryd:
Adding a button for pedestrians should be an easy addition, try to do it, we can help if you run into problems.

I will for sure, Thank you very much

RayLivingston:
In what way is this better than the existing “Blink Without Delay” example sketch? This one uses ridiculously long, confusing variable names, and has some overly-complicated code, but does basically exactly the same thing as the shorter, simpler, example sketch.

Regards,
Ray L.

Hello Ray,

Ray the reason for the long variable names is because I plan “for just a learning experience” to create a realistic 4 way intersection of USA traffic Lights and Pedestrian push buttons. The long variable names will hopefully help me keep things straight. I can always easily change them when the sketch works.

Thanks for your reply

Personally I don't have a problem with the long variable names if it helps understand the program and it is a little known fact that the Arduino IDE has auto-completion of previously used variable names using Ctrl + Enter so you do not have to retype them

stspringer:
I will for sure, Thank you very much

Just remember, you must define your algorithm fully before you start to code ;).

UKHeliBob:
Personally I don't have a problem with the long variable names if it helps understand the program and it is a little known fact that the Arduino IDE has auto-completion of previously used variable names using Ctrl + Enter so you do not have to retype them

Well, we learn something new every day +1 :slight_smile:

Going to add this to a few past posts . . .

This code...

Previous_North_Prdestrian_Button_Pin_N = currentMillis;

Should be...

Previous_North_Prdestrian_Button_Pin_N += Pedestrian_North_Red_Led_Blink_Speed_interval;

Your version accumulates any jitter, and the clock then drifts. Fine if that is your only timer, not so great if you have other timers running and you want them all to remain in lock step.

pcbbc:
This code...

Previous_North_Prdestrian_Button_Pin_N = currentMillis;

Should be...

Previous_North_Prdestrian_Button_Pin_N += Pedestrian_North_Red_Led_Blink_Speed_interval;

Your version accumulates any jitter, and the clock then drifts. Fine if that is your only timer, not so great if you have other timers running and you want them all to remain in lock step.

Well, maybe we should show the OP this while we are at it.