Què són les interrupcions?
Imagina que estàs cuinant, ja vas col·locar aigua a bullir, ja licuaste tot el necessari i de sobte toquen el timbre de casa teva, t’estan interrompent, llavors la teva funció en aquest moment serà anar a obrir la porta, atendre a la persona i tancar la porta, quan acabes, tornes a cuinar, però no tornes a començar, sinó que segueixes cuinant des d’on et vas quedar.
Quan s’activa una interrupció, el microcontrolador deixarà de fer el que està fent per realitzar la funció d’interrupció que s’hagi declarat anteriorment, per després tornar a on s’havia quedat.
Una interrupció es pot veure com un avís que pot ser activat tant per algun procés específic de l’microcontrolador (final de conversió de l’ADC, recepció de dades de la lliçó EUSART, desbordament de timer, etc.) o per un canvi extern a la mateixa (canvi en algun port específic, canvi d’un pin, etc.).
Interrupcions en PIC C Compiler
A la pestanya View de el PIC C Compiler podrem trobar una casella que diu “interrupts”, en ella tindrem la informació de les interrupcions amb què compta el nostre microcontrolador. Per exemple, per al cas de Miuva (PIC 18F4550) trobarem la següent llista:
- AD: Conversió completa de l’ADC
- BUSCOL: Col·lisió de l’autobús
- CCP1 Captura o comparació en la unitat 1
- CCP2 Captura o comparació en la unitat 2
- COMP: Esdeveniment de comparació
- EEPROM: Escriptura completa
- EXT: Interrupció externa (RB0)
- EXT1: Interrupció externa (RB1)
- EXT2: Interrupció externa (RB2)
- LOWVOLT : Sota voltatge detectat
- OSCF: Fallada en el sistema de l’oscil·lador
- RB: Canvis en el port B (RB4: RB7)
- RDA: Dades rebudes disponibles RS232
- RTCC: Desbordi de l’timer0 (RTCC)
- SPP: Port de retransmissió paral·lel Escriptura / Lectura
- SSP: Activitat SPI / I2C
- TBE: Buffer de transmissió buit RS232
- tIMER0: Desbordi de timer0
- TIMER1: Desbordi de timer1
- tIMER2: Desbordi de timer2
- TIMER3: Desbordi de timer 3
- USB: Activitat USB
La forma d’activar les interrupcions és molt similar en tots els casos, hem de “avisar” a l’compilador que la funció per descriure serà d’interrupció i posteriorment afegir la funció com si fos qualsevol altra. De la següent manera:
#int_XXXXXvoid XXXXX_isr(){ //Declaramos la función de interrupción }}
Les “XXXX” hauran de ser substituïdes pel nom la interrupció a utilitzar (el podem trobar a la secció de View – > interrupts), per exemple, per activar la funció d’interrupció externa (RB0), haurem de substituir per “EXT”. Quedant de la següent manera:
#int_EXTvoid ext_isr(){ //Función de interrupción externa (RB0) }}
Dins la nostra funció main, hem d’activar les interrupcions amb les següents línies:
enable_interrupts(GLOBAL); //Habilita interrupcionesenable_interrupts(int_XXXX); //Habilita interrupción deseada
Seguint el cas de la interrupció externa:
enable_interrupts(GLOBAL); //Habilita interrupcionesenable_interrupts(int_EXT); //Habilita interrupción externa (RB0)
Per exemple, el següent codi, en la seva funció principal estarà augmentant un comptador de 16 bits i mostrant el seu valor en la LCD, però a l’hora de que s’activi la interrupció externa (RB0), invertirà el valor d’un led ubicat al PIN E0. Després d’invertir el valor de l’LED tornarà a el programa principal i seguirà comptant al número en què hi era.
#include <18f4550.h> // la librería del PIC#Fuses HSPLL, NOWDT, NOPROTECT, NOLVP, NODEBUG, USBDIV, PLL2, CPUDIV1, VREGEN#use delay (clock=48M) //Seleccionamos la frecuencia de reloj de 48MHz#use standard_io(b)#use standard_io(e)#include "MLCD.c"int16 contador = 0; #int_EXTvoid ext_isr(){ output_toggle(PIN_E0);}void main(){ lcd_init(); set_tris_b(0xFF); //Puerto b como entrada set_tris_e(0x00); //Puerto e como salida output_e(0x07); //Apaga led rgb enable_interrupts(GLOBAL); //Habilita interrupciones enable_interrupts(int_EXT); //Habilita interrupcion externa while(true){ contador++; printf(lcd_putc, "Cont = %5lu", contador); }}
Per obtenir més informació d’en quin moment es activa cadascuna de les diferents interrupcions és important llegir el full de dades.
Nivells d’interrupció
En moltes ocasions els nostres programes necessiten realitzar diverses tasques i algunes poden ser més importants que altres, és per això que quan treballem amb interrupcions podem declarar diferents prioritats per a elles, entre més alta sigui la seva prioritat més important és la tasca a realitzar, llavors si s’activa una interrupció d’alta prioritat, no importa el que estigui realitzant el nostre programa (fins i tot encara estigui realitzant una altra funció d’interrupció de baixa prioritat) saltarà a la funció corresponent i després tornarà a on era.
Per activar els nivells de prioritat en PIC C Compiler cal afegir la següent línia a l’inici del nostre codi:
#device HIGH_INTS=TRUE //Activamos niveles de prioridad
Posteriorment serà cal especificar quina de les interrupcions voldrem configurar com alta prioritat, per això haurem de afegir “HIGH” després que declarem que s’estarà fent servir una funció d’interrupció, de la següent manera:
#int_EXT1 HIGHvoid ext_isr(){ //Función de interrupción de alta prioridad }}
En el següent codi d’exemple, definirem dues interrupcions, ambdues externes, una habilitada pel pin RB1 i l’altra pel pin RB2, ja que segons el full de dades de l’microcontrolador, ambdues poden ser configurades tant d’alta com de baixa prioritat. el nostre codi va tenir tres comptadors independents, un s’augmentarà en la funció main, un altre més quan s’activi una interrupció de baixa prioritat i l’últim a l’activar-se la interrupció d’alta prioritat. Això servirà per que l’usuari corrobori el funcionament dels nivells, ja que en la LCD es mostrarà el valor dels 3 comptadors.
Quan no s’activin interrupcions estarà augmentant el valor de, si s’activa la interrupció de baixa prioritat (RB2) deixarà d’augmentar el valor de el comptador de l’main i augmentarà el valor de el comptador de la funció de baixa prioritat fins arribar a 10000 o fins que s’activi la interrupció d’alta prioritat la qual iniciarà el seu propi comptador fins que aquest arribi a 10000.
es pot notar que no hi ha res que pugui interrompre a la funció d’alta prioritat, per tant, només serà possible sortir d’aquesta funció fins que el comptador arribi a el valor definit (10000). A diferència de la funció de baixa prioritat que pot ser pausada per la d’alta. I a diferència de la funció principal que podrà ser pausada per la de baixa o la d’alta prioritat.
#include <18f4550.h> // la librería del PIC#device HIGH_INTS=TRUE #Fuses HSPLL, NOWDT, NOPROTECT, NOLVP, NODEBUG, USBDIV, PLL2, CPUDIV1, VREGEN#use delay (clock=48M) //Seleccionamos la frecuencia de reloj de 48MHz#use standard_io(b)#use standard_io(e)#include "MLCD.c"int16 contador = 0;int16 contador2 = 0;int16 contador3 = 0; #int_EXT1 HIGHvoid ext1_isr(){ for (contador3 = 0; contador3 <= 10000; contador3++){ lcd_gotoxy(1,1); printf(lcd_putc, "%5lu", contador3); }}#int_EXT2void EXT2_isr(){ contador2++; for (contador2 = 0; contador2 <= 10000; contador2++){ lcd_gotoxy(1,2); printf(lcd_putc, "%5lu", contador2); }}void main(){ lcd_init(); set_tris_b(0xFF); //Puerto b como entrada set_tris_e(0x00); //Puerto e como salida output_e(0x07); //Apaga led rgb enable_interrupts(GLOBAL); //Habilita interrupciones enable_interrupts(int_EXT2); enable_interrupts(int_EXT1); while(true){ if (contador >= 10000){ contador = 0; } else{ contador++; } lcd_gotoxy(10,1); printf(lcd_putc, "%5lu", contador); }}