Przerwania w PIC18

Nasze polecane książki, kursy, strony internetowe, fora itp. pomocne przy przyswajaniu wiedzy związanej z PIC i pisaniem programów dla nich.
Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

Przerwania w PIC18

Postautor: Antystatyczny » sobota 24 paź 2015, 17:57

Witam,

Dzisiaj króciutko o przerwaniach w układach z rodziny PIC18.

Układy PIC18XXXX posiadają dwa podstawowe tryby pracy. Ten domyślnie włączony po resecie mikrokontrolera pozbawiony jest priorytetów (zwany jest on przez firmę Microchip trybem kompatybilności z układami rodziny PIC16F). Drugi tryb, jeśli go włączymy, oferuje nam dwa priorytety przerwania: wysoki i niski. W przypadku domyślnego trybu mamy dostępny jeden wspólny wektor przerwania, a gdy włączymy priorytety, ilość dostępnych wektorów wzrasta do dwóch. Każde źródło przerwania kontrolowane jest przez 3 bity:

[*]bit włączający dane źródło przerwania
[*]bit ustalający priorytet przerwania dla danego źródła
[*]bit sygnalizujący wystąpienie przerwania z danego źródła

W przypadku, gdy priorytety są wyłączone, zmiana bitu priorytetu jest ignorowana i przerwanie generowane jest z priorytetem wysokim.
Wektor przerwania o wysokim priorytecie znajduje się pod adresem 0x0008, natomiast wektor o niskim priorytecie pod adresem 0x0018.
Jeśli zaś mamy włączone priorytety i podczas obsługi przerwania o niskim priorytecie wystąpi przerwanie o priorytecie wysokim, przerywana jest obsługa przerwania o niższym priorytecie, by niezwłocznie obsłużyć ważniejsze przerwanie. Po zakończeniu jego obsługi kontrola przekazywana jest z powrotem do przerwania o niższym priorytecie. Ok, a teraz czas na krótkie przykłady. Umieściłem w nich komentarze, więc wszystko powinno być czytelne i zrozumiałe.

Miganie diodą z wykorzystaniem timer0 i przerwania w trybie domyślnym, czyli bez priorytetów:

Kod: Zaznacz cały

/*
 * File:   main.c
 * Author: Anty
 *
 * Created on 24 październik 2015, 14:16
 */


#include <xc.h>
#include <stdint.h>
#include <stdbool.h>

//ustawienia bitów konfiguracyjnych dla PIC18F4550 @ 48MHz (kwarc 4MHz)
#include "mpu_config.h"

#define TMR0_RELOAD (65535 - (_XTAL_FREQ/4)/256/100)
#define TMR0_RELOAD_L   (TMR0_RELOAD & 0xFF)    //0x2B
#define TMR0_RELOAD_H   (TMR0_RELOAD >> 8)      //0xFE

/*
priorytety są wyłączone, a wszelkie włączone przerwania będą wywoływały skok
pod domyślny adres 0x0008. Nie jest wymagane określanie priorytetu w kodzie
programu
*/
void interrupt myISR(void);

//zmienna realizująca funkcję timera programowego
volatile uint8_t softTimer;

void main(void)
{
    /*
    inicjalizacja sprzętu - pin sterujący diodą led:
    Należy zwrócić uwagę na ustawienie PBADEN w bitach konfiguracyjnych
    PBADEN decyduje o trybie pracy PORTB po resecie mikrokontrolera. Jeśli
    PBADEN = ON, port pracuje w trybie analogowym, a jeśli OFF, pracuje w trybie cyfrowym
    Tryb pracy mozna również zmieniać w czasie wykonywania programu. Dokładny opis
    znajdziesz w datasheet układu, a konkretnie w rozdziale opisującym
    przetwornik ADC
    */
    TRISBbits.TRISB0 = 0;//pin RB0 jako wyjście
    LATBbits.LATB0 = 0;//dioda led w stanie "zgaszonym"
   
    //inicjalizacja sprzętowego timera 0
    T0CONbits.TMR0ON = 1;   //włącz timer 0 (domyślnie jest włączony)
    T0CONbits.T08BIT = 0;   //włącz 16 bitowy tryb pracy
    T0CONbits.T0CS = 0;     //taktowanie z wewnętrznego źródła (f_osc/4)
    T0CONbits.PSA = 0;      //timer bedzie taktowany poprzez preskaler
    T0CONbits.T0PS2 = 1;    //preskaler 256
    T0CONbits.T0PS1 = 1;
    T0CONbits.T0PS0 = 1;
   
    //włączenie przerwań
    INTCONbits.TMR0IE = 1;//umożliwienie generowania przerwań przez timer0
    INTCONbits.PEIE_GIEL = 1;//włączenie przerwań dla ukłądów peryferyjnych
    INTCONbits.GIE_GIEH = 1;//globalne włączenie przerwań. Można uzyć makra ei();
       
    while(true)
    {
        if(!softTimer)
        {
            //zmień stan diody na przeciwny
            LATBbits.LATB0 ^= 1;
           
            //nakręć timerek programowy, by stan diody zmieniał się około
            //1 raz na sekundę
            softTimer = 99;
        }
    }
}

void interrupt myISR(void)
{
    //jeśli włączone jest przerwanie oraz ustawiona jest flaga dla timer0
    if(INTCONbits.T0IE && INTCONbits.T0IF)
    {
        //skasuj flagę przerwania
        INTCONbits.T0IF = 0;
       
        //załaduj licznik timera, by generował przerwanie co ok. 10ms
        TMR0H = TMR0_RELOAD_H;
        TMR0L = TMR0_RELOAD_L;
       
        //obsłuż naszą zmienną softTimer
        if(softTimer)
        {
            softTimer--;
        }
    }
}




A teraz lekko zmodyfikowana wersja, która włącza priorytety i wykorzystuje przerwanie o niskim priorytecie. Wysoki priorytet pozostaje "pusty":

Kod: Zaznacz cały

/*
 * File:   main.c
 * Author: Anty
 *
 * Created on 24 październik 2015, 14:16
 */


#include <xc.h>
#include <stdint.h>
#include <stdbool.h>

//ustawienia bitów konfiguracyjnych dla PIC18F4550 @ 48MHz (kwarc 4MHz)
#include "mpu_config.h"

#define TMR0_RELOAD (65535 - (_XTAL_FREQ/4)/256/100)
#define TMR0_RELOAD_L   (TMR0_RELOAD & 0xFF)    //0x2B
#define TMR0_RELOAD_H   (TMR0_RELOAD >> 8)      //0xFE

/*
Priorytety będą włączone, a wszelkie włączone przerwania będą wywoływały skok
pod adres zgodny z ustawionym priorytetem dla danego źródła. Dla niskiego priorytetu
jest to 0x0018, a dla wysokiego 0x0008
*/
void low_priority interrupt my_low_ISR(void);
void high_priority interrupt my_high_ISR(void);

//zmienna realizująca funkcję timera programowego
volatile uint8_t softTimer;

void main(void)
{
    /*
    inicjalizacja sprzętu - pin sterujący diodą led:
    Należy zwrócić uwagę na ustawienie PBADEN w bitach konfiguracyjnych
    PBADEN decyduje o trybie pracy PORTB po resecie mikrokontrolera. Jeśli
    PBADEN = ON, port pracuje w trybie analogowym, a jeśli OFF, pracuje w trybie cyfrowym
    Tryb pracy mozna również zmieniać w czasie wykonywania programu. Dokładny opis
    znajdziesz w datasheet układu, a konkretnie w rozdziale opisującym
    przetwornik ADC
    */
    TRISBbits.TRISB0 = 0;//pin RB0 jako wyjście
    LATBbits.LATB0 = 0;//dioda led w stanie "zgaszonym"
   
    //inicjalizacja sprzętowego timera 0
    T0CONbits.TMR0ON = 1;   //włącz timer 0 (domyślnie jest włączony)
    T0CONbits.T08BIT = 0;   //włącz 16 bitowy tryb pracy
    T0CONbits.T0CS = 0;     //taktowanie z wewnętrznego źródła (f_osc/4)
    T0CONbits.PSA = 0;      //timer bedzie taktowany poprzez preskaler
    T0CONbits.T0PS2 = 1;    //preskaler 256
    T0CONbits.T0PS1 = 1;
    T0CONbits.T0PS0 = 1;
   
    //włączenie priorytetów
    RCONbits.IPEN = 1;
   
    //przypisanie niskiego priorytetu dla timer0
    INTCON2bits.TMR0IP = 0; //timer0 wygeneruje przerwanie o niskim priorytecie
   
    //włączenie przerwań
    INTCONbits.TMR0IE = 1;//umożliwienie generowania przerwań przez timer0
    INTCONbits.PEIE_GIEL = 1;//włączenie wszystkich przerwań o niskim priorytecie
                            //dla układów peryferyjnych
    INTCONbits.GIE_GIEH = 1;//włączenie wszystkich przerwań o wysokim priorytecie
       
    while(true)
    {
        if(!softTimer)
        {
            //zmień stan diody na przeciwny
            LATBbits.LATB0 ^= 1;
           
            //nakręć timerek programowy, by stan diody zmieniał się około
            //1 raz na sekundę
            softTimer = 99;
        }
    }
}

void low_priority interrupt my_low_ISR(void)
{
    //Obsługa przerwań o niskim priorytecie. Nie zapomnij o kasowaniu flag przerwań
   
    //jeśli włączone jest przerwanie oraz ustawiona jest flaga dla timer0
    if(INTCONbits.T0IE && INTCONbits.T0IF)
    {
        //skasuj flagę przerwania
        INTCONbits.T0IF = 0;
       
        //załaduj licznik timera, by generował przerwanie co ok. 10ms
        TMR0H = TMR0_RELOAD_H;
        TMR0L = TMR0_RELOAD_L;
       
        //obsłuż naszą zmienną softTimer
        if(softTimer)
        {
            softTimer--;
        }
    }
}

void high_priority interrupt my_high_ISR(void)
{
    //tutaj umieść  obsługę przerwań o wysokim priorytecie
    //Nie zapomnij o kasowaniu flag przerwań
}


Oba programy zostały przeze mnie skompilowane i sprawdzone w fizycznym układzie PIC18F4550. Do kompletu załączam jeszcze zawartość pliku mpu_config.h, który został wykorzystany w obu programach:

Kod: Zaznacz cały

/*
 * File:   mpu_config.h
 * Author: Anty
 *
 * Created on 24 październik 2015, 14:20
 */

#ifndef MPU_CONFIG_H
#define   MPU_CONFIG_H

#ifdef   __cplusplus
extern "C" {
#endif

// CONFIG1L
#pragma config PLLDIV = 1       // PLL Prescaler Selection bits (No prescale (4 MHz oscillator input drives PLL directly))
#pragma config CPUDIV = OSC1_PLL2// System Clock Postscaler Selection bits ([Primary Oscillator Src: /1][96 MHz PLL Src: /2])
#pragma config USBDIV = 1       // USB Clock Selection bit (used in Full-Speed USB mode only; UCFG:FSEN = 1) (USB clock source comes directly from the primary oscillator block with no postscale)
// CONFIG1H
#pragma config FOSC = HSPLL_HS  // Oscillator Selection bits (HS oscillator, PLL enabled (HSPLL))
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)
// CONFIG2L
#pragma config PWRT = OFF       // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOR = ON         // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 3         // Brown-out Reset Voltage bits (Minimum setting)
#pragma config VREGEN = OFF     // USB Voltage Regulator Enable bit (USB voltage regulator disabled)
// CONFIG2H
#pragma config WDT = OFF        // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)
// CONFIG3H
#pragma config CCP2MX = ON      // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = OFF     // PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset)
#pragma config LPT1OSC = OFF    // Low-Power Timer 1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = ON       // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)
// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF        // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
#pragma config ICPRT = OFF      // Dedicated In-Circuit Debug/Programming Port (ICPORT) Enable bit (ICPORT disabled)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled)
// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 (000800-001FFFh) is not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 (002000-003FFFh) is not code-protected)
#pragma config CP2 = OFF        // Code Protection bit (Block 2 (004000-005FFFh) is not code-protected)
#pragma config CP3 = OFF        // Code Protection bit (Block 3 (006000-007FFFh) is not code-protected)
// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block (000000-0007FFh) is not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM is not code-protected)
// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 (000800-001FFFh) is not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 (002000-003FFFh) is not write-protected)
#pragma config WRT2 = OFF       // Write Protection bit (Block 2 (004000-005FFFh) is not write-protected)
#pragma config WRT3 = OFF       // Write Protection bit (Block 3 (006000-007FFFh) is not write-protected)
// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) are not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block (000000-0007FFh) is not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM is not write-protected)
// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 (000800-001FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 (002000-003FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection bit (Block 2 (004000-005FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection bit (Block 3 (006000-007FFFh) is not protected from table reads executed in other blocks)
// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot block (000000-0007FFh) is not protected from table reads executed in other blocks)



#ifdef   __cplusplus
}
#endif

#endif   /* MPU_CONFIG_H */


I to chyba tyle... Życzę miłego mrygania ;)
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

Wróć do „Źródła wiedzy na temat PIC”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 4 gości