Reputation: 141
I'm using an Arduino Uno
to control LED. I want the LED to turn on every m seconds and remain ON for n seconds.
I've tried this code using the delay()
function (by adding delays after LED is turned ON and OFF) and also using the millis()
function (by keeping a track of the time passed since the previous event - ON/OFF). However, in both the approaches, the LED develops a lag of ~1 second after a few (!10) iterations of the ON-OFF cycle. What can I do to increase the accuracy of the time at which the events occur?
int led = 13;
long experimentTime = 240000;
long ledOFFDuration = 8000;
void setup() {
pinMode(led, OUTPUT);
pinMode(button, INPUT);
}
void loop() {
for (int i = 0; i < 100; i++){
digitalWrite(led, HIGH);
delay(10000);
digitalWrite(led, LOW);
delay(10000);
}
}
I've also tried using the watchdog timer (shown below). However, it has the same issue:
#include <avr/wdt.h>
int led = 13;
volatile byte watchDogState = 0b01000000;
volatile int counter = 0;
int counterMax = 5;
bool state = 1;
void setup() {
// put your setup code here, to run once:
wdt_disable();
pinMode(led, OUTPUT);
digitalWrite(led, 1);
setWDT(watchDogState);
}
void loop() {
// put your main code here, to run repeatedly:
// if (time_elapsed == 40){
//state = !state;
//}
}
void setWDT(byte sWDT){
WDTCSR |= 0b00011000;
WDTCSR = sWDT | WDTO_2S;
wdt_reset();
}
ISR (WDT_vect){
counter++;
if (counter >= counterMax){
state = !state;
digitalWrite(led, state);
counter = 0;
}
}
I tried using the port registers directly to avoid using digitalWrite completely. But that doesn't work either. There's a lag of ~5s after 20 minutes using the following code:
int led = 13;
int m = 10;
int n = 10;
boolean on;
long change;
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
long now = millis();
if (!on && change < now) {
on = true; //led is now on
change = now + n*1000; //turn off in <n> seconds
PORTB |= B00100000;
}
else if (on && change < now){
on = false; //led is now off
change = now + m*1000; //turn on in <m> seconds
PORTB &= B11011111; // Set pin 4 to 0
}
}
Upvotes: 3
Views: 2200
Reputation: 858
The lag is caused by the digitalWrite
-calls. Your processing application waits until digitalWrite has finished and this may take 0.05 seconds or so. To fix your problem I would save the current time in milliseconds.
int led = 13;
int m = 24;
int n = 8;
boolean on;
long change;
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
long now = System.currentTimeMillis();
if (!on && change < now) { //led is off and time for change has come
on = true; //led is now on
change = += n*1000; //turn off in <n> seconds
digitalWrite(led, HIGH); //turn on led
} else if (on && change < now) { //led is on and time for change has come
on = false; //led is now off
change = += m*1000; //turn on in <m> seconds
digitalWrite(led, LOW); //turn off led
}
}
the lamp will now instantly turn on on startup, wait n
seconds, turn off, wait m
seconds and restart from the beginning.
If you want to create a delay at the beginning so that the lamp doesn't get turned on immediately you can simply add this to your setup
-function:
change = now + SECONDS*1000;
EDIT
You pointed out that it still gives you lag. One problem might be that loop() is not run every millisecond. So I maybe got a solution for you.
Replace the following two lines:
change = now + n*1000; //turn off in <n> seconds
...
change = now + m*1000; //turn on in <m> seconds
to this:
change += n*1000; //turn off in <n> seconds
...
change += m*1000; //turn on in <m> seconds
Now it won't take the current time anymore which means that even if loop is only run every second or two it should still not cause any lag.
If this won't work I'm afraid it looks like the timer on the arduino might not be the most precise one. If this is the case try to measure the exact offset and then create a miltiplicator for the time.
Upvotes: 3