|
Introducción.
Hemos avanzado en nuestro empeño de aprender un poco mas a cerca de la
programación de los micros PIC y no podemos continuar sin atender unas de las más importantes
instrucciones ("herramientas") como son las interrupciones. Veremos que hay dos tipos de interrupción en
los micros PIC16X84 y vamos a descubrir como podemos usarlas en nuestro provecho.
Las Interrupciones.
Es una de las características de los microcontroladores, de las más importantes que constituye
la capacidad de sincronizar la ejecución de programas con acontecimientos externos; es decir, cuando se
produce una interrupción, el micro automáticamente deja lo que esté haciendo, va a la dirección 04h de programa
y ejecuta lo que encuentre a partir de allí hasta encontrarse con la instrucción RETFIE que le hará abandonar
la interrupción y volver al lugar donde se encontraba antes de producirse dicha interrupción. Hemos de diferenciar entre
dos tipos de interrupciones posibles en un PIC16X84:
1. - Mediante una acción interna. El desbordamiento de
la Pila (Stack) por una operación indebida, por ejemplo:
· Al completarse la escritura de datos en una EEPROM.
· Por desbordamiento del registro TMR0 al rebasar el valor 255 (FFh) a 0.
2. - Mediante una acción externa, la más útil.
Al producirse un cambio del nivel en uno de sus pines por una acción externa.
· Estando en el modo de reposo (SLEEP), un cambio de nivel en el pin RB0/INT .
· Un cambio de nivel en uno de los pines RB4 a RB7 estando configurados como entrada.
Cuando ocurre un evento de los descritos anteriormente, se produce una petición de interrupción,
guardando el valor actual del PC
(contador de programa) en la Pila, sea cual sea la fuente de la interrupción,
se pone a cero el bit7 GIE (Global Interrupt Enable), con lo cual inhibe
cualquier otra petición de interrupción, el registro PC se carga con el valor 0004h que, es la posición del vector de
interrupción. Aquí, empieza la ejecución del programa de atención a la interrupción ISR (Rutina de
Servicio
de Interrupción). El tiempo de procesamiento de la ISR debe ser lo más breve posible, para que se ejecuten las
otras interrupciones ya que, pueden habilitarse más de una de ellas. Además, cualquier tipo de interrupción también puede
sacar al micro del modo de reposo (SLEEP).
Como he apuntado, una interrupción puede ser inhibida
sólo si existe otra interrupción en curso. Esto se debe a
que, una interrupción está controlada por dos bits que indican la fuente de la interrupción, un bit actúa como bandera (flag)
indicando si se ha producido una interrupción y el otro bit, actúa como bit de inhibición o prohibición de la interrupción en sí,
debido a que existe otra interrupción en ejecución y todo esto se realiza de forma automática por parte del micro.
Ecir, el bit GIE es el responsable del permiso de interrupción que se borra automáticamente
cuando se acepta una interrupción evitando así que se produzca ninguna otra interrupción mientras se atiende a la primera.
Estos bits de control se encuentran en el registro INTCON (0Bh y 8Bh). Estos bits corresponden al registro
INTCON
que cambia de nivel 0 a 1 cuando se produce la interrupción, excepto el último bit (bandera) que se encuentra en el registro
EECON1. Véase los detalles de los bits de INTCON.
| REGISTRO INTCON |
| Bit7 |
GIE |
1 = Todas las Interrupciones habilitadas
0 = Todas las Interrupciones inhábiles |
Bit Enabled
Interrupt Global
|
| Bit6 |
EEIE |
1 =
Habilitación Activada 0 = Desactivada |
Bit Interrupciones de Periféricos |
| Bit5 |
T0IE |
1 =
Habilitación Activada 0 = Desactivada |
Bit Interrupción del TMR0 |
| Bit4 |
INTE |
1 =
Habilitación Activada 0 = Desactivada |
Bit Interrupción externa |
| Bit3 |
RBIE |
1 =
Habilitación Activada 0 = Desactivada |
Interrupción por
cambio Puerto B |
| Bit2 |
T0IF |
1 = TMR0 desbordado 0 = No desbordado |
O Bandera del TMR0
- Borrar por software |
| Bit1 |
INTF |
1 = Hubo interrupción externa 0 = No hubo interrupción externa |
O Bandera RB0/INT
- Borrar por software |
| Bit0 |
RBIF |
1 = Uno o más pines cambiaron de nivel
0 = Ningún pin ha cambiado de nivel. |
O Bandera
en RB4 : RB7
- Borrar por software |
|
Las acciones que debe tener en cuenta el programador al crear sus
programas, son las siguientes:
-
Cuando se produce una interrupción el bit7 GIE se pone a 0.
-
El valor del PC se guarda en la Pila
(Stack) con el valor 0004h, que es el
vector de interrupciones.
-
La rutina de atención a la interrupción debe empezar con un salto a la posición de memoria de programa, antes, debe guardar todos los registros que puedan ser modificados
por la interrupción y explorar las banderas para determinar la causa de la interrupción.
-
Dependiendo de la causa, la rutina de interrupción se
bifurcará a la subrutina correspondiente.
-
Antes de volver al programa principal, se deben
devolver los valores originales salvados
de los registros anteriores a la interrupción y además limpiar (poner a 0) las banderas que indican la fuente de la misma.
-
Como última instrucción de la rutina de interrupción
usar RETFIE, que cargar el PC con el valor de Pila y el bit GIE se pondrá automáticamente a 1.
- Para detectar interrupción: TOIF (bandera (Flag) de interrupción por desbordamiento de
TMR0)
- Para habilitar interrupción: TOIE (habilita la interrupción por desbordamiento de
TMR0)
Por tanto, el bit7 GIE, es el encargado de la activación global que habilita las interrupciones al ponerse
a 1 y al reconocer una interrupción se pone a 0 de forma automática, evitando se produzca otra interrupción mientras se atienda
la actual. El bit GIE se pone de nuevo a 1 al retornar de la atención a la interrupción al encontrar una instrucción
RETFIE. Para el resto de los bits (banderas o flags) no está previsto ningún tratamiento de puesta a cero, por lo que
es el propio programa de atención a la interrupción, el que le corresponde tratarla y las banderas (flags) que indican la
interrupción, debe ponerlas a 0 (cero).
Antes de seguir, hago hincapié en que, si bien cada bandera cambia o se pone a 1 al producirse una interrupción, es tarea del propio programador, borrarla o ponerla a cero nuevamente, ya que si no lo hace, el micro siempre
permanecerá interrumpido o lo que es lo mismo, creerá que la interrupción se está produciendo continuamente.
En resumen, el micro sólo tiene un vector de interrupción en la dirección 0x04h, así que, con cualquier interrupción
el PC se carga con 0004h y el programa de atención a la interrupción (que llamamos
ISR) se encarga de comprobar
el estado de las banderas para determinar que dispositivo causó la interrupción y actuar según lo previsto,
la propia ISR se
encargará de guardar los registros implicados al principio de la rutina para poder devolver sus estados
originales al regresar de la rutina.
Ver el siguiente ej.
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; Nombre: Demo de Interrupciones ^
; Que hace => Encender un LED en RB1, lo haremos dormir y ^
; despertarlo al accionar un pulsador en RB0/INT lo encenderá para ^
; hacerlo dormir hasta la siguiente interrupcion que lo apagará. ^
; --- Descripcion del circuito --- ^
; El pin 7 (RB1) conectado al anodo del LED, el catodo a masa. ^
; El pin 6 (RB0/INT) conectado a positivo a traves de R de 10K ^
; El pin 6 (RB0/INT) conectado a contacto pulsador, el otro a masa.^
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LIST P=16F84
#include <P16F84a.INC>
ACUM equ h'000C' ;se declara acum
STAT equ h'000D' ;se declara stat
#DEFINE BANCO0 BCF STATUS,5
Org 0x00 ;Posicion 0 de la Memoria de Programa (apuntador)
;Viene cuando hay una interrupcion.
goto inicio ;Va a la etiqueta INICIO
ORG 0x04 ;viene cuando hay una interrupcion
GOTO rsi ;salta a rutina de rsi que atiende la interrupcion
ORG 0X05
; ****Bits del registro OPTION *******************************
; bit8 = 0 Resistencias de polarización deshabilitadas
; bit7 = 0 Interrupción externa por flanco bajada (no usada)
; bit6 = 0 Fuente de reloj, interno (Usa TMR0 como temporizador)
; bit5 = 0 Flanco de señal externa (no lo usamos)
; bit4 = 0 Divisor asignado al TMR0
; bit3 = 1 bit2 = 1 bit1 = 0 División por 128
; *******************************************************
;---- Inicio ------
ini BSF status,RP0 ; configurando puertos
MOVLW 01 ; carga w con 0000 0001
MOVWF trisb ; RB0/INT es entrada
BCF option_reg,6 ; seleccionamos flanco descendente
BCF status,RP0
;---- Activa interrupciones ----
BSF intcon,GIE ; habilita todas las interrupciones
BSF intcon,INTE ; que sean interrupciones externas
CLRF portb ; limpia el puerto B
dormir SLEEP
GOTO dormir ; poner a dormir
;---- rutina servicio interrupciones
rsi BTFSC portb,0 ; verifica que se suelte el pulsador
GOTO rsi ; espera
; comenzamos guardando el contenido del W
MOVWF ACUM ; Copia el acumulador al registro acum
MOVF status,W ; Guarda STATUS en el acumulador
BANCO0 ; para restaurarlos antes de volver
MOVWF STAT ; Copia el acumulador al registro STAT
BTFSC portb,1 ; y ahora sí, si el led está a 1
GOTO off_led ; ir a off_led para apagarlo
BSF portb,1 ; sino, encender el LED
BCF intcon,INTF ; borrar bandera de interrupción
GOTO HECHO ; salta a restaurar valores
RETFIE ; antes de volver
off_led BCF portb,1 ; apaga el LED
BCF intcon,INTF ; borra bandera de interrupción
; Restauramos los valores del W y status
HECHO MOVF STAT,W ; Guarda el contenido de STAT en el W
MOVWF STATUS ; Restaura el STATUS
SWAPF ACUM,F ; Da la vuelta al registro ACUM
SWAPF ACUM,W ; Vuelve a dar la vuelta al registro ACUM
; y lo restaura
RETFIE ; retorna al programa principal
END
|
Como referencia, debemos guardar el contenido del registro W y del registro STATUS,
para lo cual "no se debe usar la instrucción
MOVF" porque corrompe la bandera Z, modificando el registro STATUS.
En las hojas del fabricante recomienda el
código del siguiente ej. a la hora de tratar una rutina de servicio de interrupciones y puede tomarse, de forma general, procurando adaptarlo a la exigencia del usuario.
; ======== Inicio - Rutina de Servicio de Interrupción =========
; ========== Guardando W y el Registro de Estado ==========
MOVWF R_W ; Guardamos W en R_W (R_W=0x0A)
SWAPF STATUS,W ; invertimos los nibbles del registro STATUS (STATUS=0xAF) y
; lo pasamos a W, (W=0xFA). Si ponemos f en SWAPF STATUS,f
; se guardara en el mismo registro STATUS
MOVWF R_STAT ; Guardamos el contenido de STATUS en (R_STAT=0xFA)
. .
. . ; Aqui atendemos la rutina ISR
. . ; Deberia configurarse banco como se requiera
; ======== Fin - Rutina de Servicio de Interrupción ===========
; ======== Restaurando W y el Registro de Estado ===========
SWAPF R_STAT,W ; invertimos los nibbles del registro R_STAT
; y lo pasamos a W (R_STAT=0xFA), (W=0xAF)
MOVWF STATUS ; Restauramos STATUS (STATUS=0xAF)
; estado original del banco
SWAPF R_ACUM,F ; invertimos los nibbles de R_ACUM (R_ACUM=0xA0) que
SWAPF R_ACUM,W ; invirtiéndolo nuevamente lo pasamos a W, ahora W=0x0A
;
RETFIE
En este ejemplo; R_W y R_STAT son registros auxiliares en los que se
guardan los valores del registro W y del registro Status. Lo que
se ha hecho:
- Se guarda el registro W en R_W
- Se guarda el registro STATUS en R_STAT
- Se ejecuta la rutina de servicio de interrupciones. Y antes de salir
de la ISR
- Se restablece el registro STATUS (y el bit seleccionado del banco)
- Se restablece el registro W
Espero que se haya aprovechado la descripción del tema de las interrupciones y los registros que de algún modo se relacionan con las mismas, para avanzar en los conocimientos de la programación. En próximos artículos veremos como aplicar
estos
conocimientos. Volver al
índice
de artículos PIC.
Creada el: 12-09-07
Actualizada el: 12-09-07
© Copyright 2007, Hispavila.com. Reservados todos los derechos. |
declaración de privacidad | Póngase en contacto con nosotros
|