Stap 1: Knipperen zonder Delay()
Tot nu toe dat we zijn met behulp van de functie delay() om te pauzeren de Arduino schets even zo dat een beetje tijd kunt doorgeven tussen twee Arduino opdrachten. In de LED knipperen schets gebruikten we delay() om in te stellen hoe lang die de Arduino werd aangestoken en de hoeveelheid tijd uitgeschakeld:
digitalWrite (ledPin, hoge); //turn LED op
delay(1000); / / wait gedurende 1000 milliseconden (1 seconde)
digitalWrite (ledPin, laag); //turn LED uit
vertraging (1000); //wait één seconde
Soms gebruik van delay() is niet een geweldige optie, omdat de Arduino elke secundaire taken niet worden uitgevoerd terwijl de vertraging is gebeurd. Stel dat we wilden een LED knipperen en een druk op de knop op hetzelfde moment met behulp van delay() detecteren:
loop {}
digitalWrite (ledPin, hoge);
delay(1000);
digitalWrite (ledPin, laag);
delay(1000);
Boole buttonState = digitalRead(7);
}
In de code hierboven, zijn we alleen meten de knop eenmaal om de twee seconden, dus het tot twee seconden duren kan voordat een druk op de knop wordt ontdekt, en kort persen niet ooit krijgen herkend helemaal.
Millis() geeft ons controle wanneer gebeurtenissen plaatsvinden zonder pauzes in de schets. Telkens we millis() in een schets van de Arduino noemen, het geeft als resultaat het aantal milliseconden sinds de Arduino was ingeschakeld.
Voer de volgende code om te zien hoe millis() werkt:
//recording time with Arduino millis() void setup() { Serial.begin(9600); } void loop() { unsigned long currentMillis = millis(); Serial.println(currentMillis); }
Hier is hoe te het gebruiken van millis() te knipperen van een LED zonder gebruik te maken van delay().
//blink led without delay() int ledPin = 7; int ledState = LOW;//current state of the LED unsigned long timeOfLastLedEvent = 0;//the last time the LED was updated int intervalON = 1000;//how long we want the LED to stay on int intervalOFF = 500;//how long we want the LED to stay off void setup() { pinMode(ledPin, OUTPUT); digitalWrite(ledPin, ledState); } void loop() { unsigned long currentMillis = millis(); if (ledState == LOW){//if the LED is already off if (currentMillis - timeOfLastLedEvent > intervalOFF){//and enough time has passed digitalWrite(ledPin, HIGH);//turn it on ledState = HIGH;//store its current state timeOfLastLedEvent = currentMillis;//update the time of this new event } } else {//if the LED is already on if (currentMillis - timeOfLastLedEvent > intervalON){ digitalWrite(ledPin, LOW); ledState = LOW; timeOfLastLedEvent = currentMillis; } } }
De bovenstaande sketch introduceert enkele nieuwe dingen:
niet-ondertekende lang is een ander gegevenstype (zo ver we hebben gezien int en boolean). Unsigned long is zoals int, maar groter, leg ik uit... Elk gegevenstype vereist een bepaalde hoeveelheid ruimte in het geheugen van de Arduino en de hoeveelheid ruimte die de Arduino omhoog voor een gegeven variabele bevrijdt dicteert de min en max waarden kan worden opgeslagen in de variabele. Bijvoorbeeld, kan int de variëren van-32,768 tot 32.767, als u geprobeerd te doen iets als dit:
int myVariable = 100.000 belonen;
Je zou eindigen met een zeer vreemde bug in je code. Dit lijkt misschien een willekeurig bereik, maar het komt uit het feit dat de int 16 bits van de ruimte in het geheugen van de Arduino vereist en u met 16 bits van binaire getallen van 0 tot kunt (2 ^ 16 - 1) = 65535. Maar mensen besloten dat int moet zitten kundig voor negatieve getallen ook opslaan zodat één van de bits in de 16-bits getal dat wordt gebruikt voor het opslaan van het teken (positief of negatief) en de overige 15 bits waarde opslaan: 2 ^ 15 = 32768. Met inbegrip van 0, we eindigen met het bereik-32,768 tot 32.767. Een ander gegevenstype genoemd een insigned int slaat geen teken, dus het wordt het bereik van 0 tot 65535 dat ik berekend vóór, maar u kunt ook een negatief getal opslaan in een insigned int.
Wanneer we getallen groter dan 65535 of minder dan-32768 gebruiken moeten, gebruiken wij een gegevenstype langegenoemd. Lang 32 bits van ruimte in het geheugen van de Arduino is toegewezen. 2 ^ 32 = 4,294,967,296, centreren dit rond nul om allerlei:-2,147,483,648 naar 2,147,483,647. Niet-ondertekende lang heeft, zoals de unsigned int zijn altijd positief, dus ze variëren van 0 tot 4.294.967.295.
Er is geen grotere gegevenstype voor het opslaan van getallen dan lang, dus als u opslaan een getal groter dan 4.294.967.295 wilt, u zult moeten komen met een verschillende manier te slaan (misschien de eerste 9 bits in één getal en de laatste negen andere?). Deze beperking heeft sommige interessante gevolgen voor de millis()-functie. Aangezien millis niet-ondertekende longs retourneert, en wordt het in milliseconden voortdurend tot nu toe, zal millis() eigenlijk opnieuw terug naar nul keer het bereikt:
4.294.967.295 ms
= 4,294, 967seconds
= 49.71 dagen
Als u millis() gebruikt en u van plan bent op houden die u project uitgevoerd voor langere tijd zonder ooit het uitschakelen of opnieuw instellen, moet u zich bewust van dit.
Nog een opmerking over gegevenstypen: We kunnen gebruiken de lange of niet-ondertekende long deze hele tijd wanneer wij verklaren pin-codes of andere variabelen in de voorbeeld schetsen tot nu toe, maar over het algemeen is het een goed idee om de kleinste gegevens te gebruiken Typ mogelijk voor een variabele, op die manier heb je veel extra ruimte in het geheugen van de Arduino voor andere dingen. In de Arduino, longs worden zelden gebruikt, maar millis() is een goed voorbeeld van wanneer ze van pas komen.
Om terug naar de schets, is het algemene idee om te slaan de laatste keer dat u de LED van een knevel gevoorzid in- of uitschakelen en vergelijk dat met de huidige tijd geretourneerd door millis(). Zodra het verschil tussen die twee keer groter dan sommige interval is, weet u is het tijd om de LED opnieuw in-/ uitschakelen. Ik heb enkele nieuwe opslag variabelen ingesteld om dit te doen:
int ledState = laag; //current staat van de LED
unsigned long timeOfLastLedEvent = 0; //the laatste keer dat de LED werd bijgewerkt
int intervalON = 1000; //how lang we willen de LED te blijven
int intervalOFF = 500; //how lang we willen de LED te blijven uit
In de loop is er een bos van logica die controleert om te zien of u genoeg tijd heeft doorgegeven, en als dat zo is, schakelt de LED, werkt u de variabele "timeOfLastLedEvent", en schakelt u de opgeslagen toestand van de LED. De logica wordt tweemaal herhaald zodra voor het geval dat de LED is hoog, en eenmaal voor het geval dat de LED laag is, zal ik herhaal het lage geval hieronder:
Als (currentMillis - timeOfLastLedEvent > intervalOFF) {//and voldoende tijd verstreken
digitalWrite (ledPin, hoge); //turn op
ledState = hoog; //store zijn huidige toestand
timeOfLastLedEvent = currentMillis; //update de tijd van dit nieuwe evenement
}
currentMillis is een niet-ondertekende lange vertegenwoordigt de huidige tijd dat wordt bijgewerkt telkens wanneer die de Arduino loop functie wordt gestart. (currentMillis - timeOfLastLedEvent) geeft de sinus van de tijd de LED's staat voor het laatst werd gewijzigd, we vergelijken dit tegen de intervalOFF om te zien of is het tijd om het uitschakelen van de LED, als het niet de Arduino zal houden currentMillis bijwerken en opnieuw controleren tot het tijd is.