Help with non blocking delays

Dear friends;

How could I replace the delay in the code bellow with a non blocking timing for HIGH time of the digitalWrite ?

The default state should be LOW and periodically be HIGH only for an specified duration .

unsigned long previousMillis = 0; // last time update
long interval = 2000; // interval at which to do something (milliseconds)

void setup(){
  pinMode(3, OUTPUT); // output for a command
}

void loop(){
  unsigned long currentMillis = millis();
  // digitalWrite(3,LOW); // default Low state may be here

  if(currentMillis  - previousMillis > interval) {
   digitalWrite(3,HIGH);
   delay (100); // duration time for output be high 
   digitalWrite(3,LOW);
   //do something more
   previousMillis = currentMillis ;  
  }
}

You need to create a state machine and keep track of which state you are in

unsigned long previousMillis = 0; // last time update
const unsigned long interval = 2000; // interval at which to do something (milliseconds)
const unsigned long highPulseDuration = 100;
unsigned long highTimeStart;

const byte outputPin = 3;
enum { LOW_TIME, HIGH_TIME };
int state = LOW_TIME;

void setup() {
  pinMode(outputPin, OUTPUT); // output for a command
}

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

  if (currentMillis  - previousMillis >= interval) {
    previousMillis = currentMillis;
    state = HIGH_TIME;
    digitalWrite(outputPin, HIGH);
    highTimeStart = currentMillis;
  }
  switch (state) {
    case LOW_TIME:
      // do nothing
      break;

    case HIGH_TIME:
      // see if we are done
      if ( currentMillis - highTimeStart >= highPulseDuration ) {
        state = LOW_TIME;
        digitalWrite( outputPin, LOW );
      }
      break;
  }
}

You just want to output a square wave 2100 frequency with a 100 ms pulse? (2000 low + 100 high) You can use a non blocking square wave generator for that set it up, start it and let it go..

-jim lee

consider

#define Pin      13
#define Period   2000
#define PeriodOn 100

unsigned long previousMillis = 0; // last time update
unsigned long interval = 2000;

void setup()
{
    pinMode (Pin, OUTPUT); // output for a command
}

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

    if (currentMillis - previousMillis > interval) {
        previousMillis = currentMillis ;

        byte state = digitalRead (Pin);
        digitalWrite (Pin, ! state);

        if (LOW == state)
            interval = PeriodOn;
        else
            interval = Period - PeriodOn;
    }
}

Another alternative is to use my millisDelay class
see the tutorial at https://www.forward.com.au/pfod/ArduinoProgramming/TimingDelaysInArduino.html

#include <millisDelay.h>
// see tutorial https://www.forward.com.au/pfod/ArduinoProgramming/TimingDelaysInArduino.html
// millisDelay included in SafeString library available from library manager

const int pin = 13; // led or pin 3 in your case

millisDelay intervalDelay;
unsigned long interval = 2000; // interval at which to do something (milliseconds)

millisDelay highDelay;
unsigned long highDelaymS = 100;  

void setup(){
  pinMode(pin, OUTPUT); // output for a command
  digitalWrite(pin,LOW); // default Low state may be here
  intervalDelay.start(interval);
}

void loop(){
  if (intervalDelay.justFinished()) {
    intervalDelay.repeat(); // restart with no creep
    digitalWrite(pin,HIGH);
    highDelay.start(highDelaymS); // start the high timeout
  }

  if (highDelay.justFinished()) {
    digitalWrite(pin,LOW);
  }
}

I just decided to try something weird. If anyone spots a problem, please comment.

// BlinkWithStates 2021-02-01 aarg on Arduino forum
//
// Just to see how weird Blink could be without crashing
// Uses the forbidden future time stamp!

#define Pin      13
#define Period   2000
#define PeriodOn 100

enum states {ON, OFF, WAITING};
states state = OFF;
states nextState;

unsigned long futureMillis = millis(); // time of next update

void setup()
{
  pinMode (Pin, OUTPUT); // output for a command
}

void loop()
{
  switch (state)
  {
    case OFF:
      digitalWrite (Pin, LOW);
      futureMillis +=  (Period - PeriodOn);
      nextState = ON;
      state = WAITING;
      break;

    case ON:
      digitalWrite (Pin, HIGH);
      futureMillis +=  PeriodOn;
      nextState = OFF;
      state = WAITING;
      break;

    case WAITING:
      if (long(millis() - futureMillis) >= 0) {
        state = nextState;
      }
      break;
  }
}

I like it, it works..

Here's mine.

#include <blinker.h>

#define Pin      13
#define Period   2000
#define PeriodOn 100

blinker  aBLinker(Pin,PeriodOn,Period);

void setup() { aBLinker.setOnOff(true); }

void loop() { idle(); }

-jim lee

Thanks for all helps. Problem solved . I made my simplified code that allow polling the state of "run" at any place in the loop and then do something wanted :

#define intervaloX   1000 // intervalo do evento periodico 
#define intervaloY   100 //duração do  evento
#define outputPin 3 // pino de saida

unsigned long int timeX = 0;
unsigned char run = 0;

void setup() {
  pinMode(outputPin, OUTPUT); // output for a command
  digitalWrite(outputPin, LOW); // estado inicial
}

void loop() {
intervalometro(); // inicia o temporizador

if (run == 0) digitalWrite(outputPin, LOW); // pode ser usado para executar uma tarefa
if (run == 1) digitalWrite(outputPin, HIGH); //  another task

}

void intervalometro(){
if (millis() - timeX > intervaloX){timeX = millis(); run = 1;} //intervalo periodico
if (run == 1){if (millis() - timeX > intervaloY) {run=0;}}// duraçao do evento
}
  if (run == 0) digitalWrite(outputPin, LOW); // pode ser usado para executar uma tarefa
  if (run == 1) digitalWrite(outputPin, HIGH); //  another task

Why not

  digitalWrite(outputPin, run);

Doing the delay this way has a couple of flaws:

    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis > interval) {
        previousMillis = currentMillis ;

Firstly it triggers every interval+1 rather than every interval milliseconds.
Secondly it can (and will) accumulate error if the rest of the code takes more than a millisecond,
triggering more slowly as it cannot notice when a trigger happens late and catch up.

This is the clean and reliable way to trigger an event regularly without such error or drift:

  if (millis() - previousMillis >= interval)  // note the >=, not >
  {
    previousMillis += interval ; // step forward by exactly interval so the next event is on-schedule
    ...

acjacques:
Thanks for all helps. Problem solved . I made my simplified code that allow polling the state of "run" at any place in the loop and then do something wanted :

C/C++ has a built in data type 'bool' for boolean variables. 'run' is really a boolean, because it can only be 'true' or 'false'.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.