loader
Foto

Interrupt vs polling alkalmazása a PIC32MX5XX/6XX/7XX családban

Áttekintjük ebben a cikkben a késleltetések különböző megvalósításának a lehetőségeit. Alkalmazunk ezért szoftveres késleltetést, illetve három belső perifériát is, a Timer1-et, 2-t, illetve a 3-at. Logikai analizátorral vizsgáljuk a különböző késleltetésekhez tartozó kimeneteket, illetve a Timer1 és a Timer2 interrupt flag-jeit is.

Ebben a projektben egy olyan alkalmazást valósítunk meg, amely különböző megvalósításokkal rendelkező késleltetéseket tartalmaz. Megtaláljuk a szoftveresen kialakított késleltetést, illetve három Timer belső perifériát is alkalmazunk a késleltetések kiváltására. A Timer1 és a Timer2 megszakítást vált ki akkor, ha a TMRx regiszter értéke megegyezik a PRx regiszter értékével. A Timer3 belső perifériának a T3IF flagje fogja "jelezni" azt az állapotot, amikor a TMR3 értéke egyenlő lesz a PR3 értékével, de ehhez nem rendeltünk megszakításkérést. A T3IF flag értékét a while(1) végtelen ciklusban figyeljük a szoftveres késleltetés előtt. Ez nem az optimális megoldás, hiszen könnyen előfordulhat az, hogy a T3IF logikai "1" értéket vesz fel, de ennek a vizsgálata (illetve a flag szoftveres törlésre, és a "D" port 3. bitjének az állapotváltása) csak később történik meg, hiszen a vezérlés a "for" ciklusnál van, vagy akár valamelyik IT függvény került végrehajtásra.

Indítsuk el az MpLABX-et, és hozzunk létre egy új projektet, amelyhez adjunk hozzá egy üres "C" file-t. Ebbe a "C" file-ba másoljuk be a következő kódot.

#include <p32xxxx.h>
#include <sys/attribs.h>

// SYSCLK = 20MHz, PBCLK = 10MHz
#pragma config FNOSC = FRCPLL, FSOSCEN = OFF, POSCMOD = OFF
#pragma config FPLLMUL = MUL_20, FPLLIDIV = DIV_4, FPLLODIV = DIV_2
#pragma config FPBDIV = DIV_2

#define LED0        LATDbits.LATD0
#define LED1        LATDbits.LATD1
#define LED2        LATDbits.LATD2
#define LED3        LATDbits.LATD3

#define LED0Tg()    { LED0 = ~LED0; }
#define LED1Tg()    { LED1 = ~LED1; }
#define LED2Tg()    { LED2 = ~LED2; }
#define LED3Tg()    { LED3 = ~LED3; }
#define T1IFClear() { IFS0bits.T1IF = 0; }
#define T2IFClear() { IFS0bits.T2IF = 0; }


void __ISR(_TIMER_1_VECTOR, IPL1SRS) T1Int(void)
{
    LATDbits.LATD4 = IFS0bits.T1IF;
    LED1Tg();
    T1IFClear();
    LATDbits.LATD4 = IFS0bits.T1IF;
}

void __ISR(_TIMER_2_VECTOR, IPL1SRS) T2Int(void)
{
    LATDbits.LATD5 = IFS0bits.T2IF;
    LED2Tg();
    T2IFClear();
    LATDbits.LATD5 = IFS0bits.T2IF;
}


main()
{
    int k;
    DDPCONbits.JTAGEN = 0;
    
    // portbeállítások
    // A D porton vannak a LED-ek, amelyeket villogtatni szeretnék. -> kimenet
    TRISD = 0x0000;

    // belső perifériák beállítása, a villogás miatt
    // Timer1, 1:64
    T1CON = 0x0020;
    PR1 = 0x1234;
    TMR1 = 0x0000;
    
    // Timer2, 1:32
    T2CON = 0x0050;
    PR2 = 0x1234;
    TMR2 = 0x0000;
    
    // Timer3, 1:32
    T3CON = 0x0050;
    PR3 = 0x2345;
    TMR3 = 0x0000;
    
    // IT beállítás
    // Multivector mód -> több IT függvény lesz
    INTCONbits.MVEC = 1;

    // T1 IT beállítása
    IFS0bits.T1IF = 0;
    IPC1bits.T1IP = 1;
    IEC0bits.T1IE = 1;
    
    // T2 IT beállítása
    IFS0bits.T2IF = 0;
    IPC2bits.T2IP = 1;
    IEC0bits.T2IE = 1;
    
    
    // "GIE"
    asm volatile("ei");
    
       
    // T1, T2, T3 elindítása
    T1CONbits.ON = 1;
    T2CONbits.ON = 1;
    T3CONbits.ON = 1;
    
    while(1)
    {
        if(IFS0bits.T3IF)
        {
            LED3Tg();
            IFS0bits.T3IF = 0;
        }
        for(k = 0; k < 500; k++);
        LED0Tg();
    }
}

 

Először a "config" regiszterek írásával beállítjuk a SYSCLK és a PBCLK értékét, majd elnevezzük a "D" port alsó négy bitjét. A "LED0"-on fogjuk ábrázolni a szoftveres késleltetés eredményét, a LED1, illetve a LED2 villogási frekvenciájáért a Timer1 és a Timer2 belső perifériák felelnek. Ez a két időzítő megszakítást ad akkor, ha a TMRx = PRx. Korábban már láttuk, hogy ha két belső regiszter (TMRx, PRx) értékei megegyeznek, akkor nem csak a TxIF flag lesz logika "1", hanem a TMRx regiszter törlődik, és újra indul a számlálás.
A LED3 villogási frekvenciáját a Timer3 belső időzítő állítja elő úgy, hogy a T3IF flag nem okoz megszakításkérést, tehát ennek a flag-nek az állapotát "néha" megnézzük. Amikor logikai "1"-ben lesz, akkor szintén szoftveresen töröljük ezt a jelzőbitet, továbbá állapotváltás történik a "D" port 3. bitjén.
Látható még az is, hogy a T1IF és a T2IF flag-ek értékeit kivezettük a "D" port 4. és az 5. kimeneteire.

Amikor elindítjuk az alkalmazásunkat, akkor először tiltjuk a JTAG-et, azután beállítjuk a "D" portot kimenetre. Ezt követően a különböző belső időzítők működésének a beállítása következik. A Timer1 belső osztójának az értéke 1:64, a másik kettőnek pedig 1:32. 
Ezután beállítjuk a megszakítás tulajdonságait, multivector módot alkalmazunk, illetve a Timer1-nek és a Timer2-nek az megszakításbeállításai következnek. Mind a két belső periféria ugyanazzal a prioritással rendelkezik. A beállítások után engedélyezzük a "globális" megszakítást, majd elindítjuk a belső időzítőket.

A "while(1)" végtelen ciklusban először megnézzük a T3IF flag értékét. Ha logikai "1" az értéke, akkor a "LED3Tg()" makrót meghívjuk, a LED3 portbit állapotát negáljuk, majd szoftveresen töröljük a T3IF flag-et.
Ezután elindítjuk a szoftveres késleltetésünket, elszámolunk 0-tól 500-ig. A számolás végén a "LED0Tg()" makró meghívása következik, tehát a LED0 értékét negáljuk. Ugyanakkor meg kell jegyeznünk azt, ha valamelyik belső periféria (Timer1 vagy a Timer2) megszakítást idéz elő, akkor az előbb említett műveletek felfüggesztésre kerülnek, és a megszakításkérés kiszolgálása után kerülnek csak folytatásra.

Az első ábrán láthatjuk a mikrovezérlő "D" portján lévő változásokat. A "D0" mutatja a szoftveres késleltetést, illetve könnyen észrevehető az is, hogy a Timer2-nek a működési frekvenciája az kétszerese a Timer1 működési frekvenciájának. Ez az osztási beállításnak (1:64, 1:32) köszönhető, hiszen a két PRx regiszter a konfigurálás során ugyanazt az értékeket kapták (0x1234).

kep
1. ábra   Alkalmazásunk működése
 

Ha csökkentünk a nagyítás méretén (10ms/Div), akkor már szrevehető az, hogy a "D3" kimenet és például a "D1" kimenete közötti időkülönbség elkezd csökkeni. Ez azért van, mert a T3IF nem okoz megszakításkérést, azaz a TMR3 = PR3 egyenlőség nem rögtön kerül kiértékelésre.

kep
2. ábra   Változik a "D3" állapotváltozásainak a helyzete a "D1"-hez (vagy a "D2"-höz) viszonítva
 

Ha ezt a zoom értéket megtartva az időtengelyen később nézzük meg a mért értékeket, akkor a változás (pl.: "D1" vs "D3") még szembetűnőbb (3. ábra).

kep
3. ábra   Változik a "D3" állapotváltozásainak a helyzete a "D1"-hez (vagy a "D2"-höz) viszonítva

 



Egyéb cikkek

További cikkeink ebben a témakörben

Régebbi cikkeink

Október közepén elindítjuk az Atmel 8 bites mikrovezérlőkről szóló sorozatunkat. Ehhez használnunk kell természetesen egy fejlesztőkörnyezetet is. Több ilyen is létezik, például a WinAVR, vagy az Atmel Studio. Mi az Atmel Studio-t fogjuk használni, e. . . .

A PIC18F mikrovezérlők ma is népszerű a fejlesztők körében. Noha 8 bites architektúráról beszélünk, számos érdekes és hasznos alkalmazás megvalósítható vele. Elég csak az USB-re, vagy akár az Ethernetre gondolnunk. Ezért a Szerkesztőség egy sorozat k. . . .

A Microchip által javasolt fejlesztőkörnyezet az MPLABX, amely felváltja az MPlab-ot. Használata nehézkesnek tűnhet, ezért megnézzük ennek az IDE környezetnek a használatát, készítünk egy egyszerű projektet, amely egy PIC32 mikrovezérlőre épül.. . . .