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. 5 perc
Lapozás: OK   6 / 8

Időzítők

Az előző fejezetben láttunk néhány példát arra, hogy külső megszakítások segítségével hogyan használhatjuk az LPM4-es energiatakarékos módot. Vannak azonban olyan esetek, amikor rendszeres időközönként, belső megszakítással szeretnénk ébreszteni a CPU-t, vagy valamilyen alkalmazáshoz a szoftveres késleltetésnél pontosabb időzítésekre van szükség. Ehhez meg kell ismerkednünk az MSP430 mikrovezérlők időzítőivel. Ezek közül az "őrkutyával" Watchdog Timer, WDT) tulajdonképpen már volt dolgunk, hiszen minden programunk azzal kezdődött, hogy le kellett tiltanunk a WDT-t. Logikus tehát, ha ezzel kezdjük az ismerkedést. A  Launchpad kártyával kapott mikrovezérlőkben van ezen kívül egy sokoldalúan használható másik időzítő is (Timer) amellyel a következő oldalon foglalkozunk.

Az őrkutya (WDT)

Az őrkutya időzítő elsődleges szerep az, hogy védjen bizonyos rendszerhibák ellen: indítsa újra a mikrovezérlőt, ha a program valahol elbarangolt, vagy végtelen ciklusba került (kivéve a főprogram szándékosan végtelenné tett ismétlődő részét). Hasznos az őrkutya időzítő akkor is, ha valamelyik külső hardver eszköz nem válaszol záros időn belül, s a programunkban ez elakadást okozna.  A WDT, mint egy időzített bomba, számlálja az óraimpulzusokat. Szerencsére nem robban, hanem újraindítja (reseteli) a mikrovezérlőt a számlálója túlcsordulásakor. Éppen ezért, ha a WDT nincs letiltva, akkor gondoskodni kell róla, hogy a számlálóját rendszeres időközönként töröljük.

Az MSP430 mikrovezérlők WDT időzítője azonban beállítható úgy is, hogy ne újraindulást, hanem programmegszakítást okozzon. Ez azért jó, mert sok olyan alkalmazás van, ami rendszeres megszakítást igényel a feladatok ütemezéséhez.

A WDTCTL regiszter

A WDT beállítása és vezérlése a WDTCTL regiszteren keresztül történhet. Ez egy 16 bites regiszter, tehát minden írás vagy olvasása szó szélességű művelettel kell, hogy történjen. A WDTCTL regiszter a véletlen felülírástól yédett: íráskor a nagyobbik helyiértékű felébe egy úgynevezett jelszót kell írni (mely 0x5A). Az olyan írás műveletek, amelyeknél nem ez a szám szerepel a magasabb helyiértékű bájtban, megszakadnak, és a mikrovezérlő újraindul ("biztonsági kulcs hiba" jelzéssel). Az RST/NMI bemenet konfigurálása is ebben a regiszterben történik. A WDTCTL regiszter alsó helyiértékű felének bitkiosztása így néz ki:

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
WDTHOLD WDTNMIES WDTNMI WDTTMSEL WDTCNTCL WDTSSEL WDTIS1 WDTIS0
rw-0 rw-0 rw-0 rw-0 r0 (w) rw-0 rw-0 rw-0

WDTHOLD - Ezzel a bittel kapcsolhatjuk ki a WDT-t. (0: WDT engedélyezve, 1: WDT leállítva)

WDTNMIES - kiválasztja, hogy NMI milyen élre legyen érzékenyítve (0: felfutó élre, 1: lefutó élre)

WDTNMI - Ez a bit választja ki az RST/NMI bemenet funkcióját (0: RESET, 1: NMI megszakítás)

WDTTMSEL -a WDT időzítő funkciójának kiválasztása (0: őrkutya mód/RESET, 1: intervallum időzítés/interrupt)

WDTCNTCL - ennek a bitnek az '1'-be állítása törli WDT számlálóját. A bit automatikusan törlődik, kiolvasáskor mindig '0' értéket ad vissza. Ha '0'-t írunk ebbe a bitbe, annak nincs semmilyen hatása.


WDTSSEL - a WDT időzítő órajel forrásának kiválasztása (0: SMCLK, 1: ACLK)

WDTIS1:WDTIS0 - a WDT számláló hosszának beállítása. Ezekkel a bitekkel választhatjuk ki, hogy hány impulzus után csorduljon túl a számláló, s billenjen be a WDTIFG jelzőbit ( 00: 32768, 01: 8192, 10: 512, 11: 64)

A WDT időzítő letiltása

A fentiek alapján mostmár érthető, hogy a programok elején mit jelent az alábbi titokzatos sor, ami minden programunk elején ott díszelgett:

 

  1. WDTCTL = WDTPW + WDTHOLD;  // Letiltjuk a watchdog időzítőt

A baloldalon a WDT vezérlő regiszterének neve szerepel, melynek alapértelmezett értéke az alsó 8 biten nulla. A fenti sorral '1'-be állítjuk a WDTHOLD bitet, ami lekapcsolja a WDT időzítőt, ami onnan kezdve sem számolni, sem resetelni, sem interruptot okozni nem fog a visszakapcsolásig, vagy a következő újraindulásig.

Újraindítás (RESET) a WDT segítségével

A következő programmal LED1-et villogtatjuk, de igen szokatlan módon. A villogtatás periódusideje VLO használata esetén ~1600 ms,  a 32 kHz-es LFXT1 használata esetén pedig 500 ms.  Az időzítést most nem szoftveres programhurkokkal végezzük, hanem a WDT végzi hardveresen, s túlcsorduláskor újraindítja a programot (RESET).  A várakozás alatt a program LPM3 energitakarékos módban alszik: MCLK, SMCLK és DCO kikapcsolva, csak ACLK jár (LFXT1 vagy VLO  forrásból). Mintaként felhasználtuk az MSP430D2xx1 mintaprogramok (slac463a.zip)  wdt_06.c programját (D. Dang, Texas Instruments, Oct. 2010)

6_1. lista: a wdt_reset.c program listája

  1. #include "io430.h"
  2.  
  3. int main( void ) {
  4. // Ha be van építve a 32 kHz-es kvarc, akkor tegye kommentté a következő sort!  
  5.   BCSCTL3 |= LFXT1S_2;       // ACLK forrása: LFXT1 helyett VLO
  6.   WDTCTL = WDT_ARST_250;     // forrás ACLK, T = 32/10 * 250 ms
  7.   P1DIR |= BIT0;             // P1.0 legyen digitális kimenet
  8.   P1OUT ^= BIT0;             // P1.0 állapotának átbillentése
  9.   __low_power_mode_3();      // Altatjuk a programot WDT lejártáig
  10. }

A főprogram első sorában ACLK forrásául a VLO oszcillátort állítjuk be. Ha már beforrasztottuk a 32 kHz-es kvarcot, akkor hagyjuk ki ezt a sort! A WDT_ARST_250 makrót az io430g2230.h fejléc állomány definiálja, s azt állítjuk be vele, hogy WDT minden 8192-dik órajelre okozzon resetet.

  1. #define WDT_ARST_250   (WDTPW+WDTCNTCL+WDTSSEL+WDTIS0)      /* 250ms   " */

A 32 kHz-es órajel esetében ez 250 ms-os időzítést jelent. A kb. 10 kHz-es VLO esetében pedig T = 8192/1000 = 0.8192 s = 819.2 ms. Mivel minden újrainduláskor átbillentjük LED1 állapotát, az minden második újrainduláskor kerül azonos fázisba, tehát a LED villogási periódusa a fentebb kiszámolt érték kátszerese (32 kHz-es LFXT1 esetén 500 ms, a 10 kHz-es VLO esetében pedig kb. 1.64 s).  

Megjegyzés: A fenti programban messzemenően kihasználtuk azt, hogy a P1OUT kimeneti adatregisztert az újraindulások (PUC feltétel) nem módosítják. Ha RESET-kor törlődne a P1OUT regiszter, akkor a fenti program nem működne, hiszen minden újrainduláskor nulláról kezdenénk!

Periodikus megszakítás WDT segítségével

A következő program arra mutat példát, hogy az intervallum időzítő módba beállított WDT segítségével hogyan kelthetünk periodikus meszakításokat, s hogyan használhatjuk azt fel egy többfeladatos rendszerben ütemezésre.  A program LED1-et és LED2-t különböző ütemben villogtatja (ezen időzítések az eddigi módon, szoftveres késleltetéssel nehezen volnának előállíthatók). Az időzítéshez a periodikus megszakítást generáló  WDT  szolgáltat időalapot, kb. 51,2 ms periódussal. Az egyes feladatok egymástól eltérő késleltetéseit az interrupt kiszolgáló eljárásában, az időszeletek számlálásával, szoftveres számlálók segítségével oldottuk meg. Az időzített események száma tehát könnyen bővíthető.

  1. #include "io430.h"
  2. #include "stdint.h"
  3.  
  4. volatile uint16_t delay1,delay2;
  5.  
  6. void main(void) {
  7.   BCSCTL3 |= LFXT1S_2;                // ACLK = VLO (~10 kHz)
  8.   WDTCTL = WDT_ADLY_16;               // WDT ~50 ms periódussal
  9.   IFG1 &= ~OFIFG;                     // Clear OSCFault flag
  10.   BCSCTL2 |= SELM_3 + SELS;           // MCLK = SMCLK = VLO
  11.   IE1 |= WDTIE;                       // WDT interrupt engedélyezése
  12. //--- LED-ek és késleltetések beállítása --------------------------------  
  13.   P1DIR |= BIT0+BIT6;                 // P1.0 P1.6 legyen kimenet
  14.   P1OUT |= BIT0+BIT6;                 // P1.0 P1.6 kezdetben világít
  15.   delay1 = 30;                        // LED1 periódusa ~3,1 s
  16.   delay2 = 70;                        // LED1 periódusa ~7.3 s
  17.   __low_power_mode_3();               // Interrupt és LPM3 engedélyezése
  18. }
  19.  
  20. //--- Watchdog Timer megszakításának kiszolgálása -----------------------
  21. #pragma vector=WDT_VECTOR
  22. __interrupt void watchdog_timer(void) {
  23.   if(--delay1==0) {                   // Számláljuk a megszakításokat
  24.     P1OUT ^= BIT0;                    // P1.0 állapotának átbillentése
  25.     delay1 = 30;                      // Lejárt számláló újratöltése
  26.   }
  27.   if(--delay2==0) {
  28.     P1OUT ^= BIT6;                    // P1.6 állapotának átbillentése
  29.     delay2 = 70;                      // Lejárt számláló újratöltése
  30.   }
  31. }


 

A főprogram előtt egy-egy globális változót kell deklarálnunk minden feladat ütemezéséhez. Ezeket a változókat illékonynak (volatile) deklaráltuk, mert a főprogramban és a megszakítási rutinban is használjuk. A változók 16 bites előjel nélküli egészek, így legfeljebb 65535 időszelet (kb. 3350 s) a leghosszabb beállítható késleltetési idő. Az uint16_t típust az stdint.h fejléc állomány deklarálja, ezért azt is be kellett csatolnunk.

A főprogram első sorában most is a VLO oszcillátort állítjuk be ACLK forrásául. A WDT_ADLY_16 makrót az io430g2230.h fejléc állomány definiálja, s azt állítjuk be vele, hogy WDT minden 512-dik órajelre okozzon programmegszakítást.

  1. #define WDT_ADLY_16   (WDTPW+WDTTMSEL+WDTCNTCL+WDTSSEL+WDTIS1)   /* 16ms    " */

A 32 kHz-es órajel esetében ez 16 ms időzítést jelentene, de az általunk kiválasztott kb. 10 kHz-es VLO esetében valójában T = 512/1000 = 51.2 ms. Ez lesz az időalap, s minden ütemezéshez beállított késleltetés ennek egész számú többszöröse lesz. Az időzítéseket ugyanis az időszeletek számlálásával valósítjuk meg.  

Az egyszerűség kedvééért az elvégzendő feladatokat  (LED-ek villogtatása) is a megszakítást kiszolgáló eljárásban végezzük el. Így megtakarítottuk a főprogram és a megszakítási szint közötti kommunikációt. A másik lehetőség az volna (s bonyolultabb esetekben azt az utat kell követni), hogy a megszakítási rutinban szemaforokat állítunk be, melyeket a főprogram használ fel.


A cikk még nem ért véget, lapozz!
Következő: »»   6 / 8
Értékeléshez bejelentkezés szükséges!
Bejelentkezés

Belépés

Hirdetés
XDT.hu
Az oldalon sütiket használunk a helyes működéshez. Bővebb információt az adatvédelmi szabályzatban olvashatsz. Megértettem