Está en la página 1de 29

Programación del microcontrolador en

lenguaje ensamblador.

2.1. Programación en lenguaje ensamblador.

2.1.1. Modos de direccionamiento.


MODOS DE DIRECCIONAMIENTO:

El modo de direccionamiento es la forma en la que se obtienen el o los datos que van a ser
utilizados en la instrucción. Existen 4 modos de direccionamiento:
Inherente, literal, directo e indirecto.
Modo de direccionamiento inherente: en este modo o bien la instrucción no tiene
operando o bien el operando viene especificado en el propio código de operación de la instrucción.

RESET ; Realiza un reset por software (los operandos son todos los registros afectados
por el reset)
DAW ; Ajuste decimal del acumulador (el operando es el acumulador). Formato BCD
NOP ; No realiza ninguna operación (no hay operando)

Modo de direccionamiento literal: en este modo el valor del operando viene indicado de
forma explícita en la instrucción.

GOTO 0x100 ; Salto incondicional a la dirección 100H (el operando es 0x100)


MOVLW .23 ; Cargar en el acumulador el valor 23 (el operando es el .23)

MODOS DE DIRECCIONAMIENTO A LA MEMORIA RAM DE DATOS:

Modo de direccionamiento directo: en este modo la dirección en la que se encuentra el


valor del operando viene indicada de forma explícita en la instrucción.
El operando puede ser un byte o un bit:

- Operando de tipo byte:


 Mediante la instrucción MOVFF org,dest:

MOVFF 0x011,0x120 ;
 Mediante la combinación del BSR y el valor de 8 bits indicado en la instrucción

MOVLW 0xB4
MOVLB .1
MOVWF 0x21,1

 Mediante el banco de acceso rápido

MOVLW 0x74
MOVWF 0x06,0 ; También es válido MOVWF 0x60,A

- Operando de tipo bit: en este caso en la instrucción se especifica el registro en


el que se encuentra el bit y luego la posición del bit dentro del registro.

MOVLB .2
BSF 0x31,6

Para facilitar las tareas de programación, en el lenguaje ensamblador los valores


numéricos que corresponden a datos literales o a direcciones de memoria se
representan mediante etiquetas.

VAR1 EQU 0x010


CTE1 EQU .24
...
MOVLW CTE1
MOVWF VAR1,0

Modo de direccionamiento indirecto: en este modo la dirección de memoria en


la que se encuentra el dato viene especificado en uno de los registros FSR0,
FSR1 y FSR2. Para acceder al valor se debe escribir la dirección del dato (12 bits)
en el registro FSRx (FSRxH[3..0] y FSRxL[8..0]) y se lee/escribe el dato en el
registro INDFx.

Los registros INDFx son registros virtuales, aunque tienen una dirección asignada
en la zona de SFR’s, físicamente se corresponden con la dirección de memoria
apuntada por el correspondiente FSRx.
Además de los INDFx existen otros registros virtuales que permiten acceder el
dato apuntado por los FSRx, permitiendo operaciones adicionales:

– POSTDEC0, POSTDEC1, POSTDEC2: al acceder a un registro POSTDECx se


accede a la posición de memoria apuntada por el FSRx correspondiente y a
continuación se decrementa el valor de dicho FSRx.
– POSTINC0, POSTINC1, POSTINC2: al acceder a un registro POSTINCx se
accede a la posición de memoria apuntada por el FSRx correspondiente y a
continuación se incrementa el valor de dicho FSRx.
– PREINC0, PREINC1, PREINC2: al acceder a un registro PREINCx se
incrementa el valor del FSRx correspondiente y, a continuación, se accede a la
posición de memoria apuntada por el nuevo valor del FSRx.
– PLUSW0, PLUSW1, PLUSW2: al acceder a un registro PLUSWx se accede a la
dirección de memoria RAM formada por la suma del valor del FSRx y del
acumulador WREG (se considera en valor de WREG con signo [-127;128]). En
este caso el valor del FSRx no se modifica.

La lectura de los registros virtuales (INDFx, POSTDECx, POSTINCx, PREINCx)


mediante direccionamiento indirecto da por resultado 0x00. La escritura de los
registros virtuales mediante direccionamiento indirecto da por resultado un NOP.
No se deben modificar los valores de los FSRx’s mediante direccionamiento
indirecto; se debe acceder a estos registros siempre mediante direccionamiento
directo.
Instrucciones Ensamblador más usuales:

MOVLW .25 ; 25 → W

MOVWF 0x50, A ; W → pos mem RAM [0x50]

MOVF 0x50,W, A ; pos mem RAM [0x50] → W

MOVFF 0x70, 0x60 ; [0x70] → [0x60]


LFSR FSR0, 0x100
; Cargar valor 0x100 → FSR0

ADDWF 0x50,W, A ; ([0x50] + W) → W

ADDLW 5 ; incrementa W en 5, (W+5) → W

ADDWFC sum, F,A ; sumar: ( sum + W + Carry) → sum

MOVLW 0x30 ; 0x30 → W

SUBWF 0x50, F, A ; Restar: ([0x50] - 0x30) → [0x50]

MOVLW n ; n→W

CPFSGT cnt, A ;compara “cnt” con “n” y salta si: cnt > n
; Si se cumple la condición NO ejecuta sig. Instrucción

Goto menor ; Si cnt ≤ n salta a la etiqueta menor

Goto mayor ; Si cnt > n salta a la etiqueta mayor

2.3. Programación del microcontrolador en lenguaje ensamblador.


2.3.1. Programación básica.
LO BÁSICO EN ENSAMBLADOR
Comencemos la programación en ensamblador definiendo algunos términos
Las direcciones de inicio del
PIC son:

0x0000 MCLR (Master Clear Reset)

0x0008 High Vector Sector

0x0018 Low Vector Sector

La numeración en ensamblador puede ser hexadecimal colocando 0xNN


y el número, colocando H'NN' y el número o colocando NLh (0Ah), para este tipo
de numeración, se debe de comenzar por un número, en caso de ser de dos
letras, se utiliza cero (0FFh). La numeración decimal se realiza colocando un
punto y el número en decimal. Para la numeración binaria se procede a colocar
B'XXXXXXX' y el número en binario.

La configuración inicial (La plantilla)

Para iniciar con la plantilla necesitamos incluir el archivo P18F4550.INC


que es un archivo que contiene definiciones de registros y sus direcciones de
memoria.
#include <P18F4550.INC> esta parte del código es para que
ensamblador reconozca los registros del pic y las direcciones de memoria.
LIST P=18F4550 es para que reconozca el tipo de microcontrolador a
programar el ensamblador.

Bits de configuración

Son los que controlan el comportamiento del microcontrolador. Los tres básicos
son:

CONFIG FOSC = HS ;Configura el oscilador a usar, los posibles


osciladores son RC (oscilador RC), XT (cristal de baja frecuencia), HS (cristal de
alta frecuencia). Hay más, para mayores referencias consultar el manual.
CONFIG WDT = OFF ;configura el perro guardián (este es un timer que
resetea al pic en caso de que tenga un ciclo infinito) el valor que nosotros
manejamos es OFF (apagado).
CONFIG LVP = OFF ;configura el bajo voltaje de programación, nosotros
lo apaga- mos para que programe en alto voltaje.
Sectores de código
Los sectores de código son aquellos que le dicen al programador
(PICKIT2, PICKIT3, etc) en que parte de la memoria de programa va a programar
el código. Hay dos formas de hacerlo: ORG $dirección o CODE $dirección
Ejemplo 1: Colocar el vector de reset en la localidad cero de la memoria.

ORG
0x0000 ;localidad
cero goto main

RESET_VECTOR_SECTOR CODE 0x0000 ;localidad cero (notar que


podemos nombrar dicho sector con CODE)
goto main

La palabra reservada END termina con todos los CODE. Se utiliza para
finalizar el código. Solo se pone una vez y hasta el final del programa.

Sectores de memoria

Los sectores de memoria especifican la memoria que va a ser reservada


para los registros del microcontrolador o un espacio de memoria que se necesite
para guardar algún dato o información.
El sector de memoria se ubica debajo de la palabra UDATA, para
reservar memoria para registros del microcontrolador, básicamente para usar
información que restaure el algunos registros del microcontrolador en la
interrupción del baja prioridad.
Para reservar memoria de datos, vamos a hacerlo debajo de la palabra
UDATA_ACS y se reserva memoria colocando un nombre al registro de
memoria, posteriormente se coloca la palabra RES y finalizar con el número de
bytes que se desean reservar.
Ejemplo: Reservar memoria para un dato, donde el registro de memoria
tendrá el nombre de DATO1.
UDATA_ACS ;UDATA y UDATA_ACS llevan
sangría DATO1 RES 1 ;la reserva de memoria
no lleva sangría.

En el ejemplo anterior reservamos un byte de memoria para un registro


llamado DATO1. Podemos hacer la reserva de memoria mientras no terminemos
la memoria RAM del microcontrolador.

UD
ATA_AC
S DATO1
RES 1
DATO2 RES 1
DATO3 RES 1

Constantes

Para que el lenguaje ensamblador reconozca una constante, es


necesario darle un nombre y un número al cual será igualada; para ello se utiliza
la palabra reservada EQU.

UNO EQU 1
DOS EQU 2
TRES EQU 3

Y con esto tenemos a UNO con un valor de 1, DOS con un valor de 2 y a


TRES con un valor de 3.
Nuestra plantilla quedará de la siguiente forma:

;****************************************************************
********
; Autor: Francisco Javier García Olmos *
; Fecha: 2 de Enero de 2012 *
; Plantilla para trabajar con BOOTLOADER en Ensamblador *
;****************************************************************
********
LIST P=18F4550, F=INHX32

#include <P18F4550.INC>

;****************************************************************
***********
;Bits de configuración

CONFI PLLDIV = 5
G
CONFI CPUDIV = OSC1_PLL
CONFI USBDIV = 2
CONFI FOSC = HSPLL_HS
CONFI FCMEN = OFF
CONFI IESO = OFF
CONFI PWRT = OFF
CONFI BOR = ON
CONFI BORV = 3
CONFI VREGEN = ON
config WDT = OFF
config WDTPS = 32768
config MCLRE = ON
config LPT1OS = OFF
config PBADEN = OFF
config CCP2MX = ON
config STVREN = ON
config LVP = OFF
config ICPRT = OFF
config XINST = OFF
config CP0 = OFF
config CP1 = OFF
config CP2 = OFF
config CP3 = OFF
config CPB = OFF
config CPD = OFF
config WRT0 = OFF
config WRT1 = OFF
config WRT2 = OFF
config WRT3 = OFF
config WRTB = OFF
config WRTC = OFF
config WRTD = OFF
config EBTR0 = OFF
config EBTR1 = OFF
config EBTR2 = OFF
config EBTR3 = OFF config EBTRB
= OFF

;**********************************************************************
*****
;**********************************************************************
*****

; Definición de
variables

; Variables definidas si se utiliza la interrupción de baja

prioridad UDATA

WREG_TEMP RES 1 ;variable en RA para guardar contexto


STATUS_TEMP RES 1 M
;variable en RA para guardar contexto
BSR_TEMP RES 1 ;variable en RA para guardar contexto
M

RESET_VECTOR CODE
0x0000

goto main

HIGH_VECTOR CODE 0x0008

bra ISRH

LOW_VECTOR CODE 0x0018


bra

ISRL

CODE

0x102

ISRH:

; *** Interrupción de alta


prioridad retfie FAST

ISRL:

movff STATUS,STATUS_TEMP ;guarda el registro de


estado movff WREG,WREG_TEMP ;guarda el registro de
trabajo movff BSR,BSR_TEMP ;guarda el registro BSR

; *** Interrupción de baja prioridad ***

movff BSR_TEMP,BSR ;restaura el registro BSR


movff WREG_TEMP,WREG ;restaura el registro de
trabajo movff STATUS_TEMP,STATUS ;restaura el registro
de estado retfie

main:
clrf WREG
; *** La función principal va
aquí *** ciclo

goto

cicl

END

Instrucciones básicas del lenguaje ensamblador

Antes de ver las instrucciones veremos cuáles son los comentarios en el


lenguaje ensamblador. El lenguaje ensamblador toma como comentario
cualquier texto que esté después de punto y coma.
; esto es un comentario

Instrucción NOP
Esta instrucción se utiliza para que el microcontrolador no realice
operación alguna.
Se utiliza para hacer retardos de tiempo equivalentes a cuatro ciclos del
oscilador principal.
Su sintaxis es:
NOP
No realiza operación alguna.

Instrucción MOV Mover


Mueve datos de un registro a otro. Hay que tomar en cuenta que los
microcontroladores de Microchip usan el registro de trabajo para realizar este
proceso. Este registro es llamado WREG o solamente W.
La instrucción MOVLW 0x01 mueve el número 0x01 al registro de
trabajo.

La instrucción MOVWF REGISTRO mueve el contenido guardado en el


registro de trabajo a cualquier otro registro.
Ejemplo: Configurar el registro ADCON1 con 0x0F

MOVLW 0x0F
MOVWF ADCON1

Ejemplo mover e número 0xF0 a la variable DATO1

MOVLW 0xF0
MOVWF DATO1

La instrucción MOVF se usa para mover contenidos de registros al


mismo registro o al registro W. Su sintaxis es:
MOVF REGISTRO, DESTINO

Donde DESTINO puede ser 0 o 1. Si es cero, se guarda en el registro


W, si es uno se guarda en el mismo registro.

Ejemplo: mover el contenido de la dirección de INTCON al registro de

trabajo:

MOVF INTCON, W

Si colocamos MOVF INTCON, 1 movemos el contenido de ese registro al


mismo registro. No es muy útil hacer esto a menos que sea necesario refrescar la
memoria RAM.

La instrucción MOVFF se usa para mover el contenido de un registro a


otro registro.

DATO1.
Ejemplo: mover el contenido del registro PORTB a un registro de memoria
llamado

MOVFF PORTB, DATO1


Instrucción CLRF
Coloca a cero un registro.

Ejemplo: Limpiar el registro de trabajo.

CLRF WREG

Instrucción SET
La instrucción SET se utiliza para colocar todo el registro con uno, como
si colocáramos 0xFF al registro.

Ejemplo: Colocar en uno todo el registro de


trabajo. SET WREG

Es idéntico que hacer:

MOVLW 0xFF

GOTO y Etiquetas
Para usar una etiqueta y GOTO necesitamos colocar sangrías (tecla
tabulador) y dejar las etiquetas sin sangría y las instrucciones con sangría. Las
etiquetas se colocan con nombre y puede o no llevar dos puntos al final, pero
los dos puntos se recomiendan para funciones o subrutinas. Las etiquetas no
se pueden repetir dentro de un programa, hay que cambiar el nombre en caso
de que tengamos dos con el mismo, si no, provocará un error en el
compilador.
El GOTO se usa para dirigirse a una etiqueta colocando enfrente el nombre.

Ejemplo:

main: ;rutina principal main lleva dos puntos y no lleva sangría.


CLRF WREG ;código con
sangría infinito ;etiqueta sin sangría
GOTO infinito ;ir a la etiqueta infinito (se hace un bucle infinito)

Instrucción BCF
La instrucción BCF coloca un bit en cero de un registro específico. El
conteo de bits es desde del cero hasta el siete. Su sintaxis es la que a
continuación se muestra:

BCF REGISTRO, BIT

Ejemplo: Colocar el BIT 0 del registro


PORTC en cero.
BCF PORTC, 0

También podemos usar el nombre del bit, para eso, consultar el manual
del microcontrolador y algunos de ellos serán explicados en este documento.

Ejemplo: Colocar el BIT RC0 del registro PORTC en cero.

BCF PORTC, RC0


o
BCF PORTC, 0

Comparando ambos códigos, es exactamente lo mismo.

Instrucción BSF
Es exactamente igual que BCF solo que este coloca en uno el bit
indicado del registro deseado.

Ejemplo: Colocar en uno el bit RA4 del registro


PORTA.
BSF PORTA, RA4
Instrucción RLCF
Esta instrucción realiza un giro a la izquierda de bits del contenido un
registro cualquiera pasando por la bandera Carry del registro STATUS. La
instrucción que realiza la misma operación sin que pase por la bandera Carry
del registro STATUS es RLNCF. Con esta instrucción el contenido será el mismo
pero desplazado un bit a la izquierda. Su sintaxis es:
RLCF
REGISTRO,DESTIN
O

RLNCF REGISTRO,
DESTINO
Donde DESTINO puede ser 0 o 1. Si es cero, se guarda en el registro
W, si es uno, se guarda en el mismo registro (REGISTRO).

Instrucción RRCF
Esta instrucción realiza un giro a la derecha de bits del contenido de
cualquier registro pasando por la bandera Carry del registro STATUS. La
instrucción que realiza la misma operación sin que pase por la bandera Carry
del registro STATUS es RRNCF. Con esta instrucción el contenido será el
mismo, pero desplazado a la derecha. Su sintaxis es:
RRCF REGISTRO, DESTINO

RRNCF REGISTRO, DESTINO


Donde DESTINO puede ser 0 o 1. Si es cero, se guarda en el registro
W, si es uno, se guarda en el mismo registro (REGISTRO).

Instrucción COMF
Realiza el complemento de un registro y lo puede guardar en el mismo
registro o en el registro W. Su sintaxis es:

COMF REGISTRO, DESTINO

Donde DESTINO puede ser 0 o 1. Si DESTINO es 0, el resultado se


guarda en el registro W, si es 1, se guarda en el mismo registro (REGISTRO).
Instrucción SWAPF
Cambia el nibble alto por el nibble bajo y viceversa. Su sintaxis
es: SWAPF REGISTRO, DESTINO
Donde DESTINO puede ser 0 o 1. Si es 0, se guarda en el registro W, si
es 1, se guarda en el mismo registro.
Ejemplo:
Si registro contiene
35h.

SWAPF REGISTRO, 1
Ahora registro contendrá 53h.

Instrucción CALL
Esta instrucción manda a llamar a una subrutina. Las subrutinas son
aquellas etiquetas especiales y terminan en la palabra reservada RETURN.

Ejemplo: Llamar a la subrutina OPERACION desde la rutina main.

OPERACION:
RETURN ;regresa al main

main:
CALL OPERACION ;llama a la subrutina OPERACION
;sigue el programa

Instrucción RETURN
Esta instrucción se utiliza para regresar de una subrutina a la instrucción
siguiente de la rutina principal. Solo se coloca RETURN al final de la subrutina.
Véase el ejemplo anterior.
Si queremos devolver algún valor en el registro de trabajo podemos
finalizar la subrutina con la palabra reservada RETLW. Su sintaxis es:
RETLW LITERAL
Donde LITERAL puede ser cualquier valor dentro del rango 0 a 255.
Este valor será guardado en el registro W.
Instrucción RETFIE
Esta instrucción se utiliza para finalizar una subrutina de interrupción. Si
se finaliza la subrutina de interrupción de alta prioridad, se coloca FAST frente a
la palabra reservada RETFIE.

Instrucción RESET
Realiza un RESET desde el software. Se realiza exactamente lo mismo
que si se presionara el botón MCLR en la tarjeta de pruebas del PIC.

Comparadores

Estas instrucciones sirven para comparar resultados o bits de estados


de distintos registros. Sirven para tomar decisiones acerca del comportamiento
del programa y cambiar su flujo.

Instrucción TSTFSZ
Esta instrucción comprueba que un registro sea cero; si es verdadero,
salta una instrucción. Su sintaxis es:
TSTFSZ REGISTRO

Ejemplo: Comparar si el registro PORTB es


cero.
TSTFSZ PORTB
;no es cero
;es cero

Instrucción CPFSEQ
Esta instrucción compara el registro W con cualquier otro registro. Salta
si el contenido de los registros es idéntico. Su sintaxis es:
CPFSEQ REGITRO
Ejemplo: Comparar PORTA con W.

CPFSEQ PORTA
;no son identicos
;son idénticos
Instrucción CPFSGT
Compara si un registro con el registro W. Salta si el contenido del registro
es más grande que el contenido de W. Su sintaxis es:
CPFSGT REGISTRO

Ejemplo: Comparar si el contenido de un registro es mayor al contenido de


W. CPFSGT REGISTRO
;no es mayor
;es mayor

Instrucción CPFSLT
Compara un registro con el registro W. Salta si el contenido del registro
es más pequeño que el contenido de W. Su sintaxis es:
CPFSLT REGISTRO

Ejemplo: Comparar si el contenido de un registro es menor al contenido de


W.
CPFSLT REGISTRO
;no es menor
;es menor

Instrucción BTFSC
Verifica si un bit específico de un registro es cero, en caso de que sea
verdadero, salta una instrucción.
Ejemplo: Verificar que el bit RB4 del registro PORTB sea cero.

BTFSC PORTB, RB4


GOTO falso
GOTO
verdadero

En el ejemplo anterior, si la comparación es falsa, lee la instrucción


siguiente la cual es GOTO falso, donde falso es una etiqueta. Si es verdadero,
salta la instrucción y lee la instrucción GOTO verdadero, donde verdadero es
una etiqueta.
Esta instrucción se utiliza para realizar comparaciones y tomar
decisiones acerca de un bit específico de un registro.

Instrucción BTFSS
Es idéntico que la instrucción anterior. Verifica que un bit específico de
un registro sea uno, en caso de que sea verdadero, salta una instrucción.

Ejemplo: Verificar que el bit RB5 del registro PORTB sea uno.

BTFSS PORTB, RB5


GOTO falso

GOTO
verdadero

En el ejemplo anterior, si la comparación es falsa, lee la instrucción


siguiente la cual es GOTO falso, donde falso es una etiqueta. Si es verdadero,
salta la instrucción y lee la instrucción GOTO verdadero, donde verdadero es
una etiqueta.
Al igual que la instrucción anterior, también esta se utiliza para realizar
comparaciones y tomar decisiones en cuanto un bit específico de un registro.

Operadores Lógicos

Los operadores lógicos realizan las operaciones del álgebra booleana.


Estas operaciones en ensamblador son AND, OR, XOR, que corresponden
respectivamente a una operación AND (Y), operación INCLUSIVE OR (O
inclusiva) y EXCLUSIVE OR (O exclusiva).

Operación AND
Se puede realizar de dos maneras: ANDWF y ANDLW. La primera
realiza la operación AND entre un registro y el registro W; la segunda, realiza la
operación AND entre el registro W y una literal (un número). Sus sintaxis
respectivas son:
ANDWF REGISTRO, DESTINO
Donde DESTINO puede ser 0 o 1. Si es cero, se guarda en W, si es
uno, se guarda en el mismo registro.
ANDLW LITERAL
Donde LITERAL es un número del 0 al 255.

Operación OR
Igual que la instrucción anterior, se puede realizar de dos maneas:
IORWF o con la instrucción IORLW. La primera realiza al operación OR entre un
registro y el registro W, la segunda realiza la operación OR entre el registro W y
una literal. Sus sintaxis respectivas son:
IORWF REGISTRO, DESTINO

Donde DESTINO puede ser 0 o 1. Si es cero, se guarda en W, si es


uno, se guarda en el mismo registro.

IORLW LITERAL
Donde LITERAL puede ser cualquier número del 0 al 255.

Operación XOR
La operación XOR al igual que las anteriores tiene dos formas de
hacerse entre registros y una a bit. Primero veamos la operación XOR a
registros.
Se puede realizar de dos maneras: XORWF o XORLW. La primera
realiza la operación XOR entre el registro W y cualquier otro registro, la segunda
realiza la operación XOR entre un registro y una literal. Sus sintaxis respectivas
son:
XORWF REGISTRO, DESTINO
Donde destino puede ser 0 o 1. Si es cero, se guarda en W, si es uno,
se guarda en el mismo registro.
XORLW LITERAL
Donde LITERAL puede ser cualquier número del 0 al 255.
Hay un caso particular en donde se puede realizar la operación XOR a
un bit. Lo que realiza esta instrucción es cambiar el estado de un bit, si es cero,
lo cambia a 1, si es uno lo cambia a 0. Puede ser también visto como una
negación o una operación toggle (refiriéndose a flip-flops). Esta instrucción es
BTG. Su sintaxis es:
BTG REGISTRO, BIT
Donde REGISTRO es cualquier registro y BIT, es el número de bit entre el 0 y el
7. Básicamente se puede usar para realizar parpadeos o cambios de estado en
un registro.

Operadores aritméticos

Los operadores aritméticos se utilizan para sumar, restar y multiplicar


números y registros. Tomar en cuenta que en ensamblador para PIC no existe la
operación DIVISIÓN, mas sin embargo, se puede realizar una operación que la
realice. Como la operación módulo depende de la operación división, tampoco
existe dentro de las operaciones básicas del ensamblador.
Una cosa muy importante que hay que tomar en cuenta es que al
realizar operaciones aritméticas se generan cambios en el registro STATUS.
Este registro de estado controla el resultado de una operación aritmética o
lógica. Su descripción la veremos más adelante cuando veamos registros y lo
explicaremos ampliamente por importancia.

Operador NEGF
Este operador sirve para convertir un número contenido en un registro a
negativo o viceversa. Su sintaxis es:

NEGF REGISTRO
Donde REGISTRO es cualquier registro que contiene un número entre el
-128 a 127.

Suma o adición
Para realizar la suma o adición se suelen usar dos instrucciones:
ADDWF para hacer la adición entre el registro W y otro registro o ADDLW para
hacer la suma del registro W con una literal. Sus sintaxis respectivas son:
ADDWF REGISTRO, DESTINO
Donde REGISTRO es cualquier registro y DESTINO puede ser un valor
0 o 1. Si es cero, se guarda el resultado en W, si es uno se guarda el resultado
en el mismo registro.
ADDLW LITERAL
Donde LITERAL es cualquier número entre el 0 y el 255.
En ambos casos si la suma supera el 255 se encenderá las banderas
de Carrier y Overflow del registro STATUS.
Resta o sustracción
Para realizar la suma o sustracción, se suelen usar dos instrucciones:
SUBWF para hacer la sustracción entre el registro W y cualquier otro registro o
SUBLW para hacer la resta del registro W con una literal. Sus sintaxis
respectivas son:
SUBWF REGISTRO, DESTINO
Donde REGISTRO es cualquier registro y DESTINO toma el valor de 0 o
1. Si es cero, se guardará el resultado en el registro W, si es uno, se guardara el
resultado en el mismo registro.
SUBLW LITERAL
Donde literal es cualquier número entre el 0 y el 255.

Multiplicación
La multiplicación se realiza con dos instrucciones: MULWF para realizar
la multiplicación entre el registro W y cualquier otro registro o MULLW para
realizar la multiplicación entre el registro W y una literal. Sus sintaxis
respectivas son:
MULWF REGISTRO

MULLW LITERAL
Donde LITERAL puede ser cualquier número del 0 al 255. Registro
puede ser cualquier registro de estado o memoria.

NOTA: El resultado de esta operación se guarda en los registros PRODH


y PRODL que son el resultado de 16 bits en su nible alto y bajo respectivamente.

Incrementos y decrementos

Los incrementos y decrementos se realizan de dos formas, realizando


solo su operación convencional o realizando su operación con una comparación.
Explicaré esto en cada caso.

Incremento
Los incrementos lo que realizan es sumar uno a un determinado
registro. Una vez que llegue a 255 el siguiente incremento causará que el
contenido del registro sea cero, y se encenderá la bandera de overflow del
registro STATUS. La palabra reservada para realizar un incremento se utiliza la
palabra reservada INCF. Su sintaxis es la siguiente:
INCF REGISTRO
Donde registro es cualquier registro de memoria.
Para evitar que estemos comprobando el error de OVERFLOW en la
bandera STATUS, tenemos una instrucción que lo hace por nosotros y cuando
esto sucede, salta una instrucción. Esta instrucción tiene la palabra reservada
INCFSZ que compara cuando el registro vuelve a ser cero y como mencioné
anteriormente, salta la siguiente instrucción. INCFSNZ realiza lo mismo pero
salta la siguiente instrucción si no es cero. Sus sintaxis respectivas son las
siguientes:
INCFSZ REGISTRO
;No hay overflow
;Hay overflow

INCFSNZ REGISTRO
;Hay overflow
;No hay overflow

Decrementos
Los decrementos lo que hacen es restar uno a un determinado registro
hasta llegar a cero. La palabra reservada para realizar un decremento es DECF
y su sintaxis es la siguiente:
DECF REGISTRO
Donde REGISTRO es cualquier registro de memoria.

Hay una instrucción que comprueba automáticamente cuando llega a


cero, la cual es DECFSZ y salta la siguiente instrucción cuando esto sucede.
DECFSNZ realiza la misma tarea pero salta la siguiente instrucción mientras no
sea cero. Sus sintaxis son:
DECFSZ REGISTRO
;no es cero
;es cero

DECFSNZ REGISTRO
;es cero
;no es cero
PROGRAMACIÓN BÁSICA DEL PIC18F4550

Ahora en este apartado vamos a ver como se programa el PIC18F4550,


pero antes vamos a ver una descripción de los registros que vamos a utilizar en
los primeros pasos.

Registros básicos del PIC18F4550

Vamos a ver tres registros básicos del PIC18F4550, los cuales son WREG,
TRIS y PORT.

Un registro es un mapeo en memoria RAM de algún dispositivo físico del PIC,


como son los puertos de entrada o salida, temporizadores, módulo usb, modulo
serial, módulo ADC, etc.

Registro WREG
El registro WREG se utiliza para guardar datos temporales en RAM para
operaciones y el intercambio de datos entre las mismas operaciones. Se puede
utilizar para regresar datos de subrutinas y de tablas.

Registros TRIS
Los registros TRIS sirven para configurar puertos, lo explicaré más
adelante. Hay cinco, que son el número de puertos que tiene el PIC18F4550,
los cuales son TRISA, TRISB, TRISC, TRISD y TRISE. Todos son de 8 bits,
excepto TRISE que es de 4 bits (nibble bajo) los demás no tienen efecto.

Registros PORT
Los registros PORT sirven para leer y escribir puertos, y también lo
explicaré más adelante. Hay cinco, que son el número de puertos que tiene el
PIC18F4550, los cuales son PORTA, PORTB, PORTC, PORD y PORTE. Todos
son de 8 bits excepto PORTE que es de 4 bits y se lee como cero el nibble alto
del registro.
Configurar puertos

Antes de configurar los puertos es necesario saber que si usamos el


oscilador externo (que es nuestro caso) el puerto A tendrá dos pines menos los
cuales son RA6 y RA7. También están desactivados de forma predeterminada
los pines RC4 y RC5 ya que utilizan el módulo USB y no está disponible RC3;
esto nos deja el puerto C de bits, a menos que desactivemos el módulo USB. El
puerto E tiene solo 3 bits ya que RE3 es usado por MCLR.
Para configurar todo el puerto A como salida (6 pines que tiene el puerto A
porque dos se usan con el oscilador) se realiza lo siguiente:

MOVLW
0x00
MOVWF
TRISA

Configurar el puerto B como salida:

MOVLW 0xFF
MOVWF TRISB

Configurar la primera mitad del puerto como entrada y la segunda mitad


del puerto como salida.

MOVLW 0xF0 ;nibble bajo salida (0) nibble alto


entrada (F) MOVWF TRISD

Para los demás puertos es exactamente el mismo procedimiento,


considerando las restricciones que tenemos en los pines de los puertos A, C y E.

Leer y escribir puertos

Debemos tener las mismas consideraciones que en el registro TRIS


sobre los pines desactivados por el uso de oscilador externo, USB y MCLR.
Ahora veamos cómo se escribe y se leen los puertos.
ESCRIBIR:

MOVLW 0xFF
MOVWF PORTD ;se encienden todos los pines del puerto D

LEER:

MOVF PORTB, W ;se mueve el dato en PORTB al registro de trabajo.

O también podemos realizar la lectura hacia un registro de memoria.


MOVFF PORTB, VARIABLE ;se mueve el contenido en el registro
PORTB a una variable en RAM.

Consideraciones para el flujo del programa

El PIC cuando es borrado, solo tiene instrucciones NOP en su interior


las cuales son el código 0xFFF. Para evitar que al terminar un programa vuelva
al inicio de la memoria (VECTOR RESET) debemos de realizar un ciclo infinito
que evite que se lea la zona de NOP que está al final del programa. Para esto
usamos la etiqueta ciclo y el goto ciclo al final de la plantilla.
Otra consideración importante es que cuando encendemos el
microcontrolador PIC18F4550 los puertos son configurados como analógicos,
para configurar los puertos como digitales tenemos que colocar 0x0F en el
registro ADCON1. Ahora no lo explico porque lo vamos a ver más adelante en
Convertidor Analógico Digital.
Antes que cualquier instrucción, se debe de limpiar el registro de trabajo
W. Debe de ser la primera instrucción después de la etiqueta main.
Ahora veamos un pequeño programa. Colocaré solo el código que va
dentro de la rutina principal llamada main para evitar colocar toda la plantilla.

Ejemplo 1: Encender todo el puerto A.

Solución: Colocar 0xFF o 0x3F en el PORTA y en TRISA 0x00 o 0xC0,


considerando los pines que no están disponibles por el oscilador.
Solución 1.1
main:

CLRF WREG ; Limpiamos el registro de trabajo.

MOVLW H'0F' ;Configuramos todos los puertos como


digitales

MOVWF ADCON1

CRLF TRISA ; Configuramos todo el


puerto como salida

SETF PORTA

ciclo
GOTO ciclo

END

Solución 1.2
main:

CLRF WREG ; Limpiamos el registro de trabajo.

MOVLW H'0F' ; Configuramos todos los puertos como digitales


MOVWF ADCON1

MOVLW H'C0'

MOVWF TRISA

MOVLW H'3F'

MOVWF PORTA

ciclo

GOTO ciclo

END

Las dos soluciones nos dan el mismo resultado.

Ejemplo 2: Encender solo el pin RA4.


Solución: Colocamos 0x00 en TRISA y 0x10 en PORTA o usar BSF
para encender el PIN RA4.

Solución 2.1
main:

CLRF WREG

MOVLW H'0F'

MOVWF ADCON1 ;Configuramos los puertos como digitales


CLRF TRISA

MOVLW H'10'

MOVWF PORTA

ciclo
GOTO ciclo

END

Solución 2.2
main:

CLRF WREG

MOVLW H'0F'

MOVWF ADCON1 ; Configuramos los puertos como digitales


CLRF TRISA ;Todo el puerto como salida

CLRF PORTA ; Ponemos el puerto A en ceros


BSF PORTA, RA4 ;Encendemos RA4

Ciclo
GOTO ciclo
END

Los dos ejemplos realizan exactamente lo mismo. Como podemos ver,


se puede colocar todo el puerto como salida aunque no utilicemos el resto de los
pines.

Ejemplo 3: Verificar que el puerto B contenga el número 55h o AAh, en


el primer caso, encender RC0, en el segundo caso encender RC1, cualquier otro
caso apagar ambos pines; los dos pines no pueden estar encendidos al mismo
tiempo. Hacer la comprobación de forma indefinida.
Solución: Colocar la comprobación dentro del ciclo infinito. Utilizar la
comparación de igualdad CPFSEQ.

main:

CLRF WREG

MOVLW H'0F'

MOVWF ADCON1 ; Configuramos los puertos como digitales


CLRF TRISC ;Todo el puerto como salida

SETF PORTB ; Todo el puerto como entrada


CLRF PORTC ;Ponemos el puerto C en ceros

ciclo
MOVLW H'55'
CPFSEQ PORTB

GOTO comprueba2

MOVLW H'01'

MOVWF PORTC

GOTO ciclo
comprueba2

MOVLW H'AA'
CPFSEQ PORTB

GOTO apagapuerto
MOVLW H'02'
MOVWF PORTC

GOTO ciclo
apagapuerto

CLRF PORTC

GOTO ciclo
END
Notemos que cada vez que realizamos un programa más avanzado, va
aumentando su tamaño. Todo es dependiendo del objetivo a alcanzar. Hay que
tener mucha lógica para realizar un programa para microcontrolador.

También podría gustarte