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