Programació en pic-as del PIC 16F690

Referència Trucs Perifèrics   Recursos CITCEA
Tutorial Exemples Projectes   Inici

Interrupcions

El microcontrolador té la possibilitat que alguns esdeveniments facin una interrupció al programa. Quan hi ha una interrupció, el microcontrolador deixa el que estava fent i executa el programa d'interrupció; quan acaba la funció d'interrupció (instrucció retfie), torna on estava i segueix el que estava fent.

Podem activar o desactivar individualment les interrupcions provinents de cada un dels elements que en poden generar. Addicionalment, podem habilitar o deshabilitar les interrupcions de forma global. El bit GIE del registre INTCON controla globalment les interrupcions. També caldrà activar la interrupció concreta al registre corresponent. La següent taula conté els registres que controlen les interrupcions més destacades. Els bits de control són els que permeten activar (quan estan a 1) o desactivar la interrupció. Les banderes són les que ens permeten saber quina interrupció és lque s'ha activat (i cal desactivar-les manualment).

Important: La interrupció del microcontrolador es produeix quan està activada la bandera corresponent a una interrupció activada i està activat el bit GIE. Això vol dir que si quan activem el bit GIE hi ha alguna bandera activada la interrupció es produirà immediatament. El microcontrolador no gestiona la desactivació de les banderes sinó que les hem de desactivar en el nostre programa un cop les hem consultat.

Registre Núm. bit Adreça bit Funció
INTCON 7 GIE Activació global de les interrupcions
6 PEIE Activació de les interrupcions per perifèrics
(Controlats pels registres PIE1 i PIE2)
5 T0IE Activació de la interrupció per Timer 0
4 INTE Activació de la interrupció externa (RA2)
3 RABIE Activació de la interrupció per canvis als ports A i B
(Controlats pels registres IOCA i IOCB)
2 T0IF Bandera de la interrupció per Timer 0
1 INTF Bandera de la interrupció externa (RA2)
0 RABIF Bandera de la interrupció per canvis als ports A i B⦿
PIE1 6 ADIE Activació de les interrupcions per conversor A/D
5 RCIE Activació de les interrupcions per recepció de la comunicació sèrie asíncrona
4 TXIE Activació de les interrupcions per emissió de la comunicació sèrie asíncrona
3 SSPIE Activació de les interrupcions per la comunicació sèrie síncrona
2 CCP1IE Activació de les interrupcions per capturador/comparador
1 TMR2IE Activació de les interrupcions per timer 2
0 TMR1IE Activació de les interrupcions per timer 1
PIE2 7 OSFIE Activació de les interrupcions per fallada de l'oscil·lador
6 C2IE Activació de les interrupcions per comparador C2
5 C1IE Activació de les interrupcions per comparador C1
4 EEIE Activació de les interrupcions per EEPROM
PIR1 6 ADIF Bandera de la interrupció per conversor A/D
5 RCIF Bandera de la interrupció per recepció de la comunicació sèrie asíncrona
4 TXIF Bandera de la interrupció per emissió de la comunicació sèrie asíncrona
3 SSPIF Bandera de la interrupció per la comunicació sèrie síncrona
2 CCP1IF Bandera de la interrupció per capturador/comparador
1 TMR2IF Bandera de la interrupció per timer 2
0 TMR1IF Bandera de la interrupció per timer 1
PIR2 7 OSFIF Bandera de la interrupció per fallada de l'oscil·lador
6 C2IF Bandera de la interrupció per comparador C2
5 C1IF Bandera de la interrupció per comparador C1
4 EEIF Bandera de la interrupció per EEPROM
OPTION_REG 6 INTEDG Si està activat la interrupció externa és a l'activació
Si està desactivat és a la desactivació.
IOCA 0 a 5 IOCA0   a IOCA5 Si està activat el bit, la pota corresponent del port A farà interrupcions
(a l'activar-se i al desactivar-se)
IOCB 4 a 7 IOCB4   a IOCB7 Si està activat el bit, la pota corresponent del port B farà interrupcions
(a l'activar-se i al desactivar-se)

Cal que l'entrada implicada no estigui configurada com a analògica.

⦿ Cal tenir present que la bandera RABIF s'activa quan la darrera lectura del port no es correspon amb el valor actual. Si desactivem la bandera sense haver llegit encara el port ens trobarem que es torna a activar immediatament. Cal, doncs, llegir el port abans de desactivar la bandera.

Important: Atès que el PIC16F690 només pot tenir una funció d'interrupció, el més habitual és que dins d'aquesta es miri si està activat el bit corresponent a cada una de les interrupcions que es fan servir en el programa (T0IF, RABIF, TMR1IF, etc.) i, si ho està, es faci el que correspon. Això pot donar algun conflicte quan el programa fa servir diverses interrupcions que no estan sembre activades. Per exemple, imaginem un programa que fa servir Timer 1 i RA5 com a fonts d'interrupció i en un moment determinat estan desactivades les interrupcions per Timer 1 (TMR1IF) però el temporitzador segueix en marxa. Quan hi hagi una interrupció per RA5 (s'activi RABIF) es farà el que toca per aquesta interrupció però si també està activat TMR1IF també es farà la part corresponent; encara que la interrupció per Timer 1 estigui desactivada (TMR1IE desactivat). En alguns casos (com en els temporitzadors 1 i 2) és possible desactivar la font de les interrupcions (TMR1ON i TMR2ON) però en altres casos (com el temporitzador 0 o les interrupcions per entrades) això és més complicat o impossible. Per això és recomanable que la funció d'interrupció miri si estan activats simultàniament el bit de control de la interrupció (TMR1IE) i el que indica que s'ha produït l'esdeveniment (TMR1IF).

Interrup:
  ...
  btfss	RABIE  ; Mira si la interrupció per canvis als ports està activada
               ; Si ho és, no fa la instrucció següent
  goto	NoRAB  ; Si la interrupció no és per ports, saltem
  btfss	RABIF  ; Mira si la interrupció és per canvis als ports
               ; Si ho és, no fa la instrucció següent
  goto	NoRAB  ; Si la interrupció no és per ports, saltem
RAB:  ; Programa corresponent a canvi als ports
  ...
NoRAB:
  btfss	TMR1IE  ; Mira si la interrupció per timer 1 està activada
               ; Si ho és, no fa la instrucció següent
  goto	FiInt  ; Si la interrupció no és per timer 1, saltem
  btfss	TMR1IF  ; Mira si la interrupció és per timer 1
               ; Si ho és, no fa la instrucció següent
  goto	FiInt  ; Si la interrupció no és per timer 1, saltem
  ...
FiInt:
  ...
  retfie  ; Torna al programa principal, on s'havia quedat  

Atès que la interrupció pot venir en qualsevol moment, ens podem trobar que el programa d'interrupció ens modifiqui registres que poden ser importants per tal que el programa principal segueixi en la forma correcta. Cal doncs guardar una còpia d'aquests registres en una altra part de la memòria. Així doncs al començament del programa d'interrupció guardarem els registres i al final del programa els tornarem a copiar al seu lloc. Com el microcontrolador té quatre bancs de registres, podríem equivocar-nos si durant la funció d'interrupció es canvia a un altre banc o si en el moment de la interrupció no estàvem al banc esperat. Per evitar problemes, el millor és guardar aquests registres en una part de memòria que és físicament la mateixa en tots els bancs. Si mirem l'estructura dels registres, veurem que això passa a les adreces 70h a 7Fh (que si s'adrecen com F0h-FFh, 170h-17Fh o 1F0h-1FFh estan adreçant exactament el mateix registre físic).

La funció d'interrupció modificarà sempre, com a mínim, dos registres, W i STATUS, ja que els modifiquen la majoria de les instruccions. Al començar el programa o funció d'interrupció guardarem aquests valors i quan acabem la funció d'interrupció hem de recuperar els valors dels registres. Per recuperar STATUS (o altres variables) hem de fer servir l'acumulador W ja que no podem moure directament les variables; per tant cal recuperar primer STATUS i les altres variables i deixar W per al final. Si recuperéssim W amb MOVF ens trobaríem que segons el valor que tingués ens canviarien els bits d'estat (C, DC i Z) a STATUS. Hem de fer servir una funció per copiar que no canviï els bits d'estat: swapf. Així per copiar el valor guardat a W primer permutarem els nibbles sobre l'adreça on està guardat i després els tornarem a permutar guardant el resultat a W. Així aconseguim copiar el valor sense que, per exemple, ens variï Z.

; Zona de memòria que no depèn del banc triat
W_Copia EQU 0x70  ; Guardarà el contingut de W durant la interrupció
ST_Copia EQU 0x71  ; Guardarà STATUS durant la interrupció
Interrup:
  movwf W_Copia  ; Copiem l'acumulador a W_Copia
  swapf STATUS,w  ; Copiem STATUS a l'acumulador permutant els nibbles
  clrf STATUS  ; Posa a 0 i així segur que el banc és el 0
  movwf ST_Copia  ; Guarda STATUS permutat a ST_Copia
  ...
FiInt:
  swapf ST_Copia,w  ; Copia permutant ST_Copia a l'acumulador
  movwf STATUS  ; I ho passa a STATUS recuperant el valor d'abans
                ; de la interrupció
  swapf W_Copia,f  ; Permuta els bits de W_Copia
  swapf W_Copia,w  ; Torna a permutar els bits de W_Copia
                   ; i els guarda a l'acumulador sense variar STATUS
  retfie  ; Torna al programa principal, on s'havia quedat

La memòria de programa té dues adreces reservades. L'adreça 000h és on comença a executar després de posar en marxa el microcontrolador i l'adreça 004h és on comença a executar quan hi ha una interrupció. Com entre 000h i 003h no ens hi cap el programa, el que farem serà el que es mostra a la figura següent.

Interrupcions

Quan es volen desactivar les interrupcions des de fora de la funció d'interrupció, cal tenir present que existeix la remota possibilitat que aparegui una interrupció en el mateix instant en el que es vol desactivar el bit GIE. Si això passés, les interrupcions no es desactivarien. Per evitar aquest problema, es pot comprovar la desactivació de GIE i repetir la desactivació si no s'ha fet:

  ...
  bcf GIE  ; Desactiva les interrupcions momentàniament
  btfsc GIE  ; Comprova si el bit s'ha desactivat
  goto $-2  ; Si no ho ha fet, torna-ho a provar
  ...

Quan el microcontrolador té activades dues o més interrupcions, pot succeir que se n'activin dues de simultànies o amb poca diferència de temps. Per això és recomanable que la funció d'interrupció comprovi tots els bits ja que si només fa el que correspon a la primera interrupció que troba, alguna altra pot quedar sense servir.

En programes que fan servir diverses interrupcions pot donar-se el cas que no ens interessi desactivar completament les interrupcions perquè hi pot haver una interrupció més prioritària. Llavors el normal és establir dos nivells de prioritat (a vegades tres). Quan hi ha una interrupció del nivell més baix es desactiven les interrupcions del mateix nivell i es mantenen activades les de nivell superior. En aquests casos cal preveure que la funció d'interrupció sigui interrompuda i, per tant, cal preveure tantes variables per guardar els registres crítics (W i STATUS) com nivells d'interrupció s'hagin definit.

A l'Exemple IT es fa servir una interrupció corresponent al Timer 0.

A l'Exemple IE es fa servir una interrupció externa.

A l'Exemple IR es fa servir una interrupció per canvi al port A.

La informació completa de les interrupcions la podeu trobar a l'apartat 14.3 del document de característiques del PIC 16F690.

 

 

Llicència de Creative Commons
Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.