LAS INTERRUPCIONES

en los PIC

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:

  1. Cuando se produce una interrupción el bit7 GIE se pone a 0.

  2. El valor del PC se guarda en la Pila (Stack) con el valor 0004h, que es el vector de interrupciones.

  3. 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.

  4. Dependiendo de la causa, la rutina de interrupción se bifurcará a la subrutina correspondiente.

  5. 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.

  6. 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.

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 o 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:

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