delay() Funcția Arduino: Bucle strânse și cod de blocare
Ați realizat vreodată un proiect Arudino și doriți ca ceva să se întâmple la un interval de timp? Poate că la fiecare 3 secunde doriți ca un servo să se miște, sau poate că la fiecare 1 minut doriți să trimiteți o actualizare de stare către un server web.
Cum faceți asta? Există o funcție simplă și directă care să ne ajute în acest sens? Da, există! Vom discuta despre funcția delay, precum și despre funcția millis(), în videoclipul de mai jos:
Aceasta este partea a doua a mini-serialului nostru despre funcția millis(). Partea 1 ne ajută să înțelegem ce face funcția millis(), partea 2 discută buclele strânse și codul de blocare, iar partea 3 discută când funcția millis() depășește funcția delay().
Subiecte abordate în această lecție
- Bucle strânse
- Cod blocant
- Rețeta antică pentru muzică inspirată
Millis() versus Delay()
Așa că doriți ca ceva să se întâmple la un interval stabilit și căutați o soluție. Dacă răspunsul tău este să folosești funcția delay, ei bine, ai cam dreptate. Dar există o altă cale.
Opțiunea mai cool și mai șmecheră este funcția Arduino millis(). Și cu cât sunteți mai familiarizat cu utilizarea funcției millis, pentru a vă ajuta să cronometrați evenimentele din codul Arduino, cu atât mai ușor va fi să încorporați alte părți în programul dvs. mai târziu.
După ce veți începe să folosiți funcția millis(), veți fi mai fericiți, mai veseli și, fir-ar să fie, oamenii vă vor plăcea.
![Funcția Millis() Arduino](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/03/people_like_you.png)
Bucle strânse
În primul rând, să discutăm conceptul de buclă strânsă. Și când spunem o buclă strânsă, ce înseamnă asta?
Să aruncăm o privire la o schiță Arduino pentru o demonstrație a unei bucle strânse. Pornind de la cea mai de bază schiță, avem doar două funcții: void setup și void loop. Și după cum probabil știți, void setup se execută doar o singură dată, iar apoi predă spectacolul către void loop.
![Arduino void setup loop](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/03/void_setup_loop_2.png)
Void loop trece apoi prin fiecare linie de cod care ar putea fi în interiorul buclei (în interiorul acestor paranteze curbe).
Execută prima linie, apoi o execută pe a doua, apoi pe a treia, și așa mai departe, până când ajunge la sfârșit. Și apoi se întoarce la început.
Cu cât de repede execută bucla? Depinde de placa Arduino pe care o folosești, dar un Arduino Uno are o viteză de ceas de 16 megahertzi. Deci asta înseamnă că 16 milioane de instrucțiuni se întâmplă în fiecare secundă pe Arduino!
![Viteza ceasului Arduino](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/03/16-Mhz.png)
Care linie de cod nu este neapărat o instrucțiune. De fapt, cel mai probabil este vorba de mai multe instrucțiuni. Dar, cu toate acestea, este relativ rapid (procesorul computerului dvs. funcționează probabil la viteze de Gigahertzi… asta înseamnă miliarde).
Așa că ați considera acea schiță goală o buclă strânsă? Categoric, este atât de rapidă și de strânsă pe cât se poate face o buclă. Din moment ce nu există nimic în interiorul buclei care să fie executat, timpul necesar pentru a parcurge schița este practic zero. Altfel spus, intervalul de la începutul buclei până la sfârșit este scurt (prin urmare, este rapidă, sau „strânsă”).
Să adăugăm câteva linii de cod. Vom începe comunicarea serială și apoi vom imprima ceva în fereastra monitorului serial.
![Arduino tight loop serial communication](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/03/tight_loop.png)
Este aceasta o buclă strânsă? Adică, de la începutul buclei până la sfârșitul buclei, durează mult timp? Durează foarte puțin timp, deci este o buclă rapidă și strânsă.
Este demn de remarcat, totuși, că această buclă nu este la fel de strânsă ca exemplul anterior. În exemplul anterior, nu aveam niciun cod. Așa că era doar o cursă prin buclă. Acum că avem o funcție aici, serial print, va dura (un pic) de timp pentru a imprima „Ice Ice Baby” pe monitorul serial.
Dar aceasta este totuși o buclă destul de rapidă. Așa că haideți să mai adăugăm un pic de cod. Vom face ca programul să verifice dacă un buton este apăsat, iar dacă este apăsat, vom avea ceva nou trimis la monitorul serial
![Arduino tight loop serial monitor with button push](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/04/tight_loop_2.png)
Am declarat deci un buton și am folosit o instrucțiune if pentru a verifica și a vedea dacă butonul a fost apăsat. Este tensiunea la pinul 5 ridicată? Dacă da, atunci imprimăm altceva în fereastra monitorului serial.
Este aceasta o buclă strânsă? Deci, de la începutul buclei, până la sfârșitul buclei, este destul de rapid?
Da, este încă destul de rapid. Aceasta este o buclă destul de strânsă. Avem patru linii de cod. Imprimăm pe monitorul serial, iar apoi facem o verificare rapidă pentru a vedea dacă este apăsat un buton. Și dacă este, imprimăm ceva. Tot strâns, tot rapid.
În continuare să adăugăm o întârziere la acest program folosind funcția Arduino delay(). Puteți vedea mai jos că am adăugat o întârziere de o mie de milisecunde (1 secundă) la buclă.
![Arduino tight loop with delay](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/04/tight_loop_3.png)
Este aceasta încă o buclă strânsă? Timpul, de la începutul buclei până la sfârșitul buclei, este mult timp? Nu, aceasta nu este cu siguranță o buclă strânsă. Codul începe rapid, facem imprimarea în serie, dar apoi ne oprim chiar acolo, la funcția de întârziere.
Întregul program se oprește în timp ce așteptăm ca acest cod de întârziere să se termine.
Când Arduino ajunge la această linie de cod, este ca și cum ar merge la magazinul alimentar. Ajungi la linia de 12 articole sau mai puțin, dar apoi tipul din fața ta își scoate carnetul de cecuri și începe să scrie un cec. Știi că vei sta acolo pentru un minut. Este aceeași treabă și aici.
![Când cineva scoate un cec la linia expres](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/04/checkout.png)
Așa că nu este o buclă strânsă. Timpul de la începutul buclei până la sfârșitul ei este destul de semnificativ. Mai ales în comparație cu ultimele două programe. Ordinul de mărime al timpului este uriaș.
Acum, ceea ce am încercat să demonstrăm aici este că toată această idee despre buclele strânse este relativă. Totul depinde de aplicația voastră. Dacă aveți nevoie să verificați starea unui senzor la fiecare 10 milionime de secundă, atunci un program care are trei linii de cod s-ar putea să nu fie suficient de strâns, depinde.
O altă observație care trebuie făcută este că nu toate liniile de cod necesită același timp de execuție. Dacă apelați o funcție care face o grămadă de lucruri, cum ar fi, de exemplu, serial print, atunci acea linie de cod poate dura mult mai mult decât alte 10 linii de cod.
Așa că strângerea unei bucle este o idee relativă.
![Închiderea unei bucle Arduino este relativă - Einstein](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/04/The-tightness-of-a-loop-is-relative.png)
Cod de blocare
Când un program se oprește la un moment dat și durează ceva timp pentru a executa un anumit cod, acel cod poate fi numit cod de blocare. Acesta este un termen general.
În programul nostru avem funcția delay care acționează ca și cod de blocare. Niciunul dintre codurile de după delay nu se poate executa până când delay nu se termină, deci se blochează.
Codul de blocare nu este, totuși, doar atunci când folosim funcția delay().
Să luăm programul nostru și să scăpăm de delay, dar vom adăuga o buclă for. Bucla noastră for va imprima numere și text pe portul serial.
![Arduino strânge o buclă for](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/04/tight_loop_4.png)
Atunci, cât timp rulează această buclă? Va rula un timp pentru că trebuie să treacă prin 100 de iterații înainte de a se opri.
Și cum rămâne cu codul de după această buclă for? Este capabil să ruleze? Nu, trebuie să aștepte pentru că este blocat de bucla for.
Această buclă for este imbricata în interiorul buclei principale. Este bucla for o buclă „strânsă”? Înainte de a răspunde, haideți să subliniem din nou modul în care ar trebui să vă gândiți la ea: este nevoie de mult timp pentru a parcurge această buclă for, de sus în jos?
Păi, nu chiar. Are doar două linii de cod. Deci aceasta este o buclă destul de strânsă.
Dar este o buclă strânsă care trebuie să treacă printr-o mulțime de iterații înainte ca programul să ajungă la codul de sub ea. Deci, chiar și o buclă strânsă, dacă este forțată să treacă prin mai multe iterații, poate bloca codul nostru.
Mai multe despre funcția delay()
Să vorbim puțin mai mult despre această funcție delay. Ce am stabilit până acum?
În primul rând am spus că funcția delay scade strângerea unei bucle. Dacă aveți o buclă strânsă și adăugați funcția de întârziere, aceasta va lua mai mult timp și o va face mai puțin strânsă. Adică, cantitatea de timp necesară pentru a ajunge de la începutul buclei până la sfârșit, va crește odată cu funcția de întârziere.
Știm, de asemenea, că funcția de întârziere blochează codul. Acest lucru merge mână în mână cu ceea ce tocmai am spus. Atunci când funcția de întârziere rulează, blochează alt cod să ruleze în timp ce întârzie.
Ați putea crede că această funcție de întârziere este un leneș total! Nu va însemna niciodată nimic în proiectele noastre. Dar pentru o mulțime de programe simple pe care le scriem, funcția de întârziere funcționează fantastic. Este simplu de utilizat, este foarte ușor de silabisit și face exact ceea ce spune.
![Funcția de întârziere Arduino fiind un cartof de canapea](https://i0.wp.com/www.programmingelectronics.com/wp-content/uploads/2019/04/Is-the-delay-function-a-total-slacker__.png)
Așa că nu ar trebui să ostracizăm neapărat funcția delay() din setul nostru de instrumente de programare. Ar trebui doar să recunoaștem că este o funcție de programare simplă care poate funcționa într-o mulțime de cazuri.
Există însă un moment în care începeți să întâmpinați probleme. Aceasta are de-a face cu efectul de blocare pe care funcția delay îl are în programul nostru.
În următoarea lecție din serie, partea 3, vom identifica unde acest lucru devine cu adevărat o problemă. Veți învăța când are sens să folosiți funcția delay() într-un program și când este timpul să treceți la utilizarea funcției millis().
Revizuire
Primul lucru pe care l-am discutat a fost despre caracterul strâns al unei bucle. Am spus că etanșeitatea unei bucle este relativă. Depinde de ceea ce este aplicația dumneavoastră.
În al doilea rând, am vorbit despre codul blocant, sau codul care blochează. În esență, este un termen generic pe care îl putem da codului care va avea nevoie de ceva timp pentru a se executa și care va opri alte părți ale programului nostru să ruleze în timp ce se execută.
Sperăm că v-a plăcut această lecție! În următoarea parte a acestei serii, vom continua călătoria noastră învățând cum să folosim funcția millis pentru a crea evenimente cronometrate și repetitive în codul nostru Arduino. Ne vedem data viitoare!
![Rețeta străveche Arduino pentru muzică inspirată](https://programmingelectronics.com/wp-content/uploads/2019/04/ancient-recipe-gif.gif)
.