delay() Arduino-funktionen: Täta slingor och blockeringskod | Programmering Electronics Academy delay() Arduino-funktionen:
Har du någonsin gjort ett Arudino-projekt och vill att något ska inträffa i ett tidsbestämt intervall? Kanske vill du att en servo ska röra sig var tredje sekund, eller kanske vill du skicka en statusuppdatering till en webbserver var 1 minut.
Hur gör du det? Finns det en funktion som är enkel och okomplicerad som hjälper oss med detta? Ja, det finns det! Vi kommer att diskutera delay-funktionen, liksom millis() funktionen, i videon nedan:
Detta är del 2 i vår miniserie om millis() funktionen. Del 1 hjälper oss att förstå vad millis() funktionen gör, del 2 diskuterar täta slingor och blockerande kod och del 3 diskuterar när millis() funktionen överglänser delay() funktionen.
Teman i den här lektionen
- Täta slingor
- Blockeringskod
- Angammalt recept för inspirerande musik
Millis() kontra Delay()
Så du vill att något ska inträffa med ett bestämt intervall och du letar efter en lösning. Om ditt svar är att använda fördröjningsfunktionen har du rätt. Men det finns ett annat sätt.
Det coolare, snyggare alternativet är Arduino millis()-funktionen. Och ju mer bekant du är med att använda millis-funktionen, för att hjälpa dig att tidsbestämma händelser i din Arduino-kod, desto lättare blir det att införliva andra delar i ditt program senare.
När du väl börjar använda millis() funktionen kommer du att bli gladare, gladare, och för tusan, folk kommer att gilla dig.
Täta slingor
Först ska vi diskutera konceptet med en tät slinga. Och när vi säger en tight loop, vad betyder det?
Låt oss ta en titt på en Arduino-skiss för en demonstration av en tight loop. Om vi börjar med den mest grundläggande skissen har vi bara två funktioner: void setup och void loop. Och som du kanske vet körs void setup bara en gång, och sedan lämnar den över showen till void loop.
Void loop går sedan igenom varje kodrad som kan finnas inom slingan (inom de här krökta parenteserna).
Den exekverar den första raden, sedan exekverar den den andra, och sedan den tredje, och så vidare och så vidare, tills den kommer till botten. Och sedan går den tillbaka till toppen.
Hur snabbt utför den slingan? Det beror på vilket Arduinokort du använder, men en Arduino Uno har en klockfrekvens på 16 megahertz. Det betyder alltså att 16 miljoner instruktioner sker varje sekund på Arduino!
Varje kodrad är inte nödvändigtvis en instruktion. I själva verket är det mest troligt att det är flera instruktioner. Men det är ändå relativt snabbt (din datorprocessor kör troligen med gigahertz-hastigheter… det är miljarder).
Så skulle du betrakta den tomma skissen som en tight loop? Definitivt, det är så snabbt och så tätt som man kan göra en slinga. Eftersom det inte finns något inuti slingan som ska exekveras är den tid det tar att gå igenom skissen praktiskt taget noll. Sagt på ett annat sätt är intervallet från början av slingan till slutet kort (därför är den snabb, eller ”tight”).
Låt oss lägga till några rader kod. Vi kommer att starta seriell kommunikation och sedan skriva ut något till det seriella monitorfönstret.
Är detta en tight loop? Det vill säga, från början av slingan till slutet av slingan, tar det mycket tid? Det tar väldigt lite tid, så det är en snabb, tät slinga.
Det är dock värt att notera att den här slingan inte är lika tät som det föregående exemplet. I det föregående exemplet hade vi ingen kod. Så det var bara att rusa genom slingan. Nu när vi har en funktion här, serial print, kommer det att ta (en liten) stund att skriva ut ”Ice Ice Baby” till serial monitor.
Men detta är fortfarande en ganska snabb slinga. Så låt oss lägga till lite mer kod. Vi låter programmet kontrollera om en knapp är nedtryckt, och om den är det får vi något nytt skickat till den seriella monitorn
Så vi har deklarerat en knapp och använt ett if-uttalande för att kontrollera och se om knappen har tryckts ned. Är spänningen vid stift fem hög? Om så är fallet skriver vi ut något annat i fönstret för den seriella monitorn.
Är detta en tight loop? Så från början av slingan till slutet av slingan, är det ganska snabbt?
Ja, det är fortfarande ganska snabbt. Detta är en ganska snäv slinga. Vi har fyra rader kod. Vi skriver ut till den seriella monitorn och sedan gör vi en snabb kontroll för att se om en knapp trycks in. Och om så är fallet skriver vi ut något. Fortfarande tight, fortfarande snabbt.
Nästan ska vi lägga till en fördröjning till det här programmet med hjälp av Arduino-funktionen delay(). Du kan se nedan att vi har lagt till en tusen millisekunder (1 sekund) fördröjning till slingan.
Är detta fortfarande en tight loop? Är tiden, från början av slingan till slutet av slingan, mycket lång? Nej, detta är definitivt inte en tight loop. Koden börjar snabbt, vi gör serieutskriften, men sedan blir vi stoppade precis där vid fördröjningsfunktionen.
Hela programmet stannar upp medan vi väntar på att den här fördröjningskoden ska bli klar.
När Arduino kommer till den här kodraden är det ungefär som att gå till mataffären. Du kommer in i raden med 12 varor eller mindre, men sedan tar killen framför dig fram sitt checkhäfte och börjar skriva ut en check. Du vet att du kommer att vara där i en minut. Det är samma sak här.
Det här är alltså ingen snäv slinga. Tiden från början av slingan till slutet av slingan är ganska betydande. Särskilt jämfört med de senaste programmen. Storleksordningen på tiden är enorm.
Nu har vi försökt visa här att hela den här idén om täta slingor är relativ. Allt beror på ditt program. Om du behöver kontrollera statusen på en sensor var tiondels miljondels sekund så kanske ett program med tre rader kod inte är tillräckligt tight, det beror helt enkelt på det.
En annan sak som bör påpekas är att alla rader kod inte tar lika lång tid att exekvera. Om du anropar en funktion som gör en massa saker, som till exempel serieutskrift, så kan denna enda kodrad ta mycket längre tid än tio andra kodrader.
Så tätheten i en slinga är en relativ idé.
Blockeringskod
När ett program stannar upp vid en viss punkt och tar en viss tid på sig för att exekvera en viss kod, kan den koden kallas för blockeringskod. Detta är en allmän term.
I vårt program har vi fördröjningsfunktionen som fungerar som blockerande kod. Ingen av koden efter delay kan köras förrän delay är över, så den blir blockerad.
Blockeringskod är dock inte bara när vi använder funktionen delay().
Låt oss ta vårt program och göra oss av med delay, men vi lägger till en for-slinga. Vår for-slinga kommer att skriva ut siffror och text till den seriella porten.
Hur länge körs den här slingan? Den kommer att köra ett tag eftersom den måste gå igenom 100 iterationer innan den stannar.
Och hur är det med koden efter denna for-slinga? Kan den köras? Nej, den måste vänta eftersom den blockeras av for-slingan.
Denna for-slinga är inbäddad inuti huvudslingan. Är for-slingan en ”tight” slinga? Innan du svarar ska vi återigen betona hur du ska tänka: tar det mycket tid att gå igenom den här for-slingan, från toppen till botten?
Nja, inte riktigt. Den har bara två rader kod. Så detta är en ganska snäv slinga.
Men det är en snäv slinga som måste gå igenom många iterationer innan programmet kan komma till koden under den. Så även en tät slinga kan blockera vår kod om den tvingas gå igenom flera iterationer.
Mer om funktionen delay()
Vi ska prata lite mer om den här fördröjningsfunktionen. Vad har vi konstaterat hittills?
För det första har vi sagt att fördröjningsfunktionen minskar tätningen av en slinga. Om du har en tät slinga och lägger till fördröjningsfunktionen kommer det att ta mer tid och göra den mindre tät. Det vill säga, den tid det tar att komma från början av slingan till botten, kommer att öka med fördröjningsfunktionen.
Vi vet också att fördröjningsfunktionen blockerar kod. Detta går hand i hand med det vi just sa. När fördröjningsfunktionen körs blockerar den annan kod från att köras medan den fördröjer.
Du kanske tycker att den här fördröjningsfunktionen är en total slacker! Den kommer aldrig att betyda något i våra projekt. Men för många enkla program som vi skriver fungerar fördröjningsfunktionen fantastiskt bra. Den är enkel att använda, den är verkligen lätt att stava och den gör precis vad den säger.
Så vi bör inte nödvändigtvis utestänga delay() funktionen från vår programmeringsverktygslåda. Vi bör bara erkänna att det är en enkel programmeringsfunktion som kan fungera i många fall.
Det finns dock en tid när du börjar stöta på problem. Det har att göra med den blockerande effekt som fördröjningsfunktionen har i vårt program.
I nästa lektion i serien, del 3, ska vi identifiera var detta verkligen blir ett problem. Du kommer att lära dig när det är vettigt att använda funktionen delay() i ett program och när det är dags att byta till att använda funktionen millis().
Review
Först pratade vi om hur tight en loop är. Vi sa att tätheten i en slinga är relativ. Det beror på vad din applikation är.
För det andra talade vi om blockerande kod, eller kod som blockerar. I huvudsak är det en allmän term som vi kan ge till kod som kommer att ta en viss tid att exekvera, och den kommer att stoppa andra delar av vårt program från att köras medan den exekverar.
Vi hoppas att du gillade den här lektionen! I nästa del av den här serien kommer vi att fortsätta vår resa och lära oss hur man använder millis-funktionen för att skapa tidsbestämda, repetitiva händelser i vår Arduino-kod. Vi ses nästa gång!
.