I'm trying to write a blink without delay code that will wait 20 seconds, then blink 5 times, then wait another 20 seconds - rinse and repeat.
Here's the minimal code I wrote:
if (currentTime % 20000 == 0) {
for (int x = 0; x <= 5; x++) {
if (currentTime % 500 == 0) {
if (solenoid == LOW) {
solenoid = HIGH;
} else {
solenoid = LOW;
}
digitalWrite(solenoidpin, solenoid);
}
}
}
}
All this seems to do is set solenoid to HIGH and keep it there. If I get rid of the for loop and the second if statement, I can get it to switch between low and high every 20 seconds, but adding the if and for loops seems to kill it. Any thoughts on how to make this work?
2 Answers 2
// assuming blinking is 500ms ON, 500ms OFF, so 4500ms for 5 blinks.
int tick = (currentTime/500) % 49;
// if one tick is 500ms, that means,
// 1 tick ON, 1 tick OFF, 1 tick ON, ... , 1 tick ON, 40 ticks OFF (for a total of 49 ticks)
if( ( tick < 5*2 ) && ( tick%2==0 ) )// only turn ON the led on the first 10 ticks (5 ON; 5 OFF)
// and only if the number of ticks is ODD
digitalWrite(solenoidpin, HIGH);
else
digitalWrite(solenoidpin, LOW);
What I did was convert the milliseconds in to ticks
of 500 ms. Then based on the tick
value, update the led.
PS I tested it on a Arduino Pro Mini
-
converting elapsed time to
tick
makes all kinds of sense. ... it is so easy to expand the number of controlled pins ... you could use lookup tables to make complex timing patterns like in a drum machinejsotola– jsotola2018年01月30日 18:10:00 +00:00Commented Jan 30, 2018 at 18:10 -
1This is smart. But note that: 1. The division and modulo operators are computationally expensive, although
tick%2
would be cheap iftick
was unsigned. 2. The formula fortick
is ill-behaved whenmillis()
rolls over. Both issues could be fixed by updatingtick
within aif (millis() - lastMillis > 500) { ... }
construct.Edgar Bonet– Edgar Bonet2018年01月31日 08:38:31 +00:00Commented Jan 31, 2018 at 8:38
Here is a solution:
void setup()
{
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
}
#define INTERVAL 20000L
#define BLINK_TIMES 5
void loop()
{
static unsigned long lastBlink = 0;
static int count = 0;
unsigned long now = millis();
if(count > 0) {
count -= blink();
lastBlink = now;
} else {
if(now - lastBlink >= INTERVAL) {
count = BLINK_TIMES;
}
}
}
/*
* Do one blink.
* Return 1 when blink is done.
*/
int blink()
{
static unsigned long lastFlip = 0;
static int count = 0;
bool last = false;
unsigned long now = millis();
if(now - lastFlip >= 500) {
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
Serial.print(now / 1000); Serial.print(". "); Serial.println("blink");
lastFlip = now;
count++;
if (count == 2) {
count = 0;
last = true;
}
}
return (last) ? 1 : 0 ;
}
The count
variable controls when to blink and how many times. While it's zero, no blinking.
When not blinking, it keeps comparing actual time with the last time it blinked. When the time exceed 20s, it puts count
to five, and in the next loop, the blinking start.
Variables are declared static
so they keep their values between loop
executions.
-
Since the last blink will end with a 500ms delay, the wait-time of 20 seconds, will become 20.5 seconds (-:Gerben– Gerben2018年01月30日 17:08:40 +00:00Commented Jan 30, 2018 at 17:08
-
@jsotola. My bad. I correct my answer.user31481– user314812018年01月30日 17:45:45 +00:00Commented Jan 30, 2018 at 17:45
-
@Gerben. Check the new answer without delays.user31481– user314812018年01月30日 17:46:06 +00:00Commented Jan 30, 2018 at 17:46
for
loop 6 times? IfcurrentTime % 500 == 0
is true, it will flip the solenoid state 6 times (i.e., not change it).micros()
value, you will only "trigger" if you happen to approach eachif
statement on exactly the microsecond boundary. Depending on your other code, you may find that the Arduino doesn't get around to yourif
statements on every sequential millisecond, and so you may miss some triggers. Better to do the subtract-and-compare operation that the BlinkWithoutDelay actually uses. That way, yourif
will trigger, even if you happened to miss the time by one millisecond.for
loop and the secondif
are pointless. In thefor
loop the variablecurrentTime
doesn't change and the secondif
is always true because 20000 is divisible by 500.