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..
#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;
}
}
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
}
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'.