Professional Documents
Culture Documents
Características analógicas:
2
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
La memoria de programa
En los PIC16Fxxx es de tipo flash, por eso la F. Aquí es donde se aloja el programa que el CPU ejecutará. En
los PIC16 la memoria de programa se cuantifica en palabras, de 14 bits cada una. Son de 14 bits porque
cada instrucción es de 14 bits. Esto suele impresionar un poco al novel, quien está habituado a medir la
capacidad de las memorias en bytes (8 bits).
El PIC16F84A tiene 1 k (1024) palabras de memoria. En tiempo de ejecución son de solo lectura. Con 1 k
puede almacenar hasta 1024 instrucciones de código ensamblador.
Los PIC16F877A/876A tienen 8 k (8192) palabras de memoria de programa mientras que los
PIC16F874A/873A tienen 4 k (4192). Los cuatro PICmicros ofrecen la posibilidad de escribir en su memoria
de programa incluso en tiempo de ejecución. Esta función puede ser aprovechada para almacenar datos
procesados por el usuario o para permitir la autoprogramación del PIC.
En las siguientes figuras las memorias de programa del PIC están acompañadas por el PC (Program Counter)
y la Pila (Stack). Es así porque hay una extrecha relación en su trabajo.
3
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
El Contador de Programa, PC
El PC es un registro que indica la siguiente instrucción que debe ejecutar el CPU. Al arrancar
microcontrolador, el PC vale 0x0000 y se va incrementando automáticamente, con lo que el PIC debería
ejecutar una a una todas las instrucciones del programa.
La Pila o STACK
Es una memoria que almacena temporalmente el valor del PC (Program Counter) cuando el programa llama
a una subrutina o cuando salta al Vector de Interrupción, en una interrupción.
En los PICs de la familia Mid-Range la Pila tiene únicamente 8 niveles y se administra a nivel hardware, esto
es, no hay instrucciones para acceder a ella directamente. Su operación es enteramente en background.
Solo debemos cuidar de que no se llegue a desbordar.
La memoria RAM
A diferencia de las RAMs de los microcontroladores convencionales, que tienen mapa de memoria plano, la
RAM de los PICs de familia Mid-range está dividida en sectores denominados bancos. Cada byte de la RAM
se conoce como registro.
4
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
Hay dos tipos de registros de RAM: los registros de función especial SFR y los registros de propósito general
GPR.
No todos los registros están implementados físicamente. La escritura en dichas locaciones no significa nada
y siempre se leen como 0.
El PIC16F84A es de los muy pocos que tienen 2 bancos de RAM; el resto de los PIC16F, que son la gran
mayoría, tienen 4 bancos. La existencia de los bancos solo es de consideración (y un dolor de cabeza)
cuando se programa en lenguaje ensamblador.
Los registros SFR (Special Function Register) están ubicados en las primeras posiciones de cada banco de
RAM, los que en la figura anterior aparecen con nombre propio, como TMR0, PORTA, etc. Su principal
función es controlar las operaciones del microprocesador y de los módulos periféricos. Como se ve, algunos
de esos registros aparecen duplicados en los bancos; eso es para facilitarnos su acceso porque son de uso
muy frecuente o porque son un poquito más especiales, como STATUS, INTCON o PCL.
También son registros de 1 byte cada uno. Los registros GPR (General Purpose Register) sirven para
almacenar los datos o variables que se procesan en el programa.
El PIC16F84A tiene 68 registros GPR, todos ubicados en el banco 0, entre las direcciones 0x0C y 0x4F. En el
banco 1 no hay registros GPR, solo hay accesos a los registros del banco 0. Dicho en otras palabras, los
registros GPR del banco 1 son un reflejo de los GPR del banco 0.
5
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
Los PIC16F877A/876A tienen 368 registros GPR. Los últimos 16 registros de los bancos 1, 2 y 3 son los
mismos que del banco 0.
Los PIC16F874A/873A tienen 192 registros GPR. Su mapa de RAM es un poco diferente debido
principalmente a los accesos repetidos. Todas estas diferencias serán de preocupación solo cuando se
programe en ensamblador.
6
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
7
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
Los registros GPR no tienen nombres propios, pero los compiladores de alto nivel saben cómo
administrarlos para almacenar las variables del programa. Por otro lado, si se programa en ensamblador, se
8
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
les debe acceder mediante sus direcciones, ya sea directamente usando números, o asignándoles nombres
a las direcciones con algunas directivas, como equ o cblock.
Por ejemplo, en el siguiente código se designan los nombres var1 y var2 a los registros de direcciones 0x25
y 0x30, respectivamente.
Luego se podrán usar esos nombres para acceder a los registros designados. Por ejemplo, el siguiente
código copia el contenido del primer registro al segundo.
El diseñador puede elegir cualesquiera registros GPR como sus variables de programa. Para ello debe
recordar siempre dónde se localizan. Según las figuras de arriba, en el PIC16F84A están mapeados a partir
de la dirección 0x0C. En los PIC16F87xA empiezan en la dirección 0x20 en el banco 0; los otros bancos se
usan raramente en ensamblador.
PIC16F876A se diferencia del PIC16F877A porque viene en empaque PDIP de 28 pines, lo que le descuenta
los puertos D (de 8 pines) y E (de 3 pines). La función excluyente de estos puertos es la interface del PSP
(Parallel Slave Port), del que muy pocos se acuerdan. El puerto E también provee tres canales adicionales
para el conversor ADC. En consecuencia, si no vamos a utilizar estas funciones, no se presentarán
problemas de compatibilidad y los programas pueden ser usados para el PIC16F877A o el PIC16F876A
indistintamente, tanto en código fuente como en código ejecutable *.hex.
Las mismas diferencias descritas arriba también se presentan entre los PIC16F873A y PIC16F874A.
Adicionalmente, estos PICmicros se diferencian de los dos anteriores por tener menos memoria de
programa FLASH, de datos RAM y de EEPROM, y en la ligera variación de disposición de los registros GPR de
la RAM. Esto último puede dar origen a incompatibilidades hasta en los códigos *.hex resultantes.
La siguiente tabla resume las diferencias más evidentes entre los PICmicros citados.
Tabla Dispositivo
9
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
De estos 4 PICs en este curso se utiliza el PIC16F876A, aunque los programas, que están escritos en
lenguaje C, serán totalmente compatibles con los otros 3. Para cambiar de PIC solo hará falta establecerlo
como PIC destino y recompilar el proyecto. El compilador se encargará de los detalles de bajo nivel.
Los fuses se programan mediante los llamados Bits de Configuración, los cuales están contenidos en un
registro de EEPROM especial denominado Configuration Word. Este registro está situado en la dirección
0x2007, aunque tiene poco sentido saberlo porque es inaccesible desde el programa en tiempo de
ejecución.
El PIC16F84A tiene 4 fuses y los PIC16F87xA tienen 9. Por tanto habrá diferencias en sus palabras de
configuración.
La Palabra de Configuración de los PIC16F87xA incluye todos los bits del PIC16F84A, aunque varíen algunos
nombres. De todos modos, esos nombres son raramente usados como tal. Los fuses se suelen programar
usando máscaras que los representan. Por fortuna, las máscaras sí son iguales.
La Palabra de Configuración se puede cambiar en el momento de “quemar” el PIC en el IDE del software de
programación, pero sería mejor que sus valores se cargaran desde el archivo *.hex junto con el código
ejecutable. En seguida se muestra un ejemplo de cómo establecer los fuses en el código fuente del
programa en lenguaje ensamblador, mediante la directiva __config:
__config _XT_OSC & _WDT_OFF & _PWRTE_ON
Esta línea pone tres máscaras (_XT_OSC, _WDT_OFF y _PWRTE_ON) enlazadas por el operador &. Cada
máscara indica el estado de un fuse. En este caso se indica: adaptar el circuito interno de oscilador para un
XTAL, inhabilitar el Watchdog y habilitar el Power-up Timer. El resto de los fuses (los no citados) tendrán
sus valores por defecto.
No te preocupes si el anterior parrafo se leyó extraño. A continuación se describen los 9 fuses de los
PIC16F87xA. El PIC16F84A solo cuenta con los 4 primeros. También se muestran las máscaras
correspondientes utilizadas en ensamblador.
10
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
_LP_OSC = Oscilador LP. Se usa cuando el PIC va a trabajar con un cristal de baja potencia.
_XT_OSC = Oscilador XT. Se usa cuando el PIC trabajará con un cristal o resonador de frecuencias
iguales o menores que 4 MHz. Es la opción que usaremos a lo largo del curso.
_HS_OSC = Oscilador HS. Se usa cuando el PIC operará con un cristal o resonador de alta frecuencia,
iguales o mayores que 4 MHz.
_RC_OSC = Oscilador RC. Se usa cuando el PIC va a operar con un circuito RC. Es útil para sistemas
de bajo costo aunque con frecuencias bajas y de menor nivel de estabilidad. Es la opción
por defecto.
El Watchdog
El Watchdog o WDT es un temporizador que una vez vez alcanzado su tiempo límite puede provocar un
reset en el pic. El watchdog es un simple contador, que se puede reiniciar para que no llegue a desbordarse
de modo que no se produzca el reset.
El watchdog está habiitado por defecto y se debe reiniciar con la instrucción de ensamblador clrwdt. En el
programa el watchdog se inhabilita poniendo la máscara _WDT_OFF.
Power Up Timer
Protección de Código
Se representa por el bit CP. Este fuse pone protección a la memoria de programa. Como sabemos, es
posible leer el programa contenido en el PICmicro mediante el dispositivo programador (JDM por ejemplo).
Si activamos este fuse, dicha lectura será impedida. También implica renunciar a la característica de
verificación del programa; así que si lo vas a activar, no olvides reconfigurar el software de programación.
11
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
Se representa con los bits WRT1 y WRT0. Los PIC16F87xA ofrecen la posibilidad de escribir en su memoria
de programa Flash en tiempo de ejecución. Sin embargo, esto algunas veces puede resultar riesgoso. Así
que para dotarle se seguridad adicional al programa este fuse permite configurar qué área de memoria
quedará protegida y qué área no. El efecto no es siempre el mismo en los PIC16F877A/876A que en los
PIC16F874A/F873A: no es lo mismo la mitad de la memoria del PIC16F876A que la mitad de memoria del
PIC16F873A.
Modo ICD
Se representa con el bit DEBUG. Con el módulo ICD (In Circuit Debugger) habilitado, los PIC16F87xA
monitorizan el estado de todos sus elementos hardware internos. Los resultados serán almacenados en un
área reservada de la memoria RAM y luego enviados a una computadora a través de los pines RB6 y RB7. La
computadora recibirá los datos mediante algún programa que soporte el modo ICD
Al habilitar el modo ICD se debe renunciar a los pines RB6 y RB7 como puertos de E/S convencionales, a un
nivel de pila y a algo de memoria RAM.
Se representa con el bit CPD. Sirve para proteger la memoria EEPROM interna de los PIC16F87xA contra
accesos mediante un dispositivo externo. Funciona similar a la protección de la memoria de programa, esto
es, podrá ser accedida normalmente por el CPU en tiempo de ejecución, mas no, por ejemplo, por un
programador de PICs.
12
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
Se representa con el bit LVP. Los PIC16F87xA también ofrecen la posibilidad de ser programados con una
tensión igual a Vdd en el pin MCLR, en vez de los 12 V acostumbrados. Éste es el modo de programación
ICSP (In Circuit Serial Programming) de bajo voltaje. Los pines RB6 y RB7 también deben ser sacrificados
para uso exclusivo del programador y además se les suma la presencia del pin RB3 como señal del modo de
programación. Dada esta interface, no debe sorprender que esta característica puede ir muy de la mano
con el depurador ICD. Sin embargo, para la programación en bajo voltaje no se requiere de herramientas
especializadas.
Habilitado este fuse, los pines RB7, RB6 y RB3 no responderán como puertos de E/S típicos.
El circuito Brown out del PIC detecta las caídas en la tensión de alimentación y puede generar un reset ante
tal evento para evitar que el PIC siga trabajando con alimentación insuficiente. En los PIC16F el valor
umbral típico del circuito Brown out es de 4V. De hecho, a tensiones aceptablemente por debajo de este
nivel de tensión el PIC todavía puede tener una operación correcta pero no garantizada.
Si no se quiere correr el riesgo y se prefiere optar por que el PIC reinicie todo, se puede activar este fuse
mediante su bit de configuración BOREN o mediante su máscara respectiva.
13
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
Cuando actúan como salidas, los pines pueden entregar tensiones de hasta Vdd. Cuando actúan como
entradas pueden manejar niveles de hasta 0.3V por encima de Vdd. Cada pin de puerto puede soportar
hasta 25 mA de corriente.
14
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
El puerto B
Empezamos con el puerto B porque es el más fácil. Los nombres sencillos de sus pines revelan que no
tienen muchas funciones. Los 8 pines RB0...RB7 trabajan como E/S digitales bidireccionales por igual. Es
adecuado para interfaces ordinarias como el manejo de LEDs, control de LCDs, teclados, lectura de
switches, pulsadores, etc.
La etiqueta INT en el pin RB0/INT significa que además se puede configurar para recibir interrupciones
externas. Solo en ese estado se comporta como entrada Schmitt Trigger. De hecho, los pines RB4, RB5, RB6
y RB7 también pueden responder a interrupciones. Estas interrupciones le permiten al microcontrolador
atender inmediatamente a los eventos de cambios de nivel lógico en los puertos sin necesidad de estar
monitorizándolos constantemente. Las interrupciones se estudian con profundidad mucho más adelante.
El puerto B es el único entre los PIC16F que incluye resistencias de pull up internas. Eso nos ahorrará el
tener que ponerlas externamente cuando sean requeridas, aunque lo ideal sería que hubiera pull-ups en
todos los puertos, así como que todos los pines fueran Schmitt Trigger.
Recordemos que los pines RB6 y RB7 también sirven de interface para la programación del PICmicro. Solo
en ese modo estos pines actúan como Schimitt Trigger, aunque tenga poca relevancia para nuestros
propósitos.
También recordemos (del capítulo 3) que los PIC16F87xA soportan la programación en bajo voltaje. En ese
modo su pin RB3 tiene una función muy crucial. Eso explica la inscripción adicional PGM (Modo
Programación). La programación en bajo voltaje se habilita/inhabilita vía los Bits de Configuración.
El puerto A
El PIC16F84A tiene un puerto A de 5 pines, desde RA0 hasta RA4. Los cuatro primeros funcionan
normalmente como pines de E/S bidireccionales y también soportan niveles TTL. El pin RA4, no obstante, es
un tanto especial. Como salida es de drenador abierto y requerirá de una resistencia de pull externa si se
usa como tal. Es el único pin que en todo momento tiene buffer Schmitt Trigger, lo que como entrada le da
una mejor performance, y el único pin que puede recibir voltajes hasta de 8.5 V.
RA4 puede funcionar adicionalmente como entrada del Timer0 cuando opera en modo Contador. Por eso
su etiqueta adicional T0CKI (Timer0 Clock Input). (Descuida, si por el momento no entiendes mucho de
estos conceptos, esto no se aprende de la noche a la mañana.)
En los PIC16F87xA el puerto A tiene 6 pines. Los cinco primeros son compatibles con los del PIC16F84A. El
pin RA5 también es E/S, TTL y bidireccional. Ahora, la gran diferencia en el puerto A de los PIC16F87xA es
que está multiplexado para recibir 5 de los 8 canales posibles del conversor ADC (analógico-digital) de estos
PICs. Eso es lo que indican las etiquetas ANx que poseen algunos pines. Nota que el pin RA4/T0CKI no está
en este grupo.
15
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
Ahora un punto clave: para confusión de los que migran a los PIC16F87xA el puerto A inicia con una
configuración analógica. Si se quiere usarlo para interface digital será necesario reconfigurarlo en el registro
ADCON1. Más adelante se muestra cómo.
El puerto C
Muchos (casi todos) los módulos o periféricos nuevos de los PIC16F87xA tienen salida al exterior mediante
los pines de este puerto. Aquí están los pines de recepción RX y transmisión TX del puerto serie del USART;
aquí están los pines de datos SDA y reloj SCL del módulo MSSP cuando funciona en modo I2C; aquí están las
salidas de los dos canales de PWM CCP1 y CCP2 de los módulos del mismo nombre cuando generan ondas
PWM; aquí están las entradas del Timer1 T1OSO/T1CKI y T1OSI cuando opera en modo Contador.
Creo que no tiene caso seguir con la descripción porque sería casi interminable y porque nos
familiarizaremos con muchos de estos pines cuando estudiemos los módulos a los que están relacionados.
Por lo demás, los pines del puerto C no necesitan de configuración previa alguna para trabajar como E/S
bidireccionales, compatibles con TTL.
El puerto D
Está conformado por los 8 pines RD0...RD7. Junto con el puerto E solo están presentes en los PIC16F de 40
pines y tienen la característica destacable de ser la interface del módulo PSP o Puerto paralelo esclavo. Pero
como ese módulo casi ni se usa, el puerto D podría tranquilamente reemplazar o ayudar al puerto B en las
interfaces con los dispositivos fotoelectrónicos, electromecánicos, etc., dado que es también es
bidireccional, configurable pin por pin y maneja señales TTL.
El puerto E
Solo tiene 3 pines RE0...RE2, que se pueden usar como analógicos o digitales. Como pines digitales son
bidireccionales y también pueden funcionar como señales de control RD, WR y CS del módulo PSP.
Como pines analógicos, dan ingreso a 3 de los 8 canales posibles del conversor ADC. Al igual que el puerto
A, el puerto E también inicia con sus pines como entradas analógicas y habrá que configurarlos del mismo
modo para que trabajen como pines de E/S digital, si así se desea.
16
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
• 0 → Output = salida
• 1 → Input = entrada
Por ejemplo, si escribimos el valor 00001111 en TRISB, entonces los cuatro pines de menor peso del puerto
B serán entradas digitales y los cuatro pines superiores serán salidas.
Si escribimos 00000001 en TRISA, únicamente el pin RA0 será entrada y los demás serán salidas. Como el
puerto A no tiene los 8 pines completos, los bits de mayor peso de PORTA y TRISA no tienen significado.
Otra forma de configurar los puertos es pin por pin, utilizando las instrucciones bsf (bit set file = setear bit
en registro) y bcf (bit clear file = limpiar bit en registro). Por ejemplo.
Así hemos configurado los pines RB2 para entrada y el pin RA5 para salida. El resto de los bits de los
registros TRISA y TRISB conservarán sus valores anteriores.
Finalmente, el siguiente fragmento configura los puertos del PIC empleando una forma de cofidicación
alternativa y a veces más ventajosa.
17
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
La pregunta es: ¿acaso los puertos no se configuraban en los registros TRISx? Bueno, sucede que los siete
primeros bits de los registros PORTx y TRISx son iguales, de modo que una vez cambiado de banco se
pueden llamar por igual. Esto es extensible a todos los registros de la RAM, aunque solo resulta práctico al
trabajar con los puertos.
Ahora observemos una piedra con la que todos en algún momento hemos tropezado sobre todo al portar
nuestros códigos del PIC16F84A a los PIC16F87xA. Se trata de los puertos A y E. Estos puertos además de
entradas inician configurados como pines analógicos (entradas del ADC). El código del programa parece tan
lógico pero el PIC no funcionaba bien porque el puerto A no era digital.
Es posible establecer varias combinaciones seleccionando los pines que serán digitales y los que serán
analógicos. Por ejemplo, si se quiere que todos los pines sean digitales, hay que escribir el siguiente código
en ensamblador.
O en lenguaje C
Los códigos mostrados cargan el registro ADCON1 con el valor 0x06. ADCON1 es uno de los registros que
controlan el conversor ADC. Este módulo lo estudiaremos tendidamente en su momento. Por ahora nos
bastará con saber que si escribimos 6 ó 7 en él, todos los pines de los puertos A y E tendrán
comportamiento digital de E/S.
18
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
Las 8 pull ups se pueden habilitar al mismo tiempo limpiando el bit NOT_RBPU, del registro OPTION_REG.
Las pull ups solo serán efectivas en los pines que actúan como entradas; en los pines RBx configurados
como salidas las pull ups quedan automáticamente inhabilitadas.
La siguiente figura muestra la conexión de un pulsador al PIC aprovechando la pull-up del pin RB7. Fíjate en
que las pull-ups no se pueden usar como resistencias para excitar dispositivos como LEDs, relés, etc.
Los siguientes códigos habilitan todas las pull-ups del puerto B, aunque solo se activarán en los pines
configurados como entradas.
O en lenguaje C
OPTION_REG.NOT_RBPU = 0; // Habilitar pull-ups de PORTB
19
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
Ejemplo N° 1
El ineludible LED parpadeante. Es el programa por el que todo aficionado o profesional ha pasado alguna
vez en su vida. La tarea consiste en prender un LED, hacer una pausa, apagar el LED, hacer otra pausa y
repetir todo de nuevo, una y otra vez, indefinidamente.
Circuito de la práctica
20
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
Quizá el programa éste, que solo enciende un LED, sea una trivialidad, pero no te confíes. Los µCs no
entienden nuestro lenguaje humano y hay que aprender a hablarles en el suyo. Eso, como cualquier idioma
nuevo, nos tomará un poquito de tiempo. Así que no te vayas a echar para atrás cuando veas el programa
ni cuando leas la enorme explicación del mismo.
;************************************************************************
list p = PIC16F84A ; Seleccionar procesador
#include "P16F84A.inc" ; incluir archivo P16F84A.inc
__config _PWRTE_ON & _WDT_OFF & _XT_OSC & _CP_OFF
;************************************************************************
; Subrutina pausa. Genera 325 milisegundos aprox.
pausa
movlw d'100' ; Mover 100 a W
movwf cont1 ; Mover W a cont1 (cargar cont1)
movlw d'255' ; Mover 255 a W
movwf cont2 ; Mover W a cont2 (cargar cont2)
loop1
decfsz cont1, f ; decrementar cont1, saltear si da 0
goto loop2 ; saltar a loop2
decfsz cont2, f ; decrementar cont2, saltear si da 0
loop2 goto loop1 ; saltar a loop1
return ; retornar de subrutina
21
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
El programa se compone básicamente por directivas, instrucciones y comentarios. Las directivas le dan
alguna orden al ensamblador para realizar su trabajo. En este código aparecen en color azul. Las
instrucciones son el verdadero código ejecutable y sus nombres aquí se muestran en marrón. Un
comentario es el texto decorativo que sigue a un punto y coma (;) y aparece de color verde. El siguiente
capítulo describe mejor estos conceptos.
La primera línea significativa es una directiva que le dice al ensamblador que estamos haciendo un
programa para el PIC16F84A.
La siguiente línea es una directiva para decirle al ensamblador que incluya el archivo de dispositivo
P16F84A.inc como parte del código. Allí se encuentran los nombres de los registros, de los fuses de
configuración, etc., del PIC usado. El ensamblador sabe dónde buscarlo.
Lo que sigue es la directiva para poner los Fuses de Configuración. Ya los conocimos en el capítulo anterior,
así que no diré mucho. Solo nota que no era necesario añadir el _CP_OFF porque es la opción por defecto
de ese fuse.
__config _PWRTE_ON & _WDT_OFF & _XT_OSC & _CP_OFF
Luego tenemos dos directivas más. Sirven para nombrar con cont1 y cont2 a los registros GPR de las
direcciones 0x0C y 0x0D. Se usan esas direcciones porque son los primeros registros GPR del PIC16F84A.
Pueden ser otros, siempre que estén en el área de los GPR.
La siguiente línea es una directiva para indicarle al ensamblador a partir de qué dirección empezará a
mapear el código ejecutable que sigue. Como el CPU empieza a ejecutar el código desde la dirección 0x00,
la primera instrucción debería estar allí.
Ahora viene el código ejecutable en sí. Es una instrucción que significa setear el bit RP0 del registro STATUS.
Con esto basta para pasar al banco 1 del PIC16F84A. Querremos acceder a los registros TRISA y TRISB.
22
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
Ahora viene el código ejecutable en sí. Es una instrucción que significa setear el bit RP0 del registro STATUS.
Con esto basta para pasar al banco 1 del PIC16F84A. Querremos acceder a los registros TRISA y TRISB.
En la siguiente línea tenemos la instrucción para Limpiar el bit 0 del registro TRISB.
A continuación está la instrucción para Limpiar el bit RP0 de STATUS. Regresamos al banco 0, para acceder
a PORTB.
En el siguiente código MLoop es una etiqueta. Con bsf PORTB, 0 seteamos el bit 0 de PORTB, que es el
registro que representa al puerto B. Así que nuestro LED conectado al pin RB0 se prenderá.
Apenas han pasado 4 microsegundos desde la primera instrucción. No deberíamos apagar el LED ahora, tan
pronto. Necesitamos un tiempo. La llamada a pausa es una instrucción con la que el programa saltará a la
etiqueta pausa. Luego ejecutará todo el código que se encuentre en este bloque hasta llegar a la
instrucción return.
;************************************************************************
; Subrutina pausa. Genera 325 milisegundos aprox.
pausa
movlw d'100' ; Mover 100 a W
movwf cont1 ; Mover W a cont1 (cargar cont1)
movlw d'255' ; Mover 255 a W
movwf cont2 ; Mover W a cont2 (cargar cont2)
loop1
decfsz cont1, f ; decrementar cont1, saltear si da 0
goto loop2 ; saltar a loop2
decfsz cont2, f ; decrementar cont2, saltear si da 0
loop2 goto loop1 ; saltar a loop1
return ; retornar de subrutina
No creas que voy a explicar el flujo de esta subrutina ahora porque está más enredada que una pelea de
pulpos. Puedes ver que hay saltos para adelante, para atrás, luego otra vez para adelante y así... El hecho es
que todo esto le tomará al PIC cerca de 0.3 segundos. Los delays se ven con detenimiento en el siguiente
capítulo. Tras ejecutar return el programa retornará al punto desde donde se hizo la llamada y continuará
con la siguiente instrucción, que es
23
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
Luego llamamos nuevamente a la rutina pausa para mantener el LED apagado durante otros 0.3 segundos.
call pausa ; Llamar pausa
En seguida se ejecutará la instrucción goto para que el programa salte a la parte del código marcada con la
etiqueta MLoop. Así se volverá a ejecutar todo el código descrito y tendremos un LED que se prende y
apaga constantemente hasta que le quitemos la alimentación al circuito.
goto MLoop ; Saltar a MLoop
Al final de todo el código tenemos la última directiva que se debe poner en un programa. end es una
directiva del ensamblador para decirle que nuestro código termina aquí y que ya no busque más líneas que
ensamblar.
end ; Fin del código
Puede parecer laborioso, pero los comienzos siempre son así; ya verás que todos los programas son muy
parecidos y requieren que cada vez menos explicación.
24
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
Ejemplo N° 2
Antes de que empieces a creer que programar PICs es una tarea formidable por la enorme explicación del
anterior programa, haremos otro programa para ver que todos son muy similares entre sí.
Se trata de un secuenciador de 8 canales. Hay 8 LEDS conectados al puerto B. Solo tiene un efecto que
consiste en un par de LEDS que se desplazan desde el centro hacia los costados.
Circuito de la práctica
25
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
26
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
El prefijo 0x representa un número en formato hexadecimal, los números entre comillas simples y
precedidos por una b o d indican formatos binario o decimal, respectivamente.
La instrucción clrf (Clear File), que limpia todo un registro, es más directa para configurar todo el puerto B
como salida.
La subrutina pausa es esencialmente la misma del programa anterior. Utiliza las variables cont1 y cont2
para decrementar sus valores. La subrutina termina cuando ambos registros lleguen a 0. En este programa
cont2 inicia en el 196. El valor unicial de cont1 es menos significativo.
;************************************************************************
; Subrutina pausa. Genera 250 milisegundos.
pausa
movlw d'79' ; Mover 79 a W
movwf cont1 ; Mover W a cont1 (cargar cont1)
movlw d'196' ; Mover 196 a W
movwf cont2 ; Mover W a cont2 (cargar cont2)
loop1
decfsz cont1, f ; decrementar cont1, saltear si da 0
goto loop2 ; saltar a loop2
decfsz cont2, f ; decrementar cont2, saltear si da 0
loop2 goto loop1 ; saltar a loop1
return ; retornar de subrutina
;************************************************************************
27
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
Ejemplo N° 3
Luego de haber trabajado manipulando los puertos del PIC para salidas, veremos que las entradas se
manejan casi igual.
Según este programa, cada vez que se presione un botón (pulsador) conectado al pin RA4 el LED conectado
al pin RB0 permutará, es decir, si estaba apagado, quedará prendido y si estaba encendido quedará
apagado.
Circuito de la práctica
El circuito de entrada al pin RA4 constituye un filtro pasa-bajas. Servirá para filtrar los cortísimos pulsos
irregulares que se pueden producir al oprimir el pulsador, conocidos como rebotes. Este filtro funciona
mejor al combinarse con la etapa Schmitt Trigger del pin RA4.
También se pueden implementar simples filtros de software para evadir los rebotes, como por ejemplo
dejar un tiempo de 20ms y volver a consultar por el estado de la entrada.
28
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
El código fuente
;************************************************************************
; Processor: PIC16F84A
; Purpose: Uso de Puertos - entradas
;************************************************************************
list p = PIC16F84A ; Seleccionar el procesador
#include <P16F84A.inc> ; Incluir archivo P16F84A.inc
__config _PWRTE_ON & _WDT_OFF & _XT_OSC
Las cuatro primeras instrucciones hacen lo que indican los comentarios. Recuerda que una vez en al banco
1 también podemos referirnos a los registros TRISA y TRISB con los nombres PORTA y PORTB.
El nemónico btfsc significa “Bit Test File and Skip if Clear”, o sea, Testear el bit 4 de PORTA y saltearse la
siguiente instrucción si vale 0. RA4 es donde está nuestro pulsador y cuando no está presionado la lectura
de RA4 será 1, es decir, se ejecutará goto Esperar_Pulsado, con lo que el programa quedaría dando vueltas
en este bucle, esperando hasta leer un 0.
29
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: CARACTERISTICAS DE LOS PIC 2013
Esperar_Pulsado
PermutarLed ; Sí
Ahora, una vez oprimido el botón, RA4 se leerá como 0, el programa saltará y por encima de goto
Esperar_Pulsado y ejecutará el código que sigue a PermutarLed.
PermutarLed ; Sí
Hay varias formas de permutar el estado de un bit. Particularmente, prefiero emplear la operación XOR.
Recuerda que un XOR de un 1 con un bit lo invierte y un XOR de un 0 con un bit lo deja como estaba. Como
ves, las dos instrucciones mostradas solo invertirán el bit 0 de PORTB, donde está nuestro LED. Por si acaso,
la etiqueta PermutarLed está de adorno, solo es referencia para nosotros, no para el ensamblador.
Con las dos primeras instrucciones hacemos que el programa se quede dando vueltas aquí hasta que el
pulsador sea liberado.
btfss es el par de btfsc y significa “Bit Test File and Skip if Set”, es decir, Testear el bit indicado del registro
indicado y saltearse la siguiente instrucción si vale 1. Mientras el pulsador esté presionado, RA4 se leerá
como 0 y se ejecutará goto Esperar_Libre, o sea, el programa se quedará dando vueltas en este bucle
esperando a que se lea un 1.
Aunque se oprima el botón instantáneamente, puedes estar seguro de que el programa dara miles y miles
de vueltas en este bucle.
Una vez liberado el pulsador, el programa pasará a goto MLoop. Con esto el programa saltará a la etiqueta
MLoop y se quedará en el primer bucle esperando a que se vuelta a presionar el botón.
30
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
Introducción
Siempre ha sido tema de debate la elección del ensamblador o un compilador de alto nivel como lenguaje de
programación. Cada herramienta tiene sus ventajas e inconvenientes. Siempre habrá aplicaciones donde no
sea necesaria la eficiencia del ensamblador o la flexibilidad de un compilador, así como aplicaciones que sí
demanden de ambas facilidades. Sea como sea, un buen diseñador debe estar preparado para emplear el
ensamblador como eventual recurso.
Una razón de gran peso que quiero añadir por la que tarde o temprano se debe aprender el ensamblador es
que la mayor parte (casi toda) la información proporcionada por Microchip en los datasheets, notas de
aplicación o manuales de referencia sobre sus PICmicros se incluyen códigos en ensamblador.
1
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
;************************************************************************
; Processor: PIC16F84A
;************************************************************************
;****************************************************************************
; Subrutina pausa. Genera 325 milisegundos aprox.
pausa
movlw d'100' ; Mover 100 a W
movwf cont1 ; Mover W a cont1 (cargar cont1)
movlw d'255' ; Mover 255 a W
movwf cont2 ; Mover W a cont2 (cargar cont2)
loop1
decfsz cont1, f ; decrementar cont1, saltear si da 0
goto loop2 ; saltar a loop2
decfsz cont2, f ; decrementar cont2, saltear si da 0
loop2 goto loop1 ; saltar a loop1
return ; retornar de subrutina
Visto el código de izquierda a derecha podemos notar que sobresalen cuatro columnas. (Los colores ayudan
mucho, aunque no determinan nada.)
La primera columna es la que contiene las etiquetas y también algunas directivas. Las etiquetas
sirven para marcar las direcciones de las instrucciones a las que preceden. Pueden ser útiles para
algunas instrucciones y en otros casos están de adorno. Por ejemplo, la etiqueta Start vale por la
2
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
dirección de bsf STATUS, RP0. El nombre de las etiquetas es un identificador. Pueden opcionalmente
ir seguidas de dos puntos (:).
En este programa tenemos las etiquetas Start, MLoop, pausa, loop1 y loop2.
En la segunda columna están los mnemónicos de las instrucciones, como bsf, movlw, etc. (en el
ejemplo aparecen de color marrón), macros o directivas del ensamblador. Las directivas (cuyos
nombres aparecen de color azul) no son instrucciones del PIC ni constituyen código ejecutable. Son
ordenes que el ensamblador tendrá en cuenta en el momento de ensamblar el código fuente. Tienen
diversas funciones y ayudan bastante, como lo veremos en adelante.
Ahora, lo que puede resultar desalentador es la cantidad de directivas que existen. De la enorme lista
disponible solo un grupo de ellas son realmente elementales e iremos conociéndolas de a poco. La
lista inicial indispensable está formada por list, include, __config, banksel, equ, org, end, define,
cblock, endc, dt.
La tercera columna está constituida básicamente por los operandos de instrucciones, como STATUS,
RP0; TRISB; pausa; etc.
En la cuarta columna sobresalen los comentarios. Un comentario es todo lo que sigue en el renglón a
un punto y coma (;) y será ignorado por el ensamblador (en el listado es todo lo que se ve de color
verde). Digamos que son texto de adorno que solo sirve para documentar el programa. De hecho, los
comentarios pueden ponerse en cualquier parte del listado.
Ésa es una forma algo burda de estructurar un programa, pero ayuda muchísimo. Ahora pasaremos a
revisarlo de arriba abajo.
Los identificadores son los nombres que podemos usar para identificar ciertos elementos del código fuente,
como registros GPR, etiquetas, macros, etc. Los nombres se forman a criterio del usuario, usando los
caracteres alfanuméricos disponibles y los signos _ y ?, respetando las siguientes reglas:
A diferencia de los nemónicos, por defecto el ensamblador distingue entre caracteres mayúsculas y
minúsculas.
Hasta el momento hemos visto la operación de varias de las instrucciones del PIC. Como habrás notado, son
bastante fáciles de usar. Ahora, antes de continuar y para no tener que seguir explicándolas al vuelo,
conoceremos el resto de las 35 instrucciones de los PICs Mid-range.
Es un alivio saber que estos PICs tengan tan pocas instrucciones, haciendo todo el honor a su procesador de
arquitectura RISC (Reduced Instruction Set Computer).
3
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
Convención de términos
Expresiones adoptadas
Para fines de documentación vamos a emplear algunos signos o expresiones que resumen el significado de
alguna operación, como:
(W) → (PORTB) Significa “el contenido del registro W se pasa al registro PORTB”.
= A pesar de la sencillez de estos símbolos, yo prefiero emplear el operador =, propia de los lenguajes
de alto nivel. Solo debes acostumbrarte a que la transferencia del dato se dirige de derecha a
izquierda y entender que el signo = no implica una ecuación matemática (donde los dos miembros de
la expresión son iguales de antemano), solo significa que el valor del segundo miembro es asignado
al primero. Por ejemplo.
4
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
cnt = PORTB + 0x06; significa cnt será la suma de PORTB y la constante 0x06.
Se puede notar que se prescinde de la expresión “el contenido del registro...”, ya que se asume que de eso se
trata.
Aunque en la documentación de Microchip se adoptan los signos < > para indicar la posición de un
bit dentro de un registro, aquí también prefiero cambiar a otra notación, punto en este caso. Por
ejemplo
5
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
6
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
d Є [0,1]
Operación: (W) AND (f) → (W)
Status Afectado: Z
Descripción: AND entre el registro W y el registro ‘f’.
7
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
0≤b≤7
Operación: 0 → (f<b>)
Status Afectado: Ninguno
Descripción: Limpiar (poner a cero) el bit ‘b’ del registro ‘f’.
Ejemplo 1: BCF REG, 6 ; REG.6 = 0
Antes de instrucción Después de instrucción
REG = 01101001 REG = 00101001
0≤b≤7
Operación: 1 → (f<b>)
Status Afectado: Ninguno
Descripción: Setear (poner a uno) el bit ‘b’ del registro ‘f’.
Ejemplo 1: BSF PORTA, 5 ; PORTA.5 = 1
Antes de instrucción Después de instrucción
REG = 10000011 REG = 10100011
8
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
0≤b≤7
Operación: Saltear si (f<b>) = 0
Status Afectado: Ninguno
Descripción: Si el bit ‘b’ en el registro ‘f’ es ‘1’, entonces se ejecuta la siguiente instrucción.
0≤b≤7
Operación: Saltear si (f<b>) = 1
Status Afectado: Ninguno
Descripción: Si el bit ‘b’ en el registro ‘f’ es ‘0’, entonces se ejecuta la siguiente instrucción.
9
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
10
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
d Є [0,1]
Operación: (f) → (destino)
Status Afectado: Z
Descripción: El contenido del registro ‘f’ es complemetado a 1.
11
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
12
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
13
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
14
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
15
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
Si d = 0, el destino es el registro W.
Si d = 1, el destino es el mismo registro ‘f’. d = 1 se usa para testear un registro,
dado que afecta el bit de Status Z.
Ejemplo 1: MOVF INTCON, W ; W = INTCON
Antes de instrucción Después de instrucción
INTCON = 0x11 INTCON = 0x11
W = ? W = 0x11
Z = ? Z = 0 ; Resultado no es cero
16
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
17
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
Status Afectado: C
Descripción: El contenido del registro ’f’ se rota a la izquierda un bit mediante el flag de
Carry.
Status Afectado: C
Descripción: El contenido del registro ’f’ se rota un bit a la derecha mediante el flag de
Carry.
18
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
19
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
20
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
21
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
22
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
Las directivas no son instrucciones del microcontrolador, son indicaciones que se le dan al ensamblador para
controlar algunos aspectos del ensamblado del código. Todas las directivas se detallan en el manual
respectivo de los tantos que se instalan junto con el paquete MPLAB.
Como con los mnemónicos de instrucciones, al ensamblador le da igual si las directivas están en mayúsculas
o en minúsculas.
Aquí presentaremos las que suelen ser las más habituales. Ya vimos en acción a muchas de ellas y las
restantes las empezaremos a usar en adelante.
Directiva list
Directiva processor
Directiva include
Directivas __config y __fuses
Directiva equ
Directivas cblock y endc
Directiva org
Directiva end
Directiva banksel
Directiva #define
Directiva $
Directiva dt
Directiva errorlevel
Directiva messg
Directivas if, ifdef, ifndef, else y endif
La directiva list
Es una directiva para listar una serie de opciones de ensamblado de diversa índole. Los parámetros listados
se separan por comas. Por ejemplo, siguiente directiva
23
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
b: establece la cantidad de espacios en blanco que serán insertados en lugar de cada tabulación
del archivo *.lst. Éste es un archivo secundario de los tantos que genera el ensamblador. De
cualquier forma, más adelante veremos para que puede servir.
f: establece el Formato del archivo hexadecimal de salida. las opciones disponibles son INHX8M,
INHX8S e INHX32. La primera es el valor por defecto.
Además de los citados en este ejemplo hay muchos más parámetros que se pueden incluir con la directiva
list. Lo curioso es que ninguno puede ser necesario, es decir, todos se pueden indicar de otra forma, ya sea
desde el entorno del ensamblador MPASM, del mismo MPLAB o mediante otra directiva. Mas aun, ni siquiera
suele ser necesario mover las configuraciones por defecto.
Es una costumbre poner list con al menos el parámetro p = indicando el procesador. Para este propósito
sería más práctivo e intuitivo usar la directiva processor, descrita continuación, que tiene el mismo objetivo.
La directiva processor
Es una directiva para establecer el PICmicro para el que se ensamblará el código fuente. Es equivalente a
poner la directiva list con el parámetro p. Con esta directiva el ensamblador sabrá qué tipo de instrucciones
utilizar, aunque en ese sentido hay muy pocas variaciones entre uno y otro “procesador”.
No obstante, resalto que poner estas directivas solo suele ser necesario cuando se llame al ensamblador
desde una línea de comandos, por ejemplo, cuando se ensambla el programa desde Proteus VSM. No hacen
falta, por ejemplo, cuando se cuando se contruye el proyecto desde MPLAB IDE.
processor PIC16F84A
La directiva include
Es la directiva para incluir como parte del programa el archivo que se indica. La inclusión se realiza como si se
aplicara un “copiar - pegar” del contenido entero del archivo incluido en el lugar donde aparece la directiva.
Esta directiva debe aparecer en todos los programas de ensamblador al menos para incluir el archivo de
dispositivo del PIC usado, como muestra el siguiente ejemplo. Estos archivos se hallan en la carpeta de
instalación del ensamblador MPASM, que a su vez se instala con MPLAB IDE, norlmalmente
C:\Microchip\MPASM Suite. Solo ponemos la directiva y el ensamblador sabrá dónde buscarlo.
Include también se usa para incorporar archivos de otros tipos, como librerías de códigos. Es una convención
usar los signos < > para referirse a los archivos estándar y los signos “ ” para referirse a los archivos de
usuario. Incluso pueden ignorarse dichos signos asi como poner por delante el signo #. Queda claro que no se
imponen las restricciones que tiene esta directiva en el lenguaje C.
24
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
__config es más popular que __fuses a pesar de tener el mismo propósito (por lo menos en los PIC16) y de
que el nombre de la segunda parecería más ilustrativo.
Son directivas para establecer los Fuses de Configuración. Los fuses también se pueden establecer en el
entorno del programa grabador (WinPic800, por ejemplo), pero es recomedable hacerlo mediante esta
directiva para que formen parte del archivo *.hex resultante.
Recuerda que el PIC16F84A tiene 4 fuses y los PIC16F87xA tienen 9. Todos los hemos estudiado antes. Los
fuses se ponen con un número o a través de máscaras que las representan. Estas máscaras se encuentran en
el archivo de dipositivo del PICmicro.
Por ejemplo, en la gran mayoría de las prácticas con el PIC16F84A de este curso vamos a usar la siguiente
configuración:
que es equivalente a:
Los fuses no indicados, como la Protección de Código, quedarán con su valor por defecto. Para mayor
información puedes volver al capítulo 3.
La directiva equ
Cuando se quiere acceder a los registros (SFR o GPR) de la RAM se les debe referenciar por sus direcciones.
Como eso sería una labor muy tediosa, el ensamblador permite identificarlos con un alías o nombre escogido
por el usuario mediante la directiva equ.
Aunque equ permite igualar (equal = igual) un identificador con cualquier constante numérica, su principal
aplicación es “darles nombres” a los registros de la RAM. De hecho, todos los registros SFR del PIC ya están
identificados así en su correspondiente archivo de dispositivo (revísalos, si quieres). A nosotros equ nos
servirá para trabajar con los registros GPR.
Con el siguiente ejemplo se “bautizan” con cont1 y cont2 a los registros ubicados en las direcciones 0x0C y
0x0D, respectivamente.
25
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
Incluso si usamos la directiva equ para referirnos con más comodidad a los registros GPR, si nuestro
programa va a procesar varios datos y variables, seremos propensos a cometer errores con las designaciones.
Las directivas cblock y endc siempre deben ir juntas para formar un bloque de variables que ocupan
posiciones consecutivas en la RAM del PICmicro, siendo la dirección de la primera variable la indicada
después de cblock. Para tener un mejor contexto de su uso analicemos el siguiente boceto de código:
processor PIC16F84A
include <P16F84A.inc>
org 0x000
Start
; ...
call subroutine
; ...
goto Start
;************************************************************************
cblock ; Aquí no necesitas establecer una
bus ; dirección base
del0
endc
subroutine
; ...
; ...
return
end
En el boceto el primer bloque cblock - endc es equivalente a haber puesto las líneas de código:
cont equ 0x0C ; Ubicar count en dirección 0x0C
var equ 0x0D ; Ubicar var en dirección 0x0D
temp equ 0x0E ; Ubicar temp en dirección 0x0E
Más abajo aparece otro bloque cblock - endc con dos variables, bus y del0, que también se pudieron incluir
en el primer bloque, pero que se separan, como muchas veces se preferirá, por guardar alguna relación entre
ellas y para tratar de ordenar el código. No obstante, a diferencia de los lenguajes como el C, estos registros
serán accesibles desde cualquier parte del programa.
Ahora bien, si como dice el comentario, el segundo bloque no necesita una dirección base, ¿qué direcciones
les corresponden a esas variables? Como el ensamblador sabe dónde se quedó, a las variables del siguiente
bloque les asignará las locaciones subsiguientes. Es decir, el segundo cblock - endc sería equivalente a:
26
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
De hecho, en un programa puedes poner varios bloques más de este tipo, pero sin olvidar que, a menos que
sepas lo que haces, solamente el primero debe tener la dirección de la primera variable, inclusive si está
vacío.
La directiva org
Su nombre deriva de origen. Es para indicarle al ensamblador a partir de que dirección empezará a mapear el
subsiguiente código ejecutable. Como el CPU empieza a ejecutar el código desde la dirección 0x000, al
menos la primera instrucción de código debería estar allí.
Sin embargo, poner org 0x00 en programas con código continuo se ha convertido en un hábito a veces hasta
innecesario porque el ensamblador, que no es tan tonto, sabe que por defecto debe colocar el código a partir
de la dirección 0x000.
org 0x000
Usar org sí es útil cuando se quiere reubicar algunas rutinas de código en determinados segmentos de la
memoria de programa.
La directiva end
Es la directiva que pone fin a la lectura del código fuente por parte del ensamblador. Cualquier código
ubicado después de esta directiva ya no será tomado en cuenta, lo que implica que solo debería haber una
directiva end por programa, incluso si consta de varios archivos. Son sofisticados los programas donde se
puede usar varias veces.
La directiva banksel
El nombre de esta directiva es un acrónimo de BANK SELection y, como se prevé, sirve para cambiar de
bancos.
Como sabemos, la RAM de los PICmicros de familias Baseline y Midrange se divide en varios bancos por los
que tenemos que ir saltando para acceder a sus registros, “jugando” con los bits RP0 y RP1, del registro
STATUS, así:
27
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
En los PIC con dos bancos, como el PIC16F84A, solo se trabaja con el bit RP0.
Dado el tedio que puede acarrear este trabajo, sobre todo si no recordamos a qué banco pertenece un
registro, la directiva banksel puede ser de gran ayuda. Banksel se encargará de colocar las instrucciones
necesarias para acceder al registro que se le indica como parámetro.
La directiva #define
Es otra directiva que se utiliza muy a menudo. Los que programaron alguna vez en C/C++ saben cómo
funciona. Para los otros, deben saber que tiene tres partes: el mismo define, un identificador y toda la
cadena restante.
Lo que hará el ensamblador es sustituir el identificador por toda la cadena restante tal cual es en cada punto
del programa donde se encuentre identificador. Por eso se le conoce como directiva de sustitución de texto.
identificador es una palabra con las mismas reglas impuestas a otros identificadores, como las etiquetas o
nombres de registros GPR. En cambio, cadena puede estar formado por cualesquiera otros elementos de
código ensamblador.
Un típico ejemplo de define es para establecer los puertos de interface, más o menos así:
La directiva $
Recordemos que las etiquetas en el fondo representan las direcciones de las instrucciones a las que
preceden y sirven de referencia para las instrucciones de salto. Así mismo, la directiva $ marca la dirección de
la instrucción actual y, por ejemplo, $ - 2 será la dirección de la instrucción que está dos posiciones atrás.
Normalmente es preferible colocar etiquetas y dejar el uso de $ solo para los casos donde la propensión a
cometer errores sea mínima, por ejemplo, para las instrucciones de saltos cortos.
A continuación se muestran dos rutinas de delay de 50 ms aprox. Ambas son equivalentes, solo que la
segunda emplea la directiva $ en vez de las etiquetas. Se asume que la variable cont ha sido definida
previamente.
28
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
delay_50ms
movlw .33
movwf cont
laba addlw .1
btfss STATUS, Z
goto labb ; Saltar a labb
decfsz cont, F
labb goto laba ; Saltar a laba
return
delay_50ms
movlw .33
movwf cont
addlw .1
btfss STATUS, Z
goto $ + 2 ; Saltar 2 instrucciones adelante
decfsz cont, F
goto $ - 4 ; Saltar 4 instrucciones atrás
return
La directiva dt
Dt construye una tabla de datos a base de instrucciones retlw. Las tablas son matrices de constantes a cuyos
elementos se puede acceder secuencialmente mediante una variable índice.
Dt puede recibir uno o más parámetros separados por comas. Los parámetros de cadenas de texto serán
descompuestos en sus letras. Por ejemplo, la siguiente directiva
dt "test"
retlw 't'
retlw 'e'
retlw 's'
retlw 't'
La directiva errorlevel
Después de ensamblar o intentar ensamblar el código el ensamblador generará una serie de mensajes,
errores y advertencias. Con la directiva errorlevel podemos indicar cuáles de ellos pueden ser ignorados o
reportados. Los errores no se pueden inhibir.
29
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
Los valores de msgnum forman una lista casi interminable que la puedes encontrar en el manual del
ensamblador MPASM.
Por ejemplo, un clásico mensaje que aparece constantemente incluso cuando el código está escrito
correctamente es el 302, que dice “Register in operand not in bank 0. Ensure that bank bits are correct”. Allí
nos avisa que estamos accediendo a un registro que no es del banco 0 y que debemos asegurarnos de estar
haciendo lo correcto. Si nos cansamos de verlo, podemos escribir la siguiente directiva.
errorlevel -302
La directiva messg
Sirve para generar mensajes personalizados definidos por el usuario. El mensaje suele ser condicional, para lo
que se requiere de algunas otras directivas como if, ifdef, ifndef, else y endif.
Ejemplo, la siguiente directiva hará surgir el mensaje “Este código está realizado para el PIC16F876A”, si es
que se trata de ensamblar para otro PICmicro. (la constante __16F876A está definida en el archivo de
dispositivo P16F876A.inc.)
ifndef __16F876A
endif
Son directivas para ensamblado condicional. Mediante ellas indicaremos si una o algunas rutinas de código o
directivas inclusive serán tomadas en cuenta o no por el ensamblador.
30
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
A modo de ejemplo, supongamos que hacemos un programa para el PIC16F84A y que eventualmente
querremos cambiar el código para que se pueda ensamblar para el PIC16F877A. Sabemos que los principales
cambios a tener en cuenta son el archivo de dispositivo a incluir, la directiva de los fuses, el inicio de los
registros GPR y la configuración del registro ADCON1 de los PIC16F87xA para que el puerto A sea de E/S
digital.
El siguiente boceto de programa considera estos cuatro puntos y se puede ensamblar para uno u otro
microcontrolador tan solo cambiando la directiva processor, aunque tampoco eso sería necesario si el
programa se construye desde otro IDE como MPLAB, por ejemplo.
processor PIC16F84A ; Seleccionar PIC destino
ifdef __16F877A
include <P16F877A.inc>
__config _XT_OSC & _WDT_OFF & _PWRTE_ON & _LVP_OFF
cblock 0x20
endc
else ; Si no es PIC16F877A, asumir que es PIC16F84A
include <P16F84A.inc>
__config _XT_OSC & _WDT_OFF & _PWRTE_ON
cblock 0x0C
endc
endif
cblock
; Algunas variables del programa
endc
org 0x000
Start
ifdef __16F877A ; Si está definido __16F877A
banksel ADCON1
movlw 0x06 ; Hacer PORTA digital
movwf ADCON1 ;
endif
; Resto del cuerpo del programa
end
31
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
Por una razón que acabo de borrar (no era liviana), de los 8 ó 9 bits de dirección de cada registro (SFR o GPR)
de los PIC16F solamente los 7 primeros están presentes en el código de las instrucciones. Los 2 bits restantes
se extraerán de los bits RP0 y RP1, del registro STATUS y son la razón de la existencia de hasta cuatro bancos.
Así, se puede entender, por ejemplo, que cuando RP0 y RP1 valen 0, se accede a los registro del banco 0.
En los PICs con dos bancos, como el PIC16F84A, basta con modificar el bit RP0 para navegar entre ellos. El bit
RP1 debe dejarse en 0 por compatibilidad con otros dipositivos.
Una directiva que nos puede mitigar el fastidio de cambiar de bancos es banksel. Ya fue descrita
anteriormente.
Los delays
Un delay es una rutina de demora o retardo que sirve para poner una pausa entre dos puntos del programa.
Los Timers permiten realizar temporizaciones con gran presición pero para pausas ordinarias se prefiere
poner un delay a base de bucles de conteo anidados.
Los delays no son más que rutinas donde se cuenta con una variable. Por ejemplo, la siguiente subrutina
decrementa el registro cont desde 200 hasta 0, y genera un delay de 600 us aproximadamente.
cblock
cont
endc
delay_600us
movlw .200 ; 200 a W
movwf cont ; W a cont
bucle1
decfsz cont, F ; Decrementar cont, saltear si da 0
goto bucle1 ; Saltar a bucle
return
El tiempo del retardo se puede ajustar modificando el valor a cargar en el registro cont. Sin embargo, se
llegará a un límite que puede ser insuficiente. En esos casos se puede insertar algún código de relleno entre
la etiqueta bucle1 y la instrucción decfsz cont, F. Para hacer las cosas con más orden ese código de relleno
puede ser otro bucle de conteo (bucle anidado).
En la siguiente subrutina se muestra en otro color el bucle de conteo insertado, el cual cuenta desde 100
hasta 0. Esta subrutina toma en ejecutarse aproximadamente 20 ms. Para ajustar el tiempo del retardo ahora
se pueden modificar los conteos de las dos variables cont y cont2. Si el tiempo buscado es mayor que lo que
se obtiene así, se puede interpolar o extrapolar otro bucle de conteo hasta conseguir lo deseado.
32
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
cblock
cont, cont2
endc
delay_20ms
movlw .200 ; 200 a W
movwf cont ; W a cont
bucle1
movlw .100 ; 100 a W
movwf cont2 ; W a cont2
bucle2 decfsz cont2, F ; Decrementar cont2, saltear si da 0
goto bucle2 ; Saltar a bucle2
A quienes ya estamos acostumbrados a trabajar con estas rutinas los ajustes de los delays no son gran
molestia, sobre todo si nos apoyamos en herramientas como el simulador del MPLAB o Proteus VSM, que
estudiaremos luego. A los nuevos en el tema puede resultar de gran ayuda recurrir a herramientas libres que
se hallan en Internet. Te recomiendo practicar con el generador de delays de http://www.piclist.com/cgi-
bin/delay.exe. El algoritmo que emplean esos delays es una variante ingeniosa de los bucles de conteo
anidados. Tienen la siguiente forma:
cblock
cont, cont2
endc
delay_20ms
movlw .16 ; 16 a W
movwf cont ; W a cont (contador principal)
movlw .100 ; 100 a W
movwf cont2 ; W a cont2 (contador secundario)
bucles
decfsz cont2
goto $ + 2 ; Saltar 2 instrucciones adelante
decfsz cont
goto $ - 3 ; Saltar 3 instrucciones atrás
return
Aunque al principio te parezca algo enredado seguir el flujo del código para saber cuándo termina, con un
poco de observación lo lograrás. A mí me fascina la forma cómo están trenzados los dos bucles; por eso uso
este tipo de delays en casi todos mis programas. Otra ventaja que tienen es que es relativamente fácil
calcular el valor del delay. En el código de arriba depende sobre todo del contador principal. El contador
secundario se utiliza para afinar la precisión.
Comparaciones
La filosofía de los procesadores con diseño RISC es reducir en lo posible el juego de instrucciones; aunque en
mi opinión a la gente de Microchip se le paso un poquito la mano con estos PICs. Por desgracia solo
contamos con el repertorio de 35 instrucciones para construir los programas de todos los proyectos con PICs
33
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
¿ registro = 0 ?
¿ registro = registro/constante ?
¿ registro < registro/constante ?
¿ registro ≤ registro/constante ?
¿ registro > registro/constante ?
¿ registro = 0 ?
Para saber si un registro vale 0 hay que aplicarle cualquier instrucción que afecte el flag Z, como mover el
registro hacia sí mismo, sumarle 0, etc. Ejemplo:
movf REG, F ; REG = REG
btfss STATUS, Z ; ¿Z = 1?, ¿REG = 0 ?
goto Notzero ; no
goto Zero ; yes
¿ registro = registro/constante ?
El bit C indica si una operación de suma ha producido un resultado mayor que 255 (el máximo valor
representado por un número de 8 bits). O sea, C = 1 si el resultado fue mayor que 255 y C = 0 si no fue así.
Por otro lado, si después de una resta el bit C se ha seteado, significa que el resultado ha sido positivo o cero.
Si C vale 0, es que la resta ha dado un resultado negativo. Como vemos, el bit C funciona al revés con las
restas. Ésta es una peculiaridad exclusiva de los PICs.
Veamos como comparar un registro con una constante:
34
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
¿ registro ≤ registro/constante ?
El fundamento de lo que viene es: si un dato no es menor que otro, entonces es mayor o igual que él. Como
ya sabemos evaluar el primer caso, los siguientes serán fácilmente deducibles.
35
Profesor: Ing. Jorge Tobar Pinto
MICROCONTROLADORES: LENGUAJE ENSAMBLADOR 2013
36
Profesor: Ing. Jorge Tobar Pinto