Blinking LEDs issue

OK, here it's how this sounds:

  • 1 RED led is ON for 3s;
  • 1 YELLOW led is blinking in the last second of the RED led(so from 2 to 3s) with a frequency of 50ms;
  • turn RED and YELLOW leds OFF
  • 1 GREEN led is ON for 5s, so the other two are OFF, while in the last second of this led, the YELLOW led
    blinks again
  • loop this again and again

The only constraint of this is: only use delay function once, and that is delay(50);

So I've tried to wrap my head around this the last couple of days but I cannot come up with anything that works, how am I supposed to bind all of the 3 leds of a single factor, that is the time passing, while doing multiple things? Any advice is appreciated, I know I'm new and this is my first post, so don't hit me too hard :slight_smile:

Well, when you reveal all details of your project according to the instructions, we just might be able to answer.

So if the use of delay() is constrained, are you allowed to use millis()?

Btw, when does the green come on?

Have a look at Robin2's Several things at the same time which explains exactly what you need to know.

Steve

elvon_blunden:
So if the use of delay() is constrained, are you allowed to use millis()?

Btw, when does the green come on?

Hi, yes, I can use millis, thats what I'm tryin' to figure out. The green comes ON after 3s have passed: Starting with RED ON for 3s, in the interval [2, 3] the YELLOW blinks, both are OFF after 3 while GREEN comes on for 5, and in the interval [4, 5] the YELLOW blinks again. Loop to the infinity.

Paul__B:
Well, when you reveal all details of your project according to the instructions, we just might be able to answer.

There is no project, this is just an exercise given to me by somebody who makes a living off embedded and I'm sorry if I've not posted any code that shows the progress, it's just broken logic and repeated failures

#define RED_LED 2
#define YELLOW_LED 4
#define GREEN_LED 8

bool var = true; //used to increment either the first/second time

void setup(){
  pinMode(RED_LED, OUTPUT);
  pinMode(YELLOW_LED, OUTPUT);
  pinMode(GREEN_LED, OUTPUT);
}

int firstTimeCount = 0; //the time for RED and YELLOW
int secondTimeCount = 0; //the time for GREEN and YELLOW
int redLedState = 1;
int yellowLedState = 0;
int greenLedState = 0;

void loop(){
  digitalWrite(RED_LED, redLedState);
  digitalWrite(YELLOW_LED, yellowLedState);
  digitalWrite(GREEN_LED, greenLedState);
 
  delay(50);
  if(var){
    firstTimeCount += 50;
  }else{
    secondTimeCount += 50;
  }
  
  if(firstTimeCount >= 2000 && firstTimeCount <= 3000){
    yellowLedState = !yellowLedState;
  }
  
  if(secondTimeCount >= 4000 && secondTimeCount <= 5000){
    yellowLedState = !yellowLedState;
  }
  
  if(firstTimeCount >= 3000 && var){
    yellowLedState = 0;
    redLedState = 0;
    greenLedState = 1; //this had to be '1', not '0' as it was the first time
    var = false;
    firstTimeCount = 0;
  }
  
  if(secondTimeCount >= 5000 && !var){
    yellowLedState = 0;
    greenLedState = 0;
    redLedState = 1;
    secondTimeCount = 0;
    var = true;
  }
  
}

Here's what I've managed to come up with.Also, I simulate this on tinkercad.com, on an arduino uno R3 board.

So is there a more elegant and classy version of this? :slight_smile: using "ifs" like a dumbass doesn't seem quite right.

  • consider "delay" as not existing.
  • see the example "02.Digital | BlinkWithoutDelay"
  • solve your problem without delay

if it works without delay it should be easy to implement a dummy delay(50) without negative effecting your code.

Start by looking at Using millis() for timing. A beginners guide, Several things at the same time and look at the BlinkWithoutDelay example in the IDE.

Normally it would be better to use millis for something like this, but as an academic exercise in only using a single delay(50) it can be done.

Your code is vastly over complicated. It is easier if you restate the problem a bit. Your original description is:

  • 1 RED led is ON for 3s;
  • 1 YELLOW led is blinking in the last second of the RED led(so from 2 to 3s) with a frequency of 50ms;
  • turn RED and YELLOW leds OFF
  • 1 GREEN led is ON for 5s, so the other two are OFF, while in the last second of this led, the YELLOW led
    blinks again
  • loop this again and again

Think of it in terms of the following:

at 0 seconds, turn RED led ON
at 2 seconds, start flashing YELLOW led
at 3 seconds, turn RED and YELLOW led's off, turn GREEN led on
at 7 seconds, start flashing YELLOW led ( 3 seconds from RED led, plus 4 seconds from GREEN led)
at 8 seconds, turn GREEN and YELLOW led's off
start over

Use the delay(50) for timing by keeping a count, but a simple increment of the count will do, no need to use the +=50 to convert to milliseconds as you did in your code. All timing for the led's can be expressed in units of 50 millisecond, so 1 second = 20, 2 seconds = 40, etc. You can also use == in the IF statements instead of >=, that is needed for millis(), but when keeping your own count you don't have to worry about missing an increment of the counter.

As an additional challenge, see if you can implement it with only two variables, one to hold the count, and one to indicate if the yellow led should be flashing.

only use delay function once, and that is delay(50);

Does that mean you can have as many delay() as you want but they must all be 50? Or just one delay(50)?

I think if "somebody" has been so specific about the challenge they set you, then they would probably consider using millis() to be cheating. Did they say millis() was allowed? If so, why did they insist you have one delay(50)?

I think you can do it with delay() and do not need millis(). You are not attempting to do more than one thing at the same time, after all. But you can't flash your yellow led with a 50Hz frequency if you can only have delay(50). You would need delay(25) for that.

as mentioned above I see no need for a delay.

How ever - if anyone insist on a delay, here's a code with one delay :wink:

/* Switch on/off LEDs and Blink LEDs without Blocking the Code

  Requirement
  - 1 RED led is ON for 3s;
  - 1 YELLOW led is blinking in the last second of the RED led(so from 2 to 3s) with a frequency of 50ms;
  - turn RED and YELLOW leds OFF
  - 1 GREEN led is ON for 5s, so the other two are OFF, while in the last second of this led, the YELLOW led
     blinks again
  - loop this again and again

  this gives us 4 states:

  RED  YELLOW   Green    from
  on   off      off      0 - 2
  on   blink    off      2 - 3
  off  off      green    3 - 7
  off  blink    green    7 - 8

  based on http://forum.arduino.cc/index.php?topic=602045.msg4088827#new

  2019-03-08 noiasca

*/

// Pin definitions:
const int redPin =  2 ;
const int yellowPin =  3 ;
const int greenPin =  4 ;

const byte useDelay = 0;            // do we need a delay  - No we don't
const byte interval = 50;           // interval at which to blink (milliseconds)
byte yellowShouldBlink = 0;         // status of yellow LED

// Generally, you should use "unsigned long" for variables that hold time
unsigned long previousMillis = 0;                // will store last time LED was updated
unsigned long previousMillisState = 42 * 1000UL; // will store last time State was changed - set to a value which will activate the first state on startup

// define our state machine
enum status {RED, RED_YELLOW, GREEN, GREEN_YELLOW};   // the states
status myStatus = RED;                                // the next status during runtime
const byte durance[] = {2, 1, 4, 1};                  // how many seconds should each state last

void setup() {
  // set the digital pin as output:
  pinMode(redPin, OUTPUT);
  pinMode(yellowPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  Serial.begin(115200);
  Serial.println(F("BlinkWithoutDelay Challange"));
}

void loop() {
  unsigned long currentMillis = millis();

  if (useDelay) delay(50);  // who needs a delay for blinking?

  // our state machine cares about the timekeeping of each status
  if (currentMillis - previousMillisState >= durance[myStatus] * 1000)
  {
    Serial.println(F("Time limit reached"));
    previousMillisState = currentMillis;

    switch (myStatus)
    {
      case RED:
        Serial.println(F("enter RED"));
        digitalWrite(redPin, 1);                                // switch the pins accordingly
        digitalWrite(yellowPin, 0); yellowShouldBlink = 0;
        digitalWrite(greenPin, 0);
        myStatus = RED_YELLOW;                                  // define next status
        break;
      case RED_YELLOW:
        Serial.println(F("enter RED YELLOW"));
        digitalWrite(redPin, 1);
        yellowShouldBlink = 1;
        digitalWrite(greenPin, 0);
        myStatus = GREEN;
        break;
      case GREEN:
        Serial.println(F("enter GREEN"));
        digitalWrite(redPin, 0);
        digitalWrite(yellowPin, 0); yellowShouldBlink = 0;
        digitalWrite(greenPin, 1);
        myStatus = GREEN_YELLOW;
        break;
      case GREEN_YELLOW:
        Serial.println(F("enter GREEN YELLOW"));
        digitalWrite(redPin, 0);
        yellowShouldBlink = 1;
        digitalWrite(greenPin, 1);
        myStatus = RED;
        break;
    }
  }

  // if neccessary - blink the LED
  if (yellowShouldBlink && (currentMillis - previousMillis >= interval)) {
    previousMillis = currentMillis;
    digitalWrite(yellowPin, !digitalRead(yellowPin));
  }

  // here is where you'd put code that needs to be running all the time.
  
}

code compiles and works on UNO, please set your own pins.