Escolar Documentos
Profissional Documentos
Cultura Documentos
Por ello, obviaré muchas cosas que ya seguramente todos tenemos por sabidas y me
ahorraré prólogos e introducciones innecesarias.
Para programar en ensamblador para los PIC16F realmente necesitamos pocas cosas:
Proteus o MPLAB en cualquiera de sus versiones incluyen el compilador necesario. Yo
uso y aconsejo tener en vuestro ordenador abierto los siguientes elementos:
– El entorno con el que vayáis a programar(MPLAB,Proteus...)
– El archivo .pdf con el datasheet del PIC16F en cuestión (importante)
– El archivo .inc del mismo microcontrolador (si tenéis instalado Notepad++ mejor
abrirlo con el mismo) El archivo .inc lo encontraréis en la carpeta del MPASM.
– La calculadora ;-)
– El manual en pdf de MPASM también puede venir bien.
Aquí incluyo un trozo de programa en ensamblador con las partes que he comentado.
;Lista de opciones (tipo de procesador, base numérica y mostrar las advertencias y errores)
LIST p=16F1933,r=HEX,w=1
;Este include del microcontrolador es necesario en MPASM, además podemos incluir otros ficheros
#include p16f1933.inc ; Include register definition file
;Configuración del microcontrolador, como este PIC lleva dos registros se especifican por separado
__config _CONFIG1,_FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_ON & _CPD_ON & _BOREN_ON
& _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
__config _CONFIG2,_WRT_OFF & _VCAPEN_OFF & _PLLEN_OFF & _STVREN_ON & _BORV_HI & _LVP_OFF
;Constantes
#define ZERO STATUS,Z
#define CARRY STATUS,C
;Macros
MOVLWF macro literal,file
MOVLW literal
MOVWF file
endm
;Variables (en este caso le indicamos que las variables empiezan el la dirección 32 del banco 0)
cblock 0x20
LINE
endc
banksel PIE3
CLRF PIE1
CLRF PIE2
MOVLWF 1<<TMR4IE,PIE3
banksel PORTA
CLRF PIR1
CLRF PIR2
CLRF PIR3
MOVLWF (1<<GIE|1<<PEIE),INTCON
banksel T4CON
MOVLWF b'00100110',T4CON
banksel PORTA
MOVLWF .1,LINE
…
…
end
La directiva LIST
Como comentamos antes, las diferentes opciones del compilador se ajustan mediante las
llamadas directivas. Existen 6 tipos de directivas, aunque muchas raramente se usan. Una
de ellas, y que se suele usar en la primera línea de nuestro archivo .asm es LIST, que nos
permite resumir en un sólo renglón una serie de opciones, sobre todo relacionadas en
cómo se listará nuestro archivo compilado.
Vamos a describir las opciones de esta directiva con un ejemplo:
LIST p=16F1933,r=HEX,w=1,f=INHX8,x=ON
Como se puede ver, delante de LIST no se pone almohadilla o guión bajo, las opciones se
separan con coma y entre el nombre de la opción y su valor se escribe un signo igual.
La siguiente opción (r) indica la base numérica que vamos a usar de modo
predeterminado (decimal, hexadecimal u octal), es decir, la base en que el compilador
entenderá los números si no le añadimos ningún prefijo. Esta opción NO nos obliga a
introducir los número en ninguna base en concreto, sólo nos facilita introducir los números
de manera más cómoda en la base que queramos. Si usamos la directiva propia radix
podemos ir cambiando a lo largo del archivo de base numérica predeterminada (ej: radix
DEC)
Más adelante veremos los distintos prefijos para las diferentes bases numéricas.
Con w modificamos los mensajes que veremos durante la compilación, de modo que
podemos indicar si queremos que nos muestre todos los mensajes (w=0), sólo los errores
y advertencias (w=1) o sólo los errores (w=2) . Tiene su directiva propia errorlevel que se
puede ir añadiendo en el código, de manera que podemos seleccionar porciones de
código donde queramos ver todos los mensajes, sólo los errores,etc
La opción f hay que usarla con cuidado, o mejor dejarla por defecto. Con ella elegimos el
formato de salida del archivo .hex generado. Lo normal es dejar que el IDE o entorno de
programación escoja el más adecuado para el grabador o simulador que estemos usando.
Por último veremos la opción x que se usa para activar (ON) o desactivar (OFF) la
expansión de macros en el listado. Suena raro, pero es sencillo: durante la compilación se
genera un archivo .lst donde ya se han sustituido las constantes y asignado las posiciones
de memoria de programa. Este archivo es muy útil en la depuración, pero puede llegar a
ser bastante largo, por lo que a veces se desactiva la expansión de macros para hacerlo
más legible. Recordemos que las macros en assembler se usan para sustituir una serie
de instrucciones por una sola línea. Esta opción también tiene directivas propias expand y
noexpand de modo que podamos indicar qué macros se expanden y cuáles no, a lo largo
del código.
Hay algunas opciones más en la directiva LIST, que son principalmente para dar formato
al archivo .lst, pero como vimos en el apartado anterior, generalmente todas estas
opciones vienen por defecto o las podemos modificar de manera gráfica en el IDE, por lo
que no le dedicaremos más tiempo.
#include
Al igual que en lenguajes de alto nivel, es importante indicar los archivos adicionales que
vamos a usar, y, sobre todo, el .inc del microcontrolador en cuestión para el que compilar
nuestro proyecto.
Hay que tener en cuenta que es como si pegásemos todo el archivo de texto que
incluimos en el mismo punto del #include, por lo que hay que tener cuidado con los
nombres repetidos de constantes o subrutinas, o con posiciones absolutas de memoria,
ya que nos puede generar errores.
#include p16f1933.inc
Como vemos en el ejemplo, no es necesario incluir el nombre del archivo entre comillas,
pero SÍ es obligatorio si dicho nombre contiene espacios. Si el archivo que vamos a usar
no se encuentra en la ruta del MPASM o en el directorio de trabajo de nuestro proyecto,
deberemos especificar la ruta completa.
Por ejemplo, podemos tener un archivo que se llame Segmentos.inc donde hemos
especificado cómo se dibujarán los números y letras del alfabeto en un display de 7
segmentos, e incluirlo con la directiva #include para nuestro proyecto actual.
Puede usarse include sin almohadilla delante, pero no se aconseja, ya que en próximas
versiones del MPASM puede dejar de estar soportado.
__config
Aquí vemos lo especial que es MPASM con los prefijos en las directivas: __config lleva un
doble guión bajo delante, aunque para los PIC18 es aconsejable usar config sin guiones,
que es una directiva diferente.
Los bits de configuración son muy diferentes de un PIC a otro, es por ello que aconsejo
tener abierto el .pdf del datasheet y el .inc de nuestro microcontrolador, mientras
programamos. Veamos el ejemplo en un PIC16F:
__config _CONFIG2,_WRT_OFF & _VCAPEN_OFF & _PLLEN_OFF & _STVREN_ON & _BORV_HI & _LVP_OFF
Aquí la directiva es __config (con 2 guiones), el resto de componentes (con un sólo guión)
son constantes definidas en el .inc: _config2 indica que los bits siguientes se almacenan
el registro 2.
Los bits de configuración funcionan como “fusibles” que el grabador apaga durante la
programación del dispositivo, por ello usamos todas las opciones “unidas” por el operador
& (and), de manera que esta operación genera una palabra del tamaño correcto que se
graba en el registro de configuración, en este caso _CONFIG2.
Como podemos ver, entre la directiva y el registro de configuración sólo se pone un
espacio, y entre este registro y los fusibles se pone una coma.
Si nuestro PIC sólo tiene un registro de configuración, no es necesario especificarlo, el
resultado sería entonces así:
__config _WRT_OFF & _VCAPEN_OFF & _PLLEN_OFF & _STVREN_ON & _BORV_HI & _LVP_OFF
Otra manera, si no nos gustan las líneas tan largas, es realizar la operación AND de todos
los valores y poner directamente el resultado del registro:
__config _CONFIG1,3FC0
Para los PIC18 se puede usar la manera anterior, pero NO se aconseja, vamos a ver la
manera correcta de establecer los bits de configuración en esta gama de micros.
CONFIG CP0=OFF, WDT=ON
Aquí apreciamos que se usa config sin guiones y que además se emplea la dupla
ajuste=valor, bien separadas por comas o en líneas diferentes.
Todos los bits de configuración se explican en el datasheet del PIC en cuestión, además
al final del archivo .inc están también todos los valores de los fusibles y las direcciones de
los registros, por lo que no hay que preocuparse de recordar esto de cabeza.
También podemos usar MPLAB para generar estas directivas de manera gráfica y
sencilla, dentro del apartado Production>Set Configuration bits. Es importante pegarlas en
nuestro código una vez generadas por el asistente, sobre todo si queremos simular en
Proteus o compilar con otra herramienta.
Es importante tener bien ajustados los bits de configuración, esto no es sólo de ASM, sino
de cualquier lenguaje que usemos para programar los PIC. Así, por ejemplo, evitaremos
que el watchdog timer nos reinicie nuestro PIC “inexplicablemente”, o que por una patilla
que pensamos que es una entrada nos salga la frecuencia del reloj ;-)
Las Constantes
Aparte de a los valores numéricos o de cadena que no varían, en assembler también se
denominan constantes al símbolo o nombre que le damos para referirnos a esos valores.
Esto también se usa en lenguajes de alto nivel, así que lo explicaremos brevemente con
un ejemplo: si durante nuestro programa escribimos repetidas veces PORTB,1, que es el
pin donde queremos encender un led, y luego queremos modificar nuestro programa para
usar otro pin en lugar de ese, tendremos que buscarlo por todo nuestro archivo y
sustituirlo. Lo mejor es declarar una constante a la que le damos como nombre, por
ejemplo, PIN_LED y asignarle el valor PORTB,1, de este modo si queremos modificar el
pin al que conectamos el led, sólo debemos cambiar la asignación de la constante.
BSF PORTB,1 #define PIN_LED PORTB,1
… …
BCF PORTB,1 BSF PIN_LED
… …
BTFSS PORTB,1 BCF PIN_LED
…
BTFSS PIN_LED
Esto, además, nos produce un código más inteligible y fácil de corregir, ya que usando un
nombre adecuado es más sencillo que andar recordando los pines donde conectamos
cada cosa. El nombre de la constante y la cadena que sustituye sólo se separan con un
espacio.
Debemos tener en cuenta que usando #define, lo que hacemos es una sustitución de
cadena por otra, por lo tanto hay que tener cuidado con que esta sustitución no nos
genere errores de sintaxis.
Junto a la directiva #define existe también #undefine que suprime esa asignación o
sustitución de una cadena por otra, por lo que, a partir de #undefine PIN_LED, ya no
podremos usar PIN_LED, a menos que volvamos a definirla, dándole incluso otro valor si
queremos, con un nuevo #define.
Es curioso que he visto códigos donde se usa #define para “definir” variables en
assembler, pero esta no es la manera correcta, ya que las sustituciones que hagamos con
esta directiva no aparecerán en la tabla de variables de MPLAB o de PROTEUS.
Las constantes declaradas con #define se usan sobre todo en compilado condicional, que
veremos en artículos más avanzados.
Por último, en relación a las constantes, se puede incluir una constante dentro de la
declaración de otra constante, por lo que el siguiente código, es perfectamente válido.
#define ESTADO STATUS
#define ZERO ESTADO,Z
#define CARRY ESTADO,C
En próximos artículos seguiremos viendo en detalle el resto de las partes, así como las
instrucciones de máquina, las diferentes directivas, ejemplos...