loader
Foto

Az interrupt flag elmaradt szoftveres törlésének hatása

Ha egy flag-et nem törlünk szoftveresen, az nem szintaktikai hibát eredményez, hanem működési hibát okoz a program működése során. Ez rosszabb, mert a szintaktikai hiba esetén a projektünket nem tudjuk lefordítani, és azután letölteni a mikrovezérlőbe, de egy nem törölt flag olyan működési változást okoz, amelynek a felderítése nem mindig egyszerű.

A WebElektronika különböző cikkeiben már hansúlyoztuk, hogy az interrupt flag-eket szoftveresen törölni kell, amikor olyan mikrovezérlős alkalmazást fejlesztünk, ahol használunk megszakításkezelést. De miért is kell nekünk törölni, amikor a flag beállítása logikai "1"-be nem programból történik? Nézzük meg ezt egy alkalmazás segítségével, amikor a szoftveres törlést "véletlenül" elfelejtjük.
Indítsuk el az MpLABX-et, és hozzunk létre egy projektet, ahova másoljuk be a köveztkező programot, amely már ebben a cikkben is szerepelt.

#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();
    }
}

 

Ez a program megegyezik a korábbi cikkünk alkalmazásával, de a különbség az, hogy a Timer2 IT flag-jét nem töröljük szoftveresen (ezt a makró kikommentelésre került az IT handlerben). Ezért, amikor a Timer2 először ad megszakításkérést, akkor a vezérlés a T2Int() it függvényre kerül, megtörténik a "D2" állapotváltása, és kilép a vezérlés a T2Int() függvényből. Viszont a T2IF flag értéke logikai "1" maradt, ezért újra meghívásra kerül a T2Int() függvény, megint ennek a függvénynek a tartalma kerül végrehajtásra, és így tovább. 
Látható tehát az, hogy a Timer2-höz tartozó interrupt handler állandóan meghívásra kerül, ez alól csak akkor van kivétel, ha a Timer1 belső periféria szintén megszakításkérést ad. 

Látható a "D0" kimeneten (1. ábra), hogy az végig logikai "0"-ban van, a for ciklus soha nem tud elszámolni 0-tól 500-ig. A Timer1 időzítő normálisan működik, és amikor a TMR1 értéke megegyezik a PR1 értékével, akkor a T1IF flag logikai "1"-be vált, a "D1" kimenet állapotot vált, majd nullázzuk a T1IF flag-et. Ugyanakkor látható még az is az első ábrán, hogy a T2IF flag végig logikai "1"-ben van (először "0"-ban volt), ezért a "D2" kimenet állandóan állapotot vált.

kep
1. ábra   Nem törölt IT flag hatása, "rezonál" a "D2" kimenet
 

Érdemes még megjegyezni azt is, hogy a "D3" kimenet logikai "1"-ben van, soha nem vált állapotot. Ez azért van, mert a vezérlés mindig a két interrupt fügvény egyikében van.

Ha kinagyítjuk a kapott eredményt, akkor láthatjuk azt is, hogy a T1Int() függvénynél először a "D1" kimenetet negáljuk, majd azután töröljük a flaget. A két művelet között kb 1 tized osztás van, tehát a két művelet végrehajtása között kb 2uS idő telik el (2. ábra).

kep
2. ábra   Két utasítás között eltelt idő
 

Látható tehát az az első ábra alapján, hogy ha nem töröljük szoftveresen az IT flageket, akkor a programunk működése jelentősen megváltozik. Tekintettel arra, hogy ez a hiba nem szintaktikai, a lefordított (de rossz) alkalmazásunkat gond nélkül tudjuk letölteni a mikrovezérlőbe.

 



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.. . . .