Arduino kezdőknek 6 – Bistabil multivibrátorok, megszakításkezelés
Szilágyi Sándor Zoltán Villamosmérnök, mérnök-informatikus
A cikket megírtam: 2022. 04. 25-én
A Rádiótechnikában megjelent: 2022. június-július dupla számban
Ez a blog oldal tehát az eredeti, saját tulajdonomban levő dokumentum, és nem a nyomtatásban megjelent másolata. A cikket én írtam, én küldtem be, és csak azután jelent meg nyomtatott formában is. A nyomtatásban megjelent cikkeimre szerződést nem kötöttek velem, és anyagi juttatást se kaptam soha érte. Mivel a magazin már nem kapható, ezért a megjelent 13 cikkemet itt folytatnám, mivel Magyarországon jelenleg nincs hobbielektronikával foglalkozó magazin.
6.1 Megszakítás kezelés
Mint minden elektronikai szakirodalomban, az astabil és a monostabil multivibrátorok ismertetése mellett a bistabil billenőkapcsolásoknak is ott kell lennie. Ez a programozás terén is új ismeret bővítést hoz, mégpedig a megszakítások kezelését. Évekkel ezelőtt, a főiskolán egy tanáromat megkérdeztem arról, hogy mivel kezdjek, ha robotot akarok építeni. Ő azt válaszolta, hogy a megszakítás-kezelést kell első körben megtanulni. Tanácsát akkor megfogadtam, és ebben a cikkben közreadom a tapasztalataim egy kis részét. A megszakításoknak számtalan alkalmazási lehetősége van, ezért itt is az alapokkal kezdeném, melyeknek egy konkrét és alapvető alkalmazása a bistabil multivibrátor lesz.
A bistabil multivibrátorok vagy flip-flop-ok olyan billenőkapcsolások, melyeknek két stabil állapota van. A kimeneti állapotát a bemenetre adott impulzus hatására változtatja meg.
Az astabil- és a monostabil multivibrátorok „arduinós” lemodellezésénél nem volt szükség a megszakításokra. A programokat könnyedén meg lehetett írni. Bistabil billenőkapcsolásoknál viszont szükséges ezek megismerése is előtte, ugyanis valahogy meg kell oldani, hogy az egyik led vezérlését megállítsa a processzor és a másikat magas állapotba hozza, majd fordítva, és mindezt egy-egy nyomógomb hatására. A nyomógomb ugyanis egy impulzust (vagy nyomva tartás esetén egy hosszabb 1-állapotú bemenő jelet) ad, és a kimenetnek nem csak a nyomógomb megnyomási idejére kell átbillennie a másik állapotba, hanem tartósan ott is kell maradnia (még elengedés után is) egészen addig, amíg egy másik jelet nem kap, majd ezután (a másik gomb elengedése után is) tartósan abban az állapotban kell maradnia.
Tegyük fel, hogy fut egy program és eközben az egyik interrupt bemenet magas (H) állapotba kerül, akkor felfüggeszti a processzor a program futását, végrehajtja a megszakítási alprogramot, majd ha az lefutott, visszaadja a vezérlést az eredetileg futó programnak. Az eredeti programot tehát onnan folytatja, ahol a megszakításkor abbahagyta.
Az Arduino UNO, amit az első cikkemben bemutattam, két interrupt bemenettel rendelkezik. Ezek a digitális I/O soron a 2-es és a ~3-as pinek.
16. Program: 1-gombos megszakítás kezelés
A próbapanelon 2 db ledre, 1 nyomógombra, 2 db 220 ohmos és 1 db 10K-s ellenállásra lesz szükségünk. A kapcsolási rajz a 24-edik ábrán látható. A ledek a korábban használt 11-es és 12-es kimenetekre vannak kötve, míg a nyomógomb a pl 8-as helyett a 2-es interrupt bemenetre. A védőellenállások változatlanul ugyanazok, mint korábban.
A megszakítások kezelésére több függvény is rendelkezésre áll, de itt most csak az attachInterrupt(digitalPinToInterrupt(pin), ISR, mode)-t fogjuk használni. Ezzel állítjuk be a megszakítást az adott lábra. Az arduino.cc referencia ajánlása szerint nem elég csak a pin számot megadni, illetve adattípusnak az integert ajánlja. Ezt ki is próbálhatjuk, a digitalPinToInterrupt(pin)-helyére akár a deklarált „button”-t, akár a definiált „2”-t írjuk, a program futtatásakor a nyomógomb megnyomására nem fog történni semmi. Ha viszont egy értéket adunk meg, jelen esetben a 0-át (azaz most egy kicsit eltérünk az ajánlástól), akkor a program „helyesen” (vagy inkább csak látványosan) fog működni, azaz ha 0 van a 2-es bemeneten, akkor meghívódik az ISR (Interrupt Service Rutin – megszakítási rutin vagy alprogram) függvény, ami nálam az „intr” nevet kapta. Ezt a függvényt a „void loop()” után ki kell fejteni, ez lesz a „void intr()”. A függvény utasítás részében csak a korábban ismertetett ledek ki- és bekapcsolása van, egy pergésmentesítéssel. A megszakításkezelés harmadik paramétere a mód. Négy fajtája van:
- LOW: az interrupt bemenet alacsony állapotban marad.
- RISING: kiváltja a megszakítást, amikor alacsony szintről magas szintre változik
- FALLING: ez előző ellentéte, azaz magas szintről alacsony szintre váltáskor váltja ki a megszakítást.
- CHANGE: kiváltja a megszakítást akár alacsony szintről magas szintre, akár magas szintről alacsony szintre történik váltás.
A példában (25. ábra) a LOW-mód került alkalmazásra.
A program működése ezek után elég egyszerűnek tűnik. Alap állapotban a 12-es pinre kötött led2 világít, folyamatosan, azaz ez a főprogram, a void loop() tartalma. Az interrupt bemenetre van kötve egy nyomógomb, melyet ha megnyomunk, elindul egy megszakítási alprogram úgy, hogy az éppen futó főprogramot félbeszakítja: elalszik a led2, és felgyullad a 11-es lábra kötött led1. Az alprogram futása addig tart, amíg a gombot nyomva tartjuk, azaz akár egy impulzus idejű is lehet, akár több másodperces. Ezután a gombot elengedve, a megszakítási alprogram befejezi a futását, majd vissza kapja a vezérlést a főprogram, azaz a led1 elalszik, is ismét állandóra felgyullad a led2.
24. ábra
25. ábra
17. Program: 1-gombos megszakítás kezelés felfutó/lefutó élre
Az előző feladatban levő négy mód közül érdemes a CHANGE-t is kipróbálni, ez lesz a másik leglátványosabb. A kapcsolás változatlan marad.
A program (26. ábra) működése: a 12-es lábra kötött led2 folyamatosan világít. A gombot megnyomva a felfutó él idejéig (gomb megnyomásakor) elalszik a led2, és felvillan a 11-es lábra kötött led1. Ezután ismét csak a void loop() -ban meghatározott led2 fog folyamatosan világítani. A nyomógombot akár folyamatosan is nyomva tarthatjuk, a led1 akkor is csak a felfutó él idejéig fog világítani, majd kialszik, és az eredeti led2 folytatja a világítást. A gombot elengedve a led2 egy pillanatra kialszik és ugyanekkor a led1 ismét felvillan, majd ismét led2 következik. Ezután (már nem érünk a gombhoz) továbbra is a led2 világít folyamatosan a végtelenségig.
26. ábra
A négy mód működését a 27-edik ábra szemlélteti. A gombot bármennyi ideig nyomva tarthatjuk, ez látható az ábra első sorában. Az egyes módok alacsony/magas szintjeit alatta láthatjuk.
27. ábra
6.2 Bistabil multivibrátorok
18. Program: 2-gombos megszakítás kezelés - bistabil multivibrátor
Ebben a feladatban két dolog is teljesül: egyrészt kipróbáljuk mindkét interrupt bemenet együttes használatát, másrészt a bevezetőben említett bistabil multivibrátort itt építjük meg.
A hardvert tekintve egy új nyomógombbal és egy 10K-s védőellenállással bővül a kapcsolásunk (28. ábra)
28. ábra
A program (29. ábra) deklarációs/definíciós része egy új sorral bővül. Fel kell vennünk a 3-as pinre kötött nyomógombot is. Az előző feladathoz képest egy kis névváltoztatás lesz, itrp_button_1 és itrp_button_2 (interrupt button - azaz ezek lesznek a megszakításokat előidéző nyomógombjaink). Az egyenlőség jel utáni 2-es illetve 3-as szám az adott digitális pint definiálja.
A setup részben itrp_button_1 illetve itrp_button_2 néven lebegésmentesítve beállítjuk a nyomógombokat. Itt kerül sor a „attachInterrupt(digitalPinToInterrupt(pin), ISR, mode)” formájú megszakítás fügvények beállításaira is, melyek egy kicsit másabbak lesznek, mint az előző két feladatban. A függvény első paramétere ugyanis nem „0” (nulla) lesz, hanem az arduino.cc referencia ajánlása szerinti digitalPinToInterrupt(itrp_button_1) illetve digitalPinToInterrupt(itrp_button_2) paraméterek. (Mint fentebb említettem, a 16-17 feladatokban az alapok ismertetése miatt egy kicsit eltértünk az ajánlástól) További változás az előző példákhoz képest, hogy a paraméter zárójelében meg kell adni a deklarált interrupt bemenet nevét. Az ISR megszakítási rutin az interrupt_1 illetve az interrupt_2 lesz. A mód itt is LOW mindkét sornál.
Végül a programunk utolsó részében két új függvényt kell megírni, void interrupt_1() és void interrupt_2() néven. Mindegyik három sorból áll: az adott függvényhez tartozó ledek beállítása magas és alacsony értékre, illetve az utolsó sorban a 20 msec-os pergésmentesítés.
Ha bistabil multivibrátort akarunk, akkor a „void loop()” főprogramot üresen kell hagyni. Így feltöltés után nem lesz működő programunk egészen addig, míg valamelyik gombot meg nem nyomjuk. Azaz olyan lesz, mintha stand by üzemmódban lenne, és valamelyik csatorna start gombját várja. Ha kezdéskor (vagy a futó program folyamatában) a led1-hez tartozó gombot (itrp_button_1) nyomjuk meg, akkor az kezd el folyamatosan világítani. Ezután (vagy kezdéskor) a 3-as pinhez tartozó itrp_button_2 nyomógombot megnyomva a hozzá tartozó, 12-es lábra kötött led2 fog folyamatosan világítani. Mivel nincs főprogram, csak két megszakítási alprogram, így azok egymást fogják megszakítani. Egy gombot többször is, vagy folyamatosan megnyomva nincs változás, a hozzá tartozó folyamatban levő megszakítási rutin fog futni egészen addig, míg a másik gombbal meg nem szakítjuk azt, hogy a másik rutin fusson. Így létrehoztuk a bistabil multivibrátort is -Arduino-val.
A LOW helyett kipróbálhatjuk a FALLING, RISING, CHANGE módokat. Változás szinte alig érzékelhető, viszont a bistabil jelleg megmarad.
29. ábra
Ez így tehát egy lebegésmentesített/pergésmentesített/megszakítás kezelt bistabil multivibrátor. Minden benne van amit eddig tanultunk, viszont csak egy modell, melyet később, pl a játékrobotoknál (akadály érzékelés – irányváltás), vagy a led-kockáknál (program váltás) fogunk majd felhasználni.
Felhasznált irodalom:
Zsom Gyula: Digitális technika 1. (7. kiadás, 2010)
Kovács Csongor: Digitális elektronika (ismeretlen évjárat)
https://hu.wikipedia.org/wiki/Flip-flop_(elektronika) (2022. 04. 18-i állapot)
http://www.elektromanoid.hu/progi22.html (2022. 04. 18-i állapot)
https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/ (2022. 04. 18-i állapot)
A cikket megírtam: 2022. 04. 25-én
A Rádiótechnikában megjelent: 2022. június-július dupla számban