Вы находитесь на странице: 1из 13

Tutorial: Arduino timing methods with millis()

The millis function makes use of an internal counter within the ATmega microcontroller at the heart of your
Arduino. This counter increments every clock cycle – which happens (in standard Arduino andcompatibles) at a
clock speed of 16 Mhz. This speed is controlled by the crystal on the Arduino board (the silver thing with T16.000
stamped on it):

Crystal accuracy can vary depending on external temperature, and the tolerance of the crystal itself. This in turn
will affect the accuracy of your millis result. Anecdotal experience has reported the drift in timing accuracy can be
around three or four seconds per twenty-four hour period. If you are using a board or your own version that is
using a ceramic resonator instead of a crystal, note that they are not as accurate and will introduce the
possibility of higher drift levels. If you need a much higher level of timing accuracy, consider specific timer ICs
such as the Maxim DS3232.

Arduino UNO - Timing


In Tutorial 1 we flashed an LED on for a second then off for a second in a continuous loop.

Using function delay(n) the microcontroller cannot perform any other functions in the main loop().

If you try and add more code to the loop() you will find it is very slow to execute.
So Don't use delay( )
/* Flashing LED
* ------------
* Turns on and off a light emitting diode(LED) connected to a digital
* pin, in intervals of 2 seconds using delay() function. *
*/

int ledPin = 13; // LED connected to digital pin 13


void setup() {
pinMode(ledPin, OUTPUT); // sets the digital pin as output
}
void loop() {
digitalWrite(ledPin, HIGH); // sets the LED on
delay(1000); // waits for a second
digitalWrite(ledPin, LOW); // sets the LED off
delay(1000); // waits for a second
}

Above prog can re-written using NOT operater


void loop()
{
digitalWrite(ledPin, !digitalRead(ledPin)); // toggles the LED on/off
delay(1000); // waits for a second
//other process has to wait
}

Instead of delay() we will use the Arduino millis() function.


The millis() function returns the number of milliseconds since the Arduino board began running the current
program. This number will overflow (go back to zero), after approximately 50 days. Alternatively for faster timings
the micros() function can be used. This returns the number of microseconds since the Arduino board began
running the current program. This number will overflow (go back to zero), after approximately 70 minutes.

We will use the millis() function to control our LED as before. Since the delay() function is not used the
processor is not tied up waiting and can carry out any additional processing in the main loop that is needed

/* Flashing LED Version 2


* ------------------------
*
* Turns on and off a light emitting diode(LED) connected to a digital
* pin, in intervals of 2 seconds using millis() function
*
*/
int ledPin = 13; // LED connected to digital pin 13
unsigned long currentTime;
unsigned long loopTime;

void setup()
{
pinMode(ledPin, OUTPUT); // sets the digital pin as output
currentTime = millis();
loopTime = currentTime;
}

void loop()
{
currentTime = millis();
if(currentTime >= (loopTime + 1000)){
digitalWrite(ledPin, !digitalRead(ledPin)); // toggles the LED on/off
loopTime = currentTime; // Updates loopTime
}
// Other processing can be done here
}

A Repeating Timer using elapsedMillis

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).

#include <elapsedMillis.h>
int led = 13;
elapsedMillis timer0;
#define interval 1000 // the interval in mS

void setup() {
pinMode(led, OUTPUT);
timer0 = 0; // clear the timer at the end of startup
}

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);
}
}

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>
int led = 13;
elapsedMillis timer0;

#define interval 500 // the interval in mS


boolean timer0Fired;

void setup() {
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
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 incrementing to the
next interval
// toggle led
if (digitalRead(led)) {
digitalWrite(led, LOW);
} else {
digitalWrite(led, HIGH);
}
}
}

Single Shot Timer


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)) {
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);
} else {
digitalWrite(led, HIGH);
}
}
}

Example code: count down timers- both repeating and one off

that will reliably execute even if loop() takes more the 1mS to execute.

/*
Robust Timer
Works even if sometimes the loop() takes longer the 1mS to
execute.
*/

static unsigned long lastMillis = 0;


static int timer_1 = 0; // timer1 is repeat timer
#define TIMER_INTERVAL_1 2000 // 2S interval
static int timer_2 = 0; // timer2 is oneshot timer
#define TIMER_INTERVAL_2 5000// 5 sec interval

void setup() {
timer_1 = TIMER_INTERVAL_1;
timer_2 = TIMER_INTERVAL_2;

Serial.begin(9600);
while (Serial.available()) {
}
Serial.println("Timer Begin");
lastMillis = millis();
}

void loop() {
unsigned long deltaMillis = 0; // clear last result
unsigned long thisMillis = millis();

if (thisMillis != lastMillis) {
deltaMillis = thisMillis-lastMillis;
lastMillis = thisMillis;
}
if (deltaMillis> 0) {
// handle one off timer
if (timer_2 > 0) { // still counting down
timer_2 -= deltaMillis;
if (timer_2 <= 0) {
// timer2 timed out
Serial.println("oneoff Timer2 timed out");
}
}

// handle repeating timer


timer_1 -= deltaMillis;
if (timer_1 <= 0) {
// reset timer since this is a repeating timer
timer_1 += TIMER_INTERVAL_1;

Serial.println("Repeating Timer1 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.

Motor control example:


unsigned long interval = 20000UL; // 20,000 ms = 20s
unsigned long previousMillis = 0;
int E1 = 5;
int M1 = 4;
int Led1 = 9;
int Led2 = 10;
int Led3 = 11;
int x;
int i;

String readString;
//#include
//LiquidCrystal_I2C lcd(0x20,16,2);

char command = '\0';


int pwm_speed; //from 0 – 255

void setup() {
pinMode(Led1, OUTPUT);
pinMode(Led2, OUTPUT);
pinMode(Led3, OUTPUT);
pinMode(M1, OUTPUT);
Serial.begin(9600);

// lcd.init(); // initialize the lcd


// lcd.backlight();
// lcd.home();
}

void loop()
{
char *help_menu = "\’e\’ go forward\n\’d\’ stop\n\’s\’ left\n\’f\’
right\n\’c\’ go backward\n";

if (Serial.available() > 0)
{
command = Serial.read();

switch (command)
{
case 'e': //go forward
forward();
break;

case 'c':
reverse();
break;

case 'd':
Stop();
break;
}
command = '\0'; //reset command
}
if ((unsigned long)(millis() - previousMillis) >= interval) {
Stop();
}
}

void forward() {
Serial.println("Go!!\r\n");
digitalWrite(M1, LOW);
digitalWrite(Led1, HIGH);
digitalWrite(Led2, LOW);
digitalWrite(Led3, LOW);
// lcd.setCursor(0, 0);
// lcd.print("forward");
analogWrite(E1, 255); //PWM speed control
previousMillis = millis();
}

void reverse() {
Serial.println("Back!!\r\n");
digitalWrite(M1, HIGH);
digitalWrite(Led1, LOW);
digitalWrite(Led2, HIGH);
digitalWrite(Led3, LOW);
// lcd.setCursor(0, 0);
// lcd.print("backward");
analogWrite(E1, 255); //PWM speed control
previousMillis = millis();
}

void Stop() {
analogWrite(E1, 0); //PWM speed control
digitalWrite(Led1, LOW);
digitalWrite(Led2, LOW);
digitalWrite(Led3, HIGH);
Serial.println("Stop!\r\n"); // usually you want to stop immediately
// lcd.setCursor(0, 0);
// lcd.print("stop ");
}

========Multitask LED example==========


Pin 13 will flash on and off once per second
Pin 12 will flash on and off once per second, starting 1 second after Pin 13
pin 11 will flash on and off once every 2 seconds, starting 3 second after Pin 13

long sequenceDelay = 1000; //delay from turning On LED12 after LED13


long sequenceDelay2 = 2000; //Delay from turning on LED11 after LED12

long flashDelay = 1000;


long flashDelay2 = 2000;

boolean LED13state = false;


boolean LED12state = false;
boolean LED11state = false;

long waitUntil13 = 0;
long waitUntil12 = sequenceDelay;
long waitUntil11 = sequenceDelay + sequenceDelay2;

void setup() {
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
pinMode(11, OUTPUT);
}
void loop() {
if (millis() >= waitUntil13) {
LED13state = !(LED13state);
waitUntil13 += flashDelay;
}

if (millis() >= waitUntil12) {


LED12state = !(LED12state);
waitUntil12 += flashDelay;
}

if (millis() >= waitUntil11) {


LED11state = !(LED11state);
waitUntil11 += flashDelay2;
}
digitalWrite(13, LED13state);
digitalWrite(12, LED12state);
digitalWrite(11, LED11state);

================

Ex1: using Delay() problem


if digitalreadA==Down
then digitalWriteA ON , delay 15 sec , digitalWriteA OFF
if digitalreadB==Down
then digitalWriteB ON , delay 15 sec , digitalWriteB OFF

This code can not turn on both LEDs no matter how you push the
buttons.This is whydelay() is fatal and very wrong if you need to
do more than one single thing at a time.

You can use code using millis() function

Ex2: Two seperate "timers start and stop independently.

unsigned long TimerA "ALWAYS use unsigned long for timers..."


unsigned long TimerB

if digitalReadA==Down
then TimerA= millis() , digitalWriteA ON
if millis()-TimerA >= 15000UL
then digitalWriteA Off
if digitalReadB==Down
then TimerB= millis() , digitalWriteB ON
if millis()-TimerB >= 15000UL
then digitalWriteB Off

Ex3: Timer with State change

boolean LEDon = false


unsigned long Timer "ALWAYS use unsigned long"

if not LEDon and digitalRead==Down


then "set timer" Timer= millis , digitalWrite ON , LEDon = true
if LEDon and millis-Timer >= 15000UL
then digitalWrite Off , LEDon = false

Result: This will not do a digitalRead or reset the timer, once the
LED has turned on, ie we are starting the timer on button push
(like attempt 1 earlier). Likewise it only tests the timer if the LED
is on, and only turns it off once (which make very little difference,
so I would normally omit the LEDon test in the 2nd part)

And this will work fine with two or more buttons and LEDs, as the
timers are independent and the code will not block.

Example 4

One button, one LED - each with their own timer; A more
usefull(?) example of doing two timing things "at once"

boolean LEDon = false


boolean buttondown = false
unsigned long LEDtimer = 0 "ALWAYS use unsigned long..."
unsigned long buttontimer = 0

if millis - buttontimer >= 5UL "debounce 5 millisec"


and not buttondown and digitalReadButton==Down
then buttondown = true , buttontimer = millis
if millis - buttontimer >= 5UL
and buttondown and digitalReadButton==Up
then buttondown = false , buttontimer = millis

if not LEDon and buttondown "can use: not buttondown"


then LEDtimer = millis , digitalWrite ON , ledon = true
if millis - LEDtimer >= 15000UL
then digitalWrite Off , LEDon = false
Result: The button timer will purposefully skip digitalRead of the
button for 5 millisec after it has changed. This filters away the
"noise" in any mechanical button. The Led on/off code can be set
to trigger on button down or up.

A challenge :)

If you use a previousbuttonup indicator instead of LEDon, you can


ensure that the button has to be released before a new timer
cycle can start - but that is left as an exercise, and is more about
state transition than about timers.

millis() Tutorial: Arduino Multitasking

A fter learning how to flash a single LED on your Arduino, you are

probably looking for a way to make cool patterns, but feel limited by the
use of delay(). If you ask in the forums you get told to look at the “Blink
Without Delay” example. This example introduces the idea of replacing
delay() with a state machine. If you’re confused how to use it, this tutorial
is setup to take you from blinking two LEDs with delay, to using an
alternate method, right down to how you can use millis().
Instead of “waiting a certain amount of time” like you do with delay(), you can use millis()
to ask “how much time has passed”?

Let’s start by looking at a couple of ways you can use delay() to flash LEDs.
Example #1: Basic Delay
This is the basic delay example you are probably already familiar with. It is included in the
Arduino IDE’s Examples as “Blink.”

void setup() {
pinMode(13, OUTPUT);
}
void loop() {
digitalWrite(13, HIGH); // set the LED on
delay(1000); // wait for a second
digitalWrite(13, LOW); // set the LED off
delay(1000); // wait for a second
}

Note that cpu is blocked for entire delay period doing nothing.

Example #2: Basic Delay with for() loops


For our 2nd example, we are only going to delay for 1ms, but do so inside of a for() loop.

void setup() {
pinMode(13, OUTPUT);
}

void loop() {
digitalWrite(13, HIGH); // set the LED on
for (int x=0; x < 1000; x++) { // Wait for 1 second
delay(1);
}
digitalWrite(13, LOW); // set the LED on
for (int x=0; x < 1000; x++) { // Wait for 1 second
delay(1);
}
}
This new sketch will accomplish the same sequence as Example #1. The difference is that the
Arduino is only “delayed” for 1 millisecond at a time. A clever trick would be to call other
functions inside of that for() loop. However, your timing will be off because those
instructions will add additional delay.

Example #3: for() loops with 2 LEDs


In this example, we’ve added a second LED on Pin 12 (with a current limiting resistor!).
Now let’s see how we could write the code from Example #2 to flash the 2nd LED.

void setup() {
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
}

void loop() {
digitalWrite(13, HIGH); // set the LED on
for (int x=0; x < 1000; x++) { // wait for a secoond
delay(1);
if (x==500) {
digitalWrite(12, HIGH);
}
}
digitalWrite(13, LOW); // set the LED off
for (int x=0; x < 1000; x++) { // wait for a secoond
delay(1);
if (x==500) {
digitalWrite(12, LOW);
}
}
}
Starting with the first for() loop, while Pin 13 is high, Pin 12 will turn on after 500 times
through the for() loop. It would appear that Pin 13 and Pin 12 were flashing in Sequence.
Pin 12 would turn on 1/2 second after Pin 13 turns on. 1/2 second later Pin 13 turns off,
followed by Pin 12 another 1/2 second.

This is pretty complicated looking though isn’t it?

If you wanted to add other LEDs or change the sequence, you have to start getting really
clever with all of the if-statements. Not to mention the comment from example #2. The
timing of these LEDs is going to be off, because the if() statement and digitalWrite() function
all take time, adding to the “delay()”.

So… let’s look at how millis() gets around this problem.

Example #4: Blink with millis()


This is the same “Blink” example from #1 re-written to make use of millis().

BinkWithoutDelay illustrates a very important concept known as a State Machine.


Instead of relying on delay() to time the blinking. BlinkWithoutDelay remembers the current
state of the LED and the last time it changed. On each pass through the loop, it looks at the
millis() clock to see if it is time to change the state of the LED again.

unsigned long interval=1000; // the time we need to wait


unsigned long previousMillis=0; // millis() returns an unsigned long.

void setup() {
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
}

void loop() {
unsigned long currentMillis = millis();
if ((currentMillis - previousMillis) >= interval) {
previousMillis = currentMillis;
digitalWrite(13, !digitalRead(13));
}
}
Millis() convert the “Blink” example into non-blocking code.

Example #5: Adding a 2nd LED with millis()


long sequenceDelay = 500;
long flashDelay = 1000;

boolean LED13state = false; // the LED will turn ON in the first iteration of l
boolean LED12state = false; // need to seed the light to be OFF
long waitUntil13 = 0; //equivalent to prevMillis_led13
long waitUntil12 = sequenceDelay; //equivalent to prevMillis_led12
void setup() {
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
}
void loop() {
digitalWrite(13, LED13state); // each iteration of loop() will set the IO p
digitalWrite(12, LED12state);
// checking to see if enough time has elapsed
if (millis() >= waitUntil13) {
LED13state = !(LED13state);
waitUntil13 += flashDelay;
// this if-statement will not execute for another 1000 milliseconds
}
// keep in mind, waitUntil12 was already seeded with a value of 500
if (millis() >= waitUntil12) {
LED12state = !(LED12state);
waitUntil12 += flashDelay;
}
}

Other Examples
Check out this list of millis() examples: http://www.baldengineer.com/millis-cookbook.html
There are examples to create a Police Light Strobe Effect, Time your Code, Change the ON-
time and OFF-time for a LED, and others.
Conclusion
At first it seems that using the millis() function will make a sketch more complicated than
using delay(). In some ways, this is true. However, the trade off is that the sketch becomes
significantly more flexible. Animations become much simpler. Talking to LCDs while
reading buttons becomes no problem. Virtually, you can make your Arduino multitask.

cant you help me how to me after 20 sec forward and reverse motor will stop automaticly

=======