PRIMER PROYECTO CON EL PIC 16F84A


Introducción.

Esta es la primera incursión en este apartado de programación para microcontroladores PIC, pretendo mostrar algunos proyectos con los que el interesado en aprender a programar microcontroladores PIC, consiga ciertos conocimientos y cierta fluidez, al mismo tiempo que disponga de una 'librería' de rutinas en la que inspirarse a la hora de plantear un proyecto o la solución a un posible problema que le surja. 

El Primer Proyecto.

Esta pretende ser una aproximación muy lineal a la escritura de un programa. Son muchos los que escriben y producen subrutinas muy pequeñas con saltos (GOTO's) de una subrutina a otra, de modo que el programa salta por todas partes como 'palomitas de maíz'. El micro es capaz, perfectamente capaz de saltar por un programa, sin embargo, éste tipo de disposición es muy difícil de seguir incluso por un lector avezado.

Es mucho más fácil seguir la secuencia de acontecimientos y así, muy pronto seremos capaces de escribir programas similares a los de la sección de proyectos de cualquier empresa." - Así, empieza otro de los artículos que tengo en esta web.

En incontables sitios se utiliza un listado de apoyo al que se inicia en la programación, dicho listado describe qué hace dicho listado. En este caso describe, cómo controlar el encendido y apagado de un punto de luz mediante un diodo LED. Después de considerar otros modos de empezar este camino, he llegado a la conclusión que, por algo hay que empezar y ese camino trazado por otros puede que sea el mejor y en ello estamos.

Se debe utilizar un editor de texto que no añada códigos extraños, puede utilizarse el Bloc de Notas, aunque hay otros más adaptados a la programación que ofrecen mejores prestaciones como el EditPlus2, eso lo dejo a elección del lector. El MPLAB integra un editor eficiente, aunque tiene sus "cosas" y distingue entre mayúsculas y minúsculas, así que, decídase por un criterio y sigamos.

El listado del programa en lenguaje ensamblador se muestra en las líneas siguientes, recuérdese que cualquier línea que empieza por un ';' (punto y coma) se interpretará como un comentario sin efecto en el programa, estas líneas sirven de ayuda y recomiendo utilizarlas para una mejor comprensión de qué hace el programa en ciertos momentos.

El listado debe ser guardado con la extensión .asm  

 01 ;*******************************************************************
 02 ;	Autor: V. Garcia
 03 ;	Fecha:06/07/2005
 04 ;	Titulo:	 rutina1.asm
 05 ;  Programa de ejemplo para detallar las lineas que lo integran y 
 06 ;  detallar rutinas. 
 07 ;*******************************************************************
 08   list               p=16F84
 09  #include	"p16F84A.inc"	;Encabezado para el MPLAB
 10  
 11	; Igualdades o "equ" y Mapa de memoria 
 12	
 13 port_a	equ	0x05h	;registro del puerto A 
 14 port_b	equ	0x06h	;registro del puerto B 
 15 trisa	equ	0x05h	;registro trisa
 16 trisb	equ	0x06h	;registro trisb
 17 status	equ	0x03h	 ;
 18 count1	equ	0x0Ch	 ;variables que usemos siempre a
 19 count2	equ	0x0Dh	 ; partir de la direccion 0Ch
 20 count3	equ	0x0Eh

 22	org         0x00	;origen  del programa 
 23	goto	Primero		;se pone este GOTO para que salte al principio
									;
 25 Primero:	bsf	status, RP0	;selecciona banco 1 para configurarlo
 26		bcf	tris_b, 03	;pone a 0 el bit 3 (RB3) como salida 
 27		bcf	status, RP0	;selecciona banco 0, para continuar programa

 29 inicio:
 30		call flash	;Llama la subrutina flash para destellar brevemente LED 
 31		call ret_largo	;Llama la subrutina ret_largo, donde espera un tiempo
 32		goto inicio	;Hazlo otra vez, y otra vez, ...

 34 	;Subrutina para destellar el LED, una vez
 25 flash:
 36 		bsf port_b, 03	;pone a 1 el bit 3 del puerto B, que enciende el LED
 37 		call ret	;llama la subrutina para retardo corto, mientras el LED luce
 38 		bcf port_b, 03	;pone a 0 el bit 3 del puerto B, que apaga LED
 39 		return		;retorna al punto de llamada.

 41 		;Retardo largo, lazo de subrutina que llama la subrutina de retardo corto
 42 ret_largo: 			;inicializar contador retardo largo
 43		movlw 0x03Fh	;carga el acumulador con el valor 3Fh 
 44		movwf count3	;mueve el contenido del acumulador a count3,

 45 largo1:	 call ret	;llama la subrutina retardo corto 
 46 	decfsz count3, 1	;Decrementa count3, guarda el resultado en F y
				;si no es cero salta la siguiente instruccion.
 47 	goto largo1		;vuelve a decrementar mientras largo1 no sea 0
 48 	return			;si es 0, regresa al punto de llamada.

 50 		;La subrutina de retardo corta con dos lazos anidados. -
 51 ret: movlw 0xFF		;Carga el acumulador con el valor FF
 52	movwf count1		;mueve contenido del acumulador a count1 
				;para iniciar lazo externo.
 54 ret1: movlw 0x0Fh		;Carga el acumulador con el valor 0Fh 
 55	movwf count2		;mueve contenido del acumulador a count2  
				;para iniciar lazo interno
 57 ret2: decfsz count2, 1	;decrementa contador de lazo interno, guarda el resultado en F 
				;si no es cero salta una instruccion.
 58 	goto ret2		;volver a la subrutina ret2 otra vez (lazo ret2) 
 59 	decfsz count1, 1	;decrementa count1 (lazo externo) si contador no es cero
				; salta una instruccion.
 60 	goto ret1		;vuelve a decrementar mientras ret1 no sea 0.
 61 	return			;si es 0, retorna al punto de llamada. 
 
 63 		END		; Termina el programa

     

Lo qué hemos hecho.

Recordar que todo lo que hay en una línea, detrás de un punto y coma (';') son comentarios que no influyen en el programa ensamblador MPLAB, sólo se usan como ayuda. Para que el listado tenga cierta coherencia, se recomienda utilizar el tabulador en 8 para crear los espacios necesarios y que haya claridad en el listado. En el listado anterior, se ha incluido el número de línea como ayuda a esta descripción, no se deben poner en su programa.

En las primeras líneas se hacen los comentarios que describen cual es el motivo del archivo.

     ;*************************************************************
     ;  Autor:	V. Garcia		Fecha: 06/07/2005              
     ;  Titulo:      rutina1.asm
     ;  Prueba para detallar las líneas que lo integran
     ; 
     ;*************************************************************   

En las líneas 8 y 9 se indica al ensamblador que vamos a trabajar con el PIC 16F84, es necesaria su inclusión. La definición de etiqueta estándar de PIC16F84A es leída según la directriz INCLUDE. Los archivos de definición generalmente son instalados en el lugar ;       C:\Program Files\Mplab\p16f84a.inc

Al respecto del MPLAB, como este programa no admite cabeceras mayores de 60 digitos, es conveniente que creemos un carpeta, para contener nuestros ejemplos o proyectos, como C:\Archivos de Programa\Mplab\proyetos\, donde guardaremos los listados, esto nos evitará algunos errores, cuando vayamos a compilar posteriormente.

     ;****************************************
     8  list p=16F84	;Define tipo de procesador
     9  #include     "p16F84A.inc"   ;Encabezado     
     ;**************************************** 

En las líneas de la 13 a 17 se declaran las "equ" o igualdades, de la memoria.

     ;****************************************
     13 port_a	equ	0x05h	;registro del puerto A   
     14 port_b	equ	0x06h	;registro del puerto B 
     15 trisa	equ	0x05h	;registro trisa
     16 trisb	equ	0x06h	;registro trisb
     17 estado	equ	0x03h 
     ;**************************************** 

En las siguientes líneas se definen las etiquetas y direcciones de uso personal llamadas de propósito general, las direcciones de los registros personales u otros que vayamos a utilizar en el programa, éstas las decide el analista en función de sus necesidades y según el mapa de memoria que empieza en 0Ch, en el caso del F84. Debe observarse, donde empieza dicho mapa de memoria que, puede variar en cada modelo de microcontrolador. 

      ;****************************************** 
     18 conta1	equ	0x0Ch	;define contador 1.- Variables que usemos siempre a
     19 conta2	equ	0x0Dh	;define contador 2  partir de la direccion 0Ch
     20 conta3	equ	0x0Eh	;define contador 3
     ;******************************************  

En la línea 22, se encuentra el origen del programa, es decir, al iniciar el programa o al dar tensión de la fuente de alimentación al micro, es donde irá el programa cada vez que se inicie o cada véz que se resetea o hay un corte de suministro. Le sigue la orden de salto GOTO que hace saltar al programa hasta la etiqueta que le sigue, en este caso Primero

      ;******************************************      
      22 org	0x00	; origen del programa
      23 goto	Primero	;se no este GOTO para que salte al principio
      ;****************************************** 

El las líneas siguientes se definen donde empiezan las posiciones de memoria; los bancos 0 y 1, los PuertoA, PuertoB y los TRISA y el TRISB con sus posiciones. Al referirnos al Puerto A o Puerto B, nos estamos refiriendo implícitamente al Banco 0, ya que el banco 0 no dispone de los tres registros TRIS y OPTION, por este motivo se llama de 'memoria paginada', ver el mapa de memoria siguiente.

El Registro STATUS está definido por los 8 bits siguientes:

Según las hojas de especificaciones, la memoria de datos se divide en múltiples bancos, que contienen los GPRs (Registros de Objetivo General) y los SFRs (Registros de Función Especial). Los Bits RP0 y RP1 son los bits de selección de banco, el 'F8A tiene los banco 0 y banco 1, con un sólo bit se direccionan 2 bancos (los que tiene el F84), con dos bits 4 bancos, etc.

Bti7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
IRP RP1 RP0 TO PD Z DC C
  1 Banco 1 operativo
  0 Banco 0 operativo

La tabla anterior, muestra que los bancos vienen definidos por el estado del bit (5) RP0, de modo que, si RP0 = 1 el Banco 1 es el banco operativo, en el cual dispondremos la configuración de los puertos y definiremos los estados especiales de cada registro en el que debamos intervenir, como los puertos y el estado de sus bits. Si RP0 = 0 el Banco 0 es el banco operativo. En este banco 0 es donde se ejecuta el programa con sus rutinas y subrutinas.

Con viene aclarar este tema, ya que siempre produce confusiones en los que se inician en la programación.

    NO SE DEBE CONFUNDIR, POSICION DE MEMORIA DE UN REGISTRO, CON SU CONTENIDO (SU VALOR).

Veamos un ejemplo:

-Tenemos una mesa con cuatro grandes cajones numerados del 0 al 3 (son los bancos de memoria).
-Cada cajón contiene carpetas numeradas desde el 0 al 127 (son los 128 registros de cada banco).
-Y cada carpeta admite un máximo de 256 folios (el mayor valor que puede adoptar un registro de 8 bits, de 0 a 255)

Entendido este concepto, si necesitamos archivar 12 folios en la carpeta 43 del cajón 2. Cómo lo haríamos.

Se procedería de esta forma:

        BSF  STATUS,RP1  ; para seleccionar el banco 2 ó 3  (cajón 2 ó 3)
        BCF  STATUS,RP0  ; aquí defino banco 2 (elijo cajón 2, entre el 2 y el 3)
                         ; ahora, el segundo paso
        movlw   .12      ; cojo los 12 folios y
        addwf   .43, 1   ; los archivo en la carpeta y se los añado a lo que ya tenía el cajón 43.

Nota.

- Los valores expresados se harán en hexadecimal acompañados al final de una h, en caso de hacerlo en binario con una b y cuando sea en decimal anteponer un (.) punto.
- Las etiquetas y nombres de registros se expresarán en una silaba de 8 letras, se admite el subguión '_' para unir dos.
- Los nombres de los registros, conviene definirlos en minúsculas, así pues, Port A o Puerto A, lo pondremos siempre como una sola palabra porta o puertoa o también porta o puerto_a, el modo de definición es importante ya que, en el programa siempre nos tendremos que referir del mismo modo, véase el archivo inc del micro usado para más detalles. Otro ejemplo, en lugar de 'PuertoA equ 05' podemos poner 'porta equ 05' y cada vez que nos referimos al Puerto A, lo haremos como 'porta'. Sin embargo, es conveniente no modificar las definiciones que ya dispone el archivo que viene por defecto con la terminación .inc

A continuación, en las siguientes líneas, como ya se ha mencionado, definimos los pines de entrada y salida:

     ;****************** Mapa de memoria *******************      
     22 Primero: bsf   status, RP0 ;selecciona banco 1 para configurarlo
     23	bcf   tris_b, 3   ;pone a 0 el bit 3 (RB3) como salida
     24	bcf   status, RP0 ;selecciona banco 0, para continuar programa
     ;*************************************************** 

Las instrucciones bsf (bit set file) ponen un bit RP0 del registro 'status' a 1. Como ya se dijo, si el bit 5 del registro status está a 1, entonces estamos trabajando en el banco 1, se hace esto para definir los pines de entrada/salida de los puertos del micro. 

En esta sección se puede encontrar una disposición algo modificada aunque no presenta diferencias de cara al micro. Me estoy refiriendo a una definición como:

     ;****************** Mapa de memoria *******************      
     22   BSF 03,5        ;Ir al banco 1
     23   MOVLW 0F        ;Pon 0000 1111 en W para
     24   MOVWF 05        ; hacer RA0, RA1, RA2 y RA3 entradas
     25   BCF 03,5        ;Ir a banco 0
     26   GOTO Primero
     ;*************************************************** 

Incluso como:

     ;****************** Mapa de memoria *******************   
     22   bank1		;Seleccion del Banco 1
     23   movlw 0x01	;w = 0x01
     24   movwf trisb	;Bit 0 de trisb en "1" RB0 = IN; RB1-RB7 = 0
     25   clrf trisa	;trisa = 0, Todo el Puerto RA = Salida 
     26   bank0		;seleccion del Banco 0      
     ;*************************************************** 

Aunque para esto, antes deberemos definir bank1 y bank0, en la sección "equs", como sigue:

     ;****************** Mapa de memoria *******************  
     18   #define	bank1	bsf status,5	;Macro para abreviar el banco 1
     19   #define	bank0	bcf status,5	;Macro para abreviar el banco 0
       ;*************************************************** 

Ahora, sigue la rutina principal que hace llamadas mediante la instrucción CALL, a distintas subrutinas.

     ;************************************************************   
    27 inicio:            ;Etiqueta de la rutina principal
    28   call  flash   ;Llama la subrutina flash para destellar brevemente LED
    29   call  ret_largo ;Llama la subrutina ret_largo, donde espera un tiempo
    30   goto  inicio  ;Hazlo otra vez, y otra vez, ...
    ;*************************************************************   

Le sigue la subrutina encargada de encender y apagar el LED (en este ejempo) 

     ;************************************************************ 
    32          ;Subrutina para destellar el LED una vez, brevemente
    33 flash:
    34   bsf	 port_b, 03 ;pone a 1 el bit 3 del puerto B, que enciende el LED
    35   call ret	      ;llama a subrutina retardo corto, mientras, luce LED
    36   bcf	 port_b, 03 ;pone a 0 el bit 3 del puerto B, que apaga LED
    37   return		;retorna al punto de llamada.
    ;************************************************************ 

Si es el caso, definiremos nuevas rutinas que realicen nuevas tareas, como es un retardo corto y uno largo. Cuando las secuencias de encendido y apagado se suceden muy rápido, puede ser de utilidad usar un retardo, permitiendo que el efecto se aprecie por el ojo, debemos tener presente que el microcontrolador es muy rápido y no permite ver ciertos eventos si no se usan los retardos.

    ;************************************************************ 
    39;Retardo largo lazo de la subrutina que llama la subrutina retardo corto
    40 ret_largo:		;inicializar contador retardo largo
    41	       movlw	0x03Fh	;carga el acumulador con el valor 3Fh 
    42	       movwf	count3	;mueve el contenido del acumulador a count3,
    43
    44 largo1:                     
    45	       call	 ret	;llama la subrutina retardo corto
    46	       decfsz count3, 1 ;Decrementa count3, guarda el resultado en F 
				;y si no es cero salta la siguiente instruccion.
    47	       goto  largo1	 ;vuelve a decrementar mientras largo1 no sea 0
    48	       return		;si es 0, regresa al punto de llamada.
    ;************************************************************ 

El resto del listado una vez más se describe así.

    50 	 ;La subrutina de retardo corta con dos lazos anidados. 
    51 ret: movlw 0xFF	;Carga el acumulador con el valor FF
    52	     movwf count1	;mueve contenido del acumulador a count1 
    				;para iniciar lazo externo.

    54 ret1: movlw 0x0Fh	;Carga el acumulador con el valor 0Fh 
    55	     movwf count2	;mueve contenido del acumulador a count2  
    				;para iniciar lazo interno

    57 ret2: decfsz count2, 1 ;decrementa count2 lazo interno, guarda el 
    		; resultado en F y si es cero salta la siguiente instruccion.
    58	     goto ret2	;volver a la subrutina ret2 otra vez (lazo ret2) 
    59	     decfsz count1, 1  ;decrementa count1 (lazo externo) y si count1 
    		; es cero saltate la siguiente instruccion.
    60	     goto ret1	;si no, vuelve a decrementar mientras ret1 no sea 0.
    61	     return		;si es 0, retorna al punto de llamada. 
 
    63	     END		;Termina el programa
 

Este listado nos ha servido para describir ciertas partes interesante en el desarrollo de un programa escrito en ensamblador para los micros de la familia PIC. En próximos trabajos desarrollaremos otros interesantes proyectos que tengan utilidad práctica.

El ensamblador.

Una vez terminado el listado mnemónico con las instrucciones que hayamos considerado necesarias para el proyecto, debemos ensamblarlo con una herramienta que la misma empresa creadora del PIC nos proporciona gratis, como es el MPLAB©, esta la podemos encontrar en este enlace, si el lector no está familiarizado con esta herramienta, le recomiendo que lea con atención esta guía rápida, con la que puede empezar a probar con este listado que acabamos de describir, ya que entiendo que por su extensión e importancia merece un artículo a parte.

El siguiente es el listado en hex exadecimal, el que tendremos que quemar en el PIC16F84A, con el quemador que dispongamos. Si no dispone del ensamblador, puede copiar y pegar el siguiente listado que, puede guardar con el nombre "rutina1.hex", resultado de ensamblar el código descrito.

:1000000083168611831206200A20032886151020E5
:10001000861108003F308E0010208E0B0C2808003F
:10002000FF308C000F308D008D0B14288C0B1228A4
:020030000800C6
:00000001FF

Puede leer un tutorial con referencia a la herramienta del IcPorg, en este enlace, para poder grabar su microcontrolador PIC.

Descripción electrónica.

Aquí se muestra el esquema y circuito eléctrico necesario, para utilizar el programa que posteriormente grabaremos 'quemaremos' en un PIC. El proyecto pretende ser el primero de una serie que nos permita aprender cómo producir un programa. Para empezar será necesario disponer de las hojas de datos del PIC16F84A que hay en este sitio, de modo que el estudiante pueda seguir mejor las descripciones.

El esquema.

Esquema destellos con PIC

Según las características del PIC16F84A, el pin de reposición o Reset, es el pin 4, el cual debe conectarse a la línea positiva de Vcc. Sin embargo personalmente no me parece muy seguro esto y opté por utilizar una red RC típica, formada por una resistencia y un condensador que aseguren la correcta reposición (Reset) del 'F84A, cuando se ponga a 0 hasta cargarse el condensador. En la mayoría de los circuitos que se pueden ver, para el reset, no incorporan el condensador, ya que, es necesario poner esta patilla a positivo para que el micro pueda correr, por lo que el emplo del condensador, queda a su criterio.

El motivo del circuito es muy simple, se trata de hacer que un diodo LED destelle. Evidentemente tenemos que empezar desde abajo,Config. oscilador nadie nace con conocimientos avanzados, creo que es conveniente empezar por lo más simple y procurando asimilar los pasos, para ascender en los conocimientos de la programación.

Nota.- Cuando tengamos terminado el listado del programa y lo hayamos ensamblado (pasado a HEX), debemos tener presente que a la hora de quemar el chip, decidamos si usaremos para el reloj, un cuarzo o una red RC, en caso de RC, en el programador activaremos la opción RC para que funcione, si es un oscilador cerámico. En caso de usar un cuarzo activar la opción XT en el programador y lo quemaremos con estas opciones, de lo contrario no funcionará y no encontraremos fallos en el programa.

En el momento de grabar (quemar) el micro, se produce la palabra de configuración, la responsable de indicarle al micro como se ha condicionado su estructura. Es conveniente conocer mas acerca de la Palabra de Configuración, lo que ya se ha comentado en este tutorial

El circuito.

Para mantener las cosas económicas y fáciles, utilizaremos la opción de oscilador RC, si bien, este oscilador no es particularmente estable, servirá para este proyecto al igual que en otros muchos. El esquema (muy simple) que se utilizará es el anterior y el pcb, este:

Aunque la línea de Vcc del esquema dice ser de 5V, puede ser utilizada una tensión menor, una de 3V o 4' 5V que, son valores más normalizados, aun así, he intercalado un diodo 1N4007 con el que asegurar la polaridad y la tensión incluso para 6V. Como puede apreciarse el esquema es muy sencillo, en esencia debido a la presencia del PIC y en la siguiente figura se muestra el circuito muy simple ejecutado sobre la placa de pruebas. Probablemente el lector haya programado anteriormente y le parezca esto demasiado elemental, espero que sepa disculpar y tenga paciencia, no todos están a la misma altura.

Practica

Es muy sencillo como se ha mencionado, pero es una práctica que sólo pretende ayudarnos a comprender los pasos a seguir en la programación en ensamblador (.asm) de un proyecto y su puesta en funcionamiento. En próximos artículos se tratan nuevos temas, hay mucho que desarrollar y practicar.

Volver al indice de artículos PIC.

 

Creado el: 28-04-2005
Actualizado el: 18-06-2007