How to delay using millis()

Hie guys, am new here. I don't know if I am posting the right way...... My question here is, I have a power supply, I want it to power itself off when it's idle for a certain time. This power supply has voltage and current readings.

  • when current is 0 Amps for like 5 minutes, I want it to digitalWrite () a pin HIGH which will then shut the power.

I have seached but what I found was blinking only.

It's something like this but using millis ()


int shutDown = 8;

void setup (){
pinMode(shutDown, OUTPUT);
digitalWrite (shutDown, 0);
}

void loop(){
float current=analogRead(A0);

if (current==0)
{
delay(5000);
digitalWrite(shutDown, 1);

What advantage would you avail by replacing the delay() function by millis() function -- or it is just an exercise?

The above declaration is wrong as analogRead() function returns a 16-bit value of type int. So, the correct declaration is:

int current = ananlogRead(A0);
1 Like

Here's some pseudo code from under the umbrella

    if the current is high
        reset the timer variable

    if the timer variable was 60 seconds ago
        shut off the power

in a loop.

  • When there is current, the timer gets set to millis(), or "now".
  • When the timer hasn't been so reset in awhile, shut down whatever

See "blink without delay" and come to a good understanding of its simple mechanism for time keeping.

HTH

a7

2 Likes

This was just a simple way to say what I want, the full code has other things to do in loop which I don't want to stopped with delay.

Then, please post the whole sketch so that it can be assessed if there are multiple tasks in your job that can be taken care of using millis() function and NOT using delay() function which blocks the MCU.

2 Likes

Ok thanks, I see want you mean. If not mistaken, I should reset my timer variable whenever current is high.Use code tags to format code for the forum


int shutDown = 8;
int shutTimer;

void setup (){
pinMode(shutDown, OUTPUT);
digitalWrite (shutDown, 0);
}

void loop(){
int current=analogRead(A0);

if (current>=1) {shutTimer=0;}

if (current<1){
shutTimer=millis();
If ((millis()-shutTimer)>5000)
 { digitalWrite(shutDown, 1)}
}

Is this right? Am new to gramming please take me aboard

Do you have idea on the working principles of millis() function?

There is a 32-bit unsigned counter/accumulator inside the Arduino, which starts with initial value of 0 once sketch uploading is done into the Arduino. After that it advances my 1 ms time period. Using millis() function, it is possible to read the current content of the said counter at any time. So, the correct declaration is:

unsigned long int shutTimer;
or
unsigned long shutTimer;   //int is understood
1 Like

Ok thanks for fast replies..... I will do when got home...but still the code will be monitoring the current like if it goes below 1 amp it delays to shutdown for 5 seconds, but if current gets back to 1 amp or above within 4 seconds it does not shut down.

Have you tested your sketch of #6 -- is it working?

Ok to be honest am trying to understand better, I have small idea. Thank you for the input.

Not yet tested

Ok! Experiment with your sketch and come back with the results -- if it is providing you the expected result or not.

Ok I will....

1 Like

Please look at the "blink without delay" example in the IDE.

In IDE 1.8.7, it is Examples / 02.Digital / BlinkWithoutDelay.

ButI have no doubt it's in there somewhere no matter the version, or google

arduino blink without delay

Meanwhile, try this in the simulator. From some time ago:


Wokwi_badge keep it moving…


It basically triggers an activity if the button has gone unpressed for some time. I think you could read it carefully, and with your full grasp of millis() v. delay() rework it to your porpoises:

// https://forum.arduino.cc/t/timed-response-after-release/964154
// https://wokwi.com/projects/324897525243839060

// version 2. remove crude debouncing, put didIt flag in more obvious place

int soundSensor = 2;

// several tweaks because I use a button not a sound sensor

int buttonState = 0;
int lastButtonState = 0;

const int debouncePeriod = 33;

const unsigned long actionTrigger = 5000; //serial print action 5 seconds for testing - life too short
unsigned long startTimer; // time until action
unsigned long currentMillis;

void setup() {
  Serial.begin(115200);
  Serial.println("\nWake up!\n");

  pinMode (soundSensor, INPUT_PULLUP);  // for proxy pushbutton here
}

void loop() {
  static bool didIt = true;   // intial condition
  static unsigned long startTimer; // time until action
  static unsigned long lastButtonTime;

  unsigned long currentMillis;  

  currentMillis = millis();

  int buttonState = !digitalRead(soundSensor);  // button upside down

  if (currentMillis - lastButtonTime > debouncePeriod) {   // OK bounce-wise to even look at the button?
    // compare the buttonState to its previous state
    if (buttonState != lastButtonState) { // has the state changed?
      lastButtonTime = currentMillis;   // so we don't look again too soon (bounce)

      if (buttonState == HIGH) { // if high, button pressed

        // if the current state is HIGH then the button went from off to on:
        Serial.println("pressed");
//        didIt = false;    // reset do something trigger gaurd
      }
      else {
        Serial.println("released");
      }

      lastButtonState = buttonState; // Save button state
    }
  }
  // when the button is pressed, reset the timer

  if (buttonState == HIGH) {
    startTimer = currentMillis;
    didIt = false;    // reset do something trigger gaurd
// trust or verify    Serial.println("       reset timer");
  }

  if ((currentMillis - startTimer > actionTrigger) && !didIt) {
    Serial.println("                                Do something!");
    didIt = true;
  }
}

A good chunk of that code is just getting the button transition.

The last two if statements are exactly what my pseudocode was getting at. One resets the timer, the other checks if the timer has expired.

HTH

a7

1 Like

Thanks for that will get to the blink without delay in IDE and retry to understand it....

I don't recommend using the poor coded blink without delay() code in the Arduino-IDE-examples for the following reasons:

  1. there is no explanation of the fundamental difference how non-blocking timing works. This leaves beginners confused if they try to see a delay()-thing in millis()
  2. the code is poorly commented
  3. variable names are confusing
  4. It does not explain the principle with an easy to understand everyday example with explicit easy to understand numbers

I will NEVER get tired to post this again and again and again and again for the rest of my life until the point this blink without understand-example is replaced by a much better version (which will be the same as eternal)

I recommend to read this tutorial

best regards Stefan

Some helpful colleagues pointed out that all the button debouncing stuff is… not used at all. So here is the same code with the useless distraction removed.

The didIt flag just keeps the thing from happening more that once per timed gap after button release.

Wokwi_badge simpler stayin' alive…


// https://forum.arduino.cc/t/how-to-delay-using-millis/1142938
// https://wokwi.com/projects/368896943205371905

// version 3. remove any debouncing

const byte pushButton = 2;

// several tweaks because I use a button not a sound sensor

int buttonState = 0;
int lastButtonState = 0;

const int debouncePeriod = 33;

const unsigned long actionTrigger = 5000; //serial print action 5 seconds for testing - life too short
unsigned long startTimer; // time until action
unsigned long currentMillis;

void setup() {
  Serial.begin(115200);
  Serial.println("\nWake up!\n");

  pinMode (pushButton, INPUT_PULLUP);
}

void loop() {
  static bool didIt = true;   // intial condition
  static unsigned long startTimer; // time until action
  static unsigned long lastButtonTime;

  unsigned long currentMillis;  

  currentMillis = millis();

  int buttonState = !digitalRead(pushButton);  // button pulled up!

  // when the button is pressed, reset the timer
  if (buttonState == HIGH) {
    startTimer = currentMillis;
    didIt = false;    // reset do something trigger gaurd
// trust or verify    Serial.println("       reset timer");
  }

// when the timer expires, do whatever
  if ((currentMillis - startTimer > actionTrigger) && !didIt) {
    Serial.println("                                Do something!");
    didIt = true;
  }
}

HTH

a7

easier to understand code through:

  • less variables
  • selfexplaining variable-names
  • selfexplaining function-names

best regards Stefan

If you want the simple version of what @alto777 was getting at in #3, this is a complete sketch using minimal anything, and expecting only that someone has come to grips with the expression and variants often seen, no matter how hidden, viz:

    now - lastTime >= interval

Here

Wokwi_badge simple keep alive


I think discovering its flaws, which are not evident in the exact example of turning on and off the LED, can be fun. I know I had some fun once with it, not too long ago.

// https://forum.arduino.cc/t/how-to-delay-using-millis/1142938
// https://wokwi.com/projects/368911815269434369

// version 4. remove anydebouncing

const byte buttonPin = 2;
const byte ledPin = 3;

const unsigned long actionDelay = 3500; // action 3.5 seconds for testing - life too short

void setup() {
  Serial.begin(115200);
  Serial.println("\nWake up!\n");

  pinMode (buttonPin, INPUT_PULLUP);
  pinMode (ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
}

void loop() {
  static unsigned long startTimer; // time at action

  unsigned long now = millis();   // fancier 'currentMillis' ooh!
  int buttonState = !digitalRead(buttonPin);  // button pulled up!

// when the button is pressed, reset the timer, turn ON the LED
  if (buttonState == HIGH) {
    startTimer = now;
    digitalWrite(ledPin, HIGH);
  }

// when (if!) the timer expires, turn OFF the LED
  if (now - startTimer >= actionDelay) {
    digitalWrite(ledPin, LOW);
  }
}

a7

1. Let us try to understand the difference between a blocking code and a non-blocking code.

2. A blocking code is a code in which the MCU is blocked for certain amount of time is and prevented from doing any other task during that blocking period. For example:

Turn ON the built-in LED (L, Fig-1) of UNO and let it be at this ON-state for 1 sec time. After that turn OFF the LED and let it be at this OFF-state for 1 sec time. Repeat the process again. The blocking codes are given below Fig-1:
L-Built-in
Figure-1:

void setup()
{
    pinMode(13, OUTPUT);
} 

void loop()
{
     digitalWrite(13, HIGH);   //LED is ON
     delay(1000);   //LED remains ON for 1 sec time
     digitalWrite(13, LOW); //LED is OFF
     delay(1000);     //LED remains OFF for 1 sec
}

3. while delay(1000) function (in Section-2) is being executed, the MCU remains totally blocked, and it cannot do any other task. Here, we see a wastage of 1 sec valuable time of the MCU; but, it is alright as long as there is no other task for the MCU to do.

4. Let us see how we can turn ON and turn OFF the LED (L) of Fig-1 at 1 sec interval without using the delay() function. Because, we are not using delay() function, the MCU will not be blocked any more. Anyway, there is still only one task (ON and OFF the LED) for the MCU; so, there is not much utilization of MCU's time/ability keeping it unblocked.

byte ledState = HIGH;
byte ledPin = 13;
unsigned long int currMillis = millis();  //recording time t0

void setup()
{
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);  // L is turned ON
}

void loop()//MCU checks if 1 sec has elapsed without being blocked
{
  if (millis() - currMillis >= 1000)//checkingif 1 sec is elspased
  {
    //ledState = !ledState;   //1 sec has gone; invert ledState from ON ---> OFF
    if (ledState == HIGH) 
    {
      ledState = LOW;
    } 
    else 
    {
      ledState = HIGH;
    }
    digitalWrite(ledPin, ledState); //L is OFF --> ON ----> OFF....
    currMillis = millis();   //recording t1, t2, .....
  }
}

5. In this example, we will assign two tasks to the MCU which it will perform simultaneously without using delay() function, but it will be using millis() function to assign slots for their execution. the tasks are:

(1) LED (L) of Fig-2 will be turned ON/OFF at 1 sec interval.
(2) Smoke Detector will be checked if it is active (smoke has erupted from a hazardous point) in order to activate Alarm.


Figure-2:

byte ledState = HIGH;
#define ledPin 13
#define alarmLed 5
#define smokeSwitch 4

unsigned long int currMillis = millis();  //recording time t0

void setup()
{
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  pinMode(smokeSwitch, INPUT_PULLUP);
  pinMode(alarmLed, OUTPUT);
  digitalWrite(ledPin, HIGH);  // L is turned ON
}

void loop()//MCU checks if 1 sec has elapsed without being blocked
{
  if (millis() - currMillis >= 1000)//checkingif 1 sec is elspased
  {
    //edit ; ledState = !ledState;   //1 sec has gone; invert ledState from ON ---> OFF
    if (ledState == HIGH) 
    {
      ledState = LOW;
    } 
    else 
    {
      ledState = HIGH;
    }
    digitalWrite(ledPin, ledState); //L is OFF --> ON ----> OFF....
    currMillis = millis();   //recording t1, t2, .....
  }
  else
  {
    if (digitalRead(smokeSwitch) == LOW)
    {
      Serial.println("Smoke Dectected");
      digitalWrite(alarmLed, HIGH);   //alarm is activated
      while (1);  //wait to see the preventive action
    }
  }
}

Flow Chart Representation of the above sketch:


Figure-2:

6. Present the solution of the job of Section-5 using FSM (Finite State Machine) approach of post #81 @J-M-L of the following thread.
https://forum.arduino.cc/t/how-to-get-rid-of-goto-statement/1140656