arduino
Tijdsbeheer
Zoeken…
Syntaxis
niet-ondertekende lange millis ()
niet-ondertekende lange micro's ()
ongeldige vertraging (niet-ondertekende lange milliseconden)
ongeldige vertraging Microseconden (niet-ondertekende lange microseconden)
Zie de verouderde Millis-header voor constructors en operators van die klasse. In het kort:
- elapsedMillis elapsedMillisObject; maakt een object om de tijd bij te houden sinds het is gemaakt of sinds een ander expliciet ingesteld tijdstip
- elapsedMillisObject = 0; reset de tijd die door het object wordt gevolgd naar "sinds nu"
- unsigned long deltaT = elapsedMillisObject; laten we kijken naar de bijgehouden tijd
- elapsedMillisObject + = en - = deze werken zoals verwacht
Opmerkingen
Blokkerende versus niet-blokkerende code
Voor zeer eenvoudige schetsen kan het schrijven van blokkeercode met behulp van delay()
en delayMicroseconds()
geschikt zijn. Wanneer dingen complexer worden, kan het gebruik van deze functies enkele nadelen hebben. Sommige hiervan zijn:
- CPU-tijd verspillen: complexere schetsen hebben de CPU mogelijk voor iets anders nodig in afwachting van een LED-knipperperiode.
- onverwachte vertragingen: wanneer
delay()
wordt aangeroepen in subroutines die niet duidelijk worden genoemd, bijvoorbeeld in bibliotheken die u opneemt. - ontbrekende gebeurtenissen die plaatsvinden tijdens de vertraging en niet worden afgehandeld door een onderbrekingshandler, bijvoorbeeld pold-knopindrukken: een knop kan 100 ms worden ingedrukt, maar deze kan worden overschaduwd door een
delay(500)
.
Implementatie details
millis()
vertrouwt meestal op een hardwaretimer die draait op een snelheid die veel hoger is dan 1 kHz. Wanneer millis()
wordt aangeroepen, retourneert de implementatie enige waarde, maar je weet niet hoe oud dat eigenlijk is. Het is mogelijk dat de "huidige" milliseconde net is gestart of dat deze direct na die functieaanroep eindigt. Dat betekent dat bij het berekenen van het verschil tussen twee resultaten van millis()
, u bijna alles tussen bijna nul en bijna een milliseconde kunt hebben. Gebruik micros()
als een hogere precisie nodig is.
Kijkend naar de broncode van elapsedMillis
onthult dat het inderdaad millis()
intern gebruikt om twee punten in de tijd te vergelijken, dus het lijdt ook aan dit effect. Nogmaals, er is het alternatief verstreken elapsedMicros
voor hogere precisie, uit dezelfde bibliotheek.
blinky met vertraging blokkeren ()
Een van de meest eenvoudige manieren om een LED te laten knipperen is: zet het aan, wacht een beetje, schakel het uit, wacht opnieuw en herhaal eindeloos:
// 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
}
Wachten zoals gedaan in het bovenstaande voorbeeld verspilt CPU-cycli, omdat het gewoon in een lus zit te wachten op een bepaald tijdstip om voorbij te gaan. Dat is wat de niet-blokkerende manieren, met behulp van millis()
of elapsedMillis
, beter doen - in de zin dat ze niet zoveel van de hardware-mogelijkheden verbranden.
Niet-blokkerende blinky met de verstreken Millis-bibliotheek (en klasse)
De elapsedMillis-bibliotheek biedt een klasse met dezelfde naam die de tijd bijhoudt die is verstreken sinds deze is gemaakt of op een bepaalde waarde is ingesteld:
#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
}
U kunt in het voorbeeld zien dat het ledTime
object nul is toegewezen toen de LED-pin werd omgeschakeld. Dit is op het eerste gezicht misschien niet verrassend, maar het heeft wel effect als er meer tijdrovende dingen gebeuren:
Overweeg een situatie waarin de vergelijking tussen ledTime
en PERIOD
na 750 milliseconden wordt gedaan. Als u ledTime
op nul ledTime
betekent dit dat alle volgende ledTime
250 ms "te laat" zijn. Als PERIOD
daarentegen werd afgetrokken van ledTime
, zou de LED een korte periode zien en vervolgens blijven knipperen alsof er niets gebeurde.
Niet-blokkerende blinky met millis ()
Dit komt heel dicht in de buurt van een voorbeeld uit de Arduino-documenten :
// 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
}
millis()
op deze manier gebruiken - om operaties op een niet-blokkerende manier te timen - is iets dat vrij vaak nodig is, dus overweeg hiervoor de elapsedMillis
bibliotheek te gebruiken.
Meet hoe lang iets heeft geduurd met behulp van elapsedMillis en verstreken Micros
#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() {
}
In dit voorbeeld worden een elapsedMillis
object en een elapsedMicros
object gebruikt om te meten hoe lang iets heeft elapsedMicros
, door ze te maken net voordat de expressie die we willen tijd wordt uitgevoerd, en hun waarden achteraf te krijgen. Ze zullen iets andere resultaten vertonen, maar het milliseconde-resultaat zal niet meer dan één milliseconde uitblijven.
Meer dan 1 taak zonder vertraging ()
Als u meer dan 1 taak hebt om herhaaldelijk met verschillende intervallen uit te voeren, gebruikt u dit voorbeeld als uitgangspunt:
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()");
}
Om een andere taak om elke 15 seconden uit te voeren toe te voegen, het uitbreiden van de variabelen intervals
en last
:
unsigned long intervals[] = {250,2000,15000};
unsigned long last[] = {0,0,0};
Voeg vervolgens een if
instructie toe om de nieuwe taak uit te voeren. In dit voorbeeld noemde ik het thirdTask
.
if(now-last[2]>=intervals[2]){ last[2]=now; thirdTask(); }
Declareer ten slotte de functie:
void thirdTask(){
//your code here
}