3 LED blinking randomly using millis got reversed for some reason

Hi there, I'm having a simple project that makes 3 LED blink randomly but only using millis()
My object is: 1 in 3 LEDs turns on for 1000ms, then 200ms later, it randomly changes to another LED.
But the problem is in my code, somehow it got like this: All 3 LEDs are on, then 1 in 3 of them turns off for 200ms, 1000ms later it randomly change to another one and repeat the progress.
Please help me!
Here's my code:

const int LEDpin1 = 2;  // led 1 ứng với chân số 8
const int LEDpin2 = 3;  // led 2 ứng với chân số 9
const int LEDpin3 = 4;   // led 3 ứng với chân số 4

int LEDState1 =LOW;// initial state of LED
int LEDState2 =LOW;// initial state of LED
int LEDState3 =LOW;// initial state of LED

long count1 = 200;// OFF time for LED
long count2 = 1000;// ON time for LED

long rememberTime=0;// this is used by the code


byte randNumber;


void setup() {
  Serial.begin(9600); 
  pinMode(LEDpin1, OUTPUT);
  pinMode(LEDpin2, OUTPUT);
  pinMode(LEDpin3, OUTPUT);
}

void loop() {
  randomly();
}

void randomly(){  


  randNumber = random(3);
  
  switch (randNumber) {
    case 0: 
      if( LEDState1 == LOW ){
        if( (millis() - rememberTime) >= count1){   
          LEDState1 = HIGH;// change the state of LED
          rememberTime=millis();// remember Current millis() time
        }
      }
      else{   
        if( (millis()- rememberTime) >= count2){     
          LEDState1 =LOW;// change the state of LED
          rememberTime=millis();// remember Current millis() time
        }
      }
      digitalWrite(LEDpin1,LEDState1);// turn the LED ON or OFF
      break;
    
    /////
    case 1:
      if( LEDState2 ==LOW ){
        if( (millis()- rememberTime) >= count1){   
          LEDState2 = HIGH;// change the state of LED
          rememberTime=millis();// remember Current millis() time
        }
      }
      else{   
        if( (millis()- rememberTime) >= count2){     
          LEDState2 =LOW;// change the state of LED
          rememberTime=millis();// remember Current millis() time
        }
      }
      digitalWrite(LEDpin2,LEDState2);// turn the LED ON or OFF
      break;
    /////
    case 2: 
      if( LEDState3 ==LOW ){
        if( (millis()- rememberTime) >= count1){   
          LEDState3 = HIGH;// change the state of LED
          rememberTime=millis();// remember Current millis() time
        }
      }
      else{   
        if( (millis()- rememberTime) >= count2){     
          LEDState3 =LOW;// change the state of LED
          rememberTime=millis();// remember Current millis() time
        }
      }
      digitalWrite(LEDpin3,LEDState3);// turn the LED ON or OFF
      break;
    
    /////
  }
}

Why are you doing this ?

Its a simple project for practicing, can you help me?

Please show us a good image of your wiring and a hand drawn schematic of your test circuit.


See if you can follow this sketch.

Introduces a structure TIMER.

//********************************************^************************************************
//  https://forum.arduino.cc/t/3-led-blinking-randomly-using-millis-got-reversed-for-some-reason/1164916/4
//
//  LarryD
//
//  Version    YY/MM/DD    Comments
//  =======    ========    ====================================================================
//  1.00       20/09/03    Running code
//
//
//

//************************************************
#define EXPIRED                    true
#define stillTIMING                false

#define LEDon                      HIGH   //PIN---[220R]---A[LED]K---GND
#define LEDoff                     LOW

#define PUSHED                     LOW    //+5V---[Internal 50k]---PIN---[switch]---GND
#define RELEASED                   HIGH

#define CLOSED                     LOW    //+5V---[Internal 50k]---PIN---[switch]---GND 
#define OPEN                       HIGH

#define ENABLED                    true
#define DISABLED                   false

#define YES                        true
#define NO                         false

//************************************************
const byte LEDpin1               = 2;  // led 1 ứng với chân số 8
const byte LEDpin2               = 3;  // led 2 ứng với chân số 9
const byte LEDpin3               = 4;  // led 3 ứng với chân số 4
const byte heartbeatLED          = 13;

byte randNumber;
byte LEDselected;

//                          m i l l i s ( )   B a s e d   T I M E R S
//********************************************^************************************************
//TIMER definitions
//Two ways to define a new TIMER
//The first, we will call it a manual method:        example: heartbeat TIMER
//The second, we will call it the structure method:  example: scanSwitches TIMER

//****************************************
//manual method:
//heartbeat TIMER
unsigned long heartbeatTime      = 0;
unsigned long heartbeatInterval  = 500ul;
bool heartbeatTimerFlag          = ENABLED;
bool heartbeatRestart            = YES;

//****************************************
//structure method:
struct makeTIMER
{
//#define ENABLED       true
//#define DISABLED      false

//#define YES           true
//#define NO            false

//#define EXPIRED       true
//#define stillTIMING   false

  unsigned long Time;           //when the TIMER started
  unsigned long Interval;       //delay time in ms which we are looking for
  bool          timerFlag;      //is the TIMER enabled ? ENABLED/DISABLED
  bool          Restart;        //restart this TIMER ? YES/NO

  //****************************************
  //fuction to check if the TIMER is enabled and check if the TIMER has expired
  bool checkTIMER()
  {
    //*********************
    //is this TIMER enabled and has this TIMER expired ?
    if (timerFlag == ENABLED && millis() - Time >= Interval)
    {
      //*********************
      //should this TIMER restart again?
      if (Restart == YES)
      {
        //restart this TIMER
        Time = millis();
      }

      //this TIMER is enabled and has expired
      return EXPIRED;
    }

    //this TIMER is disabled and/or has not expired
    return stillTIMING;

  } //END of   checkTime()

}; //END of   struct makeTIMER

//********************************************^************************************************
/*example
  // *******************
  makeTIMER toggleLED =
  {
  0, 500ul, ENABLED/DISABLED, YES/NO  //Time, Interval, timerFlag, Restart
  };
*/

//*******************
makeTIMER LEDonTimer =
{
  0, 1000ul, DISABLED, NO      //Time, Interval, timerFlag, Restart
};
//*******************
makeTIMER LEDoffTimer =
{
  0, 200ul, DISABLED, NO      //Time, Interval, timerFlag, Restart
};
//*******************


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

  pinMode(heartbeatLED, OUTPUT);
  pinMode(LEDpin1, OUTPUT);
  pinMode(LEDpin2, OUTPUT);
  pinMode(LEDpin3, OUTPUT);

  randomSeed(analogRead(A0));

} //END of   setup()


//                                        l o o p ( )
//********************************************^************************************************
void loop()
{
  //************************************************              T I M E R  heartbeatLED
  //when enabled, is it time to toggle the heartbeat LED ?
  if (heartbeatTimerFlag == ENABLED && millis() - heartbeatTime >= heartbeatInterval)
  {
    //restart this TIMER ?
    if (heartbeatRestart == YES)
    {
      heartbeatTime = millis();
    }

    //toggle the LED
    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
  }

  //************************************************              T I M E R  LEDon
  //is the TIMER enabled and is it time to turn OFF this LED ?
  if (LEDonTimer.checkTIMER() == EXPIRED)
  {
    //LED selected goes OFF
    digitalWrite(LEDselected, LEDoff);

    //disabled this TIMER
    LEDonTimer.timerFlag = DISABLED;

    //enable the OFF TIMER
    LEDoffTimer.timerFlag = ENABLED;

    //restart the OFF TIMER
    LEDoffTimer.Time = millis();    
  }

  //************************************************              T I M E R  LEDoff
  //is the TIMER enabled and is it time to turn ON the next LED ?
  if (LEDoffTimer.checkTIMER() == EXPIRED)
  {
    //disabled this TIMER
    LEDoffTimer.timerFlag = DISABLED;
  }

  //************************************************              Next random LED
  //has LED timing stopped ?
  if (LEDonTimer.timerFlag == DISABLED && LEDoffTimer.timerFlag == DISABLED)
  {
    randomly();
  }

  //************************************************
  //other non blocking code goes here
  //************************************************

} //END of   loop()


//                                    r a n d o m l y ( )
//********************************************^************************************************
void randomly()
{
  //select a LED connected to pin 2,3 or 4
  LEDselected = random(2,5);

  //LED goes ON
  digitalWrite(LEDselected, LEDon);

  //enable the LEDon TIMER
  LEDonTimer.timerFlag = ENABLED;

  //restart this TIMER
  LEDonTimer.Time = millis();

} //END of   randomly()



//********************************************^************************************************
1 Like

Bạn nên sửa các nhận xét hoặc ghim.
You should correct the comments or the pins.

3 Likes

Hello coasty

Welcome to the worldbest Arduino forum ever.

Consider this proposal sketch.

//https://forum.arduino.cc/t/3-led-blinking-randomly-using-millis-got-reversed-for-some-reason/1164916
//https://europe1.discourse-cdn.com/arduino/original/4X/7/e/0/7e0ee1e51f1df32e30893550c85f0dd33244fb0e.jpeg
#define ProjectName "3 LED blinking randomly using millis got reversed for some reason"
#define NotesOnRelease "first proposal"
// make names
enum LedNames {One, Two, Three};
enum TimerControl {Off, On};
enum MinMax {Min,Max};
// make variables
constexpr uint8_t LedPins[] {2,3,4};
constexpr uint32_t PreviousMillis[] {200,1000};
// make structures
struct TIMER
{
  uint32_t previousMillis;
  uint32_t intervalMillis;
  uint8_t control;
};
struct LEDBLINK
{
  uint8_t pin;
  TIMER blinkMe;
};
LEDBLINK ledBlinks[]
{
  {LedPins[One], 0, 1000, On},
  {LedPins[Two], 0, 1000, Off},
  {LedPins[Three], 0, 1000, Off},
};

// make support
void heartBeat(int LedPin, uint32_t currentMillis)
{
  static bool setUp = false;
  if (!setUp) pinMode (LedPin, OUTPUT), setUp = !setUp;
  digitalWrite(LedPin, (currentMillis / 500) % 2);
}
// make application
void setup()
{
  Serial.begin(115200);
  Serial.print("Source: "), Serial.println(__FILE__);
  Serial.print(ProjectName), Serial.print(" - "), Serial.println(NotesOnRelease);
  for (auto &ledBlink : ledBlinks) pinMode(ledBlink.pin, OUTPUT);
  Serial.println(" =-> and off we go\n");
}
void loop()
{
  uint32_t currentMillis = millis();
  heartBeat(LED_BUILTIN, currentMillis);
  for (auto &ledBlink : ledBlinks)
  {
    if (currentMillis - ledBlink.blinkMe.previousMillis >= ledBlink.blinkMe.intervalMillis and ledBlink.blinkMe.control)
    {
      for (auto &ledBlink : ledBlinks) digitalWrite(ledBlink.pin,Off);
      ledBlink.blinkMe.control=Off;
      uint8_t randLed=random(0,(sizeof(ledBlinks)/sizeof(ledBlinks[0])));
      digitalWrite(ledBlinks[randLed].pin,On);
      ledBlinks[randLed].blinkMe.previousMillis=currentMillis;
      ledBlinks[randLed].blinkMe.intervalMillis=random(PreviousMillis[Min],PreviousMillis[Max]);
      ledBlinks[randLed].blinkMe.control=On;
    }
  }
}

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

1 Like

Ahh dont mind that:))

hey, your code actually works, but i dont really understand the whole thing so can you explain to me please? thank you by the way

Take a look at the comments that accompanies the major lines of code.

These comments should give you a good description of what is happening.


For example: the sketch presents two (2) types of millis( ) based TIMERs.

  • Manual.
  • Structure.

The heartbeat TIMER (manual) toggles a LED on pin 13 every 500ms (1/2 second).

We often use a heartbeat LED to show if the sketch exhibits any blocking behaviour.

If this LED does not toggle every 1/2 second, it could indicate a possible problem with our code (we always try to write code that is responsive and non blocking).

The heartbeat LED code can be removed when we have decided our sketch is finalized.


The second TIMER type is based on a structure, ex: LEDon and LEDoff TIMERs.


//*******************
makeTIMER LEDonTimer =
{
  0, 1000ul, DISABLED, NO      //Time, Interval, timerFlag, Restart
};

The above is how we make a TIMER object.

Once the TIMER code is defined with struct makeTIMER{ … };.

After definition, it is child’s play to make TIMER objects.


ex: below we are making the TIMER object LEDoffTimer.

This TIMER has:

  • interval of 200ms,
  • it is disabled at power up
  • it does not automatically restart.

//*******************
makeTIMER LEDoffTimer =
{
  0, 200ul, DISABLED, NO      //Time, Interval, timerFlag, Restart
};


If you have specific questions, we can try to answer them.

I have a question here, well im trying to do a big project for a contest so heres a question.
I have 2 buttons, one is to increase the off time of the LEDs, which default is 200ms, it increases the value when i hold it, and one is to decrease, so in this code, how can i do that? Thanks for your help!
Oh by the way it increases and decreases 100ms

While you hold the switch or each time you press the switch ?


If you are coding for a contest, make sure you fully understand the code presented so for.

Look at the line of code below, what does it do ?

LEDoffTimer. Interval = LEDoffTimer. Interval + 100ul;

While i hold it

Not really understand the whole thing so can you explain it all?

While implies as long as you hold the switch the interval is incremented/decremented by 100 but there is also a time period.

For example, the incremented switch is held and while it is is held the value is incremented by 100ms every X seconds.

Uhmm how can i do that

At Arduino power up time, when the TIMER object LEDoffTimer is initialized, it’s Interval is set to 100ms.


LEDoffTimer. Interval = LEDoffTimer. Interval + 100ul;

When the above line of code is executed, this LEDoffTimer Interval increments by 100ms


The line of code below decrements this Interval by 100ms.

LEDoffTimer. Interval = LEDoffTimer. Interval - 100ul;

1 Like

When the switch is first held, you start a TIMER for the interval you require, say it is 5 seconds.

When this TIMER expires, you increment/decrement your LEDoffTimer.Interval and restart the 5 second TIMER.

When you let go of the switch, you disable the 5 second TIMER.

1 Like

i tried to add a button, and i added this:

makeTIMER DelayButton =
{
  0, 200ul, DISABLED, NO
};

and this into the loop:

  int buttonStatus = digitalRead(button); 
  if(buttonStatus == HIGH){
    if(DelayButton.checkTIMER() == EXPIRED){
      LEDoffTimer. Interval = LEDoffTimer. Interval - 100ul;
    }
  }

but it doesnt work, can you help me fix it? thanks