Katkestused ja multitegumtöötlus Arduinos. Kuidas Arduino programmis paralleelseid ülesandeid (Threads) täita

Üldiselt ei toeta Arduino tegelikku ülesannete paralleelstamist ega mitmelõimelist. Kuid see on võimalik iga tsükli kordusega loop () juhendage mikrokontrollerit kontrollima, kas on aeg teha täiendavaid, taustaülesanne. Sel juhul tundub kasutajale, et korraga täidetakse mitut ülesannet.

Näiteks vilgutame etteantud sagedusel LED-i ja teeme samal ajal kasvavaid ja kahanevaid helisid nagu sireen piesosemiterist. Oleme juba mitu korda Arduinoga ühendanud nii LED-i kui ka pieso-emitteri. Paneme vooluringi kokku, nagu joonisel näidatud.

Kui ühendate LED-i digitaalse kontaktiga, mis ei ole "13", ärge unustage voolu piiravat takistit umbes 220 oomi.

2 LED ja pieso emitteri juhtimine kasutades operaatorit delay().

Kirjutame sellise visandi ja laadime selle Arduinosse üles.

Const int soundPin = 3; /* deklareerib muutuja koos PIN-kood, millega on ühendatud piesoelektriline element */ const int ledPin = 13; // deklareerige LED-i viigunumbriga muutuja void setup() ( pinMode(soundPin, OUTPUT); // kuulutage väljundiks viik 3. pinMode(ledPin, OUTPUT); // kuulutage väljundiks viik 13. } void loop() (// Heli juhtimine: tone(soundPin, 700); // teha heli sagedusega 700 Hz delay(200); toon (soundPin, 500); // sagedusel 500 Hz delay(200); toon (soundPin, 300); // sagedusel 300 Hz delay(200); toon (soundPin, 200); // sagedusel 200 Hz delay(200); // LED-juhtimine: digitalWrite(ledPin, HIGH); // valguse viivitus(200); digitalWrite(ledPin, LOW); // viivituse väljalülitamine (200); }

Pärast selle sisselülitamist on selge, et sketš ei toimu täpselt nii, nagu vajame: kuni sireen on täielikult töökorras, LED ei vilgu, kuid soovime, et LED vilguks ajal sireeni helin. Milles siin probleem on?

Fakt on see, et seda probleemi ei saa tavapärasel viisil lahendada. Mikrokontroller täidab ülesandeid rangelt järjestikku. Operaator viivitus () viivitab programmi täitmist teatud aja jooksul ja kuni selle aja möödumiseni programmi järgmisi käske ei täideta. Seetõttu ei saa me tsükli iga ülesande jaoks erinevat täitmise kestust määrata loop () programmid. Seetõttu peate multitegumtöötlust kuidagi simuleerima.

3 Paralleelsed protsessid ilma operaatorita "delay()".

Arduino arendajad pakkusid välja võimaluse, kus Arduino täidab pseudoparalleelseid ülesandeid. Meetodi olemus seisneb selles, et iga tsükli kordusega loop () kontrollime, kas on aeg LED-i vilkuma (taustaülesanne täitma) või mitte. Ja kui see on saabunud, siis pöörame LED-i oleku ümber. See on operaatori jaoks omamoodi möödaviiguvõimalus viivitus ().

Const int soundPin = 3; // muutuja piesoelektrilise elemendi pin numbriga const int ledPin = 13; // muutuja LED-i viigu numbriga const long ledInterval = 200; // LED-i vilkumise intervall, ms. int ledState = LOW; // LED-i algolek märgita pikk eelmineMillis = 0; // salvestab eelmise LED-i aktiveerimise aja void setup() ( pinMode(soundPin, OUTPUT); // määrake väljundiks tihvt 3. pinMode(ledPin, OUTPUT); // määrake väljundiks tihvt 13. } void loop() (// Heli juhtimine: tone(soundPin, 700); viivitus(200); toon (soundPin, 500); viivitus(200); toon (soundPin, 300); viivitus(200); toon (soundPin, 200); viivitus(200); // Vilkuv LED: // aeg Arduino sisselülitamisest, ms: märgita pikk voolMillis = millis(); // Kui vilkumise aeg on käes, if (praeguneMillis - eelmineMillis >= ledInterval) ( eelmineMillis = praeguneMillis; // siis jäta meelde praegune aeg if (ledState == LOW) ( // ja inverteeri LED-i olek ledState = HIGH; ) else ( ledState = LOW; ) digitalWrite(ledPin, ledState); // LED-i oleku muutmine) }

Märkimisväärne puudus seda meetodit on see, et koodiosa enne LED-i juhtplokki tuleb täita kiiremini kui LED-i vilkumise ajavahemik "ledInterval". Vastasel juhul vilgub harvem kui vaja ja me ei saa ülesannete paralleelse täitmise efekti. Eelkõige on meie sketšis sireeni heli muutuse kestus 200+200+200+200 = 800 ms ja LED-i vilkumise intervalliks määrame 200 ms. Kuid LED-tuli vilgub perioodiga 800 ms, mis on 4 korda pikem kui see, mille me seadsime.

Üldiselt, kui kood kasutab operaatorit viivitus (), sel juhul on pseudoparallelismi raske simuleerida, seega on soovitatav seda vältida.

IN sel juhul Oleks vaja, et ka sireeni heli juhtplokk kontrolliks, kas aeg on käes või mitte, ja ei kasuta viivitus (). Kuid see suurendaks koodi hulka ja muudaks programmi vähem loetavaks.

4 ArduinoThreadi teegi kasutamine paralleelsete keermete loomiseks

Probleemi lahendamiseks kasutame imelist raamatukogu ArduinoThread, mis võimaldab hõlpsasti luua pseudoparalleelseid protsesse. See toimib sarnaselt, kuid võimaldab vältida koodi kirjutamist, et kontrollida ajastust – kas teil on vaja selles tsüklis ülesannet täita või mitte. See vähendab koodi hulka ja parandab visandi loetavust. Vaatame raamatukogu toimimist.


Kõigepealt laadige ametlikult veebisaidilt alla raamatukogu arhiiv ja pakkige see kataloogi lahti raamatukogud/ arenduskeskkond Arduino IDE. Seejärel nimetage kaust ümber ArduinoThread-master V ArduinoThread.

Ühendusskeem jääb samaks. Muutub ainult programmi kood.

#kaasa // ArduinoThreadi teegi ühendamine const int soundPin = 3; // muutuja piesoelektrilise elemendi pin numbriga const int ledPin = 13; // muutuja LED-i viigu numbriga Thread ledThread = Thread(); // LED-juhtlõime loomine Thread soundThread = Thread(); // looge sireeni juhtlõng void setup() ( pinMode(soundPin, OUTPUT); // kuulutage väljundiks viik 3. pinMode(ledPin, OUTPUT); // kuulutage väljundiks viik 13. ledThread.onRun(ledBlink); // ülesande määramine lõimele ledThread.setInterval(1000); // määrake vastuse intervall, ms soundThread.onRun(heli); // määrame lõimele ülesande soundThread.setInterval(20); // määrake vastuse intervall, ms } void loop() (// Kontrollige, kas LED-il on aeg lülituda: if (ledThread.shouldRun()) ledThread.run(); // lõime käivitamine // Kontrollige, kas on aeg sireenitooni muuta: if (soundThread.shouldRun()) soundThread.run(); // alusta lõime } // LED-voog: tühine LEDBlink() ( static bool ledStatus = false; // LED-i olek Sees/Väljas ledStatus = !ledStatus; // oleku ümberpööramine digitalWrite(ledPin, ledStatus); // LED sisse/välja lülitamine } // Sireeni voog: tühi heli() ( staatiline sisetoon = 100; // helikõrgus, Hz toon(soundPin, ton); // lülitage sireen sisse sagedusel "ton" Hz, kui (ton )

Programmis loome kaks lõime - ledThread Ja helilõng, igaüks teeb oma toimingu: üks vilgub LED-tuli, teine ​​juhib sireeni heli. Igas tsükli iteratsioonis kontrollime iga lõime puhul, kas selle täitmise aeg on kätte jõudnud või mitte. Kui see saabub, käivitatakse see meetodi abil täitmiseks jooksma (). Peaasi, et operaatorit ei kasutataks viivitus (). Kood annab täpsemad selgitused.


Laadime koodi Arduino mällu ja käivitame selle. Nüüd töötab kõik täpselt nii nagu peab!

Juhised

Üldiselt ei toeta Arduino ülesannete tõelist paralleelsust ega mitmelõimelisust.
Kuid iga kord, kui silmust () korratakse, saate määrata, et kontrollida, kas on aeg teha mõni täiendav taustaülesanne. Sel juhul tundub kasutajale, et korraga täidetakse mitut ülesannet.
Näiteks pilgutame etteantud sagedusel ja teeme samal ajal kasvavaid ja kahanevaid helisid nagu sireen piesosemiterist.
Oleme juba mitu korda ühendanud nii LED-i kui ka Arduino Arduinoga. Paneme vooluringi kokku, nagu joonisel näidatud. Kui ühendate LED-i digitaalse kontaktiga, mis ei ole "13", ärge unustage voolu piiravat takistit umbes 220 oomi.

Kirjutame sellise visandi ja laadime selle Arduinosse üles.
Pärast tahvli vaatamist on selge, et sketš ei ole tehtud täpselt nii, nagu me vajame: kuni sireen on täielikult töökorras, LED ei vilgu ja soovime, et LED vilkuks sireeni AJAL. Milles siin probleem on?
Fakt on see, et seda probleemi ei saa tavapärasel viisil lahendada. Mikrokontroller täidab ülesandeid rangelt järjestikku. Operaator "delay()" lükkab programmi täitmist teatud aja jooksul edasi ja kuni selle aja möödumiseni programmi järgmisi käske ei täideta. Seetõttu ei saa me programmi "loop()" tsüklis igale ülesandele erinevat täitmisaega määrata.
Seetõttu peate multitegumtöötlust kuidagi simuleerima.

Arduino arendajad pakuvad artiklis https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay välja valiku, mille puhul Arduino täidab ülesandeid pseudoparalleelselt.
Meetodi olemus seisneb selles, et iga tsükli () kordusega kontrollime, kas on aeg LED-i vilkuma (taustaülesanne täitma) või mitte. Ja kui see on saabunud, siis pöörame LED-i oleku ümber. See on omamoodi "delay()" ümbersõit.
Selle meetodi oluliseks puuduseks on see, et LED-i juhtplokki eelne koodiosa tuleb täita kauem kui LED-i vilkumise intervall "ledInterval". Vastasel juhul vilgub harvem kui vaja ja me ei saa ülesannete paralleelse täitmise efekti. Eelkõige on meie sketšis sireeni heli muutuse kestus 200+200+200+200 = 800 ms ja LED-i vilkumise intervalliks määrame 200 ms. Kuid LED-tuli vilgub perioodiga 800 ms, mis on 4 korda erinev meie seatud ajast. Üldiselt, kui teie kood kasutab operaatorit "delay()", on pseudoparalleelsust raske simuleerida, seega on soovitatav seda vältida.
Sel juhul oleks vaja, et ka sireeni juhtseade kontrolliks, kas aeg on käes või mitte, ja mitte kasutada “delay()”. Kuid see suurendaks koodi hulka ja muudaks programmi vähem loetavaks.

Selle probleemi lahendamiseks kasutame imelist ArduinoThreadi teeki, mis võimaldab hõlpsasti luua pseudoparalleelseid protsesse. See on sarnane, kuid võimaldab teil mitte kirjutada koodi, et kontrollida aega - kas teil on vaja selles tsüklis ülesannet täita või mitte. See vähendab koodi hulka ja parandab visandi loetavust. Vaatame raamatukogu toimimist.
Kõigepealt laadige alla raamatukogu arhiiv ametlikult veebisaidilt https://github.com/ivanseidel/ArduinoThread/archive/master.zip ja pakkige see lahti Arduino IDE arenduskeskkonna kataloogi "libraries". Seejärel nimetage kaust "ArduinoThread-master" ümber "ArduinoThreadiks".

Ühendusskeem jääb samaks. Muutub ainult programmi kood. Nüüd näeb see välja nagu sisetükis.
Programmis loome kaks lõime, millest igaüks täidab oma toimingut: üks vilgub LED-i, teine ​​juhib sireeni heli. Igas tsükli iteratsioonis kontrollime iga lõime puhul, kas selle täitmise aeg on kätte jõudnud või mitte. Kui see saabub, käivitatakse see täitmiseks meetodi "run()" abil. Peaasi, et ei kasutataks operaatorit "delay()".
Kood annab täpsemad selgitused.
Laadime koodi Arduino mällu ja käivitame selle. Nüüd töötab kõik täpselt nii nagu peab!

Entusiasm, töönarkomaan või suurenenud ambitsioonid sunnivad meid sõna otseses mõttes võtma endale võimalikult palju ülesandeid ja kohustusi. Seetõttu on aruandeperioodi eelõhtul pea täitmata ülesannetest lõhkemas ja “to do list” kipub olema tapeedirulli pikkune.

Sa vajad

  • - korraldaja
  • - tarkvara tööaja korraldamiseks (näiteks ChromoDoro taimer - Google'i rakendus http://clck.ru/9ZC1)
  • - Ülesannete ajakava või "tegemiste nimekiri" tabeli kujul.
  • - kleebised ja markerid

Juhised

"Sulle ja mulle"

Kõik ülesanded on jagatud nendeks, mis vajavad tegemist, või saab need määrata kellelegi, kes on vähem hõivatud. On tõug liiga vastutustundlikke juhte, kes usuvad, et peavad kogu osakonna töö enda kanda võtma. Niisiis, vanemad ei luba sul kingapaelu siduda, sest vanemad oskavad seda paremini. Te ei saa alluvalt röövida ja ilma võimalusest oma võimeid näidata. Kodus on samamoodi. Selle asemel, et lubada endale igal õhtul tilkuvat kraani parandada, peate helistama torumehele ja ülesande nimekirjast välja kriipsutada.

"Maha viivitusega"

Sellel psühholoogilisel nähtusel on palju erinevaid variante ja vastavalt ka määratlusi, kuid üldiselt on see vastumeelsus probleemi lahendamisega alustada. Mõnikord on esimest sammu raske teha alateadliku ebaõnnestumise hirmu tõttu, mõnikord on see otsene soovimatus liikuda mugavast laiskuse seisundist ebamugavasse. Kõige sagedamini ütleb inimene endale: "Ma söön õuna, mängin pasjanssi ja siis ...". Peame oma meelt muutma. Ja tehke õunast ja pasjansist tasu oma pingutuste eest. Ja igapäevane mantra kõlab järgmiselt: "Kui ma töötan 15 minutit, siis ma olen selle ära teeninud." Kuid ajaplaneerimise kunst pole lihtne.

Ülesannete rühmad

Ettevõtluses võivad need olla töövaldkondadega (logistika või hinnakujundus) seotud ülesanded. Õpilasel on õpitava materjali temaatilised plokid. Edasijõudnud inimesed jagavad korteri tsoonideks. "Vannituba", "koridor", "ruum teleri kõrval" - kõigil on individuaalne lähenemine. Ja korra taastamiseks kulutage igas tsoonis mitte rohkem kui 15 minutit. Sellest piisab, et hõlpsasti puhtust säilitada, aega säästa ja mitte hulluks minna tegemata ülesannete pärast. Iga ülesannete rühma juurde on hea kirjutada ligikaudne tehtud töö protsent. Nähtavad töötulemused aitavad kaasa psühholoogiline mugavus ja suurenenud ärevus, mis pärsib ülesannete täitmist.

Motivatsioon

Kui see on olemas, siis tehnilised nipid optimeerivad tööd. Kui sellega on probleeme, siis põhjustavad elektroonilised meeldetuletused ja kleebised ärritust. Seetõttu on oluline mõista probleemide lahendamise eeliseid ja läheneda tööle teadlikult. Kui meel hulbib, meelt lahutab mõnus jama, siis võib-olla pole selles piisavalt rõõmu. Depressioonis inimesel on palju raskem olla efektiivne. See tähendab, et stiimuleid probleemide lahendamiseks, inspiratsiooni ja erilist positiivset loomingulist suhtumist tuleb otsida väljastpoolt.

Video teemal

Märge

Kõik ülesanded saab jagada nelja üldtuntud kategooriasse: olulised ja mitte kiireloomulised, olulised ja kiireloomulised, ebaolulised ja kiireloomulised, ebaolulised ja mitte kiireloomulised. Siis on lihtsam iga ülesande täitmiseks kuluvat aega arvutada. Peaasi, et ei tohi unustada viieteistminutilisi puhkepause.

Abistavad nõuanded

Ärge pihustage. Me kõik püüame vastata teiste inimeste ootustele. Kuid me peame õppima ütlema: "Stopp." Ülesande tõhusaks täitmiseks peate sellele täielikult keskenduma. Ja selleks peate ilmselt töötama ühes suunas, pingutades kõiki oma mõistuse jõupingutusi probleemide lahendamiseks.

Üldiselt ei toeta Arduino tegelikku ülesannete paralleelstamist ega mitmelõimelist. Kuid see on võimalik iga tsükli kordusega loop () juhendage mikrokontroller kontrollima, kas on aeg teha mõni täiendav taustaülesanne. Sel juhul tundub kasutajale, et korraga täidetakse mitut ülesannet.

Näiteks vilgutame etteantud sagedusel LED-i ja teeme samal ajal kasvavaid ja kahanevaid helisid nagu sireen piesosemiterist. Oleme juba mitu korda Arduinoga ühendanud nii LED-i kui ka pieso-emitteri. Paneme vooluringi kokku, nagu joonisel näidatud.

Kui ühendate LED-i digitaalse kontaktiga, mis ei ole "13", ärge unustage voolu piiravat takistit umbes 220 oomi.

2 LED ja pieso emitteri juhtimine kasutades operaatorit delay().

Kirjutame sellise visandi ja laadime selle Arduinosse üles.

Const int soundPin = 3; /* deklareerib muutuja kontakti numbriga, millega piesoelektriline element on ühendatud */ const int ledPin = 13; // deklareerige LED-i viigunumbriga muutuja void setup() ( pinMode(soundPin, OUTPUT); // kuulutage väljundiks viik 3. pinMode(ledPin, OUTPUT); // kuulutage väljundiks viik 13. } void loop() (// Heli juhtimine: tone(soundPin, 700); // teha heli sagedusega 700 Hz delay(200); toon (soundPin, 500); // sagedusel 500 Hz delay(200); toon (soundPin, 300); // sagedusel 300 Hz delay(200); toon (soundPin, 200); // sagedusel 200 Hz delay(200); // LED-juhtimine: digitalWrite(ledPin, HIGH); // valguse viivitus(200); digitalWrite(ledPin, LOW); // viivituse väljalülitamine (200); }

Pärast selle sisselülitamist on selge, et sketš ei toimu täpselt nii, nagu vajame: kuni sireen on täielikult töökorras, LED ei vilgu, kuid soovime, et LED vilguks ajal sireeni helin. Milles siin probleem on?

Fakt on see, et seda probleemi ei saa tavapärasel viisil lahendada. Mikrokontroller täidab ülesandeid rangelt järjestikku. Operaator viivitus () viivitab programmi täitmist teatud aja jooksul ja kuni selle aja möödumiseni programmi järgmisi käske ei täideta. Seetõttu ei saa me tsükli iga ülesande jaoks erinevat täitmise kestust määrata loop () programmid. Seetõttu peate multitegumtöötlust kuidagi simuleerima.

3 Paralleelsed protsessid ilma operaatorita "delay()".

Arduino arendajad pakkusid välja võimaluse, kus Arduino täidab pseudoparalleelseid ülesandeid. Meetodi olemus seisneb selles, et iga tsükli kordusega loop () kontrollime, kas on aeg LED-i vilkuma (taustaülesanne täitma) või mitte. Ja kui see on saabunud, siis pöörame LED-i oleku ümber. See on operaatori jaoks omamoodi möödaviiguvõimalus viivitus ().

Const int soundPin = 3; // muutuja piesoelektrilise elemendi pin numbriga const int ledPin = 13; // muutuja LED-i viigu numbriga const long ledInterval = 200; // LED-i vilkumise intervall, ms. int ledState = LOW; // LED-i algolek märgita pikk eelmineMillis = 0; // salvestab eelmise LED-i aktiveerimise aja void setup() ( pinMode(soundPin, OUTPUT); // määrake väljundiks tihvt 3. pinMode(ledPin, OUTPUT); // määrake väljundiks tihvt 13. } void loop() (// Heli juhtimine: tone(soundPin, 700); viivitus(200); toon (soundPin, 500); viivitus(200); toon (soundPin, 300); viivitus(200); toon (soundPin, 200); viivitus(200); // Vilkuv LED: // aeg Arduino sisselülitamisest, ms: märgita pikk voolMillis = millis(); // Kui on saabunud aeg vilkuma, if (praeguneMillis - eelmineMillis >= ledInterval) ( previousMillis = currentMillis; // siis pidage meeles praegust kellaaega if (ledState == LOW) ( // ja pöörake LED-i olek LEDState = HIGH ) else ( ledState = LOW; ) digitalWrite(ledPin, ledState); }

Selle meetodi oluliseks puuduseks on see, et LED-i juhtplokki eelnev koodilõik tuleb täita kiiremini kui LED-i vilkumise ajavahemik "ledInterval". Vastasel juhul vilgub harvem kui vaja ja me ei saa ülesannete paralleelse täitmise efekti. Eelkõige on meie sketšis sireeni heli muutuse kestus 200+200+200+200 = 800 ms ja LED-i vilkumise intervalliks määrame 200 ms. Kuid LED-tuli vilgub perioodiga 800 ms, mis on 4 korda pikem kui see, mille me seadsime.

Üldiselt, kui kood kasutab operaatorit viivitus (), sel juhul on pseudoparallelismi raske simuleerida, seega on soovitatav seda vältida.

Sel juhul oleks vaja, et ka sireeni heli juhtseade kontrolliks, kas aeg on käes või mitte, ja mitte kasutada viivitus (). Kuid see suurendaks koodi hulka ja muudaks programmi vähem loetavaks.

4 ArduinoThreadi teegi kasutamine paralleelsete keermete loomiseks

Probleemi lahendamiseks kasutame imelist raamatukogu ArduinoThread, mis võimaldab hõlpsasti luua pseudoparalleelseid protsesse. See toimib sarnaselt, kuid võimaldab vältida koodi kirjutamist, et kontrollida ajastust – kas teil on vaja selles tsüklis ülesannet täita või mitte. See vähendab koodi hulka ja parandab visandi loetavust. Vaatame raamatukogu toimimist.


Kõigepealt laadige ametlikult veebisaidilt alla raamatukogu arhiiv ja pakkige see kataloogi lahti raamatukogud/ Arduino IDE arenduskeskkond. Seejärel nimetage kaust ümber ArduinoThread-master V ArduinoThread.

Ühendusskeem jääb samaks. Muutub ainult programmi kood.

#kaasa // ArduinoThreadi teegi ühendamine const int soundPin = 3; // muutuja piesoelektrilise elemendi pin numbriga const int ledPin = 13; // muutuja LED-i viigu numbriga Thread ledThread = Thread(); // LED-juhtlõime loomine Thread soundThread = Thread(); // looge sireeni juhtlõng void setup() ( pinMode(soundPin, OUTPUT); // kuulutage väljundiks viik 3. pinMode(ledPin, OUTPUT); // kuulutage väljundiks viik 13. ledThread.onRun(ledBlink); // ülesande määramine lõimele ledThread.setInterval(1000); // määrake vastuse intervall, ms soundThread.onRun(heli); // määrame lõimele ülesande soundThread.setInterval(20); // määrake vastuse intervall, ms } void loop() (// Kontrollige, kas LED-il on aeg lülituda: if (ledThread.shouldRun()) ledThread.run(); // lõime käivitamine // Kontrollige, kas on aeg sireenitooni muuta: if (soundThread.shouldRun()) soundThread.run(); // alusta lõime } // LED-voog: tühine LEDBlink() ( static bool ledStatus = false; // LED-i olek Sees/Väljas ledStatus = !ledStatus; // oleku ümberpööramine digitalWrite(ledPin, ledStatus); // LED sisse/välja lülitamine } // Sireeni voog: tühi heli() ( staatiline sisetoon = 100; // helikõrgus, Hz toon(soundPin, ton); // lülitage sireen sisse sagedusel "ton" Hz, kui (ton )

Programmis loome kaks lõime - ledThread Ja helilõng, igaüks teeb oma toimingu: üks vilgub LED-tuli, teine ​​juhib sireeni heli. Igas tsükli iteratsioonis kontrollime iga lõime puhul, kas selle täitmise aeg on kätte jõudnud või mitte. Kui see saabub, käivitatakse see meetodi abil täitmiseks jooksma (). Peaasi, et operaatorit ei kasutataks viivitus (). Kood annab täpsemad selgitused.


Laadime koodi Arduino mällu ja käivitame selle. Nüüd töötab kõik täpselt nii nagu peab!

Optimeerige oma Arduino programme katkestustega - lihtne viis sündmustele reaalajas reageerimiseks!

Me katkestame oma edastuse...

Nagu selgub, on kõikidesse Arduinodesse sisse ehitatud suurepärane (kuid alakasutatud) mehhanism, mis sobib ideaalselt sündmuste reaalajas jälgimiseks. See mehhanism nimetatakse katkestuseks. Katkestuse ülesanne on tagada, et protsessor reageeriks kiiresti olulistele sündmustele. Kui tuvastatakse konkreetne signaal, katkestab katkestus (nagu nimigi ütleb) kõik, mida protsessor tegi, ja käivitab koodi, mis on loodud reageerima selle põhjustanud signaalile. väline põhjus, mis mõjutab Arduinot. Pärast selle koodi käivitamist naaseb protsessor oma algsele tööle, nagu poleks midagi juhtunud!

Hämmastav selle juures on see, et katkestused võimaldavad teil oma programmi organiseerida nii, et see reageeriks kiiresti ja tõhusalt olulistele sündmustele, mida programmitsüklis nii kergesti ette näha pole. Mis kõige parem, katkestused võimaldavad protsessoril teha muid asju, selle asemel et raisata aega sündmuse toimumiseni.

Nupp katkestab

Alustame sellest lihtne näide: Kasutage nupuvajutuste jälgimiseks katkestust. Alustuseks võtame visandi, mida olete ilmselt juba näinud: Arduino IDE-s sisalduv näide "Nupp" (selle leiate kataloogist "Näited", kontrollige menüüd Fail → Näited → 02. Digitaalne → nupp).

Const int buttonPin = 2; // pin number nupuga const int ledPin = 13; // PIN-kood LED-iga int buttonState = 0; // muutuja nupu oleku lugemiseks void setup() ( // seadke LED-i viik väljundile: pinMode(ledPin, OUTPUT); // määrake nupu viik sisendiks: pinMode(buttonPin, INPUT); ) void loop () ( // lugege nupu olekut: buttonState = digitalRead(buttonPin); // kontrollige, kas nuppu on vajutatud. // kui seda vajutatakse, siis buttonState on HIGH: if (buttonState == HIGH) ( // lülitage sisse LED: digitalWrite(ledPin, HIGH ) else ( // lülita LED välja: digitalWrite(ledPin, LOW); ) )

Selles, mida siin näete, pole midagi šokeerivat ega üllatavat: programm teeb ikka ja jälle läbi loop() ja loeb nupu buttonPin väärtust. Oletame korraks, et soovite loop() abil teha midagi enamat kui lihtsalt väljundi oleku lugemist. Siin tuleb kasuks katkestamine. Selle asemel, et pidevalt jälgida viigu olekut, saame selle töö määrata katkestusele ja vabale loop()-le, et teha vahepeal seda, mida vajame! Uus kood näeb välja selline:

Const int buttonPin = 2; // pin number nupuga const int ledPin = 13; // PIN-kood LED-iga volatile int buttonState = 0; // muutuja nupu oleku lugemiseks void setup() ( // seadke LED-i viik väljundile: pinMode(ledPin, OUTPUT); // määrake nupu viik sisendiks: pinMode(buttonPin, INPUT); // lisa katkestus ISR-vektorile attachInterrupt (0, pin_ISR, CHANGE) void pin_ISR() ( buttonState = digitalRead(buttonPin); digitalWrite(ledPin, buttonState); )

Silmused ja katkestusrežiimid

Märkate siin mõningaid muudatusi. Esimene ja kõige ilmsem on see, et loop() ei sisalda nüüd juhiseid! Saame hakkama ka ilma nendeta, kuna kogu töö, mida varem if/else avalduses tehti, on nüüd sisse lülitatud uus funktsioon pin_ISR() . Seda tüüpi funktsiooni nimetatakse katkestuste töötlejaks: selle ülesanne on kiiresti käivitada, käsitleda katkestust ja võimaldada protsessoril naasta põhiprogrammi (st loop() sisu). Katkestuste töötleja kirjutamisel tuleb arvestada mitme asjaga: olulised punktid, mida näete ülalolevas koodis:

  • käitlejad peaksid olema lühikesed ja sisutihedad. Sa ei taha põhitsüklit kauaks katkestada!
  • käitlejatel ei ole sisendparameetrid ja tagastavad väärtused. Kõik muudatused tuleb teha globaalsetes muutujates.

Tõenäoliselt mõtlete: kuidas me teame, millal katkestus käivitub? Mis seda põhjustab? Kolmas funktsioon, mida nimetatakse funktsioonis setup(), seadistab katkestuse kogu süsteemi jaoks. See funktsioon attachInterrupt() kasutab kolme argumenti:

  1. katkestuse vektor, mis määrab, milline viik võib katkestuse tekitada. See ei ole PIN-kood ise, vaid viide asukohale mälus, mida Arduino protsessor peab jälgima, et näha, kas katkestus on toimunud. See ruum selles vektoris vastab konkreetsele väline väljund, ja mitte kõik kontaktid ei saa katkestust tekitada! Arduino Unos võivad tihvtid 2 ja 3 katkestusvektoritega 0 ja 1 genereerida katkestusi. Katkestuste tekitamiseks vajalike kontaktide loendi leiate Arduino attachInterrupt funktsiooni dokumentatsioonist;
  2. katkestuse käitleja funktsiooni nimi: määrab koodi, mis käivitatakse, kui katkestuse käivitamise tingimus on täidetud;
  3. katkestusrežiim, mis määrab, milline kontakti toiming katkestuse käivitab. Arduino Uno toetab nelja katkestusrežiimi:
    • RISING - aktiveerib katkestustihvti tõusva serva katkestuse;
    • KUKKUMINE – aktiveerib kukkumise katkestuse;
    • CHANGE - reageerib katkestusviigu väärtuse muutustele;
    • LOW – helistab alati, kui pin on madal.

Ja kokkuvõtteks, meie attachInterrupt() seadistus vastab katkestuse vektori 0 (pin 2) jälgimisele, et vastata katkestusele koodiga pin_ISR() ja pin_ISR() kutsumine alati tuleb muutus olek pin 2 juures.

Muutuv

Veel üks tähelepanuväärne punkt on see, et meie katkestuste töötleja kasutab väljundi oleku salvestamiseks muutujat buttonState. Kontrollige selle asemel nupu buttonState: definitsiooni tippige int, määratlesime selle muutliku int-tüübina. Mis siin lahti on? volatile on C-keele märksõna, mis kehtib muutujate kohta. See tähendab, et muutuja väärtus ei ole alla täielik kontroll programmid. See tähendab, et buttonState väärtus võib muutuda ja muutuda millekski, mida programm ise ei suuda ennustada – antud juhul kasutaja sisendiks.

Veel üks kasulik asi muutlikus märksõnas on kaitsta juhusliku optimeerimise eest. Selgub, et koostajad teevad veel mõned lisaülesandeid programmi lähtekoodi masinkoodiks teisendamisel käivitatav kood. Üks neist ülesannetest on kasutamata eemaldamine lähtekood muutujad alates masina kood. Kuna buttonState muutujat ei kasutata ega kutsuta otse sisse silmusfunktsioonid() või setup() , on oht, et kompilaator võib selle kasutamata muutujana eemaldada. Ilmselgelt on see vale – me vajame seda muutujat! Märksõna muutlik on kõrvalmõju, öeldes kompilaatorile, et see muutuja tuleks rahule jätta.

Kasutamata muutujate eemaldamine koodist on funktsionaalne omadus, mitte kompilaatori viga. Inimesed jätavad mõnikord oma koodi kasutamata muutujad, mis võtavad mälu. See ei ole nii suur probleem, kui kirjutate C-programmi gigabaidise RAM-iga arvutile. Arduinol siiski RAM piiratud ja te ei taha seda raisata! Isegi arvutite C-kompilaatorid teevad täpselt sama asja, hoolimata saadaolevate arvude hulgast süsteemimälu. Milleks? Samal põhjusel, miks inimesed pärast piknikut enda järelt koristavad – see on hea harjutus, ärge jätke prügi maha.

Summeerida

Katkestused on lihtne viis panna teie süsteem kiiremini reageerima ajatundlikele ülesannetele. Neil on ka lisakasu- Main loop() tsükli vabastamine, võimaldades sellel keskenduda süsteemi põhiülesandele (ma leian, et katkestuste kasutamine hoiab mu koodi pisut organiseeritumalt: on lihtsam näha, mille jaoks peamine koodiosa on mõeldud ja milliseid perioodilisi sündmusi katkestused käsitlevad). Siin näidatud näide on katkestuste kõige lihtsam kasutusjuht; saate kasutada andmete lugemiseks I2C seadmest, traadita edastus ja andmete vastuvõtmiseks või isegi mootori käivitamiseks või seiskamiseks.

Kas on mingeid lahedaid katkestustega projekte? Jäta oma kommentaarid alla!