WebElektronika

Megszakításkezelés a PIC18F14K50-es mikrovezérlőnél

person access_time 2015.04.13.
Noha korábban már foglalkoztunk a PIC18F mikrovezérlő megszakításkezelésével, most ismét elővesszük ezt a témakört, készítünk prioritásos és nem prioritásos megszakításra is példát. Az AD átalakító, a Timer0 és a Timer1 fognak megszakításokat generálni.


A PIC18F család prioritásos megszakítással rendelkezik. Ez azt jelenti, hogy az alacsonyszintű megszakításkiszolgálás (címe : 18H) felfüggesztésre kerül akkor, ha magasszintű (címe : 8H) interruptkérés érkezik. Ehhez persze engedélyezni kell a prioritásos megszakítás lehetőségét.

Ha nem engedélyezzük a prioritásos megszakítást, akkor csak a 8H cím kerül alkalmazásra, amikor megszakításkezelést alkalmazunk.

Először egy olyan megszakításra nézünk példát, amely nem rendlekezik prioritásos megszakítással, noha az RCON regiszter IPEN bitje logikai 1-ben van, tehát a kétszintű megszakítás enegdélyezve van, de az alacsonyszintű IT Handler hiányzik.

(A programok elkészítésekor az MCC18-as fordító "main.c" programját használtuk fel kiindulásként. mplabc18\v3.46\example\Interrupt\main.c)

 

1. példa

#include <p18f14k50.h>
#pragma config LVP = OFF

void InterruptHandlerHigh(void);

main()
{
    INTCON = 0x20;            // 0010 0000
                                                 // TMR0IE = 1
    INTCON2 = 0x84;          // 1000 0100
                                                 // TMR0IP = 1
                                                // magasszintű IT
    RCONbits.IPEN = 1;     // prioritásos IT
    TMR0H = 0;
    TMR0L = 0;
    T0CON = 0x80;             // 1000 0000
                                               // TMR0 bekapcsolva
                                               // 16 bit, 1:2 osztó
    INTCONbits.GIEH = 1;    // Globális IT
                                                    // engedélyezése
    TRISC = 0x00;                  // C port kimenet
    LATC = 0x00;                  // C port nullázása
    
    while(1)
    {
      
    }
}

#pragma code InterruptVectorHigh = 0x08
void InterruptVectorHigh(void)
{
    _asm
        goto InterruptHandlerHigh
    _endasm
}


#pragma code
#pragma interrupt InterruptHandlerHigh

void InterruptHandlerHigh()
{
    if (INTCONbits.TMR0IF)
    {
        INTCONbits.TMR0IF = 0;
        LATC++;
    }
}

 

2. példa

A következő példában egy LED-et (C port 2. bit) villogtatunk, az ehhez szükséges késleltetést szoftveresen valósítottuk meg. Amikor a Timer0 túlcsordul, akkor megszakítás keletkezik, a Villog() függvény végrehajtása felfüggesztésre kerül.

#include <p18f14k50.h>
#pragma config LVP = OFF

void InterruptHandlerHigh(void);

void Villog()
{
    int i;
    for(i = 0; i < 3000; i++);
    LATCbits.LATC2 = ~LATCbits.LATC2;
}

main()
{
    INTCON = 0x20;
    INTCON2 = 0x84;
    RCONbits.IPEN = 1;
    TMR0H = 0;
    TMR0L = 0;
    T0CON = 0x80;
    INTCONbits.GIEH = 1;
    TRISC = 0;
    LATC = 0x00;
    
    while (1)
    {
        Villog();
    }
}

#pragma code InterruptVectorHigh = 0x08
void InterruptVectorHigh(void)
{
  _asm
    goto InterruptHandlerHigh
  _endasm
}


#pragma code
#pragma interrupt InterruptHandlerHigh

void InterruptHandlerHigh()
{
  if (INTCONbits.TMR0IF)
    {
      INTCONbits.TMR0IF = 0;

      LATCbits.LATC0 = !LATCbits.LATC0;
    }
}

 

3. példa

Ebben a példában már felhasználjuk a kétszintű megszakítást, elkészítettük az alacsonyszintű megszakításhoz tartozó IT Handler-t is.

A magasszintű IT-t a Timer0 túlcsordulása, az alacsonyszintű IT-t pedig az AD átalakító működésének a befejezése fog kiváltani.

Az AD átalakítót felkonfiguráljuk az ADCON1,2,3 regiszterek írásával. Elinditjuk a konverziót, de csak egyszer fog ez a modul működni a while(1); miatt. Amikor az AD átalakító a működését befejezte, ad egy megszakítást, amelynek hatására a C port 2. bitje logikai 1-be kerül.

#include <p18f14k50.h>
#include "adc.h"
#pragma config LVP = OFF

void InterruptHandlerHigh(void);
void InterruptHandlerLow(void);

main()
{
    INTCON = 0x20;
    INTCON2 = 0x84;
    RCONbits.IPEN = 1;
    TMR0H = 0;
    TMR0L = 0;
    T0CON = 0x80;
    INTCONbits.GIEH = 1;
    TRISC = 0;
    LATC = 0x00;
    
    ADCON0 = 0B00101001;
    ADCON1 = 0B00000000;
    ADCON2 = 0B10101010;
    PIE1bits.ADIE = 1;
    IPR1bits.ADIP = 0;        // alacsony, 0x18
    INTCONbits.GIEL = 1;
    
    while (1)
    {
        ConvertADC();
        while(1);
    }
}

#pragma code InterruptVectorHigh = 0x08
void InterruptVectorHigh(void)
{
    _asm
        goto InterruptHandlerHigh
    _endasm
}

#pragma code InterruptVectorLow = 0x18
void InterruptVectorLow(void)
{
    _asm
        goto InterruptHandlerLow
    _endasm
}

#pragma code
#pragma interrupt InterruptHandlerHigh

void InterruptHandlerHigh()
{
    if(INTCONbits.TMR0IF)
    {
        INTCONbits.TMR0IF = 0;
        LATCbits.LATC0 = !LATCbits.LATC0;
    }
}

#pragma code
#pragma interrupt InterruptHandlerLow

void InterruptHandlerLow()
{
    if(PIR1bits.ADIF)
    {
        PIR1bits.ADIF = 0;
        LATCbits.LATC2 = 1;
    }
}

 

4. példa

Ez a program hasonlít az előzőre, de az AD-nek is magasszintű a megszakítása. Bent maradt a C kódban az alacsonyszintű IT Handler is, de soha nem kerül végrehajtásra.

#include <p18f14k50.h>
#include "adc.h"
#pragma config LVP = OFF

void InterruptHandlerHigh(void);
void InterruptHandlerLow(void);

main()
{
    INTCON = 0x20;
    INTCON2 = 0x84;
    RCONbits.IPEN = 1;
    TMR0H = 0;
    TMR0L = 0;
    T0CON = 0x80;
    INTCONbits.GIEH = 1;
    TRISC = 0;
    LATC = 0x00;
    
    ADCON0 = 0B00101001;
    ADCON1 = 0B00000000;
    ADCON2 = 0B10101010;
    PIE1bits.ADIE = 1;
    IPR1bits.ADIP = 1;        // magas, 0x08
    
    while(1)
    {
        ConvertADC();
        while(1);
    }
}

#pragma code InterruptVectorHigh = 0x08
void InterruptVectorHigh (void)
{
    _asm
        goto InterruptHandlerHigh
    _endasm
}

#pragma code InterruptVectorLow = 0x18
void InterruptVectorLow (void)
{
    _asm
        goto InterruptHandlerLow
    _endasm
}

#pragma code
#pragma interrupt InterruptHandlerHigh

void InterruptHandlerHigh()
{
    if(INTCONbits.TMR0IF)
    {
        INTCONbits.TMR0IF = 0;
        LATCbits.LATC0 = !LATCbits.LATC0;
    }
    
    if(PIR1bits.ADIF)
    {
        PIR1bits.ADIF = 0;
        LATCbits.LATC1 = 1;
    }
}

#pragma code
#pragma interrupt InterruptHandlerLow

void InterruptHandlerLow()
{
    // Az AD magasszintű, 
    // ide nem kerülhet az IT!!!
    if(PIR1bits.ADIF)
    {
        PIR1bits.ADIF = 0;
        LATCbits.LATC3 = 1;
    }
}

 

5. példa

Ez a példa szinte megegyezik az előzővel, a különbség az, hogy a Timer1 túlcsordulása is megszakítást fog okozni, amely alacsonyszintű lesz, azaz a megszakításkor a vezérlés a 18H címre ugrik.

#include <p18f14k50.h>
#include "adc.h"
#pragma config LVP = OFF

void InterruptHandlerHigh(void);
void InterruptHandlerLow(void);

main()
{
    INTCON = 0x20;
    INTCON2 = 0x84;
    RCONbits.IPEN = 1;
    
    TMR0H = 0;
    TMR0L = 0;
    T0CON = 0x80;        // 1000 0000
    
    TMR1H = 0;
    TMR1L = 0;
    T1CON = 0B10001101;        //0x81
    IPR1bits.TMR1IP = 0;    // alacsony
    PIE1bits.TMR1IE = 1;    // engedélyezés
    
    
    INTCONbits.GIEH = 1;    // magas IT engedély
    INTCONbits.GIEL = 1;    // alacsony IT engedély
    TRISC = 0;
    LATC = 0x00;
    
    ADCON0 = 0B00101001;
    ADCON1 = 0B00000000;
    ADCON2 = 0B10101010;
    PIE1bits.ADIE = 1;
    IPR1bits.ADIP = 1;        // magas, 0x08
    
    while (1)
    {
        ConvertADC();
        while(1);
    }
}

#pragma code InterruptVectorHigh = 0x08
void InterruptVectorHigh (void)
{
  _asm
    goto InterruptHandlerHigh
  _endasm
}

#pragma code InterruptVectorLow = 0x18
void InterruptVectorLow(void)
{
  _asm
    goto InterruptHandlerLow
  _endasm
}

#pragma code
#pragma interrupt InterruptHandlerHigh

void InterruptHandlerHigh()
{
  if (INTCONbits.TMR0IF)
    {
      INTCONbits.TMR0IF = 0;
      LATCbits.LATC0 = !LATCbits.LATC0;
    }
    
    if(PIR1bits.ADIF)
    {
        PIR1bits.ADIF = 0;
        LATCbits.LATC1 = 1;
    }
}

#pragma code
#pragma interrupt InterruptHandlerLow

void InterruptHandlerLow()
{
    if(PIR1bits.TMR1IF)
    {
        PIR1bits.TMR1IF = 0;
        LATCbits.LATC3 = ~LATCbits.LATC3;
    }
}