Professional Documents
Culture Documents
SIGNAL(TIMER0_OVF_vect)
7
8
m += MILLIS_INC;
f += FRACT_INC;
1
0
if (f >= FRACT_MAX) {
f -= FRACT_MAX;
1
1
m += 1;
}
1
2
1
3
timer0_fract = f;
1
4
timer0_overflow_count++;
timer0_millis = m;
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
{
unsigned long m;
uint8_t oldSREG = SREG;
2
3
2
4
2
5
2
6
2
7
2
8
return m;
}
2
9
3
0
3
1
3
2
Arduino - multiple LEDs with different delays
This question is Not Answered.
So far I have set up the hardware: 3 LEDs on digital pins 6, 7 and 8 using my
Arduino UNO board and a breadboard.
Code-wise I understand that I can't use the "delay" function because it causes
the whole system to delay i.e. causes 'blocking'. At the moment I'm using the
millis() function. My problem is that at the moment my code causes LED1 to turn
ON for 25 ms and off for 25 ms, LED2 turns ON for 50 ms and off for 50 ms etc.
So I need to somehow alter the OFF period independently.
// Assigning delays.
const unsigned long LED1_interval = 25;
const unsigned long LED2_interval = 50;
const unsigned long LED3_interval = 100;
// Declaring the variables holding the timer values for each LED.
unsigned long LED1_timer;
unsigned long LED2_timer;
unsigned long LED3_timer;
//LED2 loop
void toggle_LED2 ()
{
if (digitalRead (LED2) == LOW)
//LED 3 loop
void toggle_LED3 ()
{
if (digitalRead (LED3) == LOW)
digitalWrite (LED3, HIGH);
else
digitalWrite (LED3, LOW);
void loop ()
{
} // end of loop
[/code]
Any help would be greatly appreciated because I'm [b]very[/b] new to this!
Thanks!
7783 Views
Tags:
Reply
Most Arduino boards have two external interrupts: numbers 0 (on digital pin 2) and 1 (on digita
Official Arduino.cc Example
void setup()
{
pinMode(pin, OUTPUT);
attachInterrupt(0, blink, CHANGE); //0 is digtal pin 2
}
void loop()
{
digitalWrite(pin, state);
}
void blink()
{
state = !state;
}
Observing that all your time factors are multiples of 25 ms, I would suggest that
you use a digital pin on your UNO to initiate a self generated external interrupt.
Here is the guts of it: pin 9 is pulsed every 25 ms by your loop(), the
iHandler() bumps a counter, the main loop() has a case statement that allows the
required LED transistion actions to take place depending on the counter value
only when old_counter is not equal to counter.
FYI: http://arduino.cc/en/Reference/AttachInterrupt
Then again, you could just call the iHandler directly without the external
interrupt - but what fun would that be?
Reply
I've been working on this tonight and made a few alterations to my code. I think
I'm going in the right direction with the method I've chosen.
Defined seperate ON and OFF intervals for each LED
Adapted my loops to use both the OFF and ON intervals.
Unfortunately I've ended getting myself really confused and now my LEDs seem
to sometimes flash the OFF interval, sometimes with the ON and sometimes with
a combination of the both.
I hope I'm slowly moving in the right direction. If not I might have to try a
different approach like using the interupt function. I am very new to the Arduino
and writing code of any sort, so that approach seems quite daunting to me.
[code]
// Declaring the variables holding the timer value, i.e. time of last state change.
unsigned long LED1_statechange_Timei;
//SETUP
// Setting 3 digital pins as LED output pins and starting millisecond timer
void setup ()
{
pinMode (LED1, OUTPUT);
pinMode (LED2, OUTPUT);
pinMode (LED3, OUTPUT);
LED1_statechange_Timei = millis ();
LED2_statechange_Timei= millis ();
LED3_statechange_Timei = millis ();
} // end of setup
//LOOPS 1
//LOOPS 2
//LED 1
// If the time since the last change in state from OFF to ON is equal or greater
than the ON interval
//then run the loop toggle_LED1i
if ( (millis () - LED1_statechange_Timei) >= LED1_ON_interval)
toggle_LED1i ();
// If the time since the last change in state from ON to OFF is equal or greater
than the OFF interval
//then run the loop toggle_LED1ii
if ( (millis () - LED1_statechange_Timeii) >= LED1_OFF_interval)
toggle_LED1ii ();
//LED 2
// If the time since the last change in state from OFF to ON is equal or greater
than the ON interval
//then run the loop toggle_LED2i
if ( (millis () - LED2_statechange_Timei) >= LED2_ON_interval)
toggle_LED2i ();
// If the time since the last change in state from ON to OFF is equal or greater
than the OFF interval
//LED 3
// If the time since the last change in state from OFF to ON is equal or greater
than the ON interval
//then run the loop toggle_LED3i
if ( (millis () - LED3_statechange_Timei) >= LED3_ON_interval)
toggle_LED3i ();
// If the time since the last change in state from ON to OFF is equal or greater
than the OFF interval
//then run the loop toggle_LED2ii
if ( (millis () - LED3_statechange_Timeii) >= LED3_OFF_interval)
toggle_LED3ii ();
} // End of loop
[/code]
Thanks!
Reply
Q: Just out of curiosity, what exactly controls the periodicity of your LEDs?
{
digitalWrite (*LEDxP, (*LEDxP_state = !(*LEDxP_state))); // see note below
} // End of toggle_LED
Reply
Then you can write a function that will scan this array and find the event with the
soonest next time-of-day. Set an interrupt timer for that time-of-day. While
waiting for the timer, any work can be going on. When the timer goes off,
turn the specified LED On or Off, and update the next time-of-day field by adding
the specified time between events for that LED. Loop back and scan the array
again to find the next soonest event.
o
Reply
Please check out my modified code above for pointer ref. & deref. usage!
Code in previous post updated based on the following experiment which does
compile and run correctly!
boolean ON = HIGH;
boolean OFF = LOW;
boolean led1 = ON;
void setup()
{ //led1 = OFF;
pinMode(13, OUTPUT);
void loop()
{ test(&led1);
digitalWrite(13, led1);
delay(1500);
}
Reply
In toggle_LED1ii ()
you have:
LED1_statechange_Timei = millis (); // Remember when LED1's state was
changed from OFF to ON
but that should be Timeii (two i's).
Similarly, in toggle_LED2i ()
you have:
LED2_statechange_Timeii = millis (); // Remember when LED2's state was
changed from ON to OFF
but that should be Timei (one i).
Also, in setup(), I think you need to initialize the Timeii statechange variables, in
order to prevent referring
to random values in the loops.
Billabott is probably right that by using pointers you can condense the code, but I
haven't
looked at that closely, and I think you probably want to get it working first, and
then improve it later.
Introduction
Using delay() causes your system to be stuck while waiting for the delay to
expire. However replacing delays requires some care. This page explains in a
step by step way how to replace delays with repeating timers in a reliable way.
Warning: Do not run the standard Arduino BLINK example code, or any
other code using pin 13 (LED) as an output, on the Fio V3 board when a
battery is connected. You may damage the board.
See this page for more warnings about the FioV3 board
Timers Using elapsedMillis
A Repeating Timer using elapsedMillis
A Once Off Timer using elapsedMillis
Code Examples to be Avoided
Simple Blink Example using Delay
Second Attempt to Blink without Delay
Almost Final solution to Blink without Delay
Word of Warning Add a loop monitor
Final Solution for Reliable Timers (Superseded by above elapsedMillis examples,
8th Nov 2013)
Timers Using elapsedMillis
Lets start at the end with the two working examples that don't have problems.
These working examples are based on elapsedMillis by Paul Stoffregen, one for a
repeating timer and one for a once off timer.
Follow those two examples are working alternatives that don't use the
elapsedMillis library.
First install the elapsedMillis library. Downloaded the elapsedMillis.zip file.
Unzip this file to your Arduino/libraries directory (open the IDE File->preferences
window to see where your local Arduino directory is).
Some times the instructions for How to Install a Library - Automatic
installation work, but not always. Unzipping the file manually is safest.
A Repeating Timer using elapsedMillis
This is a simple example of a repeating timer
#include <elapsedMillis.h>
// see warning above about FioV3
int led = 13;
// Pin 13 has an LED connected on most Arduino boards.
// if using Arduino IDE 1.5 or above you can use pre-defined
// LED_BUILTIN instead of 'led'
//
elapsedMillis timer0;
#define interval 1000
// the interval in mS
void loop() {
if (timer0 > interval) {
timer0 -= interval; //reset the timer
int ledPin = digitalRead(led);
// read the current state and write the opposite
digitalWrite(led, !ledPin);
}
}
The code above loop() continues to run without being stuck waiting for the delay
to expire.
During each pass of the loop(), a timeout interval is compared to a free running
timer.
When the timer exceeds the value of the interval the desired action is taken (in
this example change the state of the LED) and the timer is reset.
The reason for using
timer0 -= interval; //reset the timer
is that it allows for the possibility that the timer just happened to be incremented
between testing it
if (timer0 > interval) {
and resetting it
timer0 -= interval; //reset the timer
or if there is some other delay the prevents the main loop from running every
milli-second. (See the Adding a Loop Montor below)
Using timer0 -= interval; also gives you the option of varying the timing interval.
Another point is to clear timer0 at the end of startup(), using
timer0 = 0;
This ensures the timer is accurate at the start of the loop(), even if startup()
takes some time to execute.
A Once Off Timer using elapsedMillis
If you only want the timer to fire once and never again you need to add a guard
boolean to prevent code being executed again after the timer has fired
#include <elapsedMillis.h>
// see warning above about FioV3
int led = 13;
// Pin 13 has an LED connected on most Arduino boards.
// if using Arduino IDE 1.5 or above you can use pre-defined
// LED_BUILTIN instead of 'led'
//
elapsedMillis timer0;
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
digitalWrite(led, HIGH);
timer0Fired = false;
timer0 = 0; // clear the timer at the end of startup
}
void loop() {
if ((!timer0Fired) && (timer0 > interval)) {
timer0Fired = true; // don't execute this again
digitalWrite(led, LOW); // turn led off after 5 sec
}
}
Also see http://playground.arduino.cc//Code/ElapsedMillis
Code Alternatives to using ElapsedMillis
Here are two code examples that do not used ElapsedMillis.
Repeating Timer
The following sketch shows a simple repeating timer. You can download the
sketch from RepeatingTimer.ino
int led = 13;
unsigned long timer; // the timer
unsigned long INTERVAL = 1000; // the repeat interval
void setup() {
pinMode(led, OUTPUT); // initialize LED output
timer = millis(); // start timer
}
void loop() {
if ((millis()-timer) > INTERVAL) {
// timed out
timer += INTERVAL;// reset timer by moving it along to the next interval
//
toggle led
if (digitalRead(led)) {
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
} else {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
}
}
}
Single Shot Timer
This sketch shows a simple single shot timer. You can download the sketch
from SingleShotTimer.ino
int led = 13;
unsigned long timer; // the timer
boolean timedOut = false; // set to true when timer fired
unsigned long INTERVAL = 5000; // the timeout interval
void setup() {
pinMode(led, OUTPUT); // initialize LED output
timedOut = false; // allow timer to fire
timer = millis(); // start timer
}
void loop() {
// this will toggle the led ONCE only after 5sec (timeOut)
if ((!timedOut) && ((millis() - timer) > INTERVAL)) {
// timed out
timedOut = true; // don't do this again
// you can reset the single shot timer by setting
// timedOut = false;
// timer = millis();
//
toggle led
if (digitalRead(led)) {
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
} else {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
}
}
}
If you try and add more code to the loop() you will find it is very slow to execute.
So the first point is:Don't use delay( )
Second Attempt to Blink, without Delay
But if you don't use delay what are the alternatives. Well Arduino provides a
millis() method that returns the number of milli Seconds since the last uC reset.
Using this method we can code this second attempt at a delay.
// Second attempt
int led = 13; // don't use on FioV3 when battery connected
// Pin 13 has an LED connected on most Arduino boards.
// if using Arduino IDE 1.5 or above you can use pre-defined
// LED_BUILTIN instead of 'led'
//
unsigned long timeout;
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
timeout = millis();
}
Now there are no delays in the main loop() and your other code will be run
promptly.
However all it not good with this solution.
The second attempt above has a failing. About 50 days after the Arduino board is
reset, millis() goes back to counting from 0. This is because the 32bits used to
store the value overflow and start counting from zero again. See the Arduino
reference description for millis(). The timeout variable is also 32bits and so
eventually timeout + 1000 will overflow and become a small number. What this
means is that for about 1 second every 50 days
if (millis() > timeout) {
will be true every loop and the led will flash at a very high rate for that second
until millis() over flows back to a small number as well.
For a blinking led this may not be a problem but in a real application it could
cause damage every 50 days when the timers stop working as expected.
If you are just interested in a repeating timer then
see http://arduino.cc/en/Tutorial/BlinkWithoutDelay for a simple reliable repeating
timer which does not count down. The code below works because even
if currentMillis overflows back to a small number, currentMillis
previousMillis still gives the correct result.
void loop() {
unsigned long currentMillis = millis();
if(currentMillis - previousMillis> interval) {
// save the last time
previousMillis = currentMillis;
// do stuff here each interval (interval -- an unsigned long)
...
}
The loop monitor is very similar to the blink example. A small piece of code at
the top of the loop() method just toggles the Led each time loop() is executed.
You can then use a digital multimeter with at Hz scale to measure the frequency
of the output on the LED pin (pin 13 in this case)
The code is:// Loop Monitor this checks that the loop() is executed at least once every 1mS
// (c)2013 Forward Computing and Control Pty. Ltd.
// www.forward.com.au
//
// This example code is in the public domain.
int led = 13; // don't use on FioV3 when battery connected
// Pin 13 has an LED connected on most Arduino boards.
// if using Arduino IDE 1.5 or above you can use pre-defined
// LED_BUILTIN instead of 'led'
//
You can download the monitor code here. When I run this code on my Uno board
the multiMeter on the Hz range connected between pin 13 and GND reads
57.6Khz. i.e. about 100 times >500hz. As you add your code to loop() the Hz
reading will reduce. Just check it stays well above 500Hz in all situations.
Final Solution for Reliable Count Down Timers
(Note: this code has been superseded by the elapsedMillis code at the
top of this page)
This last example shows how to code count down timers, both repeating and one
off, that will reliably execute even if loop() takes more the 1mS to execute.
The idea is to capture the number of millis() that have gone by since the last
loop() and use that number to decrement your timers. This code can
be downloaded from here. As noted above
seehttp://arduino.cc/en/Tutorial/BlinkWithoutDelay for an alternative simple
reliable repeating timer which does not count down.
/*
Robust Timer
(c)Forward Computing and Control Pty. Ltd.
Works even if sometimes the loop() takes longer the 1mS to execute.
This example code is in the public domain.
*/
static int timer_2 = 0; // a one off timer max time 32768 mS = 32sec use a long
if you need a longer timer
// NOTE timer MUST be a signed number int or long as the code relies on timer_2
being able to be negative
// NOTE timer_2 is a signed int
timer_2 -= deltaMillis;
if (timer_2 <= 0) {
// timer timed out
// do timeout stuff here
// in this set the led HIGH
Serial.println("Timer 2 timed out");
}
}
}
}
Note that for the one off timer, timer_2, we first check if the timer is >0 before
subtracting the deltaMillis so that we only process the timeout once.
For the repeating timer, timer_1, we just subtract the deltaMillis every time, but
most of the time deltaMillis will be 0.
So for both types of timers, you can also add a check for deltaMillis > 0 and skip
all the timer code except for those times when the mS ticks over. i.e.
if (deltaMillis> 0) {
// handle one off timer
// repeat this code for each timer you need to handle
.. etc
pfodDevice and pfodApp are trade marks of Forward Computing and Control
Pty. Ltd.