Obsługa przerwań w mikrokontrolerach PIC16F

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
Marcin
User
User
Posty: 145
Rejestracja: środa 09 wrz 2015, 19:30

Obsługa przerwań w mikrokontrolerach PIC16F

Postautor: Marcin » niedziela 11 lut 2018, 19:45

Witam

Od jakiegoś czasu są u mnie na topie mikrokontrolery PIC z serii PIC16F. Jako że świeżo mam na tapecie przerwania chciałbym je omówić w mikrokontrolerach z serii PIC16F. To zagadnienie omówię na przykładzie mikrokontrolera PIC16F18326, który od jakiegoś czasu siedzi u mnie na płytce stykowej.

Konfiguracja przerwań zawiera się w trzech rejestrach.
INTCON - INTERRUPT CONTROL REGISTER
PIEx - PERIPHERAL INTERRUPT ENABLE REGISTER x (gdzie x to numer rejestru, w tym mikrokontrolerze jest pięć rejestrów konfiguracyjnych PIE0, PIE1, PIE2, PIE3, PIE4)
PIRx - PERIPHERAL INTERRUPT REQUEST REGISTER x (gdzie x to numer rejestru, w tym mikrokontrolerze jest pięć rejestrów konfiguracyjnych PIR0, PIR1, PIR2, PIR3, PIR4)

Domyślnie przerwania są wyłaczone. Aby je włączyć należy ustawić bit GIE (Global Enable Interrupt) oraz dla obsługi przerwań od układów peryferyjnych bit PEIE (Peripheral Interrupt Enable) - oba bity znajdują się w rejestrze INTCON, a także włączyć przerwania od poszczególnych układów w rejestrach PIE0, PIE1, PIE2, PIE3, PIE4.

Istnieje zasadnicza różnica obsługi przerwań miedzy dobrze znanymi u nas AVRami a PICami. W AVR każde źródło przerwania ma przydzielony wektor przerwania (funkcję obsługującą przerwanie) Dla przykładu, przepełnienie licznika TIMER0 jest obsługiwane przez inną funkcję niż np zakończenie konwersji ADC a jeszcze inną niż odebranie danych z UART. W przypadku mikrokontrolerów z serii PIC16F jest tylko jeden wektor przerwania. Wszystkie moduły, niezależnie czy to liczniki, przetworniki ADC, komparatory czy moduły komunikacyjne generują zdarzenia, które są obsługiwane przez jeden wspólny wektor przerwania. Skąd wiadomo który moduł zgłasza konieczność obsługi ? Źródła przerwania należy szukać w rejestrach PIR0, PIR1, PIR2, PIR3 oraz PIR4. Każdy moduł czy peryferium zgłaszając zdarzenie ustawia jednocześnie odpowiednia flagę w jednym z rejestrów PIR. Dla przykładu zakończenie konwersji przez ADC ustawi bit ADIF w rejestrze PIR1. Przepełnienie licznika TIM3 ustawi flagę TMR3IF w rejestrze PIR3. Po szczegóły innych źródeł odsyłam do datasheet. Bardzo ważne by w funkcji obsługi przerwania programowo skasować flagę aktualnie obsługiwanego przerwania.

A teraz może praktyczny przykład na wspomnianym PIC16F18326 - pomiar napięcia przez ADC. Pomiar przez ADC wyzwalany jest przepełnieniem licznika Timer1, wartość z ADC leci do CCP pracującego w trybie PWM. Pokażę tylko to co jest związane z obsługą przerwania.

main.c

Kod: Zaznacz cały

void main(void)
{
    SYSTEM_Initialize();

    //włączenie przerwań
    INTCON |= (_INTCON_PEIE_MASK) | (_INTCON_GIE_MASK);

    //wybór kanału na którym ADC mierzy
    ADC_SelectChannel(0x14);

    //pomiar przez adc uruchamiany jest przy przepełnieniu licznika Timer1 wobec czego musimy włączyć ten licznik
    T1CON |= (_T1CON_TMR1ON_MASK);

    while (1)
    {
    }
}


konfiguracja pzetwornika ADC

Kod: Zaznacz cały

void ADC_Initialize(void)
{
    // set the ADC to the options selected in the User Interface
   
    // ADGO stop; ADON enabled; CHS ANA0;
    ADCON0 = 0x01;
   
    // ADFM right; ADNREF VSS; ADPREF VDD; ADCS FOSC/4;
    ADCON1 = 0xC0;
   
    // ADACT TMR1_overflow;
    ADACT = 0x04;
   
    // ADRESL 0;
    ADRESL = 0x00;
   
    // ADRESH 0;
    ADRESH = 0x00;
   
    // Enabling ADC interrupt.
    PIE1bits.ADIE = 1;      //Tu właczamy przerwania od ADC !!!
}


Obsługa przerwania

Kod: Zaznacz cały

void interrupt INTERRUPT_InterruptManager (void)
{
    // interrupt handler
    if(INTCONbits.PEIE == 1)
    {
        if(PIE1bits.ADIE == 1 && PIR1bits.ADIF == 1)
        {
            ADC_ISR();      //tu skaczemy do funkcji ADC_ISR która jest zaimplementowana w pliku adc.c
        }
        else
        {
            //Unhandled Interrupt
        }
    }     
    else
    {
        //Unhandled Interrupt
    }
}


I wspomniana wyżej funkcja ADC_ISR()

Kod: Zaznacz cały

void ADC_ISR(void)
{
    // Clear the ADC interrupt flag
    PIR1bits.ADIF = 0;         //Kasujemy flagę przerwania !!!!
   
    CCPR2 = ADC_GetConversionResult();
}


Zaznaczam że powyżej opis dotyczy mikrokontrolera PIC16F18326, w innych mikrokontrolerach układ flag i bitów włączających przerwania może być inny, należy sięgnąć po notę katalogową aktualnie używanego mikrokontrolera. Mam nadzieję że materiał będzie pomocny dla innych.

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1075
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: Obsługa przerwań w mikrokontrolerach PIC16F

Postautor: Antystatyczny » niedziela 11 lut 2018, 20:53

Materiał jest bardzo pomocny i ładnie opisany. W przypadku tego układu mamy sytuację całkiem klarowną, bo nie ma priorytetów przerwań i program zawsze skacze do 0x0004. Szkielet programu generowałeś w MCC, czy klepnąłeś ręcznie?
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

Awatar użytkownika
Marcin
User
User
Posty: 145
Rejestracja: środa 09 wrz 2015, 19:30

Re: Obsługa przerwań w mikrokontrolerach PIC16F

Postautor: Marcin » niedziela 11 lut 2018, 21:02

Antystatyczny pisze:Szkielet programu generowałeś w MCC, czy klepnąłeś ręcznie?

Wszystko w MPLab Code Configurator. Bardzo ładnie tworzy kod, czytelnie i bez nadmiarowego kodu.


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 1 gość