Fórum témák
» Több friss téma |
Cikkek » Launchpad: ismerkedés az MSP430 mikrovezérlőkkel II. Launchpad: ismerkedés az MSP430 mikrovezérlőkkel II.
Szerző: icserny, idő: Nov 3, 2011, Olvasva: 22764, Oldal olvasási idő: kb. 9 perc
ProgrammegszakításokA mikrovezérlő programjának végrehajtása, utasításainak sorrendje többnyire előre megszabott, előre kiszámítható módon történik. Vannak azonban kivételek, amikor a program normális menete megszakad: Programmegszakítások: általában külső vagy belső hardver esemény hatására következnek be (ha előzetesen engedélyeztük!), jelezve, hogy valamelyik periféria vagy alrendszer sürgős kiszolgálást kér. Ilyenkor a főprogram futása megszakad, s egy, a megszakítást kiszolgáló eljárásra kerül a vezérlés, melynek befejeztével a főprogram a megszakítás helyétől tovább folytatódik. Újraindítás (reset): általában ezt is hardver események váltják ki. Pl. az RST láb lehúzása, a tápfeszültség leesése, vagy más katasztrofális esemény, ami a program normális folytatását lehetetlenné teszi. Újraindítás véletlenül is bekövetkezhet ha a program elején a Wathchdog időzítőt elfelejtjük kikapcsolni. Minden RESET esemény azzal jár, hogy a program egy jól meghatározott állapotból újraindul. A kivételek közül most a programmegszakításokkal ismerkedünk meg:Képzeljük el, milyen volna, ha a mobiltelefont hívásjelzés nélkül használnánk! Időnként elővennénk a zsebünkből, s beleszólnánk: "Halló, van valaki a vonalban?". Bizonyára nevetségesnek tűnik, pedig nagyon sok program így kezeli az eseményeket (ezt hívják lekérdezéses, vagy angolul polling módnak). A fenti módszer hátránya nyilvánvaló: vagy túl gyakran nézegetjük a telefont, fölöslegesen pazarolva ezzel az időt, vagy túl ritkán vesszük elő, s akkor lemaradhatunk egy fontos hívásról. Sokkal hatékonyabb az a módszer, ha a telefon rendelkezik hívásjelzéssel, ami a programmegszakításhoz (interrupt) hasonlítható: ha hívás érkezik, cseng a telefon. Abbahagyom, amit éppen csinálok, s felveszem a telefont (kiszolgálom az interruptot). A hívás befejeztével visszatérhetek a korábbi tevékenység folytatásához.
A programmegszakítás (interrupt) tehát azt jelenti, hogy a program futása egy külső vagy belső esemény bekövetkezte miatt megszakad, s majd csak a programmemória egy másik helyén elhelyezett utasítássorozat (a progammegszakítás kiszolgálását végző kód) lefutása után tér vissza a CPU az eredeti program folytatásához, ahogy ezt az alábbi ábrán láthatjuk. 4_1. ábra: A program normál menetének megszakítás Természetesen ahhoz, hogy a programmegszakítás kiszolgálása után zavartalanul folytatódhasson a program futása, a programmegszakítási alrendszernek el kell mentenie a futó program állapotát (azt, hogy melyik a soron következő utasítás, s hogy mi volt a státuszbitek tartalma), visszatéréskor pedig helyre kell állítania. Az MSP430 mikrovezérlők vektoros megszakítási rendszerrel rendelkeznek. Ez azt jelenti, hogy a memória végén elhelyezett táblázatban minden megszakításjelzőhöz tartozik egy-egy bejegyzés, ezek az ún. vektorok. A vektorokba írhatjuk be a megszakításokat kiszolgáló eljárások kezdőcímeit. A megszakítási vektorok az 0xFFC0–0xFFFD címtartományban helyezkednek el, a 0xFFFE címen pedig a RESET vektor helyezkedik el. Az itt található (ide beírt) címről indul el a program bekapcsoláskor, illetve minden újraindításkor. A vektorok címkiosztását, prioritását és az egyes vektorokhoz kapcsolódó jelzőbitek nevét a mikrovezérlő adatlapja tartalmazza, táblázatos formában. A vektorok sorrendje egyúttal a prioritást is megszabja. Több, egyidejű megszakítási kérelem közül a magasabb prioritású érvényesül, s az a magasabb prioritású, amelynek vektora nagyobb memóriacímen található. Mi történik a mikrovezérlőben, amikor egy esemény megszakítást kér?Ahhoz, hogy egy periféria megszakítási kérelme érvényesüljön, előzetesen engedélyezni kell az adott perifériára vonatkozóan a megszakítást. Az első részben említettük, hogy az I/O portok esetében engedélyezhetjük, hogy a digitális bemenetnek kapcsolt láb megszakítást okozzon, ha állapota megváltozik. Ehhez a P1IE vagy P2IE regiszter megfelelő bitjét '1'-be kell állítani. A megszakítási kérelem érvényesülésének ezen kívül az is feltétele, hogy a mikrovezérlőben a programmegszakítási rendszer általánosságban is engedélyezve legyen. Van ugyanis egy GIE (General Interrupt Enable = általános megszakítási engedélyezés) bit, amelynek segítségével a megszakítási rendszer egészében engedélyezhető vagy tiltható. A mikrovezérlőben egy programmegszakítási kérelem érvényesülésekor a következő dolgok történnek:
A fentiek összesen 6 CPU utasítás-ciklust vesznek igénybe. Ha a CPU a megszakításkor aktív módban volt, akkor ehhez még hozzá kell adni a megszakított utasítás végrehajtási idejét is, ami legkedvezőtlenebb esetben szintén 6 órajel-ciklus lehet. Így tehát a programmegszakítási kérelem megjelenése és a megszakítást kiszolgáló eljárás megkezdése közötti megszakítási késedelem (interrupt latency) akár 12 órajel-ciklus is lehet. Minden megszakítást kiszolgáló eljárásnak a RETI utasítással kell végződnie (C nyelvű programoknál nem találkozunk ezzel, hiszen a fordító teszi oda helyettünk), melynek hatására a következő dolgok történnek:
Program megszakítása nyomógombbalAz alábbi példában a főprogram LED2-t villogtatja, végtelen ciklusban. Ez lesz az a tevékenység, amelyet egy külső esemény (példánkban az S2 nyomógomb lenyomása) megszakít. A megszakítás kiszolgálásakor átbillentjük LED1 állapotát. Végeredményben tehát a program folyamatosan villogtatja a zöld LED-et, mi pedig eközben az S2 nyomógombbal ki-be kapcsolgathatjuk a piros LED-et. Az olvasó fantáziájára bízzuk, hogy a LED villogtatás és kapcsolgatás helyére képzeljen tetszés szerinti bonyolut és hasznos tevékenységet. 4_1. lista: A p1_3_interrupt.c program listája
A program elején letiltjuk az "őrkutyát" (WDT), az S2 nyomógombhoz tartozó P1.3 lábat bemenetnek, P1 és P2 összes többi lábát pedig kimenetnek álltjuk be, és nullára húzzuk. Ha már beforrasztottuk az órakvarcot, akkor a P2 portra vonatkozó beállításokat hagyjuk ki! A P1.3 bemenetnél most nem használjuk a belső felhúzást, mivel a Launchpad kártyán külső felhúzó ellenállás csatlakozik hozzá. Megjegyzésként beírva azonban megmutattuk, hogy hogyan lehetne engedélyezni a belső felhúzást. Ez még jól jöhet saját áramkör építésénél... A P1IES regiszter megfelelő bitjét '1'-be állítva előírjuk, hogy lefutó élre legyen a bemenet, akkor kérjen programmegszakítást, amikor magas szintről alacsony szintre vált a bemeneten a jel. a felhúzás miatt ugyanis a magas szint az alapállapot, s akkor változik alacsony szintre, amikor az S2 nyomógombot megnyomjuk. (A Launchpad kapcsolási rajzát a cikksorozat első részében találjuk meg.) A P1.3-hoz tartozó megszakítás engedélyezése a P1IE regiszter 3. bitjének '1'-be állításával történik. Szokjuk meg, hogy a megszakítás engedélyezése előtt rutinszerűen mindig töröljük a hozzá tartozó megszakításkérő bitet. A beállítások után még hátra van, hogy az SR regiszter GIE bitjének '1'-be állításával általánosságban is engedélyezzük a megszakítási alrendszer működését. Ezt a beállítást azonban C nyelvű utasítással nem tehetjük meg, hanem az __interrupt_enable() beépített függvényt kell meghívnunk. A végtelen ciklusban a szokásos módon villogtatjuk a zöld LED-et. A megszakítás kiszolgálásakor csak átkapcsoljuk LED1 állapotát, s töröljük a megszakítási kérelmet jelző bitet. A PORT1_VECTOR-hoz több megszakításkérő bit tartozik, ezért nem törlődik automatikusan. A programmegszakítás kiszolgálása C nyelven roppant egyszerűen megadható:
Megjegyzések:
Program menetének befolyásolásaAz előző programban a főprogram és a megszakítás egymástól teljesen függetlenül tették a dolgukat. Most nézzünk egy olyan példát is, amikor a megszakítás befolyásolja a főprogram további menetét! Az egyszerűség kedvéért az előző programot variáljuk meg egy kicsit: a főprogramban nem egy, hanem nyolc tevékenység közül lehet választani egy szoftveres kapcsoló és egy jelző segítségével. Az S2 gomb megnyomásakor mindig eggyel léptetjük a jelzőt, ügyelve, hogy annak értéke csak 0 és 7 közötti szám lehet. A jelzőt "volatile" (illékony) módosítóval kell deklarálni. Ez arra figyelmezteti a fordítót, hogy a változó értéke máshol (jelen esetben az interrupt kiszolgáló eljárásban) is módosul, minden felhasználáskor tehát a tárból elő kell venni az aktuális értéket. 4_2. lista: A p1_3_change_state.c program listája
A jelzo nevű változó deklarálásától eltekintve a program első része megegyezik az előzővel. Eltérés csak a végtelen ciklusban és az interrupt kiszolgáló eljárásban van. A végtelen ciklusban a jelzo változó értéke szerint elágaztatjuk a programot egy switch (kapcsoló) utasítás segítségével. Minden case ... break közötti szakasz egy-egy külön ágat jelent a programban. Mivel hol az egyik, hogy a másik LED-et villogtatjuk, a rend kedvéért minden ágban egy törléssel kezdjük: nullázzuk a villogtatni nem kívánt LED kimenetet. A késleltetéseket úgy választottuk meg, hogy a várakozási idők minden lépésben feleződnek. A megszakítás kiszolgálásánál léptetjük a jelzőt, és gondoskodunk róla, hogy az a 0-7 intervallumban maradjon. Az előző programhoz hasonlóan itt is törölnünk kell a megszakításjelző bitet. Az I/O portokon kívül programmegszakítást okozhat az "őrkutya" (WDT), az időzítő/számláló (timer), az analóg-digitális átalakító (ADC), a szinkron soros port (USI), az NMI bemenetre adott külső jel, s néhány hardver hibajel (oszcillátor hiba, flash memória hozzáférés megsértése). Ezek közül jónéhánnyal találkozunk majd a későbbiekben. A cikk még nem ért véget, lapozz! Értékeléshez bejelentkezés szükséges! |
Bejelentkezés
Hirdetés |