Are these blocking delays?

I'll start off by saying I'm very very new to coding, so please bare with me.

I'm doing an assignment where the task is to create a traffic light system, but blocking delays aren't allowed. I have looked into "blink without delay", but it seems that option would require me to create far too confusing and long code than is needed. So instead I used for, else and goto functions together since it was a lot simpler and cleaner, but I have heard goto isn't a preferred option,

  for(int i = 0; i < 20; i = i + 1)
    {
break0:
      digitalWrite(Traffic_R, HIGH);
 
  long int CurrentMillis1 = millis();
 break1:
  if (millis() - CurrentMillis1 <= 250)
  {
  digitalWrite(Pedestrian_R, HIGH);
  goto break1;
  }
  else
    {
  long int CurrentMillis2 = millis();
 break2:
  if (millis() - CurrentMillis2 <= 250)
  {
  digitalWrite(Pedestrian_R, LOW);
  goto break2;
  }
    }
    }

Then I made another way without goto function,

for(int Test1 = millis(); Test1 < 7500; Test1 + millis())
{
  digitalWrite(LED, HIGH);
}

TLDR So my question is, are either of these methods a "blocking method", like delay is? Also what are the pros and cons of each method? Also I can upload the code for the first method if needed. Thanks heaps in advance!

Hello,
They are not.

For your information: I have made a series of video's about this topic as a tutorial for a finite state machine. (It even demonstrates a breakpoint functionality on an UNO)

Traffic light demo 1/7: Introduction, overview and functional description.

Traffic light demo 2/7: Hardware overview with Uno Rev2, LCD20x4 and keyboard.

Traffic light demo 3/7: Principle of FSM. (Finite State Machine)

Traffic light demo 4/7: Live demo FSM, WawiLib, breakpoints, timers.

Traffic light demo 5/7: Data recording (record Arduino data to disk file over Wi-Fi).

Traffic light demo 6/7: Arduino source code details.

Traffic light demo 7/7: Setup demo for UNO & USB serial.

Tags Arduino, WawiLib, finite state machine, Arduino breakpoints, Arduino data recording, Arduino access to variables, debug, Arduino PLC, blink without millis

Best regards,
Johi.
WawiTrafficLightDemoSerialUsb.zip (4.3 KB)
WawiTrafficLightDemoWifi.zip (4.9 KB)
(I will add these files to the WawiLib install this afternoon)

2 Likes

as you can see, a comprehensive traffic light system is becoming a very complex project- especially when you add pedestrians, level crossings and extra lanes of traffic.

There is really no other way to start than designing a state-machine and associated tables to edit your sequences. a number of struct, and arrays of those struts will hold all your data.

Worse still, you need t consider failsafe scenarios for initial startup, and controller failure.

It’s a lot of fun, but twice as much work.

3 Likes

For your assignment a state machine is clearly the way to go. My tutorial her may help, it builds to a traffic light sequence.

there are good reasons why goto is deprecated (E Dijkstra 1968)

1 Like

As I read it, they are yes both blocking methods with the same problem as delay().

And your for loop is not well-formed; if your program gets to this point within 7.5 seconds of reset (the beginning of time…), it will hang up executing the body for the remaining time, that is until it has been 7.5 seconds since reset.

Since the body just writes the same digital output, we can be sure this isn't what you are trying to say.

Forget all about goto, 'K? Just pretend it doesn't exist. If there ever comes time when you need it, you probably still don't.

Forget all about goto, 'K?

I used for, else and goto functions

Those are not functions. They are statements, or parts of statements. There is no reason to not start using the right terminology.

Lastly, take another look at block without delay. It is not going to be any more complicated then are your attempts so far, and will be in a form that is more or less idiomatic, that is to say using, containing, or denoting expressions that are natural to an experienced programmer.

a7

1 Like

Your first method is equivalent to:

  digitalWrite(Traffic_R, HIGH);
  for (int i = 0; i < 20; i = i + 1)
  {
    digitalWrite(Pedestrian_R, HIGH);
    delay(250);

    digitalWrite(Pedestrian_R, LOW);
    delay(250);
  }

Your second method is equivalent to:

  unsigned long Test1 = millis(); 
  while (Test1 < 7500)  // No loop or forever loop
  {
    digitalWrite(LED, HIGH);
  }

Both of them block. The first one is for 10 seconds (20 half-second cycles). The second is either for 0 time or infinite time.

1 Like

The essence is that you write a program where the statement delay() is not used, because during this statement you prevent the processor from executing the rest of your application code. Said in short: during the execution of delay() the processor is kept busy with doing nothing but turning in circles in a small loop killing time. (as you are a novice, i will not elaborate about interrupts, etc, but in essence, delay() = command waist of time and not doing other useful tasks.)

so things like


for(int Test1 = millis(); Test1 < 7500; Test1 + millis())

{

digitalWrite(LED, HIGH);

}

actually does a similar thing: the processor will turn in circles in the loop and forget about the rest of the application code.

This would also mean if you read a pushbutton from a predestrian that wants to cross, you will not detect this signal as the processor is busy executing the loop and prevented from executing other code.

The bases of my example is exaclty what you need: a switch statement that is implementing finite state machine:

void loopFsmStepLogic()
{
  // transfer logic:
  do
  {
    switch (stepCurrent)
    {
      case FsmState::STEP_0_IDLE:
        if (enable)
          fsmGoTo(FsmState::STEP_1_A_RED_B_RED);
        break;
      case FsmState::STEP_1_A_RED_B_RED:
        if (firstScanNewStep)
          timerFsm.setMs(waitTimeShort);
        if (timerFsm.isZero() || directionBTravelRequest)
          fsmGoTo(FsmState::STEP_2_A_GREEN_B_RED);
        break;
      case FsmState::STEP_2_A_GREEN_B_RED:
        if (firstScanNewStep)
          timerFsm.setMs(waitTimeLong);
        if (timerFsm.isZero())
          fsmGoTo(FsmState::STEP_3_A_Yellow_B_RED);
        break;
      case FsmState::STEP_3_A_Yellow_B_RED:
        if (firstScanNewStep)
          timerFsm.setMs(waitTimeShort);
        if (timerFsm.isZero())
          fsmGoTo(FsmState::STEP_4_A_RED_B_RED);
        break;
      case FsmState::STEP_4_A_RED_B_RED:
        if (firstScanNewStep)
          timerFsm.setMs(waitTimeShort);
        if (timerFsm.isZero())
          fsmGoTo(FsmState::STEP_5_A_RED_B_GREEN);
        break;
      case FsmState::STEP_5_A_RED_B_GREEN:
        if (firstScanNewStep)
          timerFsm.setMs(waitTimeLong);
        if (timerFsm.isZero())
          fsmGoTo(FsmState::STEP_6_A_RED_B_Yellow);
        directionBTravelRequest = false;
        break;
      case FsmState::STEP_6_A_RED_B_Yellow:
        if (firstScanNewStep)
          timerFsm.setMs(waitTimeShort);
        if (timerFsm.isZero())
          fsmGoTo(FsmState::STEP_0_IDLE);
        break;
    }
    firstScanNewStep = (stepCurrent != stepPrev);
    if (firstScanNewStep)
    {
      String s;
      s = (String) "Breakpoint when transfering from step " + stepStrings[(int) stepPrev] + " to step " + stepStrings[(int) stepCurrent];
      unsigned long m = millis();
      WawiSrv.wawiBreak(1, s.c_str());
      timerFsm.setMsAct(m);
    }
    stepPrev = stepCurrent;
  }
  while (firstScanNewStep);
  strcpy(stepCurrentString, stepStrings[ (int) stepCurrent]);

  // request predestrian to transfer:
  if (keyboardAnaIn < 600 && !directionBTravelRequest)
  {
    directionBTravelRequest = true;
    unsigned long m = millis();
    WawiSrv.wawiBreak(2, "Breakpoint when predestrian B hit button");
    timerFsm.setMsAct(m);
  }
}

The program does not wait, it does not loop, every scan it executes loopFsmLogic 1 time, then, if the timerFsm is zero, then it sets tha stepCurrent to a new value via fmsGoTo(....) and this way it goes from one step to another. Millis is encapsulated by timerFsm so you do not have to worry about this part, you set it to a value and it counts to 0 as in the video.

1 Like

Thank you heaps!