El uso de subrutinas lo vimos por primera vez en el tutorial Encendiendo y apagando LED's... ahora con retardo! Ahí se vio la manera en la que se llama y se regresa de las subrutinas. También se dijo que el empleo de subrutinas hacía el código más entendible, otra forma de hacer el código entendible es mediante el uso de Macros.

Las macros son de alguna forma similares a las subrutinas ya que son conjuntos de intrucciones que se ejecutan de manera secuencial mediante una llamada a una orden de ejecución, sin embargo tiene diferencias muy significativas. Mientras que una subrutina aparece una sola vez en el código, cada vez que se "invoca" una macro se inserta el código de esta en el programa. Otra diferencia es que a una macro se le pueden especificar parámetros de entrada y a una subrutina no.

Una macro se define con la directiva macro especificando el nombre de la macro y los parámetros de entrada, si existieran, de la siguiente manera:
nombre_macro macro par1, par2,...
instrucción
instrucción
...

             endm


En el programa la definición de la macro debe aparecer antes de la línea en la que se llama la macro. Cuanto mientras se ejecuta el programa se encuentra una macro esta es reemplazada por el conjunto de instrucciones que aparecen en la definición de la macro. Una manera de asegurar eso es escribiendo las macros en un archivo include (.INC) y llamando a este include al momento de llamar el include de las definiciones del micro.

Las macros pueden ahorrar mucho tiempo de escritura ya que si hay partes del código que se repiten mucho se pueden escribir en una macro y ese código se insertaría de manera automática al llamar la macro. Veamos esto con un ejemplo. Los cambios de banco pueden ser muy repetitivos asi que si se quiere cambiar de banco se podrían definir unas macros de la siguiente manera:

banco0 macro             ; Definición de macro banco0
       bcf    STATUS,RP0 ; Bit RP0=0 = Banco 0
       endm              ; Termina definición de macro


banco1 macro             ; Definición de macro banco1
       bsf    STATUS,RP0 ; Bit RP0=1 = Banco 1
       endm             
; Termina definición de macro

Así si en el programa aparece el macro banco1 este será sustituido por el código bcf STATUS,RP0.

Con ese ejemplo tal vez no queda muy claro la ventaja de usar una macro ya que la macro solo contiene una instrucción y no utiliza parámetros, pero ahora que definimos esos macros definamos otro que designe un bit de un puerto como salida:

SALIDA macro    par1, par2 ; Definición de macro
       banco1              ; Macro para cambiar al banco 1
       bcf      par1, par2 ; Bit dado como salida
       banco0              ; Macro para cambiar al banco 0
       endm               
; Termina definición de macro

Para utilizar ese macro que contiene parámetros simplemente se llama de la siguiente manera:

       SALIDA   TRISA,3

Al llamara esa macro el primer parámetro dado TRISA toma el lugar de par1 mientras que el parámetro 3, el lugar de par2 generando el siguiente código:

    bsf STATUS,RP0 ; RP0 = 1 = Banco 1
    bcf TRISA,3    ; Bit 3 de Puerto A como entrada
    bcf STATUS,RP0 ; RP0 = 0 = Banco 0


Como se puede ver las macros hacen muy la escritura del código y al poder manejar parámetros proveen un medio para simplificar muchas operaciones.

Utilizando esos macros supongamos que realizamos un programa que ponga el alto el valor del bit 3 del puerto B. El código completo del programa sería:

    list    p=16f628a
    include p16f628a.inc
    include macros.inc ; Archivo con la definición de las macros


    org 0x00
    goto INICIO


    org 0x05
INICIO
    SALIDA  TRISB,3 ; Llamada a macro salida
    bsf     PORTB,3 ; Bit 3 del puerto B en alto


    goto    $       ; Ciclo infinito

    end

El programa principal es muy sencillo y legible. El archivo macros.inc donde se definen las macros quedaría así:

banco0 macro             ; Definición de macro banco0
       bcf    STATUS,RP0 ; Bit RP0=0 = Banco 0
       endm              ; Termina definición de macro


banco1 macro             ; Definición de macro banco1
       bsf    STATUS,RP0 ; Bit RP0=1 = Banco 1
       endm
             ; Termina definición de macro

SALIDA macro  par1, par2 ; Definición de macro SALIDA
       banco1            ; Llamada a macro banco1
       bcf    par1, par2 ; Bit dado como salida
       banco0            ; Llamada a macro banco0
       endm              ; Termina definición de macro


Teniendo en cuenta las dos diferencias mencionadas podemos entonces preguntarnos ¿son mejores las macros o las subrutinas?. La respuesta final la debe dar cada quien ya que dependiendo del caso se debería usar una o la otra.

Más información sobre macros se puede encontrar en el quinto capítulo de PIC microcontrollers, for beginners too, de Nebojsa Matic.