Delay for millis

Hi!

I'm currently having a tiny project on the usage of following function:

millis()

I'm basically just going to make a code snippet for the light only. No buttons, just lights using the internal clock. Here's the project:

I'm way better on reading code than writing, so If anyone could give a helping hand on this, then I would be really greatful!

I have atleast made the following for a red light and It works:

int ledState = LOW;
unsigned long ledStarted = 0;
const long interval = 5000;

void setup() {
  pinMode(13, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(11, OUTPUT);
}
void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - ledStarted >= interval) {
    ledStarted = currentMillis;
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    digitalWrite(13, ledState);
  }
}

Output 12 is yellow light, and output 11 is green light :slight_smile:

Hello zackyo

Take some time and search for a led sequencer sketch.

Do you have experience with programming in C++.

The task can easily be realised with an object.
A structured array contains all the information, such as the pin addresses for the I/O devices, as well as the information for the timing.
A single service takes care of this information and initiates the intended action.
The structured array makes the sketch scalable until all I/O pins are used up without having to adapt the code for the service.
It is cool stuff, isn´t it?

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

Welcome to the forum

Your project will be in one of 4 states at any time. In each state a different combination of lights will be on/off

Take a look at the switch/case functionality for a neat way to run a different block of code relevant to the current state

Now to the timing. Before each state starts save the value of millis() as the start time. Then, when in the code block for the current state, each time through loop() check whether the current value of millis() minus the start time of the state previously recorded equals or is greater than the period for the current state. If no, then keep going round loop() until the period passes.

When the current period ends change the state of the lights ready for the next state, save the start time of the next state and change the variable being used in switch() to that of the next state so that the code block for that state is executed next time through loop()

define the lights status for each step
check millis, when the step need to change, apply the new light status

using arrays would make your life easier

such traffic-lights can be seen as a device with different modes of operation:

each mode of operation is a certain pattern of lights switched on/off
like shown in your picture

So you have 4 modes of operation and transisitioning from one mode to the next needs a certain time

adding the waitings you get 8 modes of operation
mode 1: switch on only red light
mode 2: wait 5 seconds with only red light on
mode 3: switch on yellow light
mode 4: wait 2 seconds with red/yellow light on
mode 5: switch off red/yellow switch on green
mode 6: wait 10 seconds with green light switched on
mode 7: switch off green light switch on yellow light
mode 8: wait 2 seconds with yellow light on
if mode 8 has finished set mode 1

using a state-machine with for each combination of lights

is the ideal thing to code something like this

take a look at the example and adapt it to your modes

The state-machine-approach enables that the code will react very fast to any button-press if you add walking lights for people walking and press the "request for green"-button

best regards Stefan

millis() is exactly where you should begin this journey…

I’m surprised nobody has mentioned the term ‘state machine’ yet.

Combined wit arrays and structs, youlll learn a lot about mid level programming.

@StefanL38 just did :wink:

a small sequencer would do (period expiration can be seen as state change trigger)

1 Like

I deliberately avoided it in my reply to avoid scaring the OP

Yes, a small sequencer for four LED sequences is indeed sufficient.
A state machine is not needed for this.

Based on what you have told us so far, it's as simple as this:

void setup() {
  pinMode(13, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(11, OUTPUT);
}
void loop() {
  digitalWrite(13, HIGH);
  delay(5000);
  digitalWrite(12, HIGH);
  delay(2000);
  digitalWrite(13, LOW);
  digitalWrite(12, LOW);
  digitalWrite(11, HIGH);
  delay(10000);
  digitalWrite(11, LOW);
  digitalWrite(12, HIGH);
  delay(2000);
  digitalWrite(12, LOW);
}

No need to make it more complex until we know there is a need!

You mentioned use of millis() but at this point we know of no reason to use millis() over delay().

I guess the aim is to learn how to use millis()

But also to learn when to use millis().

@zackyo from what you have described so far, there is no need to use millis() for the project.

There is no "need" t use delay() either, it's just a coding choice.

hey you could use millis with your approach too

void loop() {
  uint32_t now;
  digitalWrite(13, HIGH);
  now  = millis();  while (millis() - now <= 5000) yield();

  digitalWrite(12, HIGH);
  now = millis();  while (millis() - now <= 2000) yield();

  digitalWrite(13, LOW);
  digitalWrite(12, LOW);
  digitalWrite(11, HIGH);
  now = millis();  while (millis() - now <= 10000) yield();

  digitalWrite(11, LOW);
  digitalWrite(12, HIGH);
  now = millis();  while (millis() - now <= 2000) yield();
}

:innocent:
:cold_face:

2 Likes

It's to make the project bigger in the future, where I do not want the code to simply WAIT until the delay function has ran through its time. So that's why :slight_smile:

But you should not do that, because delay() is simpler, and simpler is (almost) always better when you write code.

State-machines sound scary, but in fact, like millis, arrays and structs it can massively simplify sequential coding projects, but I understand your concern.

Complete multi route traffic light controller becomes very complicated very quickly, and without these tools, becomes unmanageable in quick time !

I was just surprised they didn’t get a mention early-on !

you missed the smileys probably

Some sequencers or selectors are devolved state machines. A selector is a state machine with only two states, uses one boolean value as a state variable. A sequencer, multiple states, uses one integer variable to represent all possible states.

Lots of people make those, never realize that it's a "state machine". Because the states are not expressed as such, just implied in the logic.

They are still legitimate state machine implementations.

Just because the project might get bigger does not necessarily mean you need to use millis() instead of delay().

The point I'm trying to make is that knowing when and why to use a function is equally important as knowing how. If you know the how but not the when or why, your code gets more complex than it need to be, and that's a bad thing.