EXPERIENCIAS Y PRÁCTICAS II

con los microcontroladores PIC16F84

Introducción.

Hemos visto como mostrar desde el encendido de un LED hasta el avance del encendido de un LED en una barra o columna y su regreso al punto de partida. En esta segunda parte vamos a seguir con ejemplos que nos muestren cómo se puede aprovechar ciertas opciones, para aplicar en los proyectos que se presenten en futuros proyectos.

EXPERIMENTO 5.

Uso de las interrupciones. Vamos a usar la interrupción RB0/INT y las instrucciones SLEEP y RETFIE.

En esta ocasión, pretendo abordar un programa que se encargue de detectar cualquier cambio en un bit de un puerto, de modo que, si se cierra un interruptor, se aprieta un pulsador o se cierra un contacto conectado a dicho puerto, sea detectado y realizar la acción correspondiente.

Caso de un único contacto,  para obtener el resultado, podemos usar uno de los sistemas mas o menos sofisticados, como puede ser el uso de las interrupciones. Este sistema aprovecha una peculiaridad de los microcontroladores PIC, como ya se ha dicho, se trata de las instrucciones Interrupt y SLEEP (dormir) que como veremos nos permiten esta opción y además ahorrar energía.

Como se describe en el artículo "Interrupciones" (recomiendo leerlo), en él se dice que hay dos formas de interrupción, interna y externa, aquí usare la externa en la que, cuando se produce un cambio de nivel lógico en la patilla RB0/INT (por defecto y estando habilitada esta interrupción) o cuando se produce un reinicio o reset, se dispara por flanco de subida (rising edge), si el bit 6 llamado INTEDG del registro OPTION_REG está a 1, si ponemos este bit a 0 se disparará con el flanco de bajada (falling edge), en ese momento el programa nos enviará a una subrutina que se encarga de realizar una acción que hemos previsto con anterioridad.

El programa de esta forma es muy sencillo, sin embargo necesitaremos de una rutina de servicio de interrupciones (RSI). Esta rutina contiene una serie de instrucciones que se encargan de guardar el contenido de los registros que se estaban usando en el momento anterior a producirse la interrupción, de modo que cuando termine de atenderse dicha interrupción, el programa pueda seguir con el normal funcionamiento que venía realizando hasta ese momento. Sin embargo, dentro de la rutina RSI, podemos insertar una subrutina o CALL, para su uso, antes de la instrucción RETFIE que es la instrucción de salida o retorno de la RSI.

Este es el listado que se encarga de hacer lo que he descrito.

;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Título:  demoint.asm					   ^
;	 Autor:  V. Garcia					   ^
;	  Date:  22112006					   ^
;								   ^
;   (Las tildes estan omitidas de manera intencionada)		   ^
;_________________________________________________________________ ^
;			Demo de Rutina de Interrupciones	   ^
; Que hace => Encender un LED en RB1, lo haremos dormir y al       ^
; accionar un pulsador en RB0/INT despertarlo lo encendera para    ^
; hacerlo dormir hasta la siguiente interrupcion que lo apagara.   ^
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	LIST	P=16F84
	#include	"p16F84a.inc"
	  errorlevel  -302	; no muestra errores irrelevantes

; configurar la palabra para grabado del PIC
 __CONFIG _CP_OFF & _PWRTE_OFF & _WDT_OFF & _XT_OSC

ACUM	equ h'000C'	;declaro variable acum
STAT	equ h'000D'	;declaro variable stat
	
#define	banco1	BSF STATUS,RP0	;Macro para abreviar el banco1
			;pone a 1 el bit5 (RP0) del registro status
#define	banco0	BCF STATUS,RP0	;Macro para abreviar el banco0
			;pone a 0 el bit5 (RP0) del registro status
; bit7 (RBPU) del registro OPTION_REG a 0 activa resistencias pull-up
; bit6 (INTEDG) del registro OPTION_REG a 0 activa flanco descendente
;					
	ORG  0x00	;Posicion 0 Memoria de Programa (apuntador)
	goto ini	;Va a la etiqueta INICIO
	
	ORG  0x04	;viene cuando hay una interrupcion
	GOTO  rsi	;a subrutina rsi, a atender interrupcion
	ORG  0X05	

;---- Inicio ------
ini:	banco1		; configurar puertos
	MOVLW	01	; carga W con 0000 0001
	MOVWF	TRISB	; RB0/INT es entrada
	BCF	OPTION_REG,7   ; las resistencias pull-up conectadas
	BCF	OPTION_REG,6	;selecciona flanco descendente
	banco0
;---- 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	; se pone a dormir
;---- rutina servicio interrupciones
rsi:	BTFSC	PORTB,0	;verifica si se aprieta el pulsador
	GOTO 	rsi	; y espera. Si no, comienza 
			 	; guardando el contenido de 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 si, Si el led esta a 1
	GOTO	off_led	;ira a off_led para apagarlo
	BSF	PORTB,1	;sino, encender el LED
	BCF	INTCON,INTF  ;borrar bandera de interrupcion
	GOTO	hecho	;salta a restaurar valores
	RETFIE	; antes de volver
		
off_led: BCF	PORTB,1  ; apaga el LED
	BCF	INTCON,INTF  ; borra bandera de interrupcion
		;restaurar 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 

El Esquema.

Esta vez, he utilizado el programa Proteus, para diseñar el esquema necesario para esta 5ª práctica, se puede apreciar la sencillez del mismo. Si el lector dispone de esta herramienta que se describe en el manual rápido del Proteus, debería proceder a simularlo, para un mejor seguimiento de lo que se describe. Puede descargar aquí los archivos comprimidos [19k].

Esquema del experimento 5

Si dispone del Proteus, para simularlo, extraiga del archivo descargado, los 8 archivos que contiene. Debe guardar los 8 archivos en la carpeta BIN del Proteus, ahora, abra el archivo "ejercicio5.DSN" con un doble-clic y ya puede simularlo. Observe que la patilla 6 que corresponde al RB0 está a nivel alto, cuando presione el pulsador, se pone a 0 por un instante (hasta que lo suelte), en ese instante se habrá encendido el LED, si vuelve a presionar el pulsador el LED se apagará, justo lo que hemos previsto. Si quiere simular el programa continue con el siguiente procedimiento.

La simulación.

Abra el Proteus, abra el archivo adjunto ejercicio5.dsn, en el menú Source vaya a Add/Remove Source y en Code Generation Tool baje la corredera hasta MPASM, luego pulse el botón Change y busque el archivo ejem05.asm que previamente habrá copiado en BIN. Ahora, pulse sobre la opción Build All, cuando el programa termine de compilar y si no se ha producido ningún error como es de esperar, podremos empezar la simulación, pulsando en el botón Play del pie de la aplicación, para mayor información de como usar el simulador, se recomienda leer el mencionado tutorial manual rápido del Proteus.

A continuación se presenta el listado en hexadecimal, copie y pégue en su editor y nombrelo 'ejemp5.hex' por ejemplo, ya puede usarlo con el Icprog para quemar el 'F84A y comprobar su eficacia.
:020000040000FA
:020000000528D1
:080008000F2883160130860069
:10001000011383128B170B16860163000D28061837
:100020000F288C00030883128D0086181B28861465
:100030008B101D28090086108B100D0883008C0E74
:040040000C0E090099
:02400E00F93F78
:00000001FF

Qué hace el programa.

El programa tal cual está no hace nada. Y en eso hemos de incluir lo poco que consume, obviamente, puesto que no hace nada. Sin embargo, el lecctor puede adaptarlo en parte o todo y añadir la función que le interese. Lo más importante de este programa es que no necesita escanear constantemente una determinada rutina para detectar cuando se produce un evento, lo que libera al procesador de esa tarea, permitiendo hacer otras cosas.

Así que, en las primeras líneas vemos como se configuran los puertos y variables que vamos a usar y en esta ocasión debido a que deseamos aprovechar la opción de la interrupción, debemos desarrollar una rutina de atención y servicio de interrupciones que llamaremos RSI, por tanto en la configuración de principio añadiremos la directiva ORG 0x04 y en ella un salto incondicional (GOTO) que se encarga de enviar el flujo del programa a la rutina RSI para que ésta sea atendida.

Para minimizar los componentes necesarios (para este ejercicio, no es imprescindible, por lo reducido, sin embargo es conveniente tener en cuenta este procedimiento), me refiriero a usar las resistencias internas que dispone este micro, conocidas por "pull-up", éstas se pueden programar por software para cargar un nivel alto (H) bébil interno, sobre todas las entradas del PUERTO B, con el ahorro de tener que conectar resistencias del Vcc a cada pin de dicho puerto, para obtener el mismo resultado.

En estas condiciones cuando damos tensión al circuito, el programa se ejecutará hasta llegar a la instrucción goto ini, de aquí, salta hasta la etiqueta ini donde se configuran los puertos, con la instrucción BCF OPTION_REG,7 se activan las resistencias pull-up antes mencionadas, con la instrucción BCF OPTION_REG,6, se le dice que el flanco que activa las interrupciones es el de bajada y a continuación con BSF INTCON,GIE se activan las interrupciones, luego, limpia el puerto B y entra en la rutina denominada dormir, la cual contiene la instrucción SLEEP seguida del bucle goto dormir, del que ya no sale hasta que ocurre un cambio en la patilla RB0.

En este estado, el micro pone su funcionamiento bajo mínimos reduciendo del mismo modo su consumo. Y permanece en este modo, hasta que se produce un cambio en el bit 0 del puerto B, es decir, un cambio de nivel lógico en el pin RB0 que, lo despertará del estado dormido (SLEEP) en el que se encuentra nuestro micro, con esto, atenderá la rutina RSI y al ejecutar la instrucción RETFIE contenida en esta subrutina, se volverá a dormir, su estado SLEEP. Dentro de esta subrutina debémos incluir cualquier procedimiento que se realice a partir del despertar del micro.

Es evidente que puede ejecutar cualquier instrucción antes de la instrucción RETFIE y así es de fácil, este es un modo de realizar la tarea que nos propongamos antes de que vuelva a su estado de bajo consumo que ocurre al ejecutar la instrucción SLEEP.

Otro modo de uso de las interrupciones es, la rutina que se encarga de rastrear permanentemente un puerto de entrada y cuando se detecta un cambio de nivel en el bit o bits que se haya designado, producir un salto a la rutina de salida. El planteamiento es similar salvo que, en este caso no se trata únicamente del bit 0 (RB0) ya que se ven implicados además los cuatro bits de mayor peso del puerto B (RB0, RB4, RB5, RB6 y RB7), ver hojas de características del F84 la Tabla que sigue.

Tabla puerto b

EXPERIMENTO 6.

Puestos en este cometido de detección del estado de un bit, vamos a conocer cómo proceder para detectar la pulsación del contacto de un pulsador y saltar a la subrutina que ejecute la función prevista. En este caso, cuando se presione el pulsador, el programa saltará a una subrutina que se encarga de encender un LED como indicador de su estado de pulsado. Cuando se suelte el pulsador el LED volverá a su estado de apagado.

Necesitamos configurar los puertos de modo que porta sea de entrada y portb sea de salida. Para las entradas vamos a usar tres bits RA2, RA3 y RA4, representados por 00011100b = 1Ch.

Recordemos que, si el bit de código OP de la instrucción es 0, el destino de la operación es W y si es 1, el destino es el registro f, o sea, se selecciona el destino donde se guarda el resultado de una operación. Por ej. en: ADDWF 1F,0 el resultado de añadir el contenido de W a F, es almacenado en el registro de trabajo W y en el caso ADDWF 1F,1 el resultado de la suma es almacenado en el mismo registro F, esta claro.

Además, vamos a usar pocas líneas de programa, sin que ello haga confuso el listado. El programa dispondrá de un par de bucles o subrutinas, uno se encarga de controlar el estado del pulsador, de modo que cuando se detecte que se ha presionado el pulsador, le indicará al programa principal que salte a la segunda subrutina, encargada de ejecutar la acción que hayamos previsto, en este caso un LED se encenderá, cuando el bit RB esté a 1 (para que el consumo del PIC se reduzca, esta subrutina se puede hacer con dicha salida a 0).
;******************************************************************^
;	Título:  ejemp6.asm					   ^
;	 Autor:	 V. Garcia					   ^
;	  Date:  12012007				   	   ^
; Deben documentarse todas las rutinas y el motivo de ser	   ^
;   (Las tildes estan omitidas de manera intencionada)		   ^
;_________________________________________________________________ ^
;			 					   ^
; Que hace = Detecta Pusador e ilumina un LED mientras este pulsado^
; al soltarlo se apaga el LED					   ^
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;
;--------------- Encabezado -------------
        list           p=pic16f84a
        #include       <p16f84a.inc>
        errorlevel      -302    ;Eliminar banco mensajes
   __CONFIG _CP_OFF & _PWRTE_ON & _WDT_OFF & _RC_OSC

;****************  Definicion de Etiquetas  ********************

#define	banco1	BSF STATUS,RP0	;Macro para abreviar el banco 1
#define	banco0	BCF STATUS,RP0	;Macro para abreviar el banco 0

	; Empieza cuerpo del programa
	ORG 0x00

Start:  banco1	;Ir a banco1 para configurar puertos
	MOVLW 1Ch	 ;1C = 0001 1100b, RA2 entrada
	MOVWF TRISA
	MOVLW 00h	;Pone 00 en W 
	MOVWF TRISB	;hace todas las lineas RB, salida
	banco0		;Ir a banco0 para seguir programa

loop1:  BSF  PORTB,1	; apaga LED
	BTFSC PORTA,2	;comprueba si linea pulsador A = 1
	GOTO loop1	;no, linea es L vuelve a loop1
loop2:  BCF  PORTB,1	; pon a 0 bit 1, enciende LED
	BTFSC PORTA,2	;comprueba si linea pulsador A = 1
	GOTO loop1	; en un lazo largo.
	GOTO loop2	

	END		;termina el programa

Que hemos hecho.

Una vez descrita la cabecera en nuestro programa, si necesitamos aprovechar una subrutina o modificar una parte del listado, nos vendrá muy bien disponer de una ayuda como son nuestros propios comentarios y el resto de notas que hayamos usado la primera vez, esto nos puede servir. Este es el símbolo del PIC16F84A.

Respecto del listado, en las primeras líneas además de configurar los bancos, se ha indicado al ensamblador las directivas, librerías y el tipo de chip que vamos a usar, también hemos añadido la línea errorlevel -302, que se encarga de evitar los molestos mensajes de advertencia que no son relevantes. Se ha configurado los bits de la "Palabra de Configuración" como 3FFBH, el lector debería asegurarse de entender esta función antes de usarla.

Le sigue un bucle llamado loop1, que se encarga constantemente de comprobar si el pulsador A está presionado o no. Con la primera línea del bucle, mediante la instrucción BSF PORTB,1 ponemos a 1 el valor del bit1 del puerto B de salida, asegurando que el LED que tenemos conectado no lucirá, si por la puesta de energía estuviera luciendo, ya se sabe que al dar tensión, el registro puede enviar un bit indebido al puerto de salida, con esto, nos cercioramos que su estado es 1 y no lucirá.

El motivo de usar la puesta a 1 de la salida, responde a que, de esta forma el consumo del LED no afectará al propio micro puesto que, el transistor interno del dispositivo lo único que hace es tirar a masa la corriente de consumo del LED, lo que no incrementa la temperatura interna del micro. Sigamos.

Para conocer el estado del pulsador hemos empleado la instrucción BTFSC PORTA,2 es decir; comprueba si el bit 2 del registro 05 está a 0, si es así, salta la instrucción que sigue, eso es lo que quiere decir Bit Test F Skip Cero. Efectivamente, si el bit 2 del puerto B está a 0, el programa saltará hasta la instrucción loop2:  BCF PORTB,1 y seguirá desde ese punto.

El flujo del programa salta hasta la instrucción loop2:  BCF PORTB,1 (bucle interno) y entonces enviará el valor 0 al puerto de salida registro PORTB,1 que hará iluminar el diodo LED, mientras permanezca presionado el pulsador.

Lo propio es que, no estemos pulsando el pulsador A todo el tiempo (habrá que descansar, digo yo) y en ese caso ocurre que, la prueba (o test) BTFSC PORTA,2 nos presentará un 1 (H) como salida y eso cambia el progreso del programa ya que acto seguido se ejecutará la instrucción GOTO loop1 que nos envía a la etiqueta loop1 (posición loop1: BSF PORTB,1) por este motivo se le llama a esta subrutina de bucle (externo) o también lazo. Es cierto que, para hacer lo mismo, podemos usar la siguiente instrucción: GOTO $-5 que no necesita de etiqueta y es válida ya que le dice al ensamblador que retroceda en este punto cinco pasos (-5), lo que lleva al inicio del bucle.

Este programa no necesita ninguna subrutina de retardo debido a que, todo lo que hace es, detectar cuando se está presionando un pulsador. En el caso de tener que mantener encendido el LED durante un tiempo, habría que plantearse la inclusión de un retardo y cómo afectaría al escaneado del pulsador, puesto que mientras el programa permanezca en la subrutina de retardo, no se puede atender la rutina de escaneado para acceder al puerto de entrada.

El Esquema.

En principio, debe usarse el mismo circuito del experimento 5, aprovechando el pulsador A y el LED correspondiente que ya dispone aunque para evitar confusiones y mayor claridad, se puede usar la figura siguiente que es el esquema, para el experimento 6. Nuevamente se ha usado el programa Proteus para su simulación.

Los componentes y sus valores aparecen en el esquema, se aprecia que usa una red RC para el reloj, un pulsador (A), la resistencia del MCLR y la resistencia R3 limitadora para el LED a parte del PIC16F84A y el pulsdor A. Se presenta a quí un archivo comprimido [17k] con el listado en hex, copie y pégue en su editor de texto y llamelo 'exem06.hex' por ejemplo, ya puede usarlo con su quemador habitual para quemar el 'F84A y comprobar su eficacia.

:020000040000FA
:1000000083161C3085000030860083128614051983
:0A00100006288610051906280928A5
:02400E00F33F7E
:00000001FF

Este ejemplo nos muestra una forma de usar los bucles anidados, además de las instrucciones de comparar el estado de un bit en particular.

Con este ejercicio ponemos el punto y aparte por esta vez, seguiremos con estos ejemplos en la tercera parte. 

Volver al índice de artículos PIC.


Creada el: 12-09-07 
Actualizada el: 20-01-2008     

© Copyright 2007, Hispavila.com. Reservados todos los derechos. | declaración de privacidad | Póngase en contacto con nosotros