arduino
Tidsplanering
Sök…
Syntax
osignerad lång millis ()
osignerade långa mikros ()
ogiltig fördröjning (osignerade långa millisekunder)
void delayMicroseconds (osignerade långa mikrosekunder)
Se den förflutna Millis-rubriken för konstruktörer och operatörer i den klassen. Kortfattat:
- elapsedMillis elapsedMillisObject; skapar ett objekt för att hålla reda på tiden sedan den skapades eller eftersom någon annan uttryckligen ställd tidpunkt
- elapsedMillisObject = 0; återställa tiden som spåras av objektet till "sedan nu"
- osignat långt deltaT = förflutetMillisObject; låter oss titta på den spårade tiden
- elapsedMillisObject + = och - = dessa fungerar som förväntat
Anmärkningar
Blockering kontra icke-blockerande kod
För mycket enkla skisser kan det vara lämpligt att skriva blockeringskod med delay()
och delayMicroseconds()
. När saker och ting blir mer komplicerade kan användningen av dessa funktioner ha vissa nackdelar. Några av dessa är:
- Slösa bort CPU-tid: Mer komplexa skisser kan behöva CPU för något annat medan du väntar på att en LED-blinkande period slutar.
- oväntade förseningar: när
delay()
kallas i subroutiner som inte uppenbarligen kallas, till exempel i bibliotek som du inkluderar. - saknade händelser som inträffar under förseningen och som inte hanteras av en avbrottshanterare, till exempel pressade knapptryckningar: En knapp kan tryckas in i 100 ms, men detta kan skuggas av en
delay(500)
.
Implementeringsinformation
millis()
förlitar sig vanligtvis på en hårdvarutimer som kör med en hastighet som är mycket högre än 1 kHz. När millis()
kallas returnerar implementeringen ett värde, men du vet inte hur gammalt det faktiskt är. Det är möjligt att det "nuvarande" millisekundet just har börjat, eller att det kommer att avslutas direkt efter det funktionssamtalet. Det betyder att när du beräknar skillnaden mellan två resultat från millis()
kan du vara av med allt mellan nästan noll och nästan ett millisekund. Använd micros()
om högre precision behövs.
elapsedMillis
att elapsedMillis
källkoden för elapsedMillis
avslöjas att den verkligen använder millis()
internt för att jämföra två punkter i tid, så det lider också av denna effekt. Återigen finns det alternativet elapsedMicros
för högre precision, från samma bibliotek.
blockerar blinkande med försening ()
Ett av de mest raka sätten att få en LED-blinkning är: slå på den, vänta lite, stäng av den, vänta igen och upprepa oändligt:
// set constants for blinking the built-in LED at 1 Hz
#define OUTPIN LED_BUILTIN
#define PERIOD 500
void setup()
{
pinMode(OUTPIN, OUTPUT); // sets the digital pin as output
}
void loop()
{
digitalWrite(OUTPIN, HIGH); // sets the pin on
delayMicroseconds(PERIOD); // pauses for 500 miliseconds
digitalWrite(OUTPIN, LOW); // sets the pin off
delayMicroseconds(PERIOD); // pauses for 500 milliseconds
// doing other time-consuming stuff here will skew the blinking
}
Men att vänta som gjort i exemplet ovan slösar CPU-cykler, eftersom det bara sitter där i en slinga och väntar på att en viss tidpunkt ska gå förbi. Det är vad de icke-blockerande sätten, med millis()
eller elapsedMillis
, gör bättre - i den meningen att de inte bränner så mycket av maskinvarans kapacitet.
Blinkar inte med det förflutnaMillis-biblioteket (och klass)
Det förflutnaMillis-biblioteket ger en klass med samma namn som håller reda på tiden som gick sedan det skapades eller sattes till ett visst värde:
#include <elapsedMillis.h>
#define OUTPIN LED_BUILTIN
#define PERIOD 500
elapsedMillis ledTime;
bool ledState = false;
void setup()
{
// initialize the digital pin as an output.
pinMode(OUTPIN, OUTPUT);
}
void loop()
{
if (ledTime >= PERIOD)
{
ledState = !ledState;
digitalWrite(OUTPIN, ledState);
ledTime = 0;
}
// do other stuff here
}
Du kan se i exemplet att ledTime
objektet tilldelas noll när LED-stiftet växlades. Detta kanske inte är förvånande vid första anblicken, men det har en effekt om mer tidskrävande saker händer:
Överväg en situation där jämförelsen mellan ledTime
och PERIOD
görs efter 750 millisekunder. ledTime
ställer ledTime
till noll betyder det att alla följande växlingsoperationer kommer att vara 250 ms "sent". Om PERIOD
, PERIOD
, subtraherades från ledTime
, skulle lysdioden se en kort period och fortsätta att blinka som om ingenting hänt.
Icke-blockerande blink med millis ()
Detta är mycket nära ett exempel från arduino docs :
// set constants for blinking the built-in LED at 1 Hz
#define OUTPIN LED_BUILTIN
#define PERIOD 500 // this is in milliseconds
int ledState = LOW;
// millis() returns an unsigned long so we'll use that to keep track of time
unsigned long lastTime = 0;
void setup() {
// set the digital pin as output:
pinMode(OUTPIN, OUTPUT);
}
void loop() {
unsigned long now = millis();
if (now - lastTime >= PERIOD) // this will be true every PERIOD milliseconds
{
lastTime = now;
if (ledState == LOW)
{
ledState = HIGH;
}
else
{
ledState = LOW;
}
digitalWrite(OUTPIN, ledState);
}
// now there's lots of time to do other stuff here
}
Att använda millis()
på detta sätt - till tidsoperationer på ett icke-blockerande sätt - är något som behövs ganska ofta, så elapsedMillis
använda det elapsedMillis
biblioteket för detta.
Mät hur lång tid något tog med hjälp av elapsedMillis och elapsedMicros
#include <elapsedMillis.h>
void setup() {
Serial.begin(115200);
elapsedMillis msTimer;
elapsedMicros usTimer;
long int dt = 500;
delay(dt);
long int us = usTimer;
long int ms = msTimer;
Serial.print("delay(");Serial.print(dt);Serial.println(") took");
Serial.print(us);Serial.println(" us, or");
Serial.print(ms);Serial.println(" ms");
}
void loop() {
}
I det här exemplet används ett elapsedMillis
objekt och ett elapsedMicros
objekt för att mäta hur lång tid något tog, genom att skapa dem strax innan uttrycket vi vill att tiden körs och få sina värden efteråt. De kommer att visa något olika resultat, men millisekundresultatet kommer inte att vara av med mer än ett millisekund.
Mer än 1 uppgift utan dröjsmål ()
Om du har mer än 1 uppgift att utföra upprepade gånger med olika intervall, använd detta exempel som utgångspunkt:
unsigned long intervals[] = {250,2000}; //this defines the interval for each task in milliseconds
unsigned long last[] = {0,0}; //this records the last executed time for each task
void setup() {
pinMode(LED_BUILTIN, OUTPUT); //set the built-it led pin as output
Serial.begin(115200); //initialize serial
}
void loop() {
unsigned long now = millis();
if(now-last[0]>=intervals[0]){ last[0]=now; firstTask(); }
if(now-last[1]>=intervals[1]){ last[1]=now; secondTask(); }
//do other things here
}
void firstTask(){
//let's toggle the built-in led
digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN)?0:1);
}
void secondTask(){
//say hello
Serial.println("hello from secondTask()");
}
För att lägga till en annan uppgift att utföra var 15: e sekund, förläng variablernas intervals
och last
:
unsigned long intervals[] = {250,2000,15000};
unsigned long last[] = {0,0,0};
Lägg sedan till ett if
uttalande för att utföra den nya uppgiften. I det här exemplet thirdTask
jag det thirdTask
.
if(now-last[2]>=intervals[2]){ last[2]=now; thirdTask(); }
Förklara slutligen funktionen:
void thirdTask(){
//your code here
}