Ir al contenido

Ensamblador para PIC18

El ensamblador traduce instrucciones legibles por humanos a codigo maquina (bytes en la Flash del PIC). En el curso UNEXPO se trabaja con MPASM dentro de MPLAB v8: escribes un archivo .ASM, compilas y obtienes un .HEX que grabas en el microcontrolador.

Esta pagina cierra el bloque de Fundamentos junto con Arquitectura, Registros y Bits y hexadecimal. Ya sabes que son WREG, los SFR y las mascaras; aqui aprendes como escribir el programa linea por linea.

Tu codigo (.ASM)
↓ MPASM (ensamblador)
Archivo .HEX
↓ Programador / MPLAB
Flash del PIC18F4550 → el chip ejecuta instrucciones

Mas adelante en MPLAB y Proteus veras el entorno completo. Los config bits y la palabra de configuracion van en el mismo .ASM pero se graban en una zona especial de configuracion, no como codigo ejecutable normal.

Anatomia de un archivo MPASM — estilo “sandwich”

Sección titulada «Anatomia de un archivo MPASM — estilo “sandwich”»

En el curso UNEXPO el profesor pide ordenar el .ASM como un sandwich, parecido a int main() en C:

CapaQue vaAnalogia en C
ArribaCabecera, CONFIG, variables (CBLOCK)#include, defines, variables globales
MedioSubrutinas (CALL / RETURN)Funciones auxiliares
AbajoPrograma principalmain()
FinalENDFin del archivo

Solo al inicio va el vector de reset (ORG 0x0000 / 0000H + GOTO programa): es la unica excepcion — el hardware arranca en 0000H y debe saltar al main que esta al final.

; ══ ARRIBA — cabecera, config, variables ══════════════
LIST P=18F4550
#include <P18F4550.INC>
CONFIG FOSC = HS
CONFIG WDT = OFF
CONFIG LVP = OFF
CBLOCK 0x20
contador RES 1
; ── Vector de reset (salta al main al final) ──────────
ORG 0x0000
GOTO programa
; ══ MEDIO — subrutinas ═══════════════════════════════
config_puertos:
BCF TRISB, 0 ; RB0 salida
RETURN
encender_led:
BSF LATB, 0 ; RB0 en alto
RETURN
; ══ ABAJO — programa principal (como main) ════════════
programa:
CALL config_puertos
CALL encender_led
bucle:
GOTO bucle ; bucle infinito
END
DirectivaFuncion
LIST P=18F4550Indica el micro al ensamblador
#include <P18F4550.INC>Importa nombres de registros y bits
CONFIG …Palabra de configuracion (oscilador, WDT…)
ORG addrFija la direccion en Flash donde empieza el codigo
CBLOCK / RESReserva bytes en RAM para variables GPR
ENDMarca el final del archivo
  • Etiqueta (inicio:, bucle:): nombre de una posicion en Flash; destino de GOTO o CALL. No es un numero — MPASM la convierte en direccion al compilar.
  • Comentario (; texto): ignorado por MPASM — documenta tu codigo.

Un literal es un valor fijo escrito en la linea de codigo. No es el nombre de un registro (LATB, contador) ni una etiqueta (programa:): es el numero concreto que quieres usar.

Piensalo como una constante en C: el valor que ya decidiste y escribes tal cual, no algo que lees de una variable en RAM. Si en C pondrias resultado = 10;, en ensamblador escribes MOVLW D'10' — ese 10 es el literal (tu constante en esa linea).

En el manual MPASM aparece como k cuando la instruccion lleva un valor embebido:

ManualTu codigoQue significa
MOVLW kMOVLW D'10'Carga el literal 10 en WREG
ANDLW kANDLW 0xF0AND entre WREG y el literal 0xF0
ADDLW kADDLW B'00000001'Suma el literal 1 a WREG

El ensamblador traduce ese literal a bytes dentro de la instruccion en Flash. El PIC no “busca” un literal en RAM: el valor viaja dentro del opcode.

MPASM exige prefijos para dejar clara la base del numero. El mismo valor puede escribirse de varias formas:

NotacionEjemplo en .ASMMismo valor (informe)Base
DecimalD'200'20010
BinarioB'11110000'2402
Hex (0x)0xF0F0H16
Hex (sufijo h)0F0hF0H16 en MPASM

Reglas utiles al escribir literales:

  • Decimal: siempre D'numero' con comillas — D'10', D'255'.
  • Binario: B'01010101' — util para mascaras (ver Bits y hexadecimal).
  • Hex en .ASM: 0xF0 o 0F0h (MPASM acepta ambos; a veces se escribe 0FFh para no confundir con etiqueta).
  • Rango de un byte: un literal de 8 bits va de 0 a 255 (0x000xFF). Si te pasas, MPASM avisa al compilar.

Ejemplos en instrucciones reales:

MOVLW D'10' ; WREG = 10 (decimal)
MOVLW 0xF0 ; WREG = 240 = F0H
MOVLW B'00000001' ; WREG = mascara solo bit 0
ANDLW 0x0F ; WREG = WREG AND 0FH (filtra nibble bajo)
BSF LATB, 0 ; el 0 tambien es literal: numero de bit

Para convertir entre decimal, binario y hex (tablas, mascaras, 0x vs FFH), usa Bits y hexadecimal. Aqui el foco es como escribir el valor dentro del .ASM.

Las directivas no se ejecutan en el PIC; le dicen a MPASM donde o cuanto reservar. Tambien llevan literales numericos:

DirectivaEjemploQue literal indica
ORGORG 0x0000Direccion en Flash (0000H = vector de reset)
CBLOCKCBLOCK 0x20Direccion inicial en RAM para variables (20H)
LISTLIST P=18F4550Aqui el “literal” es el nombre del micro (simbolo, no numero)
ORG 0x0000 ; codigo empieza en 0000H
CBLOCK 0x20 ; variables desde 20H en RAM
contador RES 1 ; RES 1 = reserva 1 byte (otro tipo de literal)

Misma idea de notacion: 0x0000 = 0000H; 0x20 = 20H. Ver equivalencias en Bits y hexadecimal — notaciones hex.

La letra f en las instrucciones — que es y como se usa

Sección titulada «La letra f en las instrucciones — que es y como se usa»

Antes de los sufijos ,W y ,F, conviene entender una convencion de los manuales MPASM que aparece en casi todas las instrucciones.

Paso 1 — Como se ven las instrucciones en el manual

Sección titulada «Paso 1 — Como se ven las instrucciones en el manual»

En la documentacion, las instrucciones no traen nombres concretos como LATB o contador. Traen la letra f como hueco que tu llenas:

Instruccion en el manualQue dice en palabras
MOVF f, WCopia el contenido del registro f hacia WREG
MOVWF fCopia WREG hacia el registro f
INCF f, FSuma 1 al registro f y deja el resultado en f
BSF f, bPone el bit b del registro f en 1
CLRF fPone el registro f en cero

La f del manual significa: “aqui va el registro de archivo que tu quieras usar”. En ingles se llama file register (registro de archivo): cualquier byte de la RAM de datos.

Paso 2 — Reemplazas f por el registro que necesitas

Sección titulada «Paso 2 — Reemplazas f por el registro que necesitas»

Cuando programas, sustituyes f por el registro concreto que quieres leer, escribir o modificar:

Manual (generico)Tu codigo (concreto)Que hace
MOVF f, WMOVF LATB, WCopia LATBWREG
MOVF f, WMOVF contador, WCopia contadorWREG
MOVWF fMOVWF LATBCopia WREGLATB
INCF f, FINCF contador, Fcontador = contador + 1

En la linea MOVF LATB, W, el manual habria escrito MOVF f, W. En ese ejemplo, f y LATB son lo mismo: el unico registro que participa (ademas de WREG) es LATB. No hay otro registro oculto llamado F.

; Manual: MOVF f, W
; Tu codigo: MOVF LATB, W
; └─┬──┘
; └── aqui va lo que el manual llama "f"

Lo mismo con una variable tuya:

; Manual: INCF f, F
; Tu codigo: INCF contador, F
; └────┬────┘
; └── "f" = contador en este programa

Cualquier byte de la RAM de datos puede ocupar el lugar de f. Hay dos familias (ver Registros y Arquitectura):

Si reemplazas f por…TipoEjemplo de uso
TRISB, LATB, PORTB, INTCONSFRControlar hardware del PIC
contador, temp (con RES)GPRGuardar datos de tu programa

LATB y contador son registros de archivo porque pueden ser la f de una instruccion. La diferencia entre SFR y GPR es para que sirve ese byte, no el hecho de llamarse “archivo”.

En una misma linea pueden aparecer dos cosas distintas con la letra F:

SimboloQue esEjemplo
f (minuscula, del manual)Que registro usas — lo reemplazas por LATB, contadorMOVF LATB, W
,F (sufijo al final)Donde queda el resultado — en ese mismo registro (no en WREG)INCF contador,F
,W (sufijo)Donde queda el resultado — en WREGMOVF LATB,W

Ejemplo completo desglosado:

MOVF LATB, W
; └─┬─┘ └┬┘
; f destino = WREG (sufijo ,W)
; en codigo real, f = LATB
INCF contador, F
; └───┬───┘ └┬┘
; f destino = el mismo registro (sufijo ,F)
; en codigo real, f = contador

La seccion siguiente detalla ,W vs ,F con mas ejemplos de instrucciones.

Con la seccion anterior clara: en MOVF LATB, W, f del manual = LATB en tu codigo; el sufijo ,W indica que el resultado va a WREG.

Muchas instrucciones tienen dos formas de destino:

; f = contador; destino ,W → resultado en WREG
MOVF contador, W ; WREG = contador (contador no cambia)
; f = LATB; destino ,W
MOVF LATB, W ; WREG = LATB
; f = contador; destino ,F → resultado en el mismo registro
INCF contador, F ; contador = contador + 1

Regla mental: ,W → resultado en WREG; ,F → resultado en el mismo registro que reemplaza f (LATB, contador…).

Instrucciones basicas — movimiento de datos

Sección titulada «Instrucciones basicas — movimiento de datos»
InstruccionQue haceEjemplo
MOVLW kCarga literal k en WREGMOVLW D'10'
MOVWF fCopia WREG → registro fMOVWF LATB
MOVF f,dCopia registro fd (,W o ,F)MOVF PORTB, W
CLRF fPone registro f en 0CLRF contador
CLRWPone WREG en 0CLRW

Patron tipico — cargar y guardar:

MOVLW D'55' ; WREG = 55
MOVWF contador ; contador = 55
InstruccionOperacionActualiza STATUS
ADDLW kWREG = WREG + kSi (Z, C, DC, OV, N)
ADDWF f,dWREG + f → dSi
SUBLW kWREG = k − WREGSi
SUBWF f,df − WREG → dSi
INCF f,df + 1 → dSi (Z, N…)
DECF f,df − 1 → dSi
DECFSZ f,dDecrementa; si queda 0, salta la siguiente instruccionSi

Ejemplo — contador con bucle de N iteraciones:

MOVLW D'10'
MOVWF contador
bucle:
; ... trabajo ...
DECFSZ contador, F ; contador--; si llega a 0, salta GOTO
GOTO bucle
; aqui termina el bucle

Tras sumas y restas revisa las banderas de STATUS: Z (¿cero?), C (¿acarreo?), N (signo).

InstruccionOperacion
ANDLW k / ANDWF f,dAND bit a bit
IORLW k / IORWF f,dOR bit a bit
XORLW k / XORWF f,dXOR bit a bit
COMF f,dComplemento (NOT) de f

Detalle y mascaras en Bits y hexadecimal. La Practica 1 exige rutinas con estas operaciones.

Instrucciones de bit — un pin sin tocar el resto

Sección titulada «Instrucciones de bit — un pin sin tocar el resto»
InstruccionEfecto
BSF f,bBit b de f → 1
BCF f,bBit b de f → 0
BTFSS f,bSalta la siguiente linea si bit = 1
BTFSC f,bSalta la siguiente linea si bit = 0
; Leer boton en RB3 (entrada)
BSF TRISB, 3 ; RB3 entrada
BTFSS PORTB, 3 ; ¿RB3 = 1?
GOTO boton_suelto ; si RB3 = 1 → salta al destino
; ... codigo si boton presionado (RB3 = 0) ...
boton_suelto:
; continua si el boton esta suelto (RB3 = 1)
InstruccionFuncion
GOTO etiquetaSalto incondicional — PC va a la etiqueta
CALL subLlama subrutina — guarda retorno en la pila
RETURNVuelve del CALL — restaura PC desde la pila
RETFIEReturn from interrupt (ISR)
; ── subrutina (medio del sandwich) ──
retardo_1s:
; ... bucle que consume tiempo ...
RETURN
; ── programa principal (abajo, como main) ──
programa:
CALL retardo_1s ; va a retardo_1s; guarda direccion de retorno
BSF LATB, 0 ; al volver, enciende LED
GOTO programa

La pila es LIFO: el ultimo CALL es el primero en volver con RETURN. En Arquitectura — PC esta explicado con mas detalle.

El PIC18 no tiene instruccion CMP. Comparas operando y leyendo STATUS:

; ¿contador == 0?
MOVLW D'0'
XORWF contador, W ; si iguales → W=0 → Z=1
BTFSS STATUS, Z ; salta si Z=1 (contador era 0)
GOTO no_es_cero ; si no era 0 → salta al destino
; contador == 0 ...
GOTO fin_cero
no_es_cero:
; contador != 0 ...
fin_cero:
; ¿RB0 encendido?
BTFSS LATB, 0 ; salta si bit 0 de LATB = 1
GOTO led_apagado ; si RB0 = 0 → salta al destino
; LED encendido (RB0 = 1) ...
GOTO fin_led
led_apagado:
; LED apagado (RB0 = 0) ...
fin_led:
InstruccionSalta si…
BTFSS STATUS, ZResultado fue cero (Z=1)
BTFSC STATUS, ZResultado no fue cero (Z=0)
BTFSS STATUS, CHubo acarreo (C=1)

Traduce “enciende un LED en RB0” a pasos concretos usando Registros GPIO:

LIST P=18F4550
#include <P18F4550.INC>
CONFIG FOSC = HS, WDT = OFF, LVP = OFF
ORG 0x0000
GOTO programa
; ── (sin subrutinas en este ejemplo minimo) ──
programa:
BCF TRISB, 0 ; 1) RB0 como salida
BSF LATB, 0 ; 2) RB0 en alto → LED ON
bucle:
GOTO bucle ; 3) bucle (programa no termina)
END

En ensamblador no dices “enciende un LED”. Dices: configura direccion del pin, escribe el latch, manten el programa corriendo.

Ejercicio · Parcial

Traza este fragmento

MOVLW D'3'
MOVWF contador
INCF contador, F
DECFSZ contador, F
GOTO $-1
  1. contador queda en 3, luego INCF4.
  2. DECFSZ decrementa: 3 — no es cero → no salta.
  3. GOTO $-1 vuelve al DECFSZ.
  4. Repite hasta que contador = 0DECFSZ salta el GOTO y el bucle termina.

$-1 es la instruccion anterior (etiqueta implicita de MPASM).

  • Olvidar END: MPASM puede dar error o generar codigo incompleto.
  • MOVLW vs MOVWF: MOVLW carga en WREG; MOVWF guarda WREG en un registro — no son intercambiables.
  • Escribir salidas en PORTx: usa LATx para salidas; lee entradas con PORTx.
  • Confundir BTFSS y BTFSC: uno salta si el bit es 1, el otro si es 0 — revisa el cableado del boton.
  • No incluir P18F4550.INC: sin el include, TRISB y LATB no existen como simbolos.
  • Etiqueta sin dos puntos (programa en vez de programa:): el ensamblador no reconoce el destino del salto.
  • Programa principal arriba y subrutinas abajo: en UNEXPO va al reves — programa: al final, subrutinas en el medio (estilo sandwich / main al final).

¿Que significa la f en MOVWF f del manual MPASM?

Es un comodin: el manual no sabe que registro usaras. Tu escribes MOVWF LATB o MOVWF contadorf se convierte en ese nombre. En MOVF LATB, W, f y LATB son lo mismo.

¿Que es un literal en MPASM?

Un valor fijo escrito en la linea (D'10', 0xF0, B'10000000') — como una constante en C — que el ensamblador incrusta en la instruccion. No es un registro (contador) ni una etiqueta (bucle:).

¿Que hace MOVLW D'5' seguido de MOVWF contador?

Carga 5 en WREG y lo copia a la variable GPR contador.

¿Para que sirve ORG 0x0000 (0000H)?

Indica que el codigo empieza en la direccion 0000H de la memoria de programa (vector de reset).

¿Que diferencia hay entre GOTO y CALL?

GOTO salta sin guardar retorno. CALL salta a una subrutina y apila la direccion para volver con RETURN.

¿Que hace DECFSZ contador, F?

Decrementa contador; si el resultado es 0, no ejecuta la instruccion siguiente (util para bucles).

Examen interactivo

Ensamblador MPASM

Basado en: instrucciones pic.pdf

0 de 0 respondidas

MOVLW k carga un valor en...
La directiva ORG 0x0000 indica...
MOVWF contador copia el valor de...
La directiva END en MPASM...
CALL subrutina seguido de RETURN sirve para...
INCF contador, F hace...
DECFSZ contador, F cuando contador llega a 0...
#include <P18F4550.INC> sirve para...
RES 1 despues de un nombre en CBLOCK...
Para comparar si contador == 0 sin instruccion CMP, usas...
En la sintaxis MPASM, la letra f en MOVWF f significa...