Recursos del PIC- Uso de la Interrupción por cambio de estado en RB4-RB7

Interrupción por cambio del estado lógico en alguna de las 4 líneas de más peso de la puerta B (RB7-RB4) del PIC.

Biblioman

10/24/20097 min read

Vamos a ver un ejemplo del uso de la interrupción por cambio del estado lógico en alguna de las 4 líneas de más peso de la puerta B (RB7-RB4) del PIC. Para ello dichas líneas tienen que estar previamente configuradas como entradas. Este recurso hardware es muy utilizado para el control de teclados.

El registro del PIC encargado de su configuración es INTCON:

Como siempre debemos habilitar la interrupción global y la particular:

GIE: Permiso global de interrupción.

1 – Permite todas las interrupciones cuyos bits particulares de permiso lo permitan.

0 – Prohíbe todas las interrupciones

RBI: Permiso de interrupción por cambio de estado en RB7:RB4

1 – Permite la interrupción

0 –Prohíbe está interrupción

RBIF: Señalización ó flag por cambio de estado de las patillas RB7:RB4.

1 – indica que la interrupción se ha producido.

0 – indica que no se ha activado.

Como de costumbre para ver como CCS gestiona este recurso creamos el siguiente esquema en Proteus:

Se trata de la gestión de un mini teclado formado solo por cuatro teclas representadas por los pulsadores del 1 al 4. El valor en decimal de la tecla pulsada se mostrará en un display de cátodo común.

En esta ocasión he utilizado el PIC 16F877, a nivel de código lo único que hay que cambiar con respecto a si utilizáramos el 16f84A es el include donde están definidos los registros del PIC y los fusibles correspondientes si los hemos incluido, pero en este caso hay una razón más para no utilizar el 16f84 que explicaré en el comentario del programa.

Si creamos el programa con el asistente, además de seleccionar el PIC correspondiente, tenemos que marcar en Interrupciones la opción de permitir la interrupción particular por cambio en B4-B7, según se muestra en la figura de abajo:

El código del programa generado por el asistente tendremos que dejarlo de la siguiente manera:

/*---------------------------------------------------------------------------------*\
| Recursos del PIC. Uso de la interrupción por cambio
| en las patillas RB4-RB7 del PIC.
| autor: biblioman
| www.aquihayapuntes.com
\*----------------------------------------------------------------------------------*/

#include <16F877.h>
//Configuración de los fusibles.
#FUSES NOWDT, XT, NOPUT, NOPROTECT, NOBROWNOUT, NOLVP, NOCPD, NOWRT, NODEBUG
#use delay(clock=4000000) //Frecuencia de reloj 4MHz
#byte puerto_B = 0x06 // Identificador para el puerto B.
#byte puerto_D = 0x08 // Identificador para el puerto C.

#int_RB
void RB_isr(void) //función de interrupción
{

switch(puerto_B)
{
case 239:
puerto_D = 0x06;
break;
case 223:
puerto_D = 0x5B;
break;
case 191:
puerto_D = 0x4F;
break;
case 127:
puerto_D = 0x66;
break;
default:

break;
}
}

void main()
{
set_tris_b(0xFF); //Puerto B como entrada
set_tris_d( 0x00 ); // Puerto D como salida.

enable_interrupts(INT_RB);//habilita interrupción particular
enable_interrupts(GLOBAL);//habilita interrupción global

puerto_D =0x00; //inicializo puerto D

while(True)
{
//código principal

}

}

Nota: el asistente nos incluye algunas líneas más, sobre opciones de configuración de recursos que no estamos utilizando y que están deshabilitadas, podéis dejarlas ó quitarlas, pero es una buena costumbre si utilizáis el Wizard el quitar el código que no sea necesario para el funcionamiento de nuestro programa.

Comentario:

Dentro de la función principal configuramos el puerto B como entradas digitales, (recordar que es un requisito que RB4-RB7 estén configuradas como entradas para la utilización de esta interrupción) y el puerto D como salida ya que es donde conectaremos el display de siete segmentos (como es de cátodo común, sus entradas serán activas con nivel alto).

Habilitamos la interrupción global y particular, por medio de las siguientes instrucciones:

enable_interrupts(INT_RB);

enable_interrupts(GLOBAL);

Y inicializamos el puerto D con el valor 0.

Luego viene un bucle while infinito, la ejecución del programa permanecerá aquí, hasta que se produzca la interrupción.

Dentro de la función de interrupción chequeamos el valor en decimal del puerto B por medio de una sentencia de control switch y según sea la tecla pulsada mostramos su valor en el display.

Los cuatro bits menos significativos de la puerta B en el circuito están fijados a uno permanentemente, si pulso por ejemplo el pulsador 1 pongo RB4=0 y el valor binario a la entrada de la puerta B será:

RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0

1 1 1 0 1 1 1 1

Que en decimal tendrá un valor de: 239, de la misma forma determinamos el valor para las otras posibles entradas.

En la tabla de abajo se muestran los valores a utilizar para configurar el display de siete segmentos en cátodo común.

Para ver como CCS gestiona está interrupción, simulamos el circuito en Proteus cargando el archivo .cof en el PIC, para que nos permita la simulación paso a paso, al igual que hicimos con el ejemplo de la interrupción externa por RB0/INT.

Para parar el programa dentro de la función de interrupción podemos poner un breakpoint dentro de cualquiera de las sentencias case.

El valor del registro INTCON según la secuencia del programa será la siguiente:

Antes de producirse la interrupción:

  • GIE= 1 (Permitidas las interrupciones globales)

  • RBIE=1 (Permiso de interrupción por cambio de estado en RB7:RB4)

  • RBIF=0 (Señalización por cambio de estado de las patillas RB7:RB4 a nivel bajo)

Al producirse la interrupción:

  • GIE= 0 (No Permitidas las interrupciones globales)

  • RBIE=1 (Permiso de interrupción por cambio de estado en RB7:RB4, me da igual como este porque la global está deshabilitada)

  • RBIF=1 (Señalización por cambio de estado de las patillas RB7:RB4 a nivel alto)

Al salir de la interrupción:

  • GIE= 1 (Permitidas las interrupciones globales)

  • RBIE=1 (Permiso de interrupción por cambio de estado en RB7:RB4)

  • RBIF=0 (Señalización por cambio de estado de las patillas RB7:RB4 a nivel bajo)

Hasta aquí CCS gestiona la interrupción por cambio de estado en RB4:RB7 de forma similar a como lo hacía con la interrupción externa RB0/INT, es decir, gestionando la habilitación del bit GIE y controlando el valor del flag RBIF, según se esté dentro o fuera de la función de interrupción, todo ello de forma transparente para el programador.

Pero en este caso hay un paso que los creadores del compilador se han pasado por alto y obliga al programador a tener en cuenta cuando se trabaje con este tipo de interrupción y es la siguiente:

Si nos vamos datasheet del PIC 16f877, en lo que respecta al control de esta interrupción podemos ver lo siguiente:

"Four of the PORTB pins, RB7:RB4, have an interrupton-

change feature. Only pins configured as inputs can

cause this interrupt to occur (i.e., any RB7:RB4 pin

configured as an output is excluded from the interrup ton-

change comparison). The input pins (of RB7:RB4)

are compared with the old value latched on the last

read of PORTB. The “mismatch” outputs of RB7:RB4

are OR’ed together to generate the RB Port Change

Interrupt with flag bit RBIF (INTCON<0>)."

De aquí se deduce, que es necesario una lectura (ó escritura) del puerto B cuando se produzca esta interrupción, en el ejemplo que hemos hecho no hay problema ya que nada más entrar en la función de interrupción leemos el estado del puerto por medio de la sentencia switch(puerto_B). Pero imaginaros el ejemplo de la alarma que hicimos por activación de la interrupción RB0/INT, cuando la alarma está desactivada y pulsamos el sensor de alarma, la secuencia del programa entra en la función de interrupción pero no hace nada dentro de ella, si intentáramos implementar ese mismo circuito pero con cuatro sensores de alarma y utilizando la interrupción por cambio de estado en RB4:RB7, si no incluimos una lectura del puerto dentro de la función de interrupción, aunque no nos sirva para nada, el programa se vuelve loco y no funciona bien este recurso del PIC. Si tenéis alguna duda sobre esto, comentarlo en el foro y hacemos el ejemplo.

Otro problema que encontré, fue al realizar el ejemplo con el PIC16f84A. Al simular el circuito con Proteus me aparecía el siguiente error:

violation access error in module <UNKNOW>

La versión de compilador que utilice para el ejemplo fue la 4.038 y la de proteus la 7.1 SP2. Empecé a investigar la causa del error y me di cuenta que se debía a un bug del compilador que se producía al incluir en el código esta interrupción y utilizar el archivo .hex ó .cof resultante en proteus. Si en vez del PIC 16f84A se utiliza otro, como el 16F877, todo funciona correctamente. Por lo que se, este bug está ya corregido en versiones posteriores del compilador.

En el próximo ejemplo veremos cómo comunicar dos pic’s entre sí vía serie RS-232.

Como siempre espero vuestros comentarios, sugerencias ó mejoras al respecto en el foro.

Un saludo y hasta pronto.