- Wat is multitasking?
- Waarom delay () overslaan in Arduino?
- Waarom millis () gebruiken?
- Componenten vereist
- Schakelschema
- Programmeren van Arduino UNO voor multitasking
De multitasking heeft de computers tot een revolutie geleid waarbij een of meer programma's tegelijkertijd kunnen worden uitgevoerd, wat de efficiëntie, flexibiliteit, aanpasbaarheid en productiviteit verhoogt. In embedded systemen kunnen microcontrollers ook multitasking aan en voeren ze twee of meer taken tegelijkertijd uit zonder de huidige instructies te onderbreken.
Hier in deze tutorial zullen we leren hoe Arduino multitasking uitvoert met de Arduino millis-functie. Over het algemeen wordt een delay () -functie gebruikt in Arduino voor een periodieke taak zoals LED Blinking, maar deze delay () -functie stopt het programma voor een bepaalde tijd en staat geen andere bewerkingen toe om uit te voeren. Dus dit artikel legt uit hoe we het gebruik van de delay () -functie kunnen vermijden en deze kunnen vervangen door millis () om meer dan één taak tegelijkertijd uit te voeren en de Arduino een multitasking-controller te maken. Voordat we in detail treden, laten we beginnen met het onderschatten van multitasking.
Wat is multitasking?
Multitasking betekent simpelweg dat je meer dan één taak of programma tegelijk uitvoert. Bijna alle besturingssystemen zijn voorzien van multitasking. Dit soort besturingssystemen staat bekend als MOS (multitasking-besturingssysteem). De MOS kan een mobiel besturingssysteem of een desktop-pc zijn. Het goede voorbeeld van multitasking op computers is wanneer gebruikers de e-mailtoepassing, internetbrowser, mediaspeler, games tegelijkertijd gebruiken en als gebruikers de toepassing niet willen gebruiken, wordt deze op de achtergrond uitgevoerd als deze niet is gesloten. De eindgebruiker gebruikt al deze applicaties tegelijkertijd, maar OS neemt dit concept een beetje anders. Laten we bespreken hoe OS multitasking beheert.
Zoals te zien is in de afbeelding, verdeelt de CPU de tijd in drie gelijke delen en wijst elk deel aan elke taak / toepassing toe. Dit is hoe de multitasking wordt gedaan in de meeste systemen. Het concept zal bijna hetzelfde zijn voor de Arduino Multitasking, behalve dat de tijdverdeling een beetje anders zal zijn. Omdat de Arduino in een lage frequentie werkt en het RAM-geheugen vergelijkbaar is met die van laptop / mobiel / pc, zal de tijd die aan elke taak wordt besteed ook anders zijn. Arduino heeft ook een delay () -functie die veel wordt gebruikt. Maar laten we, voordat we beginnen, bespreken waarom we de functie delay () in geen enkel project mogen gebruiken.
Waarom delay () overslaan in Arduino?
Als de referentiedocumentatie van Arduino in overweging wordt genomen, zijn er twee soorten vertragingsfuncties, de eerste is delay () en de tweede is delayMicroseconds (). Beide functies zijn identiek wat betreft het genereren van vertraging. Het enige verschil is dat, in de functie delay (), de doorgegeven parameter integer in milliseconden is, dwz als we delay (1000) schrijven, dan is de vertraging 1000 milliseconden, dwz 1 seconde. Evenzo in de functie delayMicroseconds (), is de doorgegeven parameter in microseconden, dwz als we delayMicroseconds (1000) schrijven, dan is de vertraging 1000 microseconden, dwz 1 milliseconden.
Hier komt het punt, beide functies pauzeren het programma voor de hoeveelheid tijd die is verstreken in de vertragingsfunctie. Dus als we een vertraging van 1 seconde geven, kan de processor pas naar de volgende instructie gaan als er 1 seconde is verstreken. Evenzo, als de vertraging 10 seconden is, stopt het programma gedurende 10 seconden en zal de processor de volgende instructies niet toestaan totdat de 10 seconden zijn verstreken. Dit belemmert de prestaties van de microcontroller in termen van snelheid en het uitvoeren van de instructies.
Het beste voorbeeld om het nadeel van de vertragingsfunctie uit te leggen, is het gebruik van twee drukknoppen. Bedenk dat we twee LED's willen schakelen met behulp van twee drukknoppen. Dus als een drukknop wordt ingedrukt, moet de bijbehorende LED 2 seconden branden, en als de tweede wordt ingedrukt, moet de LED 4 seconden branden. Maar als we delay () gebruiken, als de gebruiker op de eerste knop drukt, stopt het programma voor 2 seconden en als de gebruiker op de tweede knop drukt vóór 2 seconden vertraging, dan accepteert de microcontroller de invoer niet zoals het programma is in stopfase.
De officiële documentatie van Arduino vermeldt dit duidelijk in de functiebeschrijving Notes en Warnings of delay (). U kunt dit doornemen en controleren om het duidelijker te maken.
Waarom millis () gebruiken?
Om het probleem op te lossen dat wordt veroorzaakt door het gebruik van vertraging, moet een ontwikkelaar de millis () -functie gebruiken die gemakkelijk te gebruiken is als je eenmaal gewend bent en die 100% CPU-prestaties zal gebruiken zonder enige vertraging bij het uitvoeren van de instructies. millis () is een functie die alleen het aantal milliseconden retourneert dat is verstreken sinds het Arduino-bord het huidige programma begon uit te voeren zonder het programma te bevriezen. Dit tijdsgetal zal na ongeveer 50 dagen overlopen (dwz teruggaan naar nul).
Net zoals Arduino delayMicroseconds () heeft, heeft het ook de microversie van millis () als micros (). Het verschil tussen micros en millis is dat de micros () na ongeveer 70 minuten overlopen, vergeleken met millis (), wat 50 dagen is. Dus afhankelijk van de toepassing kun je millis () of micros () gebruiken.
Millis () gebruiken in plaats van delay ():
Om de millis () voor timing en vertraging te gebruiken, moet u de tijd waarop de actie plaatsvond registreren en opslaan om de tijd te starten en vervolgens met tussenpozen controleren of de gedefinieerde tijd is verstreken. Sla zoals gezegd de huidige tijd op in een variabele.
unsigned lange currentMillis = millis ();
We hebben nog twee variabelen nodig om erachter te komen of de vereiste tijd is verstreken. We hebben de huidige tijd opgeslagen in de variabele currentMillis , maar we moeten ook weten wanneer de timingperiode begon en hoe lang de periode is. Dus het interval en de vorige millis worden gedeclareerd. Het interval vertelt ons de vertraging en previosMillis slaat de laatste keer dat de gebeurtenis heeft plaatsgevonden op.
niet-ondertekende lange vorigeMillis; ongetekende lange periode = 1000;
Om dit te begrijpen, nemen we een voorbeeld van een eenvoudig knipperende LED. De periode = 1000 geeft aan dat de LED 1 seconde of 1000 ms knippert.
const int ledPin = 4; // het LED-pincode aangesloten int ledState = LOW; // gebruikt om de LED-status niet-ondertekend lang previousMillis = 0 in te stellen; // zal de laatste keer dat de LED knippert const lange periode = 1000 opslaan ; // periode waarin te knipperen in ms void setup () { pinMode (ledPin, OUTPUT); // stel ledpin in als uitvoer } void loop () { unsigned long currentMillis = millis (); // sla de huidige tijd op if (currentMillis - previousMillis> = period) {// controleer of 1000ms voorbij is previousMillis = currentMillis; // bewaar de laatste keer dat je de LED knipperde if (ledState == LOW) {// als de LED uit is, zet hem aan en vice versa ledState = HIGH; } else { ledState = LOW; } digitalWrite (ledPin, ledState); // stel LED in met ledState om weer te knipperen } }
Hier de verklaring
Onderbrekingen in Arduino werken hetzelfde als in andere microcontrollers. Het Arduino UNO-bord heeft twee aparte pinnen voor het bevestigen van interrupts op GPIO-pin 2 en 3. We hebben het in detail besproken in Arduino Interrupts Tutorial, waar je meer kunt leren over Interrupts en hoe je ze kunt gebruiken.
Hier zullen we Arduino Multitasking laten zien door twee taken tegelijkertijd uit te voeren. De taken omvatten het knipperen van twee LED's in verschillende tijdvertragingen, samen met een drukknop die wordt gebruikt om de AAN / UIT-status van de LED te regelen. Er worden dus drie taken tegelijk uitgevoerd.
Componenten vereist
- Arduino UNO
- Drie LED's (elke kleur)
- Weerstanden (470, 10k)
- Truien
- Breadboard
Schakelschema
Het schakelschema voor het demonstreren van het gebruik van Arduino Millis () is erg eenvoudig en heeft niet veel componenten die moeten worden bevestigd, zoals hieronder wordt weergegeven.
Programmeren van Arduino UNO voor multitasking
Het programmeren van Arduino UNO voor multitasking vereist alleen de logica achter hoe millis () werkt, wat hierboven is uitgelegd. Het wordt aanbevolen om knipperende LED's keer op keer met millis te oefenen om de logica duidelijk te maken en uzelf op uw gemak te stellen met millis () voordat u Arduino UNO gaat programmeren voor multitasking. In deze tutorial wordt de interrupt ook gelijktijdig met millis () gebruikt voor multitasking. De knop zal een onderbreking zijn. Dus wanneer er een onderbreking wordt gegenereerd, dwz een drukknop wordt ingedrukt, zal de LED naar AAN of UIT schakelen.Het programmeren begint met het declareren van pincodes waarop LED's en drukknop zijn aangesloten.
int led1 = 6; int led2 = 7; int toggleLed = 5; int pushButton = 2;
Vervolgens schrijven we een variabele om de status van LED's op te slaan voor toekomstig gebruik.
int ledState1 = LAAG; int ledState2 = LAAG;
Net zoals hierboven uitgelegd in het knippervoorbeeld, worden de variabelen voor periode en vorige millis gedeclareerd om te vergelijken en vertraging voor LED's te genereren. De eerste LED knippert na elke seconde en een andere LED knippert na 200 ms.
unsigned long previousMillis1 = 0; const lange periode1 = 1000; unsigned long previousMillis2 = 0; const lange periode2 = 200;
Een andere millis-functie wordt gebruikt om de vertragingsvertraging te genereren om te voorkomen dat er meerdere keren op de knop wordt gedrukt. Er zal een vergelijkbare aanpak zijn als hierboven.
int debouncePeriod = 20; int debounceMillis = 0;
De drie variabelen worden gebruikt om de status van de drukknop op te slaan als onderbreking, wissel-LED en drukknopstatus.
bool buttonPushed = false; int ledChange = LOW; int lastState = HIGH;
Definieer de actie van pin die welke pin zal werken als INPUT of OUTPUT.
pinMode (led1, OUTPUT); pinMode (led2, OUTPUT); pinMode (toggleLed, OUTPUT); pinMode (pushButton, INPUT);
Definieer nu de interrupt-pin door interrupt toe te voegen met de definitie van ISR en interrupt-modus. Merk op dat het wordt aanbevolen om digitalPinToInterrupt (pin_number) te gebruiken bij het declareren van de functie attachInterrupt () om de feitelijke digitale pin te vertalen naar het specifieke interruptnummer.
attachInterrupt (digitalPinToInterrupt (pushButton), pushButton_ISR, CHANGE);
De interrupt-subroutine wordt geschreven en verandert alleen de buttonPushed- vlag. Merk op dat de interrupt-subroutine zo kort mogelijk moet zijn, dus probeer het te schrijven en de extra instructies te minimaliseren.
void pushButton_ISR () { buttonPushed = true; }
Loop begint met het opslaan van de millis-waarde in een currentMillis-variabele die de waarde van de verstreken tijd opslaat elke keer dat de lus wordt herhaald.
unsigned lange currentMillis = millis ();
Er zijn in totaal drie functies in multitasking, één LED knipperen op 1 seconde, knipperende tweede LED op 200ms en als de drukknop wordt ingedrukt, schakel dan de UIT / AAN LED uit. We zullen dus drie delen schrijven om deze taak uit te voeren.
De eerste is om de LED-status om te schakelen na elke seconde door de verstreken millis te vergelijken.
if (currentMillis - previousMillis1> = period1) { previousMillis1 = currentMillis; if (ledState1 == LOW) { ledState1 = HIGH; } else { ledState1 = LOW; } digitalWrite (led1, ledState1); }
Evenzo schakelt de tweede het de LED na elke 200 ms om door de verstreken millis te vergelijken. De uitleg is al eerder in dit artikel uitgelegd.
if (currentMillis - previousMillis2> = period2) { previousMillis2 = currentMillis; if (ledState2 == LOW) { ledState2 = HIGH; } else { ledState2 = LOW; } digitalWrite (led2, ledState2); }
Ten slotte wordt de buttonPushed- vlag bewaakt en na het genereren van een vertragingsvertraging van 20 ms schakelt het gewoon de status van de LED om die overeenkomt met de drukknop die als interrupt is bevestigd.
if (buttonPushed = true) // controleer of ISR wordt aangeroepen { if ((currentMillis - debounceMillis)> debouncePeriod && buttonPushed) // genereer een vertraging van 20 ms om meerdere keren te drukken { debounceMillis = currentMillis; // sla de laatste vertragingstijd op als (digitalRead (pushButton) == LOW && lastState == HIGH) // verander de led nadat de drukknop is ingedrukt { ledChange =! ledChange; digitalWrite (toggleLed, ledChange); lastState = LAAG; } else if (digitalRead (pushButton) == HIGH && lastState == LOW) { lastState = HIGH; } buttonPushed = false; } }
Hiermee is de Arduino millis () Tutorial voltooid. Merk op dat om gewoon te worden met millis (), u gewoon oefent om deze logica in sommige andere toepassingen te implementeren. U kunt het ook uitbreiden met motoren, servomotoren, sensoren en andere randapparatuur. Schrijf in geval van twijfel naar ons forum of reageer hieronder.
Volledige code en video voor het demonstreren van het gebruik van de millis-functie in Arduino vindt u hieronder.