How to replace delay with millis

I get how to make an led blink with a millis function instead of delay but i cant understand how to replace it on every second line of code?

const int R = 13;
const int O = 12;
const int G = 11;

void setup() {  
  pinMode(G, OUTPUT);
  pinMode(O, OUTPUT);
  pinMode(R, OUTPUT);
  
}

void loop() {

    digitalWrite(G,HIGH);
    delay(3000);
    digitalWrite(G,LOW);
    digitalWrite(O,HIGH);
    delay(1000);
    digitalWrite(O,LOW);
    digitalWrite(R,HIGH);
    delay(3000);
    digitalWrite(O,HIGH);
    delay(1000);
    digitalWrite(O, LOW);
    digitalWrite(R, LOW);

In the loop() I want to be able to check if a button has been pressed to "jump" to that piece of code but with the delay() function then it just stops arduino from reading the inputs, I know that millis allows the inputs to still be read but i don't know how to replace all of the delays with millis

but i cant understand how to replace it on every second line of code?

You can't. You need to understand the philosophy, and then ditch that code and start over.

You have a bunch of states - G on, G off/O on, O off/R on, etc.

Periodically, it might be time to change state. When you do, you have something to do, so do it, and update the time that the state changed.

Save the millis() value at the time that the start action happens. Then, each time through loop(), check whether the required wait period has elapsed by subtracting the start time from the millis() value now. If the period has elapsed then act accordingly and maybe save the start time for the next activity. If not, then go round loop() again, perhaps taking other actions and/or reading inputs, but don't block the free running of loop().

Have you read Using millis() for timing. A beginners guide

Here is a very short solution, i'm not sure if this is the best solution.

const int r = 13;
const int o = 12;
const int g = 11;

unsigned long previousMillis = 0;
unsigned long interval = 1000;

void setup() {
  pinMode(g, OUTPUT);
  pinMode(o, OUTPUT);
  pinMode(r, OUTPUT);
}

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

  if (currentMillis - previousMillis >= interval) {
    digitalWrite(g, HIGH);
    if (currentMillis - previousMillis >= interval * 3) {
      digitalWrite(g, LOW);
      digitalWrite(o, HIGH);
    }
    if (currentMillis - previousMillis >= interval * 4) {
      digitalWrite(o, LOW);
      digitalWrite(r, HIGH);
    }
    if (currentMillis - previousMillis >= interval * 7) {
      digitalWrite(o, HIGH);
    }
    if (currentMillis - previousMillis >= interval * 8) {
      digitalWrite(o, LOW);
      digitalWrite(r, LOW);
      previousMillis = currentMillis;
    }
  }
}

The code is untested.

The demo Several Things at a Time illustrates the use of millis() to manage timing without blocking. It may help with understanding the technique.

...R

It's not about replacing each delay with millis. It's about replacing the CONCEPT of delay with millis. This can be done with a single millis setup just like Blink Without Delay if you think about it right.

Imagine something like this:

int step = 0;   // a variable to keep track of what step you're on.

unsigned long previousMillis = 0;

unsigned long interval = 1000;  // set to length of first interval.

Then in your loop:

unsigned long currentMillis = millis();

if(currentMillis - previousMillis >= interval){
    
     // in here you put a switch case or a bunch of if statements
     //  depending on which step we are on you take whatever action
    //   you need for that step and change interval to equal whatever
   //    value it needs to be for the next step and increase the 
    //    step number by 1
}

AwesomeApollo:
In the loop() I want to be able to check if a button has been pressed to "jump" to that piece of code but with the delay() function then it just stops arduino from reading the inputs, I know that millis allows the inputs to still be read but i don't know how to replace all of the delays with millis

I have wished to model your idea in terms of the following diagram.
led4-sw.png

1. Your current program codes are doing the following:
(a) LED11(G) remains ON for 3-sec.
(b) LED11(G) goes OFF; LED12 (O) remains ON for 1-sec.
(c) LED12 (O) goes OFF; LED13 (R) remains ON for 3-sec.
(d) Let LED13 (R) remain ON for more 1-sec; LED12 remains ON for 1-sec

2. Now, you want to add a button (K1) with your hardware setup; you want to modify your program so that the program can detect the closed condition of K1 and then execute a 'block of codes (say, ignite LED10); after that the normal program flow continues.

3. Yes! You are right in saying that the goal of Step-2 could not be achieved keeping the delay() function in the program as this function prevents the MCU (blocks the MCU) from doing any other side activities like checking the close condition of K1. On the other hand, the millis() function is not a blocking function, and it allows checking the close condition of K1 while 'time delay' process is still going on.

while(millis() - previousmillis != interval)
{
   if(digitalRead(2) == LOW)
   {
      igniteED10();
   }
}

4. The following codes (a modified version of the millis() based codes of Post#3) carries out all the events of step-1; it also checks if K1 has been closed. If the closed condition of K1 is detected, the program ignites LED10 as a side job; after that the normal program flow continues -- the program carries out the events of Step-1.

const int R = 13;
const int O = 12;
const int G = 11;
const int A = 10;

void setup() 
{
  pinMode(G, OUTPUT);
  pinMode(O, OUTPUT);
  pinMode(R, OUTPUT);
  pinMode(A, OUTPUT);
  pinMode(2, INPUT_PULLUP);
  PORTB = 0x00;    //all LEDs OFF

}

void loop() 
{

  digitalWrite(G, HIGH); //11
  callMillis(3000);//delay(3000);
  
  digitalWrite(G, LOW); //11
  digitalWrite(O, HIGH);  //12
  callMillis(1000);//delay(1000);
  
  digitalWrite(O, LOW);  //12
  digitalWrite(R, HIGH);   //13
  callMillis(3000);//delay(3000);
  
  digitalWrite(O, HIGH);  //12
  callMillis(1000);//delay(1000);
  
  digitalWrite(O, LOW);   //12
  digitalWrite(R, LOW);   //13
}

void callMillis(unsigned long x)
{
  unsigned long presentMillis = millis();
  while(millis() - presentMillis != x)
  {
    if(digitalRead(2) == LOW)
    {
      igniteLED10();
    }
  }
}

void igniteLED10()
{
  digitalWrite(A, HIGH);  //10
}

led4-sw.png

GolamMostafa:
On the other hand, the millis() function is not a blocking function, and it allows checking the close condition of K1 while 'time delay' process is still going on.

while(millis() - previousmillis != interval)

{
  if(digitalRead(2) == LOW)
  {
      igniteED10();
  }
}

The millis() function does not block but using a WHILE loop() just introduces another form of blocking code. Use IF rather than WHILE and allow loop() to do the iteration,

...R

Robin2:
The millis() function does not block but using a WHILE loop() just introduces another form of blocking code. Use IF rather than WHILE and allow loop() to do the iteration,

When delay() function does not allow (at all) to check the close condition of the button, the while() structure does not prevent from doing that.

I appreciate your remarks!

It’s a state machine... just define states and transitions conditions..

GolamMostafa:
When delay() function does not allow (at all) to check the close condition of the button, the while() structure does not prevent from doing that.

I appreciate your remarks!

Yes but now that's all it does. Good non blocking code would allow it to do anything during that time. There's no reason to trap execution in a while loop. Your solution is not optimal. Not close.

@Golam you should really refrain from offering code writing advice until you know what you're doing with code. 95% of your posts just add unneeded confusion and most actually look like you trying to learn something yourself. Please just stop.

@Golam

also it’s not a good practice to rely on millis() to hit exactly your number

 void callMillis(unsigned long x)
{
  unsigned long presentMillis = millis();
  while(millis() - presentMillis != x) ...

it is possible that (millis() - presentMillis) might skip your x value (if other code takes time to execute) and then you have to wait for ~50 days to see if you are lucky again. Always test with <= or >= depending on what you do - not just == or !=

Delta_G:
Please just stop.

This will also STOP you. Have you accounted for it?

J-M-L:
it is possible that (millis() - presentMillis) might skip your x value (if other code takes time to execute) and then you have to wait for ~50 days to see if you are lucky again. Always test with <= or >= depending on what you do - not just == or !=

This is highly thought provoking indeed!

GolamMostafa:
This will also STOP you. Have you accounted for it?

I don't know what you mean. I'm not sharing bad novice ideas and calling it advice.

GolamMostafa:
This is highly thought provoking indeed!

Perhaps to you, to the rest of us who have done this sort of thing before it isn't thought provoking, just common sense.

Delta_G:
Perhaps to you, to the rest of us who have done this sort of thing before it isn't thought provoking, just common sense.

(Now, you have got the meaning of my Post#12 -- This will also STOP you.)

If it would be a matter of common sense, J-M-L would not engage so much efforts to organize the words of his Post#11 in order to bring to my vision what he thought to be conveyed. He could simply say -- don't do this (!=) operation; rather, do this (>=) operation?

hum - don't interpret what I meant....

if I wanted to put in some efforts I would have said please run this code on an UNO

const unsigned long period = 50ul;
unsigned long lastTick;
unsigned long count = 0;

void setup() {
  Serial.begin(115200);
  lastTick = millis();
}

void loop() {
  
  if (millis() - lastTick == period) {
    Serial.println(count++);
    lastTick += period;
  }
}

and explained that what I then see on the console is this

[color=purple]
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[/color]

and that it gets stuck there

then I would have gone in a long rant with diagrams etc about what is going on and why the code gets stuck whilst it feels perfectly legit....

I actually just posted enough for anyone passing by to realize it’s a bad practice.