82523998 prog pic ensamblador

Upload: erick-escogido-escobedo

Post on 29-Oct-2015

203 views

Category:

Documents


0 download

TRANSCRIPT

  • PROGRAMACIN EN ENSAMBLADOR DEL PIC18F4550

    CON BOOTLOADER

    Por Francisco Javier Garca Olmos

    Instituto Politcnico NacionalMxico 2012

    NOTA: Para utilizar este manual terico-prctico es necesario tener conocimientos bsicos de electrnica y circuitos, lgica digital y nociones bsicas de programacin de computadoras en cualquier lenguaje. Es necesario tambin tener en cuenta la lectura del manual (data sheet) para manejar los registros necesarios para la configuracin de este microcontrolador.

    1

  • Dedicado a mis amigos programadores:Francisco y Eduardo.

    Hay ms personas pero el mencionar a todas ellas requerira un documento extra para mencionarlas, ya que son muchas. Gracias Por Su Apoyo SNAR.

    2

  • INTRODUCCIN A MPLAB X

    Para iniciar con la programacin en ensamblador primero necesitamos saber acerca del IDE gratuito del cual Microchip nos provee; Microchip es la empresa que fabrica los microcontroladores PIC. Este IDE es el que usaremos para realizar nuestros proyectos, probarlos y compilarlos, ya que es multiplataforma y podemos utilizarlo tanto en Windows como en Linux.

    Ambiente de desarrollo MPLAB X

    El ambiente de desarrollo tiene la siguiente imagen; tome en cuenta que est mos-trado dentro del Sistema operativo Linux.

    Del lado izquierdo aparece una lista con los proyectos realizados, archivos y/o clases que se utilizan en MPLAB. Siempre se abrir con la pgina de inicio. Tiene su barra de men, barra de herramientas y en la parte de abajo, oculta ventanas que son necesarias a la hora de compilar, probar y analizar la memoria. Para mayor informacin, verificar un curso com-pleto de MPLAB, ya que aqu solo hablaremos de las partes ms importantes.

    3

  • Crear un proyecto para Ensamblador

    Para crear un proyecto, es necesario dar clic en el segundo icono de la barra de he-rramientas o seleccionar New Proyect del men File y se abrir una ventana donde pregunta el tipo de proyecto que deseamos crear; seleccionamos Standaalone Proyect y presionamos Siguiente; nos aparecer una lista donde tenemos que seleccionar la familia y el dispositivo a usar, en nuestro caso colocamos Advanced 8-bit MCUs (PIC18) en familia y en dispositivo PIC18F4550, posteriormente seleccionamos siguiente. Nos aparecer una lista de programa-dores a usar; nosotros colocaremos Simulator por que usaremos Bootloader y no es nece-sario un programador mas que solo una vez para ingresarle el Bootloader al PIC. Una vez presionado el botn siguiente (Next) aparecer una lista con lenguajes de programacin, de los cuales vamos a seleccionar MPASM, ya que usaremos el lenguaje ensamblador.

    Por ltimo, le damos un nombre al proyecto y lo guardamos en el directorio que nos agrade.

    4

  • Al realizar los pasos anteriores, se mostrar nuestro proyecto en la parte izquierda del IDE. Ahora es necesario crear un archivo nuevo vaci para comenzar a programar.

    Para agregar el nuevo archivo hacemos clic derecho en Source Files del proyecto que estamos creando, y le hacemos clic en New y posteriormente en Empty File y se abrir una ventana donde le colocaremos un nombre. En nuestro caso le llamaremos plantilla.asm por que ser nuestra plantilla para cualquier proyecto que realicemos con bootloader.

    Compilar un programa

    Para compilar un programa hecho previamente, solo le damos clic al botn que tiene un martillo, se compilar el proyecto y se crear el archivo ejecutable .HEX que es el que se grabar en el PIC con el HID BOOTLOADER.

    En Windows este programa es grfico y se habilitan los botones una vez que se ac-tiva el bootloader de la placa de prueba del PIC. Seleccionamos el archivo .HEX que deseamos grabar y pulsamos sobre el botn Program / Verify y se programar el PIC.

    5

  • En Linux, hay un programa en lnea de comandos que graba de forma satisfactoria el PIC con bootloader y se ejecuta anexando la direccin del archivo .HEX desde la Terminal. Tiene el nombre de hid_bootloader y solo se tiene que ingresar el nombre del archivo .HEX que se desea grabar.

    El bootloader del PIC se activa pulsando el SWITCH 3 de la placa de prueba del PIC18F4550 junto con el botn RESET, posteriormente soltar RESET quedando solo el swithc 3 y parpadearn los LEDS RC0 y RC1 de la placa de prueba, en ese momento soltar el SWITCH 3. Una vez realizado esto, la computadora reconocer al dispositivo como un Human Interface Device USB. En este momento se puede grabar el programa que hemos realizado con el bootloader.

    6

  • El PIC18F4550

    En este captulo vamos a ver algunas caractersticas del PIC18F4550, que son esen-ciales para entender la programacin en ensamblador.

    1. Es un dispositivo CMOS de bajo consumo de energa, uso de voltaje +5V y uso mximo de corriente de 25mA, no consumir ms de esta corriente ya que si no, podramos daar el pin del microcontrolador. Tambin tener en cuenta que los disposi-tivos CMOS son delicados a la corriente esttica.

    2. Es un microcontrolador que trae en su interior un microprocesador (MPU o ALU), memoria RAM y memoria de programa flash (regrabable) y memoria EEPROM de datos y sus propios bus de datos, control y direcciones internamente.

    3. Integrado de 40 pines en su presentacin DIP o 44 pines en su presentacin para montaje superficial.

    4. Es un microcontrolador de 8 bits en su bus de datos, osea que solo puede manejar 8 bits por clculo.

    5. Tiene 5 puertos de entrada y salida: A, B, C, D y E. Tres de ellos son de 8 bits, uno de 7 bits y uno de ellos es de 4 bits, mas sin embargo, estas caractersticas no son posibles por el uso de pines por oscilador externo (RA5 y RA6), uso de USB (RC4 y RC5) y por ltimo uso de MCLR (Master Clear Reset) en el pin RE4. Esto nos deja con 1 puertos de 6 bits, dos puertos de 8 bits, uno de cinco y uno de 3 bits.

    6. Oscilador interno de 8MHz. Nosotros usaremos el externo de 20MHz por el uso del mdulo USB para el BOOTLOADER.

    7. Tiene 13 canales analgicos (ADC) de 10 bits.8. Mdulo USB y posibilidad de usar BOOTLOADER.9. Modulo USART para comunicacin serial. Si se requiere comunicacin PC-PIC se

    necesitar un integrado MAX232 para la conversin de voltajes.10.Tres interrupciones externas.11. Cuatro temporizadores (Timers) o contadores.12.Dos modulos capturador/comparador/PWM (CCP).13.Un mdulo embebido capturador/comparador/PWM (ECCP).14.Un mdulo Master Synchronous Serial Port (MSSP).

    7

  • Las conexiones bsicas del PIC18F4550, les de estado y 2 botones de cambio de flanco (SW2 y SW3) para el inicio del bootloader son las siguientes:

    Conexiones bsicas:1. Conexin a VDD y VSS no mostradas en el diagrama. VDD es de +5V y VSS es tierra

    GND.2. 1 push button para MCLR con sus respectivas resistencias de PULL-UP externas.3. Oscilador de 20MHz con dos capacitores de 22pF conectados a tierra.

    Conexiones extras de la placa de pruebas del PIC18F4550:

    1. 2 Leds en RA4 y RA5.2. 2 Leds en RC0 y RC1 para el estado del Bootloader.3. 2 push button para las interrupciones de cambio de flanco con sus respectivas resiste-

    ncias de PULL-UP externas (SW2 y SW3).

    8

  • LO BSICO EN ENSAMBLADOR

    Comencemos la programacin en ensamblador definiendo algunos trminos y acla-rando algunas situaciones con respecto del bootloader.

    El bootloader es un programa dentro del microcontrolador PIC que graba otro programa a partir de la direccin 0x1000 de la memoria de programa. Es como un sistema operativo (mas sin embargo no lo es) que se ejecuta cada que presionamos el botn SWITCH 3 despus del RESET.

    Las direcciones de inicio del PIC son:0x0000 MCLR (Master Clear Reset)0x0008 High Vector Sector0x0018 Low Vector Sector

    Pero como nosotros usamos Bootloader, las direcciones cambian.0x1000 Remaped Reset Sector0x1008 Remaped High Vector Sector0x1018 Remaped Low Vector Sector

    Posteriormente explicar a que se refiere cada una de ellas en el captulo de interrup - ciones, que abarcaremos ms adelante.

    La numeracin en ensamblador puede ser hexadecimal colocando 0xNN y el nme-ro, colocando H'NN' y el nmero o colocando NLh (0Ah), para este tipo de numeracin, se debe de comenzar por un nmero, en caso de ser de dos letras, se utiliza cero (0FFh). La numeracin decimal se realiza colocando un punto y el nmero en decimal. Para la numeracin binaria se procede a colocar B'XXXXXXX' y el nmero en binario,

    Como vemos, lo que se refiere al bootloader, son las direcciones de inicio y posteriormente veremos que la frecuencia tambin cambia, as que esta programacin tam-bin se puede utiliza sin bootloader con el inconveniente que necesitamos un programador como el PICKIT2 para grabar nuestros programas.

    La configuracin 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 esta parte del cdigo 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.

    9

  • Bits de configuracinSon los que controlan el comportamiento del microcontrolador. Los tres bsicos 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 ms, para mayores referencias consultar el manual.

    CONFIG WDT = OFF ;configura el perro guardin (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 programacin, nosotros lo apaga-mos para que programe en alto voltaje.

    Para el Bootloader (modo que nosotros usaremos) hay ms bits, estn ya colocados en la plantilla y no debern de ser modificados. Para ms informacin ver la ayuda de MPLAB sobre los bits de configuracin.

    Sectores de cdigoLos sectores de cdigo son aquellos que le dicen al programador (PICKIT2, PICKIT3,

    etc) en que parte de la memoria de programa va a programar el cdigo. Hay dos formas de hacerlo: ORG $direccin o CODE $direccin

    Ejemplo 1: Colocar el vector de reset en la localidad cero de la memoria.

    ORG 0x0000 ;localidad cerogoto main

    RESET_VECTOR_SECTOR CODE 0x0000 ;localidad cero (notar que podemos nombrar dicho sector con CODE)

    goto main

    Ejemplo 2: Colocar el vector reset en la localidad mil hexadecimal.

    ORG 0x1000goto main

    REMAPED_VECTOR_SECTOR CODE 0x1000goto main

    10

  • Para usar bootloader el vector de reset se encuentra en 0x1000 ya que el dems espacio es usado por el propio bootloader previamente cargado.

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

    Sectores de memoriaLos 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 algn dato o infromacin.

    El sector de memoria se ubica debajo de la palabra UDATA, para reservar memoria para registros del microcontrolador, bsicamente para usar informacin que restaure el algunos registros del microcontrolador en la interrupcin 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 nmero 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 sangraDATO1 RES 1 ;la reserva de memoria no lleva sangra.

    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.

    UDATA_ACSDATO1 RES 1DATO2 RES 1DATO3 RES 1

    ConstantesPara que el lenguaje ensamblador reconozca una constante, es necesario darle un

    nombre y un nmero al cual sera igualada; para ello se utiliza la palabra reservada EQU.

    UNO EQU 1DOS EQU 2TRES EQU 3

    11

  • 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 Garca Olmos *; Fecha: 2 de Enero de 2012 *; Plantilla para trabajar con BOOTLOADER en Ensamblador *;************************************************************************

    LIST P=18F4550, F=INHX32#include

    ;***************************************************************************;Bits de configuracin

    CONFIG PLLDIV = 5CONFIG CPUDIV = OSC1_PLL2CONFIG USBDIV = 2CONFIG FOSC = HSPLL_HSCONFIG FCMEN = OFFCONFIG IESO = OFFCONFIG PWRT = OFFCONFIG BOR = ONCONFIG BORV = 3CONFIG VREGEN = ONconfig WDT = OFFconfig WDTPS = 32768config MCLRE = ONconfig LPT1OSC = OFFconfig PBADEN = OFF config CCP2MX = ONconfig STVREN = ONconfig LVP = OFFconfig ICPRT = OFFconfig XINST = OFFconfig CP0 = OFFconfig CP1 = OFFconfig CP2 = OFFconfig CP3 = OFFconfig CPB = OFFconfig CPD = OFFconfig WRT0 = OFFconfig WRT1 = OFFconfig WRT2 = OFFconfig WRT3 = OFFconfig WRTB = OFFconfig WRTC = OFFconfig WRTD = OFFconfig EBTR0 = OFFconfig EBTR1 = OFFconfig EBTR2 = OFF

    12

  • config EBTR3 = OFFconfig EBTRB = OFF

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

    ;***************************************************************************; Definicin de variables

    ; Variables definidas si se utiliza la interrupcin de baja prioridad

    UDATA

    WREG_TEMP RES 1 ;variable en RAM para guardar contextoSTATUS_TEMP RES 1 ;variable en RAM para guardar contextoBSR_TEMP RES 1 ;variable en RAM para guardar contexto

    RESET_VECTOR CODE 0x0000goto main

    REMAPED_RESET_VECTOR CODE 0x1000goto main

    REMAPED_HIGH_VECTOR CODE 0x1008bra ISRH

    REMAPED_LOW_VECTOR CODE 0x1018bra ISRL

    CODE 0x102A

    ISRH:; *** Interrupcin de alta prioridad

    retfie FAST

    ISRL:movff STATUS,STATUS_TEMP ;guarda el registro de estadomovff WREG,WREG_TEMP ;guarda el registro de trabajomovff BSR,BSR_TEMP ;guarda el registro BSR

    ; *** Interrupcin de baja prioridad ***

    movff BSR_TEMP,BSR ;restaura el registro BSRmovff WREG_TEMP,WREG ;restaura el registro de trabajomovff STATUS_TEMP,STATUS ;restaura el registro de estadoretfie

    main:clrf WREG

    ; *** La funcin principal va aqu ***ciclo

    goto ciclo

    END

    13

  • Instrucciones bsicas del lenguaje ensamblador

    Antes de ver las instrucciones veremos cuales son los comentarios en el lenguaje ensamblador. El lenguaje ensamblador toma como comentario cualquier texto que est despus de punto y coma.

    ;esto es un comentario

    Instruccin NOPEsta instruccin se utiliza para que el microcontrolador no realice operacin alguna.

    Se utiliza para hacer retardos de tiempo equivalentes a cuatro ciclos del oscilador principal.Su sintaxis es:NOPNo realiza operacin alguna.

    Instruccin MOVMueve datos de un registro a otro. Hay que tomar en cuenta que el los microcontro-

    ladores de Microchip usan el registro de trabajo para realizar este proceso. Este registro es llamado WREG o solamente W.

    La instruccin MOVLW 0x01 mueve el nmero 0x01 al registro de trabajo.

    La instruccin MOVWF REGISTRO mueve el contenido guardado en el registro de trabajo a cualquier otro registro.

    Ejemplo: Configurar el registro ADCON1 con 0x0F

    MOVLW 0x0FMOVWF ADCON1

    Ejemplo mover e nmero 0xF0 a la variable DATO1

    MOVLW 0xF0MOVWF DATO1

    La instruccin MOVF se usa para mover contenidos de registros a el mismo registro o al registro W. Su sintaxis es:

    MOVF REGISTRO, DESTINO

    14

  • 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 direccin de INTCON al registro de trabajo:

    MOVF INTCON, W

    Si colocamos MOVF INTCON, 1 movemos el contenido de ese registro al mismo re-gistro. No es muy til hacer esto a menos que sea necesario refrescar la memoria RAM.

    La instruccin MOVFF se usa mara mover el contenido de un registro a otro registro.

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

    MOVFF PORTB, DATO1

    Instruccin CLRFColoca a cero un registro.

    Ejemplo: Limpiar el registro de trabajo.

    CLRF WREG

    Instruccin SETLa instruccin SET se utiliza para colocar un todo el un registro con uno, como si co-

    locramos 0xFF al registro.

    Ejemplo: Colocar en uno todo el registro de trabajo.SET WREG

    Es idntico que hacer:

    MOVLW 0xFF

    GOTO y EtiquetasPara usar una etiqueta y GOTO necesitamos colocar sangras (tecla tabulador) y de-

    15

  • jar las etiquetas sin sangra y las instrucciones con sangra. Las etiquetas se colocan con nombre y puede o no llevar dos puntos al final, pero los dos puntos se recomiendan para fun-ciones 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 sangra.CLRF WREG ;cdigo con sangra

    infinito ;etiqueta sin sangraGOTO infinito ;ir a la etiqueta infinito (se hace un bucle infinito)

    Instruccin BCFLa instruccin BCF coloca un bit en cero de un registro especfico. El conteo de bits

    es desde del cero hasta el siete. Su sintaxis es la que a continuacin se muestra:

    BCF REGISTRO, BIT

    Ejemplo: Colocar el BIT 0 del registro PORTC en cero.BCF PORTC, 0

    Tambin podemos usar el nombre del bit, para eso, consultar el manual del micro-controlador y algunos de ellos sern explicados en este documento.

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

    BCF PORTC, RC0oBCF PORTC, 0

    Comparando ambos cdigos, es exactamente lo mismo.

    16

  • Instruccin BSFEs exactamente igual que BCF solo que este coloca en uno el bit indicado de el re-

    gistro deseado.

    Ejemplo: Colocar en uno el bit RA4 del registro PORTA.BSF PORTA, RA4

    Instruccin RLCFEsta instruccin realiza un giro a la izquierda de bits del contenido un registro cual-

    quiera pasando por la bandera Carry del registro STATUS. La instruccin que realiza la mis-ma operacin sin que pase por la bandera Carry del registro STATUS es RLNCF. Con esta instruccin el contenido ser el mismo pero desplazado un bit a la izquierda. Su sintaxis es:

    RLCF REGISTRO, DESTINORLNCF REGISTRO, DESTINODonde 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).

    Instruccin RRCFEsta instruccin realiza un giro a la derecha de bits del contenido de cualquier regis-

    tro pasando por la bandera Carry del registro STATUS. La instruccin que realiza la misma o-peracin sin que pase por la bandera Carry del registro STATUS es RRNCF. Con esta ins-truccin el contenido ser el mismo, pero desplazado a la derecha. Su sintaxis es:

    RRCF REGISTRO, DESTINORRNCF REGISTRO, DESTINODonde 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).

    Instruccin COMFRealiza 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 re-gistro W, si es 1, se guarda en el mismo registro (REGISTRO).

    17

  • Instruccin SWAPFCambia el nibble alto por el nibble bajo y viceversa. Su sintaxis es:SWAPF REGISTRO, DESTINODonde 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, 1Ahora registro contendr 53h.

    Instruccin CALLEsta instruccin manda a llamar a una subrutina. Las subrutinas son aquellas etique-

    tas 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

    Instruccin RETURNEsta instruccin se utiliza para regresar de una subrutina a la instruccin siguiente de

    la rutina principal. Solo se coloca RETURN al final de la subrutina. Vease el ejemplo anterior.Si queremos devolver algn valor en el registro de trabajo podemos finalizar la subru-

    tina con la palabra reservada RETLW. Su sintaxis es:RETLW LITERALDonde LITERAL puede ser cualquier valor dentro del rango 0 a 255. Este valor ser

    guardado en el registro W.

    Instruccin RETFIEEsta instruccin se utiliza para finalizar una subrutina de interrupcin. Si se finaliza la

    subrutina de interrupcin de alta prioridad, se coloca FAST frente a la palabra reservada RETFIE.

    18

  • Instruccin RESETRealiza un RESET desde el software. Se realiza exactamente lo mismo que si se

    presionara el botn MCLR en la tarjeta de pruebas del PIC.

    Comparadores

    Estas instrucciones sirven para comparar resultados o bits de estados de distintos re-gistros. Sirven para tomar decisiones acerca del comportamiento del programa y cambiar su flujo.

    Instruccin TSTFSZEsta instruccin comprueba que un registro sea cero; si es verdadero, salta una ins-

    truccin. Su sintaxis es:TSTFSZ REGISTRO

    Ejemplo: Comparar si el registro PORTB es cero.TSTFSZ PORTB;no es cero;es cero

    Instruccin CPFSEQEsta instruccin compara el registro W con cualquier otro registro. Salta si el conteni-

    do de los registros es idntico. Su sintaxis es:CPFSEQ REGITROEjemplo: Comparar PORTA con W.CPFSEQ PORTA;no son identicos;son idnticos

    Instruccin CPFSGTCompara si un registro con el registro W. Salta si el contenido del registro es ms

    grande que el contenido de W. Su sintaxis es:CPFSGT REGISTRO

    19

  • Ejemplo: Comparar si el contenido de un registro es mayor al contenido de W.CPFSGT REGISTRO;no es mayor;es mayor

    Instruccin CPFSLTCompara un registro con el registro W. Salta si el contenido del registro es ms pe-

    queo 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

    Instruccin BTFSCVerifica si un bit especfico de un registro es cero, en caso de que sea verdadero, sal-

    ta una instruccin.Ejemplo: Verificar que el bit RB4 del registro PORTB sea cero.

    BTFSC PORTB, RB4GOTO falsoGOTO verdadero

    En el ejemplo anterior, si la comparacin es falsa, lee la instruccin siguiente la cual es GOTO falso, donde falso es una etiqueta. Si es verdadero, salta la instruccin y lee la ins-truccin GOTO verdadero, donde verdadero es una etiqueta.

    Esta instruccin se utiliza para realizar comparaciones y tomar decisiones acerca de un bit especfico de un registro.

    Instruccin BTFSSEs idntico que la instruccin anterior. Verifica que un bit especfico de un registro

    sea uno, en caso de que sea verdadero, salta una instruccin.

    20

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

    BTFSS PORTB, RB5GOTO falsoGOTO verdadero

    En el ejemplo anterior, si la comparacin es falsa, lee la instruccin siguiente la cual es GOTO falso, donde falso es una etiqueta. Si es verdadero, salta la instruccin y lee la ins-truccin GOTO verdadero, donde verdadero es una etiqueta.

    Al igual que la instruccin anterior, tambin esta se utiliza para realizar comparacio-nes y tomar decisiones en cuanto un bit especfico de un registro.

    Operadores Lgicos

    Los operadores lgicos realizan las operaciones del lgebra booleana. Estas opera-ciones en ensamblador son AND, OR, XOR, que corresponden respectivamente a una opera-cin AND (Y), operacin INCLUSIVE OR (O inclusiva) y EXCLUSIVE OR (O exclusiva).

    Operacin ANDSe puede realizar de dos maneras: ANDWF y ANDLW. La primera realiza la opera-

    cin AND entre un registro y el registro W; la segunda, realiza la operacin AND entre el re -gistro W y una literal (un nmero). Sus sintaxis respectivas son:

    ANDWF REGISTRO, DESTINODonde DESTINO puede ser 0 o 1. Si es cero, se guarda en W, si es uno, se guarda

    en el mismo registro.ANDLW LITERALDonde LITERAL es un nmero del 0 al 255.

    Operacin ORIgual que la instruccin anterior, se puede realizar de dos maneas: IORWF o con la

    instruccin IORLW. La primera realiza al operacin OR entre un registro y el registro W, la segunda realiza la operacin 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.

    21

  • IORLW LITERALDonde LITERAL puede ser cualquier nmero del 0 al 255.

    Operacin XORLa operacin XOR al igual que las anteriores tiene dos formas de hacerse entre re-

    gistros y una a bit. Primero veamos la operacin XOR a registros.Se puede realizar de dos maneras: XORWF o XORLW. La primera realiza la opera-

    cin XOR entre el registro W y cualquier otro registro, la segunda realiza la operacin XOR entre un registro y una literal. Sus sintaxis respectivas son:

    XORWF REGISTRO, DESTINODonde destino puede ser 0 o 1. Si es cero, se guarda en W, si es uno, se guarda en

    el mismo registro.XORLW LITERALDonde LITERAL puede ser cualquier nmero del 0 al 255.Hay un caso particular en donde se puede realizar la operacin XOR a un bit. Lo que

    realiza esta instruccin es cambiar el estado de un bit, si es cero, lo cambia a 1, si es uno lo cambia a 0. Puede ser tambin visto como una negacin o una operacin toggle (refirindose a flip-flops). Esta instruccin es BTG. Su sintaxis es:

    BGT REGISTRO, BITDonde REGISTRO es cualquier registro y BIT, es el nmero de bit entre el 0 y el 7.Bsicamente se puede usar para realizar parpadeos o cambios de estado en un re-

    gistro.

    Operadores aritmticos

    Los operadores aritmticos se utilizan para sumar, restar y multiplicar nmeros y re-gistros. Tomar en cuenta que en ensamblador para PIC no existe la operacin DIVISIN, mas sin embargo, se puede realizar una operacin que la realice. Como la operacin mdulo depende de la operacin divisin, tampoco existe dentro de las operaciones bsicas del en-samblador.

    Una cosa muy importante que hay que tomar en cuenta es que al realizar operacio-nes aritmticas se generan cambios en el registro STATUS. Este registro de estado controla el resultado de una operacin aritmtica o lgica. Su descripcin la veremos ms adelante cuando veamos registros y lo explicaremos ampliamente por importancia.

    Operador NEGFEste operador sirve para convertir un nmero contenido en un registro a negativo o

    viceversa. Su sintaxis es:

    22

  • NEGF REGISTRODonde REGISTRO es cualquier registro que contiene un nmero entre el -128 a 127.

    Suma o adicinPara realizar la suma o adicin se suelen usar dos instrucciones: ADDWF para hacer

    la adicin 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, DESTINODonde 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 LITERALDonde LITERAL es cualquier nmero 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 sustraccinPara realizar la suma o sustraccin, se suelen usar dos instrucciones: SUBWF para

    hacer la sustraccin 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, DESTINODonde REGISTRO es cualquier registro y DESTINO toma el valor de 0 o 1. Si es ce-

    ro, se guardar el resultado en el registro W, si es uno, se guardara el resultado en el mismo registro.

    SUBLW LITERALDonde literal es cualquier nmero entre el 0 y el 255.

    MultiplicacinLa multiplicacin se realiza con dos instrucciones: MULWF para realizar la multiplica-

    cin entre el registro W y cualquier otro registro o MULLW para realizar la multiplicacin entre el registro W y una literal. Sus sintaxis respectivas son:

    MULWF REGISTROMULLW LITERALDonde LITERAL puede ser cualquier nmero del 0 al 255. Registro puede ser cual-

    quier registro de estado o memoria.

    23

  • NOTA: El resultado de esta operacin 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 opera-cin convencional o realizando su operacin con una comparacin. Explicar esto en cada caso.

    IncrementoLos 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 REGISTRODonde registro es cualquier registro de memoria.Para evitar que estemos comprobando el error de OVERFLOW en la bandera

    STATUS, tenemos una instruccin que lo hace por nosotros y cuando esto sucede, salta una instruccin. Esta instruccin tiene la palabra reservada INCFSZ que compara cuando el re-gistro vuelve a ser cero y como mencion anteriormente, salta la siguiente instruccin. INCFSNZ realiza lo mismo pero salta la siguiente instruccin si no es cero. Sus sintaxis respectivas son las siguientes:

    INCFSZ REGISTRO;No hay overflow;Hay overflow

    INCFSNZ REGISTRO;Hay overflow;No hay overflow

    DecrementosLos 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 siguien-te:

    DECF REGISTRODonde REGISTRO es cualquier registro de memoria.

    24

  • Hay una instruccin que comprueba automticamente cuando llega a cero, la cual es DECFSZ y salta la siguiente instruccin cuando esto sucede. DECFSNZ realiza la misma tarea pero salta la siguiente instruccin mientras no sea cero. Sus sintaxis son:

    DECFSZ REGISTRO;no es cero;es cero

    DECFSNZ REGISTRO;es cero;no es cero

    25

  • PROGRAMACIN BSICA DEL PIC18F4550

    Ahora en este apartado vamos a ver como se programa el PIC18F4550, pero antes vamos a ver una descripcin de los registros que vamos a utilizar en los primeros pasos.

    Registros bsicos del PIC18F4550

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

    Un registro es un mapeo en memoria RAM de algn dispositivo fsico del PIC, como son los puertos de entrada o salida, temporizadores, mdulo usb, modulo serial, modulo ADC, etc.

    Registro WREGEl 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 da -tos de subrutinas y de tablas.

    Registros TRISLos registros TRIS sirven para configurar puertos, lo explicar ms adelante. Hay

    cinco, que son el nmero 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 dems no tienen efecto.

    Registros PORTLos registros PORT sirven para leer y escribir puertos, y tambin lo explicar ms a-

    delante. Hay cinco, que son el nmero 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 exter-no (que es nuestro caso) el puerto A tendr dos pines menos los cuales son RA6 y RA7. Tambin estn desactivados de forma predeterminada los pines RC4 y RC5 ya que utilizan el mdulo USB y no est disponible RC3; esto nos deja el puerto C de bits, a menos que desactivemos el mdulo 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 por que

    26

  • dos se usan con el oscilador) se realiza lo siguiente:

    MOVLW 0x00MOVWF TRISA

    Configurar el puerto B como salida:

    MOVLW 0xFFMOVWF 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 dems 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 como se escribe y se leen los puertos.

    ESCRIBIR:

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

    LEER:

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

    27

  • O tambin 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 cdigo 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 consideracin importante es que cuando encendemos el microcontrolador PIC18F4550 los puertos son configurados como analgicos, para configurar los puertos como digitales tenemos que colocar 0x0F en el registro ADCON1. Ahora no lo explico porque lo vamos a ver ms adelante en Convertidor Analgico Digital.

    Antes que cualquier instruccin, se debe de limpiar el registro de trabajo W. Debe de ser la primera instruccin despus de la etiqueta main.

    Ahora veamos un pequeo programa. Colocar solo el cdigo que va dentro de la rutina principal llamada main para evitar colocar toda la plantilla.

    Ejemplo 1: Encender todo el puerto A.

    Solucin: Colocar 0xFF o 0x3F en el PORTA y en TRISA 0x00 o 0xC0, considerando los pines que no estn disponibles por el oscilador.

    Solucin 1.1main:

    CLRF WREG ;Limpiamos el registro de trabajo.MOVLW H'0F' ;Configuramos todos los puertos como digitalesMOVWF ADCON1CRLF TRISA ;Configuramos todo el puerto como salidaSETF PORTA

    cicloGOTO ciclo

    END

    28

  • Solucin 1.2main:

    CLRF WREG ;Limpiamos el registro de trabajo.MOVLW H'0F' ;Configuramos todos los puertos como digitalesMOVWF ADCON1MOVLW H'C0'MOVWF TRISAMOVLW H'3F'MOVWF PORTA

    cicloGOTO ciclo

    END

    Las dos soluciones nos dan el mismo resultado. Al escribir este cdigo en el pic con el HID Bootloader, veremos que se enciende todo el puerto. En nuestra placa de prueba, encendern RA4 y RA5.

    Ejemplo 2: Encender solo el pin RA4.

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

    Solucin 2.1main:

    CLRF WREGMOVLW H'0F'MOVWF ADCON1 ;Configuramos los puertos como digitalesCLRF TRISAMOVLW H'10'MOVWF PORTA

    cicloGOTO ciclo

    END

    29

  • Solucin 2.2main:

    CLRF WREGMOVLW H'0F'MOVWF ADCON1 ;Configuramos los puertos como digitalesCLRF TRISA ;Todo el puerto como salidaCLRF PORTA ;Ponemos el puerto A en cerosBSF PORTA, RA4 ;Encendemos RA4

    cicloGOTO cicloEND

    Los dos ejemplos realizan exactamente lo mismo. Como podemos ver, se puede co-locar todo el puerto como salida aunque no utilicemos el resto de los pines.

    Ejemplo 3: Verificar que el puerto B contenga el nmero 55h o AAh, en el primer ca-so, encender RC0, en el segundo caso encender RC1, cualquier otro caso apagar ambos pi-nes; los dos pines no pueden estar encendidos al mismo tiempo. Hacer la comprobacin de forma indefinida.

    Solucin: Colocar la comprobacin dentro del ciclo infinito. Utilizar la comparacin de igualdad CPFSEQ.

    main:CLRF WREGMOVLW H'0F'MOVWF ADCON1 ;Configuramos los puertos como digitalesCLRF TRISC ;Todo el puerto como salidaSETF PORTB ;Todo el puerto como entradaCLRF PORTC ;Ponemos el puerto C en ceros

    cicloMOVLW H'55'CPFSEQ PORTBGOTO comprueba2MOVLW H'01'MOVWF PORTCGOTO ciclo

    30

  • comprueba2MOVLW H'AA'CPFSEQ PORTBGOTO apagapuertoMOVLW H'02'MOVWF PORTCGOTO ciclo

    apagapuertoCLRF PORTCGOTO cicloEND

    Notemos que cada vez que realizamos un programa ms avanzado, va aumentando su tamao. Todo es dependiendo del objetivo a alcanzar. Hay que tener mucha lgica para realizar un programa para microcontrolador.

    Retardos

    Para realizar un retardo dentro de un programa podemos usar instrucciones NOP, que equivalen a 4 ciclos del oscilador principal, mas sin embargo, esta condicin no se cum-ple cuando usamos Bootloader, ya que realizamos un aumento en frecuencia para el uso de USB. La frecuencia necesaria para la comunicacin USB es de 48MHz.

    La frecuencia es una cuarta parte, por que cada instruccin se ejecuta en 4 ciclos del oscilador, por lo tanto, la frecuencia de una instruccin es de 12MHz.

    Sabemos tambin que el periodo es inverso de la frecuencia, as que, el tiempo que tarda en realizarse cada instruccin es de 83.33ns.

    T= 1f

    T= 148MHz

    =20.83ns

    Ti=4TTi=4x(20.83ns)=83.33ns

    Tomando en cuenta que cada instruccin toma 83.33ns, realicemos un retardo de 10s. Para ello tenemos que dividir 10s entre 83.33ns; esto nos dar un nmero, al cual le llamaremos nmero mgico de retardo, y lo simbolizaremos con #.

    #= 10 s83.33ns

    =120

    Entonces tenemos que realizar 120 instrucciones consecutivas para realizar el retar-do de 10s.

    31

  • Cmo vamos a realizar el retardo o demora? Usaremos decrementos.Primero vamos a generar una variable en RAM y le vamos a cargar el nmero m-

    gico, posteriormente vamos a realizar el decremento hasta llegar a cero. Esto nos garantiza que se realicen # instrucciones.

    Ejemplo: Realizar un programa que haga que el led RA5 parpadee cada 10s.

    Solucin: Realizar un retardo de 10s y usar BTG para hacer parpadear el led RA5.

    UDATA_ACSRETARDO RES 1 ;Reservamos memoria para el registro RETARDO;nos saltaremos esta parte de la plantillaretardo: ;Subrutina de retardo

    MOVLW .120 ;Colocamos 120 decimal en WREGMOVWF RETARDO ;Colocamos el valor de WREG en RETARDO

    decrementoDECFSZ RETARDO ;Realizamos el retardoGOTO decrementoRETURN

    main:CLRF WREGMOVLW H'0F'MOVLW ADCON1CLRF TRISACLRF PORTA

    cicloBTG PORTA, RA4CALL retardoGOTO cicloEND

    Como podemos observar en el ejemplo anterior, se realiz una subrutina que realiza el retardo de 10s.

    32

  • La divisin y el mdulo

    Como ya antes habamos mencionado, la divisin en ensamblador para el PIC18F4550 no existe. Nosotros tenemos que realizarla con un cdigo bastante pequeo.

    Vamos a las matemticas bsicas: La multiplicacin es una suma sucesiva de nme-ros y como la divisin es la operacin contraria, entonces por definicin es una resta sucesi-va. Esta operacin la realizaremos restando el divisor al dividendo, hasta que sea ms grande el divisor que el dividendo; en este momento tendremos el resultado que es el nme-ro de restas que hemos hecho. Si tomamos en cuenta que el mdulo es el residuo de la divi-sin, entonces el dividendo que queda al final ser el mdulo.

    Hagamos un algoritmo para la divisin y posteriormente lo pasaremos al lenguaje ensamblador.

    1. Tenemos una variable divisor y una dividendo.2. Verificamos que el dividendo sea mayor al divisor. Si es cierto seguir, si no ir al paso 6.3. Restar el divisor al dividendo.4. Incrementamos uno un contador.5. Ir al paso 2.6. El resultado de la divisin es el contador, el resultado del mdulo es el residuo del

    dividendo.7. Fin del algoritmo.

    Ahora hagamos la subrutina en ensamblador.

    UDATA_ACSDIVISOR RES 1 ;Reservamos memoria para el divisor.DIVIDENDO RES 1 ;Reservamos memoria para el dividendo.DIVISION RES 1 ;Reservamos memoria para el contador de la divisin.

    ;Nos saltaremos esta parte de la plantilla.

    division:CLRF DIVISION ;colocamos en cero el contador.MOVF DIVIDENDO, W ;Colocamos el valor del dividendo en W.

    comparadivCPFSLT DIVISOR ;Comparamos W con DIVISOR.GOTO hacerdivisionGOTO findivision

    33

  • hacerdivisionSUBWF DIVISOR, W ;Realizamos la resta. El resultado se guarda en W.INCF DIVISION ;Incrementamos el contador.GOTO comparadiv

    findivisionMOVF DIVISION, W ;Colocamos el resultado de la divisin en W.;El resultado se regresar en WREG.RETURN ;Fin del subproceso.

    Para el mdulo es exactamente lo mismo, solo cambiaremos el nombre de la sub-rutina, las etiquetas y el resultado.

    modulo:CLRF DIVISION ;colocamos en cero el contador.MOVF DIVIDENDO, W ;Colocamos el valor del dividendo en W.

    comparamoduloCPFSLT DIVISOR ;Comparamos W con DIVISOR.GOTO hacermoduloGOTO finmodulo

    hacermoduloSUBWF DIVISOR, W ;Realizamos la resta. El resultado se guarda en W.INCF DIVISION ;Incrementamos el contador.GOTO comparamodulo

    finmodulo;el resultado del mdulo est en W que es el sobrante de la resta.;El resultado se regresar en WREG.RETURN ;Fin del subproceso.

    Como podemos observar en los algoritmos anteriores, podemos realizar operaciones con las instrucciones bsicas del PIC.

    El display LCD alfanumrico

    El display LCD alfanumrico que mostrar en esta seccin, ser de 16 caracteres por dos lneas de matriz de 5x7. Realizar 4 subrutinas para hacer el proceso lo ms fcil posible; no voy a explicar estas subrutinas a fondo, solo mencionar como funcionan y qu

    34

  • es lo que hay que agregar en caso de requerir una funcionalidad extra. Explicar un archivo INC que contiene definiciones de las instrucciones del LCD. Para mayor informacin con-sultar el manual tcnico (data sheet) del LCD alfanumrico.

    Comencemos con el archivo LCD.INC. Este archivo contiene algunas constantes con instrucciones del LCD que controlan su funcionamiento.

    ;*****************************************; Autor: Garca Olmos Francisco Javier *; Fecha: 24 de Noviembre de 2011 *; Archivo: LCD.INC *; Biblioteca para el display LCD *;*****************************************

    ;Acciones del displayCLEAR EQU H'01'CURSOR_HOME EQU H'02'

    ;Control del display

    DISPLAY_CONTROL EQU H'08'DON EQU H'04'CURSOR_ON EQU H'02'BLINK_ON EQU H'01'

    ;Modo de entrada

    DISPLAY_MODE EQU H'04'INCREMENT EQU H'02'SHIFT EQU H'01'

    ;Shift_Cursor DisplaySHIFT_CUR_LEFT EQU H'13'SHIFT_CUR_RIGHT EQU H'17'SHIFT_DISP_LEFT EQU H'1B'SHIFT_DISP_RIGHT EQU H'1F'

    ;Function SetFUNCTION_SET EQU H'20'EIGHT_BIT EQU H'10'LINE_5x7 EQU H'03'LINE_5x10 EQU H'07'LINES_5x7 EQU H'0B'

    DDRAM_L1 EQU H'80'DDRAM_L2 EQU H'C0'DDRAM_L3 EQU H'90'DDRAM_L4 EQU H'D0'

    Ahora mostrar las subrutinas, las cuales se usarn en el proceso de escritura y configuracin del LCD alfanumrico.

    35

  • ;Variables necesarias para el funcionamiento del LCD alfanumrico.UDATA_ACS

    DATO RES 1DATOTEMP RES 1RTMUL RES 1RETARDO1 RES 1RETARDO2 RES 1

    ;Nos saltaremos esta parte de la plantilla

    ;Funciones para escritura y configuracin del LCD alfanumrico.Delay1K:

    retardo0DECFSZ RTMULgoto retardo1goto finretardo

    retardo1MOVLW .100MOVWF RETARDO1

    ciclo1DECFSZ RETARDO1GOTO retardo2GOTO retardo0

    retardo2MOVLW .10MOVWF RETARDO2

    ciclo2DECFSZ RETARDO2GOTO ciclo2GOTO ciclo1

    finretardoRETURN

    Comando_LCD:MOVFF DATO, DATOTEMPRRCF DATORRCF DATORRCF DATORRCF DATOMOVFF DATO, PORTDBCF PORTD, RD4BCF PORTD, RD5BSF PORTD, RD6MOVLW .60MOVWF RTMULCALL Delay1KBCF PORTD, RD6MOVFF DATOTEMP, PORTDBCF PORTD, RD4BCF PORTD, RD5BSF PORTD, RD6MOVLW .60MOVWF RTMULCALL Delay1KBCF PORTD, RD6RETURN

    36

  • Dato_LCD:MOVFF DATO, DATOTEMPRRCF DATORRCF DATORRCF DATORRCF DATOMOVFF DATO, PORTDBSF PORTD, RD4BCF PORTD, RD5BSF PORTD, RD6MOVLW .60MOVWF RTMULCALL Delay1KBCF PORTD, RD6MOVFF DATOTEMP, PORTDBSF PORTD, RD4BCF PORTD, RD5BSF PORTD, RD6MOVLW .60MOVWF RTMULCALL Delay1KBCF PORTD, RD6RETURN

    Inicializa_LCD:MOVLW .137MOVWF RTMULCALL Delay1KMOVLW 0x02MOVWF PORTDBSF PORTD, RD6MOVLW .60CALL Delay1KBCF PORTD, RD6MOVLW .187MOVWF RTMULCALL Delay1KMOVLW FUNCTION_SETIORLW LINES_5x7MOVWF DATOCALL Comando_LCDMOVLW DISPLAY_CONTROLIORLW DONMOVWF DATOCALL Comando_LCDMOVLW CLEARMOVWF DATOCALL Comando_LCDMOVLW DISPLAY_MODEIORLW INCREMENTMOVWF DATOCALL Comando_LCDRETURN

    Las cuatro subrutinas son muy fciles de entender, mas sin embargo, ser tarea ex-tra, ya que por motivos de tiempo y espacio, no podr hacer en este documento, solo explica-

    37

  • r su funcionamiento.La funcin Delay1K sirve para darnos un retardo de 1000 ciclos de mquina (4 de os-

    cilador principal). Esta funcin recibe un parmetro dentro del registro RTMUL que ser el multiplicador, entonces ser un retardo de RTMUL por mil ciclos de mquina.

    La subrutina Comando_LCD recibe un parmetro en el registro DATO y lo escribe en el LCD en forma de comando. La subrutina Dato_LCD tambin recibe un parmetro en el re-gistro DATO pero este lo escribir en el LCD como un DATO y se mostrar.

    La subrutina Inicializa_LCD no recibe parmetros. Sirve para configurar el LCD como un Display LCD de 16x2, de matriz de 5x7 y de incremento automtico. No se mostrar el cursor y no parpadear el caracter. Si se necesitan estas funciones, cambiarlas en esta subrutina.

    Procedimiento para escribir en el LCD:1. Inicializar el LCD.2. Limpiar pantalla.3. Moverse a la posicin deseada.4. Escribir.

    Bueno, entonces hagamos un pequeo programa que muestre HOLA en la pantalla pero antes mencionar que se conectar al puerto D.

    Ejemplo 1: Mostrar HOLA en el LCD de 16x2.

    Solucin: Utilizar las funciones explicadas anteriormente, as como el procedimiento.; *** Aqu van los registros de memoria ***; *** Saltaremos esta parte de la plantilla ***; *** Aqu van las subrutinas o funciones del LCD ***main:

    CLRF WREGMOVLW H'0F'MOVWF ADCON1CLRF TRISDCLRF PORTDCALL Inicializa_LCD ;Inicializamos el LCD.MOVLW CLEAR ;Instruccin para limpiar en el LCD (ver LCD.INC).MOVWF DATO ;Movemos al parmetro DATO.CALL Comando_LCDMOVLW DDRAM_L1 ;Instruccin para moverse a la lnea 1ADDLW .6 ;Sumamos 6 para desplazarnos 6 caracteres y centrar el texto.MOVWF DATO ;Movemos al parmetro DATO.CALL Comando_LCDMOVLW 'H'MOVWF DATOCALL Dato_LCDMOVLW 'O'

    38

  • MOVWF DATOCALL Dato_LCDMOVLW 'L'MOVWF DATOCALL Dato_LCDMOVLW 'A'MOVWF DATOCALL Dato_LCDCLRF PORTD ;Limpiamos el puerto D.

    cicloGOTO ciclo

    END

    Se puede observar que lo ms complicado de entender son los comandos, los datos se mandan consecutivamente sin mayor problema. Un punto importante es que se realiz una suma de 6 para desplazar la memoria y centrar el texto. Si no hubiramos hecho esta suma, el texto hubiera aparecido desde el primer carcter en el LCD.

    Ahora veamos las conexiones del LCD. El LCD tiene dos pines de alimentacin, uno de contraste, tres de control, ocho de datos y dos extras en caso de que tenga luz de fondo (back light).

    VSS y VDD se conectan a +5V y tierra, y el contraste VEE se conecta a un potencimetro de 10K, el pin 4 de control RS (decide si es dato o comando) a RD4, el pin 5 de control RW (lectura / escritura) va conectado a RD5 o a tierra, el pin 6 de control E (habilitado) a RD6. De los siguientes ocho pines de datos solo se utilizarn los ltimos 4 (D4, D5, D6, D7) que van conectados a RD0, RD1, RD2, y RD3; los pines D0, D1, D2 y D3 no se conectan. En caso de luz de fondo se conectaran a +5V y tierra los ltimos pines.

    El siguiente diagrama muestra la forma de conexin del LCD alfanumrico de 16x2.

    Forma de conectar el LCD alfanumrico de 16x2 sin luz de fondo.

    39

  • PROGRAMACIN CON INTERRUPCIONES

    En este captulo veremos la programacin con interrupciones, veremos ms profun-damente las direcciones de los vectores de interrupcin y las rutinas ISRL e ISRH. Veremos los registros INTCON y RCON que son los relacionados con las interrupciones.

    Primero explicar que es una interrupcin. Bsicamente es una peticin que se le ha-ce al microprocesador o microcontrolador (no son lo mismo) para que deje la tarea principal y haga una tarea especfica. Un ejemplo de una interrupcin es el RESET, que deja la tarea principal para reiniciar la memoria del microcontrolador.

    Clasificacin de las interrupciones

    Se pueden clasificar las interrupciones de tres formas distintas: Por enmascaramien-to, por prioridad y por su locacin.

    Clasificacin por enmascaramientoHay dos tipos de interrupciones: enmascarables y no enmascarables.

    1. Las interrupciones enmascarables son aquellas donde el microcontrolador puede decidir si la puede atender o no (enmascara la interrupcin).

    2. Las interrupciones no enmascarables son aquellas que forzosamente se tienen que atender, por ejemplo, el RESET.

    Clasificacin por prioridadHay dos tipos de interrupciones: de alta prioridad y de baja prioridad.

    1. Las interrupciones de alta prioridad son aquellas que no pueden interrumpirse mien-tras son atendidas.

    2. Las interrupciones de baja prioridad si pueden interrumpirse por otras mientras son atendidas, mas sin embargo su tiempo de respuesta es ms amplio que el de una de alta prioridad.

    Clasificacin por locacinHay tres tipos de interrupciones: Internas, cambio de flanco y externas.

    1. Las interrupciones internas son las que se provocan por los dispositivos embebidos en el microcontrolador, como son temporizadores, ADC, USB, USART, Comparadores, etc.

    2. La interrupcin por cambio de flanco es aquella que se activa al cambiar el estado del

    40

  • nibble alto del puerto B.3. Las interrupciones externas son las que se provocan al activar los tres primeros pines

    del puerto B (RB0, RB1 y RB2); se identifican como INT0, INT1 e INT2. INT0 siempre es de alta prioridad.

    Vectores de interrupcin

    Antes de comenzar, explicar que es un vector. En algunos lenguajes de programa-cin como C ANSI, C++, BASIC, etc, se pueden realizar vectores de datos y se manejan los datos a travs de un apuntador, el cual contiene una direccin de memoria. Nosotros nos referiremos a un vector de interrupcin a la posicin de memoria a la cual el microcontrolador se va a referir cuando se realice una interrupcin. En los microcontroladores PIC18 hay 3 vectores de interrupcin: RESET, alta prioridad y baja prioridad. Abajo explicare sus direccio-nes:

    0x0000 MCLR Vector de interrupcin de RESET.0x0008 ISRH Vector de interrupcin de alta prioridad.0x0018 ISRL Vector de interrupcin de baja prioridad.

    Estas direcciones se cargan automticamente en el stack de direcciones al realizarse una interrupcin. Mas sin embargo, cuando trabajamos con el BOOTLOADER, estas direcciones cambian.

    0x1000 REMAPED MCLR Vector remapeado de RESET.0x1008 REMAPED ISRH Vector remapeado de alta prioridad.0x1018 REMAPED ISRL Vector remapeado de baja prioridad.

    Como observamos, son las que estn en nuestra plantilla. Podramos hacer la rutina de interrupcin en esta direccin pero el espacio es muy pequeo, lo que realizamos es un salto a las rutinas llamadas main, ISRH e ISRL. En estas rutinas, ya podemos extendernos lo que sea necesario, siempre y cuando nos alcance la memoria de programa del microcontro -lador PIC.

    Declaramos dichos vectores con CODE o con ORG como ya lo habamos mencionado anteriormente.

    REMAPED_RESET_VECTOR CODE 0x1000goto main ;saltamos a la rutina main.

    41

  • Configurar las interrupciones

    Las interrupciones se configuran cambiando sus bits especficos en los registros de interrupcin INTCON, INTCON2, INTCON3, PIR1, PIR2, IPR1, PIR2, PIE1 y PIE2. Para las interrupciones externas y de cambio de flanco se usan solo los tres primeros registros men-cionados anteriormente. La nica interrupcin que no se configura es RESET.

    El mtodo que se utiliza es el siguiente:1. Borramos la bandera (FLAG) de interrupcin.2. Le damos una prioridad ya sea alta o baja, excepto INT0 que es de alta prioridad.3. Habilitamos la interrupcin.4. Habilitamos las interrupciones globales con RCON.5. Habilitar las prioridades globales de las interrupciones con INTCON.

    Las interrupciones globales son todas aquellas interrupciones enmascarables que hay dentro del microcontrolador. Se activan colocando el bit IPEN del registro RCON en uno. Las prioridades globales se activan colocando en uno el bit GIEH para las interrupciones de alta prioridad y GIEL para las interrupciones de baja prioridad o ambas del registro INTCON.

    Las interrupciones externas tienen que configurar tambin el flanco en el cual estas trabajan; este flanco puede ser de subida o de bajada, esto significa que al presionar un botn, el voltaje cambia de bajo a alto para subida o de alto a bajo para bajada.

    Una configuracin adicional es el uso de resistencias PULL-UP. Estas resistencias realizan que el puerto B siempre est estado alto y evitan que se usen resistencias fuera del microcontrolador. Se activan colocando el bit RBPU en cero del registro INTCON2. Al utilizar estas resistencias, el flanco de las interrupciones externas debe de ser de bajada y el botn debe de estar conectado a tierra para hacer un cambio a estado bajo.

    Para mayor referencia de los registros INTCON, RCON y los dems mencionados anteriormente, revisar el manual.

    Revisar las interrupciones

    Cuando una interrupcin se ha realizado, se enciende la bandera (FLAG) respectiva de cada interrupcin. Dependiendo de la configuracin verificamos que se ha realizado la interrupcin en las rutinas ISRH o ISRL.

    La interrupcin externa INT1 tiene su bandera (FLAG) en INTCON. El bit se llama INT0IF y est en cero mientras no se ha producido la interrupcin y cambia a uno cuando se ha realizado. Una accin muy importante es borrar la bandera de forma manual para evitar que se realice el proceso de interrupcin cuando no se ha interrumpido el microcontrolador por esta interrupcin.

    42

  • Ejemplo: Revisar si se realiz la interrupcin INT1 como interrupcin de baja prioridad.

    ISRL:movff STATUS,STATUS_TEMP ;guarda el registro de estadomovff WREG,WREG_TEMP ;guarda el registro de trabajomovff BSR,BSR_TEMP ;guarda el registro BSR

    btfss INTCON3, INT1IF ;Revisar si se realiz por INT1goto finintl ;No se realiz por INT1;si se realiz por INT1bcf INTCON3, INT1IF ;Borrar la bandera;Seguir con el proceso de interrupcin.

    finintlmovff BSR_TEMP,BSR ;restaura el registro BSRmovff WREG_TEMP,WREG ;restaura el registro de trabajomovff STATUS_TEMP,STATUS ;restaura el registro de estadoretfie

    Como podemos observar, hay que conservar el cdigo que recupera los estados de BSR, WREG y STATUS, ya que son necesarios para otras operaciones. Observamos tambin que se utiliz el comparador de bits BTFSS y el cambio de estado de bit a cero con la instruccin BCF.

    Si hubiera ms interrupciones habra que hacer el mismo procedimiento para cada una de ellas.

    Interrupciones externas

    En este apartado me enfocar solamente en las interrupciones externas. Realizar el cdigo de configuracin de las tres interrupciones y posteriormente realizar su verificacin en las subrutinas ISRH e ISRL.

    Ejemplo 1: Realizar la configuracin de las interrupciones externas con resistencias de pull-up y flanco de bajada. INT1 es de alta prioridad e INT2 es de baja prioridad. Colocar el Puerto C como salida.

    Solucin 1: Realizar el procedimiento de configuracin de las interrupciones toman-do en cuenta que INT0 siempre es de alta prioridad. Colocar el puerto B como entrada y el puerto C como salida colocando TRISB en uno y TRISC en cero.

    43

  • main:clrf WREGmovlw H'0F'movwf ADCON1 ;configuramos los puertos como digitales.setf TRISB ;Puerto B como entrada.clrf TRISC ;Puerto C como salida.clrf PORTC ;Puerto C apagado.

    ; *** Configuramos las interrupciones ***

    ;INT0BCF INTCON, INT0IF ;Limpiamos la bandera IF.BCF INTCON2, INTEDG0 ;Flanco de bajada.BSF INTCON, INT0IE ;Habilitamos la interrupcin.

    ;INT1BCF INTCON3, INT1IF ;Limpiamos la bandera IF.BCF INTCON2, INTEDG1 ;Flanco de bajada.BSF INTCON3, INT1IP ;INT1 de alta prioridad (IP=1).BSF INTCON3, INT1IE ;Habilitamos la interrupcin.

    ;INT2BCF INTCON3, INT2IF ;Limpiamos la bandera IF.BCF INTCON2, INTEDG2 ;Flanco de bajada.BCF INTCON3, INT2IP ;INT2 de baja prioridad (IP=0).BSF INTCON3, INT2IE ;Habilitamos la interrupcin.

    ;Resistencias de PULL-UPBCF INTCON2, RBPU

    ;Interrupciones GlobalesBSF RCON, IPEN ;Habilitamos las interrupciones globales.BSF INTCON, GIEH ;Habilitamos las interrupciones globales de alta prioridad.BSF INTCON, GIEL ;Habilitamos las interrupciones globales de baja prioridad.

    ciclogoto ciclo ;ciclo infinito

    END

    Del ejemplo anterior marque las configuraciones alta y baja prioridad. Ver como cambia BSF por BCF.

    Ejemplo 2: Usar INT0 para encender RC0, INT1 para encender RC1 e INT2 para apagar ambos bits.

    Solucin 2: Verificar las interrupciones en las rutinas de alta y baja prioridad con BTFSS. Utilizar BCF y BSF para apagar y encender bits.

    44

  • ISRH:btfss INTCON, INT0IF ;Revisamos si se produjo INT0.goto revisaint1bcf INTCON, INT0IF ;Limpiamos la bandera.bsf PORTC, RC0 ;Encendemos RC0.

    revisaint1btfss INTCON3, INT1IF ;Revisamos si se produjo INT1.goto finisrhbcf INTCON3, INT1IF ;Limpiamos la bandera.bsf PORTC, RC1 ;Encendemos RC1.

    finisrhretfie FAST

    ISRL:movff STATUS,STATUS_TEMP ;guarda el registro de estadomovff WREG,WREG_TEMP ;guarda el registro de trabajomovff BSR,BSR_TEMP ;guarda el registro BSR

    btfss INTCON3, INT2IF ;Revisar si se realiz por INT1goto finisrl ;No se realiz por INT1bcf INTCON3, INT2IF ;Borrar la banderaclrf PORTC ;Apagamos el puerto

    finisrlmovff BSR_TEMP,BSR ;restaura el registro BSRmovff WREG_TEMP,WREG ;restaura el registro de trabajomovff STATUS_TEMP,STATUS ;restaura el registro de estadoretfie

    En este ejemplo vemos el cambio de verificacin entre rutinas de baja y alta prioridad y la forma en la que se realizan los procedimientos requeridos para sus tareas respectivas.

    Interrupcin del puerto B por cambio de flanco

    Esta interrupcin se activa cuando cambiamos el estado del nibble alto del puerto B (RB4, RB5, RB6 y RB7). Se activa cuando pasamos de estado bajo a alto y cuando pasamos de estado alto a bajo, por eso su nombre de cambio de flanco.

    La interrupcin al igual que las interrupciones externas, se configura y se le asigna prioridad sus respectivos bits y segn su prioridad, se verifica con su bandera (RBIF).

    Ejemplo 1: Configurar la interrupcin de cambio de flanco como interrupcin de alta prioridad. Utilizar resistencias de PULL-UP. Configurar el puerto C como salida.

    Solucin 1: Realizar el procedimiento para configurar interrupciones. Se tiene que configurar el puerto B como entrada.

    45

  • main:clrf WREGmovlw H'0F'movwf ADCON1 ;Configuramos todos los puertos digitales.setf TRISB ;Puerto B como entrada.clrf TRISC ;Puerto C como salida.clrf PORTC ;Apagamos el puerto.

    ;Configuracin de las interrupciones

    ;Interrupcin de cambio de flancobcf INTCON, RBIF ;Limpiamos la bandera.bsf INTCON2, RBIP ;Le asignamos prioridad alta.bsf INTCON, RBIE ;Habilitamos la interrupcin.

    ;Ressitencias de PULL-UPbcf INTCON2, RBPU ;Habilitamos las resistencias de pull up.

    ;Interrupciones globalesbsf RCON, IPEN ;Habilitamos prioridades en interrupciones.bsf INTCON, GIEH ;Habilitamos la interrupciones de alta prioridad.;No es necesario habilitar las interrupciones globales de baja prioridad;por que no las usaremos.

    ciclogoto ciclo ;ciclo infinito

    Como observamos en los comentarios, no activamos las interrupciones de baja prioridad ya que no las vamos a usar.

    Ejemplo 2: Revisar si se provoc una interrupcin por cambio de flanco. Si sucedi, verificar que botn fue apretado. RB4 encender o apagar segn el estado de RC0, RB5 encender o apagar segn el estado de RC1, RB6 cambiar el estado de cada Led y RB7 apagar los Leds.

    Solucin 2: Verificar con BTFSS que haya sucedido la interrupcin y con BTFSC verificar que botn est en cero (estado apretado). Tomar en cuenta que se utiliza lgica negativa por el uso de las resistencias de PULL-UP.

    IRSH:btfss INTCON, RBIF ;Verificar si se produjo la interrupcin RB.goto finisrh ;Ir al final de la rutina de interrupcin.bcf INTCON, RBIF ;Borrar la bandera.btfsc PORTB, RB4 ;Verificar si se apret el botn RB4.goto revisarb5 ;Revisar el siguiente botn.btg PORTC, RC0 ;Cambiar el estado de RC0goto finisrh ;Ir al final de la rutina de interrupcin.

    revisarb5btfsc PORTB, RB5 ;Verificar si se apret el botn RB5.goto revisarb6

    46

  • btg PORTC, RC1goto finisrh

    revisarb6btfsc PORTB, RB6 ;Verificar si se apret el botn RB6.goto revisarb7btg PORTC, RC0 ;Cambia el estado de RC0.btg PORTC, RC1 ;Cambia el estado de RC1.goto finirsh

    revisarb7btfsc PORTB, RB7 ;Verificar si se apret el botn RB7.goto finisrh ;Ir al final de la rutina de interrupcin.clrf PORTC

    finisrhretfie FAST

    Como podemos observar, adems de preguntar por la interrupcin, hay que pregun-tar por el botn que se ha apretado. Como usamos lgica negativa, cuando se presiona un botn, el bit queda en estado bajo y el microcontrolador lo reconoce como cero lgico.

    Qu pasa si se aprietan dos botones al mismo tiempo? Pues viendo el algoritmo, el ms bajo ser el que reconozca como apretado, el otro, ser desechado. Tambin podramos usar operaciones AND para ver si se apretaron dos al mismo tiempo. Sin embargo por falta de espacio y de tiempo, ser tarea adicional del lector hacerlo.

    A partir de ahora, todo lo que veamos ser programado con interrupciones. Todos los mdulos embebidos en el microcontrolador tienen interrupciones y se verificarn y configura-rn exactamente igual que como lo hicimos con estas dos interrupciones.

    47

  • PROGRAMACIN DE HARDWARE INTERNO Y EXTERNO

    En este captulo ensear a programar hardware externo e interno. Como hardware externo, ensear el uso de Display de 7 segmentos, teclado matricial de 4x4 y como conec-tar transistores, puente H y compuertas lgicas con el PIC18F4550. Como hardware interno ensear a programar los temporizadores y contadores, as como el mdulo ADC.

    Tablas

    Antes de comenzar, me gustara ver un tema un poco complicado pero que nos ahorrar mucho cdigo a la hora de realizar codificaciones: Las tablas.

    Qu son las tablas? Son estructuras de datos guardados en la memoria de progra-ma ROM (flash en el caso de PIC18F). Es una alternativa a los apuntadores, ya que el uso de apuntadores es ms complicado an que las tablas. Esto tambin nos ayuda a ahorrar memoria RAM, pues es bastante reducida en caso de microcontroladores PIC18.

    Cmo funciona una tabla? Realizamos retorno de literales ordenadas una tras otra, y saltamos las instrucciones necesarias para obtener el resultado requerido. Para realizar esta operacin utilizamos el registro PC (Program Counter) que es registro que maneja la memoria de programa.

    Le sumaremos al PCL (Program Counter Low Byte) el nmero de instrucciones que queremos que salte, pero tomando en cuenta que cada instruccin toma 2 direcciones de memoria, entonces debern de ser el nmero de saltos por dos. Tomar en cuenta que si multiplicamos por dos, el nmero mximo de saltos deber ser de 127.

    Para realizar una tabla utilizaremos el registro W para colocar el nmero de instruc-ciones que deseamos saltar y realizaremos una subrutina que realice este procedimiento.

    Ejemplo 1: Realizar una tabla que retorne el nmero en BCD (Cdigo para display de 7 Segmentos) del 0 al 9.

    Solucin 1: Realizar una subrutina que realice la suma al registro PCL y retorne el nmero en BCD.

    tabla_bcd:mullw H'02'movf PRODL, W ;Movemos el resultado de la multiplicacin a Waddwf PCL, F ;Hacer la suma de W con PCL y guardarla en el mismo registro PCLretlw H'3F' ;Cero en BCDretlw H'06' ;Uno en BCDretlw H'5B' ;Dos en BCD

    48

  • retlw H'4F' ;Tres en BCDretlw H'66' ;Cuatro en BCDretlw H'6B' ;Cinco en BCDretlw H'7B' ;Seis en BCDretlw H'87' ;Siete en BCDretlw H'EF' ;Ocho en BCDretlw H'6F' ;Nueve en BCD

    Como vemos, es fcil realizar la tabla, pero lo difcil es colocarla en el lugar correcto del cdigo para que funcione, ya que el PCL es 1 byte (8 bits) y solo podr contar hasta el 255. No habr problema si estamos en un lugar que est entre el 0 y el 246 de PCL, pero si lo har si rebasamos este lmite. Es recomendable hacer tablas pequeas y colocadas exac-tamente al principio del cdigo (Antes de las rutinas de Interrupcin).

    Ahora veamos como recuperar el cdigo. Solo colocar el algoritmo.

    Ejemplo 2: Realizar el algoritmo de interrupcin de INT0. Para que cada vez se pre-sione, aumente un contador hasta el 9, llegando a este punto, reiniciarlo. Mostar el resultado en BCD en el puerto D.

    Solucin 2: Realizar el algoritmo en ISRH comprobando la interrupcin INT0, reali-zando comparaciones, incrementos y llamando a la tabla tabla_bcd realizada anteriormente.

    ISRH:btfss INTCON, INT0IF ;Comprobar si se realiz la interrupcin.goto finisrhbcf INTCON, INT0IF ;Limpiar la banderamovlw H'09'cpfseq CONTADORgoto aumentaclrf CONTADOR ;Coloca cero en contador.goto muestra

    aumentaincf CONTADOR

    muestramovf CONTADOR, W ;Copiamos el contenido de CONTADOR a W.call tabla_bcd ;Llamar a la tabla.movwf PORTD ;Colocar el valor devuelto de la tabla en PORTD.

    finisrhretfie FAST

    Con este pequeo algoritmo, hemos realizado un contador con interrupciones y un display de 7 segmentos.

    Nota 1: Como estamos usando lgica positiva, solo podemos usar un display de 7 segmentos de ctodo comn. Utilizar lgica negativa en la tabla para usar un display de no-do comn o utilizar un inversor externo 74LS04 o 74HS04.

    Nota 2: PRECAUCIN, el PIC18F4550 solo puede manejar corrientes inferiores a

    49

  • los 25mA, si superamos esta corriente podemos quemar el pin, puerto o todo el microcontro-lador. Para realizar operaciones con ms corrientes utilizar BUFFER de corriente (74LS245), Inversores (74LS04) o transistores en forma de interruptor.

    Teclado Matricial

    El teclado matricial que demostrar en este apartado, es uno de 4x4 (16 teclas). Utilizaremos para su decodificacin la interrupcin de cambio de nivel y la mitad del puerto B como salida. Este teclado tiene 4 filas y cuatro columnas, lo cual nos da un nmero de 8 lneas de datos (cables de alimentacin).

    Todas las lineas de alimentacin del teclado irn al puerto B. La mitad alimentar al teclado y la otra mitad realizar la interrupcin de cambio de nivel cuando una tecla se pre-sione, para ello es necesario activar las resistencias de PULL-UP y colocar el primer nibble en cero. Cuando se realice una interrupcin se tendr que colocar el puerto en 1 e ir cam-biando el cero de lugar hasta obtener la tecla que se presion. La comprobacin se hace en cero por el uso de resistencias de PULL-UP, entonces se utiliza la lgica negativa.

    Procedimiento:1. El primer paso es colocar en cero el nible bajo o todo el puerto B.2. Al presionar una tecla se interrumpe el microcontrolador.3. Colocar el nible bajo en uno o todo el puerto B.4. Colocar un cero en el bit 0 del puerto B. Si est la tecla, verificar el cdigo en el nibble

    alto para decodificarla y finalizar, en caso contrario, seguir al paso 5.5. Colocar un cero en el bit 1 del puerto B. Si est la tecla, verificar el cdigo en el nibble

    alto para decodificarla y finalizar, en caso contrario, seguir al paso 6.6. Colocar un cero en el bit 2 del puerto B. Si est la tecla, verificar el cdigo en el nibble

    alto para decodificarla y finalizar, en caso contrario, seguir al paso 7.7. Colocar un cero en el bit 3 del puerto B. Decodificar la tecla usando el nibble alto. Si

    no se encuentra, se ha dejado de apretar la tecla, entonces, salir.

    Recordemos que al dejar de presionar la tecla se vuelve a realizar la interrupcin por el cambio de flanco, en este caso, no decodificaremos nada y tenemos que salir sin mostrar nada.

    Para decodificar las teclas se verifica que pin se apaga. Utilizar el nibble bajo como multiplicador el nibble alto como sumador. El nible bajo codifica filas y el alto codifica colum-nas. Ejemplo: La tecla 8 est en la posicin 9 tomando como referencia la posicin inicial co-mo cero (es la dcima tecla); est en la fila 3 columna 2.

    Encontraremos presionada la tecla cuando el cero est en RB2 (fila 3) y el pin que se activar ser RB5 (columna 2). Entonces tendramos que realizar una multiplicacin de filas 1 por cuatro (nmero de filas) y sumar columnas 1. Tecla = ((Columnas 1) * 4)+ (Filas 1) = (3 1) * 4 + (2 1) = (2 * 4) + 1 = 8 + 1 = 9.

    50

  • Si realizamos una tabla con valores ASCII (diferentes a los BCD) y recorremos el nmero de tecla y lo mostramos en el LCD alfanumrico, tendremos las teclas decodificadas.

    Aqu dejo una imagen del teclado matricial para que vean cuales son las teclas que tiene y cual es el orden que tienen cada una de ellas.

    En el mercado se puede encontrar el teclado matricial con letras en vez de los sm-bolos de operaciones aritmticas, en su lugar, letras A, B, C, D, * en vez de ON/C y # en vez de igual. Sin embargo, dependiendo de la codificacin que le demos ser la ejecucin que realizar. En nuestro caso, solo se mostrar la tecla en el LCD alfanumrico.

    Realicemos un programa completo. En este programa pondremos a prueba todo lo a-prendido en los temas anteriores y algo de imaginacin, as como algunos trucos para su realizacin.

    Ejemplo 1: Realizar el programa de decodificacin del teclado matricial en una interrupcin de cambio de flanco de alta prioridad, realizar la tabla de decodificacin de cdigo ASCII para el teclado mostrado arriba y el cdigo para mostrar en el LCD.

    Solucin 1: Realizar un programa completo que incluya tablas, LCD, variables e in-terrupciones. La decodificacin se deber realizar con el procedimiento mencionado anterior-mente.

    Nota: Para evitar perdernos en el programa, ordenaremos las instrucciones en sub-rutinas. De ahora en adelante el lector debera tomar este hbito para hacer el cdigo ms e-legante.

    51

  • ;***********************************************************************; Autor: Francisco Javier Garca Olmos *; Fecha: 11 de Enero de 2012 *; Archivo: teclado.asm *; Descripcin: Programa para decodificar el teclado matricial *;***********************************************************************

    LIST P=18F4550, F=INHX32#include #include

    ;******************************************************************************;Bits de configuracin

    CONFIG PLLDIV = 5 CONFIG CPUDIV = OSC1_PLL2CONFIG USBDIV = 2 CONFIG FOSC = HSPLL_HSCONFIG FCMEN = OFFCONFIG IESO = OFFCONFIG PWRT = OFFCONFIG BOR = ONCONFIG BORV = 3CONFIG VREGEN = ON config WDT = OFFconfig WDTPS = 32768config MCLRE = ONconfig LPT1OSC = OFFconfig PBADEN = OFF config CCP2MX = ONconfig STVREN = ONconfig LVP = OFFconfig ICPRT = OFF config XINST = OFF config CP0 = OFFconfig CP1 = OFFconfig CP2 = OFFconfig CP3 = OFFconfig CPB = OFFconfig CPD = OFFconfig WRT0 = OFFconfig WRT1 = OFFconfig WRT2 = OFFconfig WRT3 = OFFconfig WRTB = OFF config WRTC = OFFconfig WRTD = OFFconfig EBTR0 = OFFconfig EBTR1 = OFFconfig EBTR2 = OFFconfig EBTR3 = OFFconfig EBTRB = OFF

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

    52

  • ;******************************************************************************; Definicin de variables; Variables definidas si se utiliza la interrupcin de baja prioridad

    UDATA

    WREG_TEMP RES 1 ;variable en RAM para guardar contextoSTATUS_TEMP RES 1 ;variable en RAM para guardar contextoBSR_TEMP RES 1 ;variable en RAM para guardar contexto

    UDATA_ACS

    DATO RES 1RTMUL RES 1RETARDO1 RES 1RETARDO2 RES 1CONTADOR1 RES 1PUERTO RES 1TECLA RES 1FILAS RES 1COLUMNAS RES 1ESTADO RES 1

    RESET_VECTOR CODE 0x0000goto main

    REMAPED_RESET_VECTOR CODE 0x1000goto main

    REMAPED_HIGH_VECTOR CODE 0x1008bra ISRH

    REMAPED_LOW_VECTOR CODE 0x1018bra ISRL

    CODE 0x102A

    tabla_cadena1:mullw 02hmovf PRODL, Waddwf PCL, Fretlw 'T'retlw 'E'retlw 'C'retlw 'L'retlw 'A'retlw ' 'retlw 'P'retlw 'R'retlw 'E'retlw 'S'retlw 'I'retlw 'O'retlw 'N'retlw 'A'retlw 'D'retlw 'A'

    53

  • retlw H'00' ;Cero es el fin de cadena (Caracter nulo).tabla_teclas:

    mullw 02hmovf PRODL, Waddwf PCL, Fretlw '7'retlw '8'retlw '9'retlw '/'retlw '4'retlw '5'retlw '6'retlw 'X'retlw '1'retlw '2'retlw '3'retlw '-'retlw 'C'retlw '0'retlw '='retlw '+'

    ISRH:; *** Interrupcin de alta prioridad

    btfss INTCON, RBIFgoto finisrh;ha entrado la interrupcinbcf INTCON, RBIF ;Limpiar la bandera de interrupcinclrf TECLAclrf FILASclrf COLUMNASmovlw H'04'movwf CONTADOR1movlw b'11111110' ;Nmero para comprobar la primer columnamovwf ESTADO ;Registro para comprobar columnas

    leepuertomovf ESTADO, Wmovwf PORTBmovff PORTB, PUERTOswapf PUERTO, F ;Cambiamos los niblesmovlw H'F0'iorwf PUERTO, F ;Solo nos interesa el nible bajo, pero todo es lgica

    ;negativa se usa Inclusive ORcomf PUERTO, F ;Realizamos el complemento para usar lgica positiva.;Iniciamos el testtstfsz PUERTOgoto nocero ;Hay tecla apretadarlncf ESTADO, F ;Nos pasamos a la siguiente columnadecfsz CONTADOR1goto leepuerto ;el contador es mayor a cero (VERDAD)clrf PORTBgoto finisrh ;Ya no hay ms que leer (FIN)

    noceromovf CONTADOR1, Wsublw H'04' ; Contador es el inverso de las columnas, le restamos 4

    ;y nos queda COLUMNAS -1movwf COLUMNAS ; Tenemos COLUMNAS - 1btfss PUERTO, 0 ;Comprueba si fue la fila 1

    54

  • goto comp1movlw H'00'movwf FILAS ;Fila 1 - 1 (0)goto muestra

    comp1btfss PUERTO, 1 ;Comprueba si fue la fila 2goto comp2movlw H'01' ;Fila 2 - 1 (1)movwf FILASgoto muestra

    comp2btfss PUERTO, 2 ;Comprueba si fue la fila 3goto comp3movlw H'02'movwf FILAS ;Fila 3 - 1 (2)goto muestra

    comp3btfss PUERTO, 3 ;Comprueba si fue la fila 4goto finisrhmovlw H'03'movwf FILAS ;Fila 4 - 1 (3)

    muestramovlw H'04'mulwf COLUMNAS ;(Columnas -1) * 4movf PRODL, Waddwf FILAS, W ;(Columnas -1) * 4 + (Filas -1)movwf TECLAmovlw DDRAM_L2addlw H'08'movwf DATOcall Comando_LCDmovf TECLA, Wcall tabla_teclas ;Decodificar la teclamovwf DATO ;Mostrar la tecla decodificadacall Dato_LCDclrf PORTB

    finisrhretfie FAST

    ISRL:movff STATUS,STATUS_TEMP ;guarda el registro de estadomovff WREG,WREG_TEMP ;guarda el registro de trabajomovff BSR,BSR_TEMP ;guarda el registro BSR

    ; *** Interrupcin de baja prioridad ***

    movff BSR_TEMP,BSR ;restaura el registro BSRmovff WREG_TEMP,WREG ;restaura el registro de trabajomovff STATUS_TEMP,STATUS ;restaura el registro de estadoretfie

    Delay1K:retardo0

    DECFSZ RTMULgoto retardo1goto finretardo

    55

  • retardo1MOVLW .100MOVWF RETARDO1

    ciclo1DECFSZ RETARDO1GOTO retardo2GOTO retardo0

    retardo2MOVLW .10MOVWF RETARDO2

    ciclo2DECFSZ RETARDO2GOTO ciclo2GOTO ciclo1

    finretardoRETURN

    Comando_LCD:SWAPF DATO, WMOVWF PORTDBCF PORTD, RD5BCF PORTD, RD4BSF PORTD, RD6MOVLW .60MOVWF RTMULCALL Delay1KBCF PORTD, RD6MOVFF DATO, PORTDBCF PORTD, RD5BCF PORTD, RD4BSF PORTD, RD6MOVLW .60MOVWF RTMULCALL Delay1KBCF PORTD, RD6RETURN

    Dato_LCD:SWAPF DATO, WMOVWF PORTDBCF PORTD, RD5BSF PORTD, RD4BSF PORTD, RD6MOVLW .60MOVWF RTMULCALL Delay1KBCF PORTD, RD6MOVFF DATO, PORTDBCF PORTD, RD5BSF PORTD, RD4BSF PORTD, RD6MOVLW .60MOVWF RTMULCALL Delay1KBCF PORTD, RD6RETURN

    56

  • Inicializa_LCD:MOVLW .137MOVWF RTMULCALL Delay1KMOVLW 0x02MOVWF PORTDBCF PORTD, RD5BSF PORTD, RD6MOVLW .60CALL Delay1KBCF PORTD, RD6MOVLW .187MOVWF RTMULCALL Delay1KMOVLW FUNCTION_SETIORLW LINES_5x7MOVWF DATOCALL Comando_LCDMOVLW DISPLAY_CONTROLIORLW DONMOVWF DATOCALL Comando_LCDMOVLW CLEARMOVWF DATOCALL Comando_LCDMOVLW DISPLAY_MODEIORLW INCREMENTMOVWF DATOCALL Comando_LCDRETURN

    Cadena_LCD: ;Subrutina para enviar una cadena al LCD.clrf CONTADOR1

    ciclocadenamovf CONTADOR1, W ;Colocamos el contenido de contador en Wcall tabla_cadena1 ;Llamamos a la tablamovwf DATO ;Colocamos el retorno en DATOtstfsz DATO ;Comprueba que no haya caracter nulogoto enviacadenagoto fincadena

    enviacadenacall Dato_LCD ;Enviamos el dato al LCDincf CONTADOR1 ;Incrementamos el contadorgoto ciclocadena

    fincadenareturn

    Configura_Puertos: ;Subrutina para configurar los puertosmovlw H'0F'movwf ADCON1movlw H'F0' ;mitad del puerto de salida, la otra mitad de entrada (para las

    ;interrupciones)movwf TRISBclrf TRISDclrf PORTDreturn

    Configura_Interrupciones: ;Subrutina para configurar interrupciones;Interrupcin de cambio de flancobcf INTCON, RBIF ;Limpiamos la bandera.

    57

  • bsf INTCON2, RBIP ;Le asignamos prioridad alta.bsf INTCON, RBIE ;Habilitamos la interrupcin.return

    main:clrf WREGcall Configura_Puertoscall Configura_Interrupcionescall Inicializa_LCDmovlw DDRAM_L1movwf DATOcall Comando_LCDcall Cadena_LCD

    ;Ressitencias de PULL-UPbcf INTCON2, RBPU ;Habilitamos las resistencias de pull up.;Interrupciones globalesbsf RCON, IPEN ;Habilitamos prioridades en interrupciones.bsf INTCON, GIEH ;Habilitamos la interrupciones de alta prioridad.

    ciclogoto cicloEND

    La tabla de teclas es para el teclado mostrado en la figura anterior, hay teclados co-merciales diferentes con diferentes teclas como ya se mencion anteriormente; hay que cambiar el orden de las teclas para esos teclados.

    Posiblemente se te haga difcil de entender este programa por su lgica, pero est comprobado, lo arm fsicamente y lo simul en el programa Proteus 7 (Software de simula-cin), con un PIC18F4620 parecido al PIC18F4550. Muestro la imagen siguiente de la simu-lacin.

    58

  • As como est el programa, no funciona en el software Proteus 7, necesitas cambiar las direcciones de interrupcin como si no tuviera bootloader. Cambiando eso, funciona per-fectamente.

    Temporizadores y contadores

    El PIC18F4550 tiene 4 temporizadores (TIMER) con funciones diferentes pero muy parecidas entre si. Podemos utilizar el Timer como contador de eventos externos, lo explicar ms adelante, ya que explicar su registro de configuracin. En este manual solo explicar dos Timer (Timer 0 y Timer 1), explicar su funcionamiento, y explicar como hacer un se-gundero, un contador de eventos externos y un generador de frecuencias.

    Qu se puede hacer con un Timer?

    Generador de frecuencia.

    Modulador de ancho de pulso (PWM).

    Segundero.

    Reloj con fecha a partir del segundero.

    Medidor de frecuencia.

    Medidor de capacitancia a partir del medidor de frecuencia.

    Medidor de resistencia a partir del medidor de frecuencia.

    Medidor de inductancias a partir del medidor de frecuencia.

    Control de motores de CD a partir de PWM.

    Control de servomotores a partir de PWM.

    Muestreadores de datos a partir de ADC (ADC lo explicar mas adelante).

    Reloj de pulsos.

    Dimmer Digital (Controlador de intensidad de luz de focos de CA).

    Comunicacin serial a partir del reloj de pulsos.

    Por motivos de espacio y de tiempo no dar lo que es comunicacin serial en este manual (USART, USB y otros ms).

    Registro de configuracinExplicar muy brevemente el registro de configuracin del TIMER 0 llamado T0CON.

    Este registro controla el funcionamiento del Timer para usarse como temporizador o como contador, configura su prescaler y el nmero de bits a usar.

    El registro T0CON (para el timer 0) tiene los siguientes elementos:

    59

  • bit 7 TMR0ON: Enciende o apaga el Timer.bit 6 T08BIT: En 1 configura el timer a 8 bits, en cero, lo configura a 16 bits.bit 5 T0CS: En uno, selecciona al pin RA4 como entrada de eventos, en cero,

    selecciona al oscilador principal para el retardo.bit 4 T0SE: Solo se usa para entrada de eventos de RA4, en uno, selecciona flanco

    de bajada, en cero, selecciona flancos de subida.bit 3 PSA: En 1 no asignamos prescaler, en cero, asignamos prescaler.bits 2 a 0 TOPS: Selector de prescaler en caso de que PSA sea cero.111 = 1:256110 = 1:128 Prescale value101 = 1:64 Prescale value100 = 1:32 Prescale value011 = 1:16 Prescale value010 = 1:8 Prescale value001 = 1:4 Prescale value000 = 1:2 Prescale value

    TimersQu es un Timer? Es un contador de ciclos de mquina o contador de ciclos de un

    oscilador externo, que al desbordarse produce una interrupcin. Tambin puede contar pul-sos externos.

    Cmo funciona un Timer? Cuenta nmeros del 0 al 255 cuando se configura en 8 bits (lo explico ms adelante) o al 65536 en caso de configurarlo de 16 bits. Puede contar ciclos de mquina (en caso de usar el oscilador principal) o contar eventos externos (usando osciladores externos o pulsos de algn circuito externo como el famosisimo NE555, flip-flops, o simplemente botones PUSH) en un pin especfico del cada timer. Cuando el timer llega a su cuenta mxima ms uno (se desborda) activa una interrupcin. Dicha interrupcin, se puede utilizar como interrupcin de alta prioridad o de baja prioridad (Ver tema configurar interrupciones).

    Cmo usar un Timer? Antes de comenzar, vamos a definir un trmino que se llama prescaler, que es una divisin de frecuencia. Ejemplo, si tengo una frecuencia principal de 20MHz y un prescaler de 1, tengo la misma frecuencia final de 20MHz, si tengo el prescaler de 2, la frecuencia es de 10MHz, si tengo un prescaler de 4 tengo una frecuencia de 5MHz. Como se observa, el prescaler provoca que mis tiempos sean ms largos y pueda alcanzar una cierta frecuencia ms fcilmente.

    Para utilizar el timer vamos a recurrir nuevamente al nmero mgico # usado en retardos, pero con una pequea variante, que es la multiplicacin por el prescaler y la posibilidad de usar 16 bits.

    60

  • t=4presc(2n#)

    Fosc

    #=2n( tFosc4presc

    )

    #=2n( t48 MHz4presc

    )

    Donde:n es el nmero de bits, pueden ser 8 o 16.t es el tiempo del timer.Focs es la frecuencia del oscilador, en caso de bootloader es de 48MHz.Presc es el prescaler utilizado, este valor se puede proponer de 1 a 128.

    Ejemplo 1: Realizar el clculo del nmero mgico para obtener un retardo de aproxi-madamente 1.25ms con 8 bits. Proponer el prescaler.

    Solucin 1: Despus de varios intentos, obtuve un prescaler de 64 para un buen n-mero mgico no muy grande, pero tampoco muy pequeo.

    #=28( 1.25ms48MHz464

    )

    #=256(60000256

    )

    #=256243.37#=21.62#22

    Este nmero ser colocado en el registros TMR0L y colocar cero en TMR0H. En ca-so de ser un nmero de 16 bits, se debe de convertir en hexadecimal y el nibble alto deber de colocarse en TMR0H y el nibble bajo deber de colocarse en TMR0L.

    Cmo configuro el timer? Segn el registro de configuracin T0CON deberemos de colocar los siguientes valores:

    Encender el timer.

    Configurarlo a 8 bits (para el ejemplo de 1.25ms).

    Seleccionar el oscilador principal.

    No importan los flancos. Colocar cero.

    Asignar prescaler.

    El prescaler es de 64.

    El nmero que se debe de colocar en binario sera B'11000101' en hexadecimal nos quedara 0xC5.

    61

  • Ejemplo 2: Realizar el programa de configuracin del Timer 0 a 8 bits para 1.25ms y realizar su interrupcin de alta prioridad para cambiar el estado de RC0 en este tiempo.

    Solucin 2: Configurar el programa con los nmeros obtenidos anteriormente y configurar la interrupcin del TIMER0. En la subrutina ISRH colocar la instruccin BTG para cambiar el estado de RC0.

    ISRH:btfsc INTCON, TMR0IF ;compruebo que se realiz la interrupcin.goto finisrhbcf INTCON, TMR0IF ;Limpio la bandera.btg PORTC, RC0 ;Cambio el estado del pin RC0.clrf TMR0Hcall Configura_Timer ;Configuro el timer nuevamente.

    finisrhretfie FAST

    Configura_Puertos:movlw H'0F'movwf ADCON1 ;Todos los puertos como digitales.clrf TRISC ;Puerto C como salida.clrf PORTC ;Apagamos el puerto C.return

    Configura_Interrupciones:bcf INTCON, TMR0IF ;Limpio la bandera.bsf INTCON2, TMR0IP ;Interrupcin de alta prioridad.bsf INTCON, TMR0IE ;Habilito la interrupcin.return

    Configura_Timer:clrf TMR0Hmovlw .22movwf TMR0Lmovlw H'C5'movwf T0CONreturn

    main:clrf WREGcall Configura_Puertoscall Configura_Interrupcionescall Configura_Timerbsf RCON, IPENbsf INTCON, GIEH

    ciclogoto cicloEND

    Como observamos en la rutina de interrupcin, volvemos a configurar el Timer ya que, como mencion anteriormente la interrupcin se realiza cuando el contador vuelve a ce-ro y debemos volver a cargar el nmero para que cuente nuevamente el ciclo de 1.25ms.

    Nota: El Timer 1 tiene una configuracin muy parecida al TIMER 0, con la diferencia que el Timer 2 puede contener un oscilador externo en RC0 y RC1 para un conteo de even-tos. Si colocamos un oscilador de baja frecuencia, podemos realizar un segundero. Reco-miendo usar el de 32KHz (32768 Hz) y cargar en TMR1H 0x80 y TMR0L 0x00. Este programa lo explicar en la seccin segundero.

    62

  • ContadoresLos contadores de eventos son Timers que en vez de contar ciclos de oscilador,

    cuentan pulsos externos. Si contamos el nmero de pulsos en un segundo, tenemos un frecuenciometro; por el contrario, si queremos que a cierto nmero de cuentas se realice una interrupcin, debemos de colocar un nmero en TMR0L para alcanzar dicha cuenta. En este caso, como no usamos oscilador interno, no dividimos la frecuencia en 4.

    Para configurar el contador en el registro T0CON debemos de considerar lo si-guiente:

    Encender el Timer

    Configurarlo a 8 o 16 bits.

    Seleccionar eventos externos.

    Seleccionar el flanco del pulso.

    No asignar prescaler para tiempo real.

    El prescaler es irrelevante por que no ha sido asignado.Por lgica digital todos los valores irrelevantes los consideramos cero. El valor

    obtenido con flancos de subida es 0xF8.

    Ejemplo 1: Realizar un programa con TIMER0 que interrumpa al microcontrolador cuando sea apretado 5 veces un botn en RA4. La interrupcin deber ser de alta prioridad y el flanco deber de ser de subida y al realizarse deber de cambiar de estado RC0 de forma repetitiva. Tomar en cuenta que RA4 no tiene resistencias de PULL-UP ni PULL-DOWN.

    Solucin 1: El nmero mgico deber ser 251 para que cuando lleguemos a 255+1 se interrumpa el microcontrolador. El circuito externo deber ser un push conectado a +5V con una resistencia de 1K a tierra. El nodo de la resistencia y botn, deber ser llevado a RA4.

    ISRH:btfss INTCON, TMR0IFgoto finisrhbcf INTCON, TMR0IF ;Limpiamos la banderabtg PORTC, RC0 ;Cambiar el estado.call Configura_Timer

    finisrhretfie FAST

    Configura_Puertos:movlw H'0F'movwf ADCON1clrf TRISC ;Puerto C como salidaclrf PORTCsetf TRISA ;Puerto A como entradareturn

    Configura_Interrupciones:bcf INTCON, TMR0IF ;Limpio la bandera.bsf INTCON2, TMR0IP ;Interrupcin de alta prioridad.

    63

  • bsf INTCON, TMR0IE ;Habilito la interrupcin.return

    Configura_Timer:clrf TMR0Hmovlw H'05'movwf TMR0Lmovlw H'F8'movwf T0CONreturn

    main:clrf WREGcall Configura_Puertoscall Configura_Interrupcionescall C