Universidad Tecnológica de Querétaro Firmado digitalmente por Universidad Tecnológica de Querétaro Nombre de reconocimiento (DN): cn=Universidad Tecnológica de Querétaro, o=Universidad Tecnológica de Querétaro, ou, [email protected], c=MX Fecha: 2011.08.31 09:54:12 -05'00' Manual de Lenguaje Ensamblador para el PIC18F252 UNIVERSIDAD TECNOLÓGICA DE QUERÉTARO Manual de Lenguaje Ensamblador para el PIC18F252 Empresa: A y B AUTOMATIZACIÓN Memoria Que como parte de los requisitos para obtener el título de: TÉCNICO SUPERIOR UNIVERSITARIO EN MECATRÓNICA ÁREA AUTOMATIZACIÓN Presenta Andrés Castelán Acosta Ing. R. Jesús Tapia Armas Asesor de la UTEQ Ing. Ernesto Alonso Partida Asesor de la Empresa Santiago de Querétaro, Qro, Agosto 2011 0 RESUMEN El proyecto consiste en un manual para la programación de microcontroladores en lenguaje ensamblador, incluyendo ejemplos de programación; para esto es necesario conocer las instrucciones del lenguaje ensamblador, sus funciones, la manera de redactarlo, las características propias de los Microcontroladores que se vayan a utilizar, algebra booleana y saber estructurar problemas diagrama de flujo; al saber conjuntar estos conocimientos se logra obtener un mayor dominio en la resolución de problemas lógico-matemáticos y al usar en particular este lenguaje se facilitarán otros software de programación más avanzados; en conclusión se llega a obtener una mejor perspectiva en la resolución de problemas, no solo matemáticos o lógicos, sino en general, las actividades en la estadía no solo se limitaron a la realización de un manual, sino, de diversas actividades más, como: cableado eléctrico de diversas máquinas, diseño de prototipos de herramentales, visitas a diversas empresas para instalar, dar mantenimiento o reparar maquinas, etc.; que también brinda mucho experiencia y conocimientos. 1 ABSTRACT The elaboration of an assembler language programming manual is presented in this document; examples are included so the reader can learn how to write instructions, functions and its syntax. It is devoted to the characteristics of several microcontrollers, Boole algebra, structure and flow diagramming. If we grab this knowledge, we will get greater dominion in math-logic problem solving too. It is also easier learning advanced programming after this language. Summarizing: we can have a better sight in problem solving, not only math or logic but in general. During this period in the industry, other activities have been made: tool prototyping, client visiting, machinery electric cabling, maintenance and repair. All those are sources of knowledge and experience. 2 INDICE Página Resumen 1 Abstract 2 Índice 3 I. INTRODUCCIÓN 4 II: ANTECEDENTES 4 III. JUSTIFICACIÓN 5 IV. OBJETIVOS 5 V. ALCANCE 6 VI. FUNDAMENTACIÓN TEÓRICA 6 VII. PLAN DE ACTIVIDADES 10 VIII. RECURSOS MATERIALES Y HUMANOS 12 IX. DESARROLLO DEL PROYECTO 13 X. RESULTADOS OBTENIDOS 32 XI. ANÁLISIS DE RIESGO 32 XII. CONCLUSIONES 33 XIII. RECOMENDACIONES 33 XIV. REFERENCIAS BIBLIOGRÁFICAS 34 ANEXO 1 35 3 I. Introducción El siguiente reporte consiste en la elaboración de un manual de lenguaje ensamblador enfocado principalmente para el microcontrolador PIC18F252 de Microchip, el nivel del manual es considerado para principiantes o básico. Muchas veces se llegan sencillas, y una solución a resolver problemas grandes con soluciones sencilla puede ser la implementación de Microcontroladores, con este se pueden hacer conversiones de binario a decimal y desplegar el dato en display o LCD, tomar señales de sensores o interruptores y activar señales de salida cuando ciertas condiciones se cumplan, adquirir y mandar datos mediante el protocolo RS-232, etc., y así como estas hay muchas aplicaciones, pero para poderlas desarrollarlas es necesario tener el conocimiento del equipo que se va a utilizar, es por esto que se decide hacer un manual para aquellos que deseen hacer aplicaciones de este tipo. II. Antecedentes En las diferentes empresas, talleres y en las mismas instituciones escolares se presentan problemas de automatización, acondicionamiento de señal, conversiones de sistemas numéricos u otras cosas, y muchas veces las personas encargadas de realizar dicha actividad no encuentran la manera de atacar el problema o la forma de hacerla resulta muy costoso o compleja, es por eso que se decide hacer un manual de lenguaje ensamblador para Microcontroladores como opción a resolver problemas de esta índole. 4 III. Justificación Para poder entender y aplicar los alcances de un Microcontrolador y lo que puede llegar a hacer es necesario saber la arquitectura del mismo hardware, las instrucciones y funciones que requiere y usar el software, y tener una mente ingeniosa, porque teniendo lo anterior, la única limitación es el programador; aunque pareciera que esto está enfocado únicamente a la informática, también se deben tener conocimientos electrónica, programación, sensores, matemáticas y diversas materias en común; es por eso que se hace un manual para poder guiar de manera sencilla y completa en la programación básica. IV. Objetivos Desarrollar un manual de lenguaje ensamblador para un PIC en particular con un nivel de conocimientos adecuado para ser considerado para nivel bajo o principiante. Un manual con 4 ejemplos explicados paso a paso cada uno con diagrama de flujo e imágenes que faciliten la interpretación, así también las características del principales Microcontrolador. 5 V. Alcances Conocer la programación en el lenguaje, tanto de instrucciones como conocer los aspectos que son necesarios para programar algún otro Microcontrolador. Poder desarrollar programas sencillos, como el encendido y apagado de un LED, hasta conversión de BCD a 7 segmentos, así como también la compilación, simulación y programación del PIC, todo esto enfocado a dar ser otra opción para la resolución de problemas de automatización. VI. Fundamentación teórica Sistemas digitales: Es una combinación de dispositivos diseñados para manipular cantidades físicas o información que estén representadas en forma digital, es decir que solo pueden tomar valores discretos. Los sistemas digitales utilizan el sistema de numeración binaria, el cual cuanta con solo dos números, el 0 nivel bajo y el 1 nivel alto o bits. Un bit es una señal electrónica que puede estar encendida (1) o apagada (0). Es la unidad más pequeña de información que utiliza un ordenador. Son necesarios 8 bits para crear un byte. Para la implementación de los circuitos digitales, se utilizan puertas lógicas (AND, OR y NOT), estas puertas siguen el comportamiento de algunas funciones del Álgebra de Boole. Sistema Binario: En el sistema Binario o de base 2, cuanta solamente con dos dígitos el 0 y el 1, empezamos con el 0 y después el 1, y para formar un número más grande, se van añadiendo 0 y 1 la izquierda del número que ya tenemos. 6 En el sistema binario sólo puede haber dos valores para cada dígito: un 0= desactivado ó un 1= activado. En la figura 6.1 se muestra la conversión de sistema binario a hexadecimal y decimal. Figura 6.1. Tabla de conversión Lenguaje ensamblador: El lenguaje ensamblador es un lenguaje de programación de bajo nivel para las computadoras, microprocesadores, Microcontroladores, y otros circuitos integrados programables. Características El código escrito en lenguaje ensamblador posee una cierta dificultad de ser entendido ya que su estructura se acerca al lenguaje máquina, es decir, es un lenguaje de bajo nivel. Con el lenguaje ensamblador se tiene un control muy preciso de las tareas realizadas por un microprocesador por lo que se pueden crear segmentos de código difíciles y/o muy ineficientes de programar en un lenguaje 7 de alto nivel, ya que, entre otras cosas, en el lenguaje ensamblador se dispone de instrucciones del CPU que generalmente no están disponibles en los lenguajes de alto nivel. El lenguaje ensamblador cuenta con un juego de instrucciones y estas se pueden dividir en grupos: CISC (Complex Instruction Set Computer): Juego de Instrucciones Complejo, más de 80 instrucciones RISC (Reduced Instruction Set Computer): Juego de Instrucciones Reducido, unas 35 instrucciones. Los Microcontroladores PICmicro son de este tipo. SISC (Specific Instruction Set Computer): Juego de Instrucciones Específico, para una mejor presentación las instrucciones se pueden clasificar según la función que desempeñan en un programa. Microcontrolador: Un Microcontrolador es un dispositivo electrónico capaz de llevar a cabo procesos lógicos. Estos procesos o acciones son programados en lenguaje ensamblador por el usuario, y son introducidos en este a través de un programador. Diagramas de flujo: Un diagrama de flujo u organigrama es una representación diagramática que ilustra la secuencia de las operaciones que se realizarán para conseguir la solución de un problema. Los diagramas de flujo se dibujan generalmente antes de comenzar a programar el código frente a la computadora. Los Diagramas de flujo se dibujan generalmente usando algunos 8 símbolos estándares. Algunos símbolos estándares, que se requieren con frecuencia para diagramar programas de computadora se muestran a continuación: Inicio o fin del programa Pasos, procesos o líneas de instrucción de programa de cómputo Operaciones de entrada y salida Toma de decisiones y Ramificación Líneas de flujo Display, para mostrar datos Envía datos a la impresora Tabla 6.1. Simbología de diagrama de flujo 9 VII. Plan de Actividades El plan de actividades fue concebido tomando en cuenta los aspectos para la realización de un manual de lenguaje ensamblador a nivel básico o principiante, estos aspectos fueron analizados para la obtención del manual y representados en una gráfica de Gantt. Se realizó una lista numerando las actividades, la gráfica de Gantt corresponde a la figura 7.1. 1. Asignación del proyecto: Se plantea el proyecto, es decir lo que se va a realizar durante la estadia. 2. Investigar sobre el microcontrolador a utilizar: Asignado el proyecto, se toma plantea los pasos a seguir para el manual y se decide que el primero es definir el microcontrolador a usar. 3. Investigación del lenguaje ensamblador: Teniendo el microcontrolador se busca el set de instrucciones de este, y se empieza a adentrar al lenguaje ensamblador. 4. Realización de programas y ejemplos: Con los conocimientos del PIC y del lenguaje de programación se procede a la realización de programas y ejemplos, para comprender el funcionamiento del programa, terminado los programas se intentan programar o en su defecto simular para ver su corecta operación. 5. Actividades diversas: Durante todo la estadia no solo se enfoca al desarrollo del manual, sino, también a desempeñar actividades diversas que surguen a lo largo de la estancia, que también sirven para la formación y adquisición de conocimientos en el area. 6. Realización del manual: Con los conocimientos obteidos de la programación se empieza a desarrollar un manual con la información necesaria para su comprensión y programas que sirvan de ejemplos para el entendimiento de las instrucciones. 10 7.1. Grafica de Gantt. 11 VIII. RECURSOS MATERIALES Y HUMANOS EL presente capitulo muestra los recursos utilizados en el desarrollo del proyecto, tanto los recursos materiales; como máquinas y herramientas, así como también los humanos. Equipo y material Cantidad Costo Unitario Costo Computadora 56 $5.00 $280.00 Programador de PICkit 1 $400.00 $400.00 Sistema mínimo para microcontrolador 1 $200.00 $200.00 PIC18F252 1 $100.00 $100.00 MPLAB IDE V8.70 1 $50.00 $50.00 ISIS 1 $50.00 $50.00 PICkit 2 1 $50.00 $50.00 56 horas $70.00 $3,500.00 Software Recursos Humanos Horas Hombre TOTAL $5,050.00 12 IX. DESARROLLO DEL PROYECTO En este capítulo se presentan las actividades realizadas para la elaboración del manual basando las actividades de la gráfica de Gantt mostrada en el capítulo VII. 9.1. Definir Microcontrolador Para la realización del manual de lenguaje ensamblador fue necesario hacerlo para un Microcontrolador en particular, ya que aunque estos microcontroladores tengan algunas similitudes físicas o de programación pueden variar las instrucciones en el lenguaje ensamblador, las capacidades de almacenamiento de memoria de datos o instrucciones son distintas, la frecuencia de operación, entradas analógicas, etc. El PIC18F252 es el que se eligió para este manual, ya que era con el que se contaba, aunque el manual sea dirigido a este Microcontrolador en particular, los ejemplos o programas pueden funcionar haciendo las adecuaciones necesarias, o basándose en los diagramas de bloques. Las características del Microcontrolador son obtenidas de su hoja de datos (Data Sheet), en este caso son obtenidas de la página web de Microchip, de donde se obtuvieron los siguientes datos: 13 Características: Características PIC18F252 Frecuencia de Operación DC-40Hz Memoria de Programa (Bytes) 32K Memoria de Programa (Instrucciones) 16384 Memoria de Datos (Bytes) 1536 Memoria de Datos EEPROM (Bytes) 256 Fuentes de Interrupciones 17 Puertos de Entrada/Salida Ports A, B, C Timers 4 Captura, Comparación/Módulos PWM 2 Comunicación Serie MSSP, Addessable, USAR Comunicación Puerto Paralelo -------- Módulo de10-bit Analógico-Digital 5 canales de entrada POR, BOR, Instructions de RESET, Stack RESERT (y retardos) Full, Stack Underflow (PWRT, OST) Detector de baja Tensión Programable Si Brown-Out Reset Programable Si Set de Instrucciones 75 Instrucciones 28-pin DIP Encapsulado 28-pin SOIC Tabla 9.1 Características del Microcontrolador PIC 18F252 Esta tabla muestra aspectos importantes del Microcontrolador, como pueden ser: la frecuencia de operación, el tamaño de las memorias, los puertos 14 de entrada y salida, canales analógicos y la cantidad de instrucciones, entre otros. El diagrama de pines, figura 9.1, también es una parte importante a resaltar, ya que de manera gráfica muestra el Microcontrolador: Figura 9.1. PIC18F252 Completando la selección del Microcontrolador y teniendo la información básica de este, ya es posible hacer la introducción al lenguaje ensamblador con respecto a las instrucciones que utiliza. 9.2. Instrucciones del Lenguaje Ensamblador El lenguaje ensamblador es un lenguaje de programación muy básico, por lo tanto también su juego de instrucciones, lo cual genera ventajas y desventajas, una de las ventajas es tener al estar realizando el programa a bajo nivel se puede hacer más eficiente el programa, es decir, que con menos 15 espacio en la memoria realice lo que se desea y con mayor velocidad, ya que el programador define las subrutinas y cada parte del programa, a diferencia de utilizar algún software de programación más avanzado que ya cuenta con funciones especiales que facilitan la programación pero, no siempre resultan de los más eficientes. Tabla 9.2.Set de instrucciones del PIC18FXXX 16 La tabla 9.2 muestra las instrucciones del PIC18FXX2, con una breve descripción de lo que realizan y de los ciclos que consume cada una de las instrucciones. Los Registros: Un registro es un lugar dentro del PIC que puede ser escrito, leído o ambas cosas. Piensa en un registro como si fuese un trozo de papel donde tú puedes ver la información o escribirla. La figura de más abajo muestra el mapa de registros del interior del PIC18F252. La figura 9.3 es solo para mostrar donde están los diferentes bits y piezas dentro del PIC, y ayudará a explicar unos cuantos comandos. Tabla 9.3. Bancos 17 La primera cosa que se nota es que está dividido en Bancos. El Banco 1 es utilizado para controlar las propias operaciones del PIC para decirle al PIC cuales bits son entradas y cuales son salidas. El Banco 0 se utiliza para manipular los datos. 9.3. Realización de programas y ejemplos La manera más fácil y eficiente de saber cómo programar un Microcontrolador es programando, y mejor forma de plantear la resolución de un problema de programación es realizando un diagrama de flujo, que nos muestre de manera gráfica la resolución del proyecto. Como primer programa se realizó el encendido y apagado de un LED, para hacer esto es necesario primero configurar un puerto como salida o un solo bit de ese puerto, el cual va a mandar un dato en alto o bajo (encender o apagar) a esto se le llama inicialización de puertos, después de tener el bit que va a ser el que controle el encendido y apagado del LED, se hace el proceso de encendido y apagado, esto se va a ser dándole instrucciones al bit elegido, es decir, si se tiene el bit 7 del puerto C conectado al LED y configurado como salida, y deseamos que encienda y apague el LED en un ciclo infinito, entonces sí se representa gráficamente mediante un diagrama, figura 9.2, este quedara de la siguiente forma: 18 Figura 9.2.Diagrama de flujo De esta manera se facilita la realización del programa, así que con este diagrama de flujo se realizó el primer programa para la introducción al lenguaje ensamblador; para la inicialización del puerto C se hizo la siguiente parte del código: BSF MOVLW MOVWF BCF STATUS, 5 00h 94h STATUS, 5 ; BANCO 1 PARA MODIFICAR EL PUERTO C ; TODOS COMO SALIDA ; LUGAR DEL REGISTRO TRISC ; REGRESA AL BANCO CERO Así se hace la configuración del cualquier puerto, moviéndose de un banco a otro y asignado los bits en 0 para salidas y en 1 para entradas, ahora 19 para asignar que uno o varios bits estén en alto se pone el bit en 1 o en bajo en 0. MOVLW MOVWF B’1000 0000 ; BIT 7 PUERTO C ACTIVADO 82h ; SE ASIGNAN AL PUERTO C Se inició el programa con todos los puertos apagados, ahora se muestra como se activa el bit 7 del puerto C MOVLW MOVWF B’0000 0000 ; TODOS LOS PUERTOS APAGADOS 82h ; SE ASIGNA AL PUERT C Para la parte del ciclo se utilizó una etiqueta y el GOTO. El GOTO manda a la etiqueta, entonces la etiqueta fue asignada en la parte del inicio del programa. BSF MOVLW MOVWF BCF INICIO MOVLW MOVWF MOVLW MOVWF GOTO STATUS, 5 00h 94h STATUS, 5 ; BANCO 1 PARA MODIFICAR EL PUERTO C ; TODOS COMO SALIDA ; LUGAR DEL REGISTRO TRISC ; REGRESA AL BANCO CERO B’0000 0000 ; TODOS LOS PUERTOS APAGADOS 82h ; SE ASIGNAN AL PUERTO C B’1000 0000 ; BIT 7 PUERTO C ACTIVADO 82h ; SE ASIGNA AL PUERT C INICIO La importancia de saber el cristal que se usó es para determinar el tiempo que dura el programa ejecutándose o una parte de él, en este caso es 20 necesario poner un retardo para que la duración del encendido y apagado sea mayor, ya que con un cristal de 20MHz. La fórmula para determinar un ciclo de instrucción es la siguiente: ( )*4= CI. Entonces, si tenemos un cristal de 20MHz un ciclo de maquina dura .2µs, entonces un retardo se realiza mediante sumas o restas de un valor predefinido, esto se hace mediante el DECFZ, que es una instrucción que decrementa en un y cuando llega al 0 salta a una instrucción, o INCFZ que en lugar de restar suma en un hasta llegar a 0. Entonces se realiza el delay ciclando esta instrucción y el tiempo va a ser igual al valor que tenga la variable a decrementar o incrementar, esto multiplicado por la cantidad de ciclos que dure la instrucción dentro del retardo y multiplicado por el ciclo de instrucción, y se puede meter un retardo dentro de otro retardo las veces necesarias para obtener un mayor tiempo. Para este programa se realizó un doble anidado, bucle o retardo. Para hacer el tiempo total va a ser igual al CONT2xTIEMPO1x3=TIEMPO2 y el TIEMPO1=CONT1xCIx3 y el diagrama de la figura 9.3 muestra la gráficamente la forma de realizarlo. 21 Figura 9.3.Diagrama de Retardo Con el diagrama se realizó la siguiente parte del programa, llamada RETARDO o DELAY: ;;;;;;;;;;;;;;;SUBRUTINA;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RETARDO MOVLW .255 ;ASIGNA 255 EN DECIMAL A W MOVWF CONT2 ;CONT2 TOMA EL VALOR DE W CICLO2 MOVLW .255 ;W TOMA EL VALOR DE 255 MOVWF CONT1 ;CONT1 ES IGUAL 1 255 CICLO1 22 DECFSZ GOTO DECFSZ GOTO RETURN CONT1,1 CICLO1 CONT2,1 CICLO2 ;DECREMENTA EN 1 A CONT1 ;SIGUE RESTANDO HASTA Q LLEGUE A 0 ;CUANDO LLEGA A 0 RESTA A CONT2 ;HASTA QUE ESTE TAMBIÉN LLEGUE A 0 ;LLEGA A 0 Y REGRESA DE DONDE LO ;LLAMARON Entonces el valor del tiempo que va a durar es retardo es el siguiente, si un ciclo de maquina dura (1/20MHz)x(4)=2 μs, las instrucciones en cada ciclo son 3 y la variable es de 255, si multiplicamos estos tres nos da un primer tiempo; TIEMPO1=(2μs)x(3)x(255); TIEMPO1= 153 ms, y el TIEMPO2=(153 ms)x(3)x(255), el TIEMPO2 = 0.117045 s, aun es un tiempo muy corto, así que lo llamaremos 5 veces, lo que dio un retardo de 0.585225.s entre encendido y apagado del LED. Figura 9.4.Programa final. 23 Se redactó el programa correspondiente al programa de encendido y apagado del LED, lo que dio como resultado lo siguiente: ;;;;;;;;;;;;;; INICIALIZACIÓN DE VARIABLES;;;;;;;;;;;;;;;;;;;;;;;;; CONT1 EQU 08h ;CONT1 SE GUARDA EN LA MEMORIA 08h CONT2 EQU 09h ;CONT2 SE GUARDA EN LA MEMORIA 09h ORG 0X00 ;;;;;;;;;;;;;;CONFIGURACIÓN DE PUERTOS;;;;;;;;;;;;;;;;;;;;;;; BSF STATUS, 5 ; BANCO 1 PARA MODIFICAR EL PUERTO C MOVLW 00h ; TODOS COMO SALIDA MOVWF 94h ; LUGAR DEL REGISTRO TRISC BCF STATUS, 5 ; REGRESA AL BANCO CERO ;;;;;;;;;;;;;;;;;;;;;;INICIO DEL PROGRAMA;;;;;;;;;;;;;;;;;;;;; INICIO MOVLW B’0000 0000 ; TODOS LOS PUERTOS APAGADOS MOVWF 82h ; SE ASIGNAN AL PUERTO C CALL RETARDO CALL RETARDO CALL RETARDO CALL RETARDO CALL RETARDO MOVLW B’1000 0000 ; BIT 7 PUERTO C ACTIVADO MOVWF 82h ; SE ASIGNA AL PUERT C CALL RETARDO CALL RETARDO CALL RETARDO CALL RETARDO CALL RETARDO GOTO INICIO END ;;;;;;;;;;;;;;;SUBRUTINA;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RETARDO MOVLW .255 ;ASIGNA 255 EN DECIMAL A W MOVWF CONT2 ;CONT2 TOMA EL VALOR DE W CICLO2 MOVLW .255 ;W TOMA EL VALOR DE 255 MOVWF CONT1 ;CONT1 ES IGUAL 1 255 CICLO1 DECFSZ CONT1,1 ;DECREMENTA EN 1 A CONT1 GOTO CICLO1 ;SIGUE RESTANDO HASTA Q LLEGUE A 0 DECFSZ CONT2,1 ;CUANDO LLEGA A 0 RESTA A CONT2 24 GOTO RETURN CICLO2 ;HASTA QUE ESTE TAMBIÉN LLEGUE A 0 ;LLEGA A 0 Y REGRESA DE DONDE LO ;LLAMARON Este fue el programa final realizado, se escribió en el MPLAB IDE V8.70 que es un software para programación de lenguaje ensamblador para PIC’s. La pantalla principal se muestra en la figura 9.4: Figura 9.4.MPLAB 25 Para poder desarrollar un programa se posiciono el mouse, en la barra de herramientas>Proyect>Proyect Wizard… y abrirá una ventana que ira preguntando paso a paso lo necesario para configurar el software para el Microcontrolador a usar, el lenguaje y donde se guarda el proyecto, figura 9.5. Figura 9.5.Pasos Proyect Wizard. Se encontró que existe diversas forma para agregar hojas nuevas para escribir el código, se encontraron dos formas, la primera y más sencilla es dándole clic derecho a Source Files>Add File y abrirá una nueva ventada en la cual se asigna el nombre y dirección donde se quiere guardar el archivo .ASM, figura 9.6; y la segunda manera es dándole en el icono de New File y automáticamente abrirá un nuevo archivo en blanco, solamente hay que tener 26 cuidado al guardarlo, se debe asignar ese archivo al proyecto y ponerle la extensión .ASM, figura 9.7. Figura 9.6. Método uno. Figura 9.7. Método dos. 27 En la hoja nueva que aparece se escribió el codigo generado anteriormente, y se compiló, la compilación es la manera de generar el codigo .HEX, qu es el que se necesita para posteriormente programar el PIC. Lo compilación se hace con un icono en la barra de herramientas, situado casi a la mitad de la barra, la figura 9.8 muestra el icono. Figura 9.8. Compilación Cuando existe un error de código el compilador marca una falla, esta muestra donde ocurre y una breve descripción, en la figura 9.9 muestra una falla errónea que se obtuvo al compilar. Figura 9.9. Falla al compilar. 28 El error es de código, ya que la instrucción BSS no existe, y por esto mismo también genera otro error con STATUS, que son los que se muestran en la imagen. Cabe resaltar que en la práctica solo me marcó los errores de programación, esto quiere decir que aunque la compilación haya sido exitosa no quiere decir que el programa realizado funcione como se planeó. Una compilación exitosa es mostrada en la figura 9.10. Figura 9.10. Compilación Exitosa. Cuando se obtuvo el .HEX ya fue posible la programación al PIC, se puede utilizar cualquier software de programación, siempre y cuando se tenga el programador adecuado para el software. 29 Este programa fue simulado en ISIS, que es programa anexo a PROTEUS, la simulación esta mostrada en las siguientes dos imágenes, figura 9.11 y figura 9.12, en la primera se muestra el apagado del LED y la segunda el encendido, además que se muestra la conexión del Microcontrolador. Figura 9.11. LED apagado. La segunda figura muestra cuando el LED está encendido. Figura 9.12. LED encendido. 30 La simulación fue elegida por problemas con el programador que se contaba, ya que al programar el PIC este no hacia ninguna función, entonces para la verificación del programa se optó por la simulación en ISIS. Este software de simulación es sencillo de usar, para la selección de los objetos se puso Component Mode y se seleccionó la librería, y en la librería se seleccionan primeramente los componentes a utilizar y se van guardando en la parte de DEVICES o componentes, la figura 9.13 muestra de una mejor manera: 9.13. Selección de dispositivos. 31 X. Resultados Obtenidos En la realización de este proyecto se logró hacer un manual de lenguaje ensamblador para el PIC18F252, el cual cuenta con 4 ejemplos paso a paso de su elaboración, además de imágenes y diagramas que ayudan a la comprensión. Se logró realizar distintos tipos de programas, abarcando gran parte de las instrucciones utilizadas frecuentemente. También se llevó a cabo la simulación de los programas, pero la programación del PIC no se logró del todo, ya que el programador con el software de programación no tuvieron compatibilidad lo cual provocaba errores al cargar el archivo al Microcontrolador. XI. Análisis de Riesgos Los impedimentos de que este proyecto no pueda ser realizado son: Falta de equipo como computadora, Microcontrolador y programador. Falta de software de programación y simulación. Realización de ejemplos que no funcionen. Falta de tiempo para entender el lenguaje o para desarrollar el manual. 32 XII. Conclusiones En la realización del manual se saca como conclusión que siempre que se utilice algún Microcontrolador para programar es necesario tener a la mano la hoja de datos, ya que esta brinda ayuda técnica que servirá para el desarrollo del programa, otra cosa que se encontró fue que para realizar un manual hay que saber de lo que se habla, es decir conocer el tema y redactarlo de la forma que te hubiera gustado a ti que te lo explicaran, en mi caso la información obtenida era muy técnica, lo que provocaba confusión, es por eso que se realiza un manual que intenta explicar de manera muy detallada cada paso y con ejemplos funcionales. XIII. Recomendaciones Después de la culminación del proyecto proseguiría hacer un curso, donde se enseñe el lenguaje ensamblador tomando el manual como fuente de consulta, el curso deberá contar con tres distintos niveles, principiante, intermedio y avanzado. 33 XIV. Referencia Bibliográfica Hyde, Randall . El arte de la programación en lenguaje ensamblador, Primera Edición. Editorial Peter Kitson. Bartlett, Jonathan. Programación desde las bases, Tercera Edición. Editorial Peter Kitson . También se consultó: http://www.microchip.com http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId= 1406&dDocName=en019469&part=SW007002 34 ANEXO 1 35 MANUAL DE PROGRAMACIÓN DE LENGUAJE ENSAMBLADOR PARA EL PIC18F252 NIVEL BÁSICO 36 Introducción El muestra de manera detallada ejemplos de programación en lenguaje ensamblador, estos fueron realizados para el PIC18F252, además que cuenta con marco teórico que ayudara al lector la comprensión de algunos términos y operaciones usadas dentro del manual. Cabe resaltar que este manual es para nivel básico o principiantes. Objetivo: Dar a conocer al lector los alcances de un Microcontrolador como dispositivo de control. Saber reconocer las características necesarias para programar un Microcontrolador. Enseñar con base ejemplos sencillos. 37 Marco teórico En este parte da a conocer conocimientos necesarios para el completo entendimiento del manual, estas definiciones ayudan al mejor entendimiento para personas que desconocen del tema. Sistemas digitales: Un sistema digital como cualquier sistema de procesamiento de información en el cual la información se encuentre representada por medio de señales que se hayan restringidas que sólo pueden asumir valores discretos. La principal ventaja de los sistemas digitales respecto a los analógicos es que son más fáciles de diseñar, de implementar y de depurar, ya que las técnicas utilizadas en cada una de esas fases están bien establecidas. Las operaciones digitales también son mucho más precisas y la transmisión de señales dentro del circuito y entre circuitos es más fiable porque utilizan un conjunto discreto de valores, fácilmente discernibles entre sí, lo que reduce la probabilidad de cometer errores de interpretación. Sistemas digitales combinacionales: Aquellos en los que sus salidas sólo depende del estado de sus entradas en un momento dado. Por lo tanto, no necesita módulos de memoria, ya que las salidas no dependen de los estados previos de las entradas. Sistemas digitales secuenciales: Aquellos en los que sus salidas dependen además del estado de sus entradas en un momento dado, de 38 estados previos. Esta clase de sistemas necesitan elementos de memoria que recojan la información de la 'historia pasada' del sistema. Para la implementación de los circuitos digitales, se utilizan puertas lógicas (AND, OR y NOT), construidas generalmente a partir de transistores. Estas puertas siguen el comportamiento de algunas funciones del Álgebra de Boole. Bit y Byte: Un bit es una señal electrónica que puede estar encendida (1) o apagada (0). Es la unidad más pequeña de información que utiliza un ordenador. Son necesarios 8 bits para crear un byte. Compuertas Digitales: Las computadoras digitales se utilizan el sistema de números binarios, que tiene dos dígitos 0 y 1. Utilizando diversas técnicas de codificación los grupos de bits pueden hacerse que representen no solamente números binarios sino también otros símbolos, tales como dígitos decimales o letras de alfabeto. Utilizando arreglos binarios y diversas técnicas de codificación, los dígitos binarios o grupos de bits pueden utilizarse para desarrollar conjuntos completos de instrucciones para realizar diversos tipos de cálculos. 39 Compuerta AND: Cada compuerta tiene dos variables de entrada designadas por A y B y una salida binaria designada por X. La compuerta AND produce UNA multiplicación lógica. Compuerta AND Compuerta OR: La compuerta OR hace la función sumar. Las compuertas OR pueden tener más de dos entradas y por definición la salida es 1 si cualquier entrada es 1. Compuerta OR 40 Compuerta NOT: El circuito NOT es un inversor que invierte el nivel lógico de una señal binaria, también llamada función complementaria. Si la variable binaria posee un valor 0, la compuerta NOT cambia su estado al valor 1 y viceversa. Compuerta NOT Compuerta NAND: Es el complemento de la función AND, como se indica por el símbolo gráfico, que consiste en una compuerta AND seguida por un pequeño círculo (quiere decir que invierte la seña, una NOT. Las compuertas NAND pueden tener más de dos entradas, y la salida es siempre el complemento de la función AND. Compuerta NAND 41 Compuerta NOR: La compuerta NOR es el complemento de la compuerta OR y utiliza el símbolo de la compuerta OR seguido de un círculo pequeño. Las compuertas NOR pueden tener más de dos entradas, y la salida es siempre el complemento de la función OR. Compuerta NOR Sistema Decimal: El sistema decimal es un sistema de numeración donde se utiliza la base diez, por lo que se compone de diez cifras diferentes: 0, 1, 2, 3, 4, 5, 6, 7, 8 y 9. Sistema Binario: En el sistema Binario o de base 2, cuanta solamente con dos dígitos el 0 y el 1, empezamos con el 0 y después el 1, y para formar un número más grande, se van añadiendo 0 y 1 la izquierda del número que ya tenemos. En el sistema binario sólo puede haber dos valores para cada dígito: un 0= desactivado ó un 1= activado. Sistema Hexadecimal: Este sistema es de base 16, lo que significa que para cada columna es posible escoger uno de entre 16 dígitos. Éstos son 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E y F. Para contar en el sistema hexadecimal se 42 inicia en la primera columna a la izquierda del punto hexadecimal y se cuenta desde 0 hasta F Sistemas numéricos Lenguaje ensamblador: El lenguaje ensamblador es un lenguaje de programación de bajo nivel para las computadoras, microprocesadores, Microcontroladores, y otros circuitos integrados programables. Características del lenguaje ensamblador: El código escrito en lenguaje ensamblador posee una cierta dificultad de ser entendido ya que su estructura se acerca al lenguaje máquina, es decir, es un lenguaje de bajo nivel. Con el lenguaje ensamblador se tiene un control muy preciso de las tareas realizadas por un microprocesador por lo que se pueden crear segmentos de código difíciles y/o muy ineficientes de programar en un lenguaje 43 de alto nivel, ya que, entre otras cosas, en el lenguaje ensamblador se dispone de instrucciones del CPU que generalmente no están disponibles en los lenguajes de alto nivel Arquitectura interna de un Microcontrolador: Un microcontrolador es un dispositivo complejo, formado por otros más sencillos. A continuación se analizan algunos de los aspectos más importantes. Procesador: Es la parte encargada del procesamiento de las instrucciones. La arquitectura von Neumann se caracterizaba porque la CPU se conectaba con una memoria única, donde coexistían datos e instrucciones, a través de un sistema de buses. Arquitectura von Neumann En la arquitectura Harvard son independientes la memoria de instrucciones y la memoria de datos y cada una dispone de su propio sistema de buses para el acceso. Esta dualidad, además de propiciar el paralelismo, permite la adecuación del tamaño de las palabras y los buses a los requerimientos específicos de las instrucciones y de los datos. 44 Arquitectura Harvard Memoria de programa: El Microcontroladores está diseñado para que en su memoria de programa se almacenen todas las instrucciones del programa de control. Como éste siempre es el mismo, debe estar grabado de forma permanente. Memoria de datos: Los datos que manejas los programas varían continuamente, y esto exige que la memoria que los contiene debe ser de lectura y escritura, por lo que la memoria RAM estática (SRAM) es la más adecuada, aunque sea volátil. Hay microcontroladores que disponen como memoria de datos una de lectura y escritura no volátil, del tipo EEPROM. De esta forma, un corte en el suministro de la alimentación no ocasiona la pérdida de la información, que está disponible al reiniciarse el programa. Líneas de E/S: A excepción de dos pines destinadas a recibir la alimentación, otras dos para el cristal de cuarzo, que regula la frecuencia de trabajo, y una más para provocar el Reset, los restantes pines de un microcontrolador sirven 45 para soportar su comunicación con los periféricos externos que controla. Las líneas de E/S que se adaptan con los periféricos manejan información en paralelo y se agrupan en conjuntos de ocho, que reciben el nombre de Puertas. El lenguaje ensamblador cuenta con un juego de instrucciones y estas se pueden dividir en grupos: CISC (Complex Instruction Set Computer): Juego de Instrucciones Complejo, más de 80 instrucciones RISC (Reduced Instruction Set Computer): Juego de Instrucciones Reducido, unas 35 instrucciones. Los Microcontroladores PICmicro son de este tipo. SISC (Specific Instruction Set Computer): Juego de Instrucciones Específico, para una mejor presentación las instrucciones se pueden clasificar según la función que desempeñan en un programa. 46 CONOCE EL MICROCONTROLADOR Para poder programar es necesario saber que vas a programar, para esto es necesario elegir el PIC a utilizar y saber sus características básicas. En este caso se utilizara un PIC18F252 para los ejemplos de programación. Los datos son obtenidos de la datasheet del propio componente, esta es obtenida de la página del fabricante Microchip. Diagrama de pines Se debe tomar en cuenta otras caracteristicas del microcontrolador, como la frecuencia de operación, la memoria, entradas analogicas, las intrucciones, entre otras; las caracteristicas se muestran en la siguiente tabla: Características PIC18F252 Frecuencia de Operación DC-40Hz Memoria de Programa (Bytes) 32K Memoria de Programa (Instrucciones) 16384 Memoria de Datos (Bytes) 1536 Memoria de Datos EEPROM (Bytes) 256 47 Fuentes de Interrupciones 17 Puertos de Entrada/Salida Ports A, B, C Timers 4 Captura, Comparación/Módulos PWM 2 Comunicación Serial MSSP, Addessable, USAR Módulo de10-bit Analógico a Digital 5 canales de entrada RESERT (y retardos) POR, BOR, Instructions de RESET, Stack Full, Stack Underflow (PWRT, OST) Características PIC18F252 Otro factor que se debe tomar en cuenta es el diagrama de bloques de la arquitectura del microcontrolador, ya que ayudara a comprender un poco mejor el uncionamiento de este . 48 El lenguaje ensamblador cuenta con instrucciones, etiquetas, operando y comentarios, todo esto facilita tanto la escritura como el entendimiento de este, a continuación se muestra la manera en que cada uno se acomoda. Etiqueta Instrucción Operando Comentario Inicio Movlw 0xf0 Movwf TRISCA Goto Inicio ;Mueve 0xf0 a W ;TRISA toma el valor de W ;Regresa a la dirección Inicio Tabla de Campos El campo del código de operación es el único que nunca puede estar vacío; éste siempre contiene una instrucción o una directiva del assembler. El campo del operando o dirección puede contener una dirección o un dato, o puede estar en blanco. El campo del comentario o de etiquetas es opcional. El programador asignará una etiqueta a una línea de instrucción o agregará un comentario según su conveniencia: normalmente, para hacer más fácil el uso y la lectura; por ejemplo si va a retomar el trabajo dentro de tres semanas. Los Registros Un registro es un lugar dentro del PIC que puede ser escrito, leído o ambas cosas. Piensa en un registro como si fuese un trozo de papel donde tú puedes ver la información o escribirla. 49 La figura de más abajo muestra el mapa de registros del interior del PIC18F252. La figura es solo para mostrar donde están los diferentes bits y piezas dentro del PIC, y ayudará a explicar unos cuantos comandos. 50 La primera cosa que notarás es que está dividido en Bancos. El Banco 1 es utilizado para controlar las propias operaciones del PIC, por ejemplo para decirle al PIC cuales bits del Puerto A son entradas y cuales son salidas. El Banco 0 se utiliza para manipular los datos. Un ejemplo es el siguiente: Digamos que queremos poner un bit del puerto A en nivel alto. Lo primero que necesitamos hacer es ir al Banco 1 para poner ese bit o pin en particular en el puerto A como salida. Después volvemos al Banco 0 y enviamos un 1 lógico a ese pin. Los registros que se van a usar más frecuentemente en el Banco 1 son STATUS, TRISA, TRISB y TRISC. El primero permite ir de un banco a otro, los TRIS permiten establecer los pines que serán de entrada y de salida con respecto al puerto. STATUS Para cambiar del Banco 0 al Banco 1 utilizamos el registro STATUS. Hacemos esto poniendo el bit 5 del registro STATUS a 1. Para cambiar de nuevo al Banco 0, ponemos el bit 5 del registro STATUS a 0. El registro STATUS se localiza en la dirección D8h (la 'h' significa que el número es hexadecimal). TRISA, TRISB y TRISC 51 Están localizados en las direcciones 92h, 93h y 94h respectivamente para este PIC. Para programar que un pin sea una salida o una entrada, simplemente enviamos un 0 o un 1 al bit en cuestión en el registro PORTA, PORTB y PORTC Para poner uno de nuestros pines de salida a nivel alto, simplemente ponemos un 1 el bit correspondiente en nuestro registro PORTA, PORTB y PORTC. El formato es el mismo que para los registros TRISA, TRISB y TRISC. Para leer si un pin está a nivel alto o nivel bajo en los pines del puerto, se ejecutar un chequeo para ver si el bit en particular correspondiente esta puesto a nivel alto (1) o está puesto a nivel bajo (0). Antes de dar algún ejemplo es necesario también explicar lo que es el registro W. El registro W es un registro de propósito genera, es decir, es al cual le puedes asignar cualquier valor que se desee. Una vez que se haya asignado un valor a ese registro, puedes sumarle cualquier otro valor, o moverlo. Si le asignas otro valor a W, su contenido es sobrescrito. A continuación se mostrará un ejemplo: de cómo utilizar las instrucciones anteriores, esto es solamente para inicializar los puertos, si se intenta compilar en este momento probablemente marque un error. Vamos configurar el puerto B, sus entradas y salidas. 52 PASO 1. Lo primero, necesitamos cambiar del banco 0 al banco 1. Hacemos esto modificando el registro STATUS, que está en la dirección D8h, poniendo el bit 5 a 1. BSF D8h,5 La instrucción BSF significa en ingles "Bit Set F" (Poner a 1 un bit de la Memoria). La letra F significa que se va a utilizar una posición de memoria, o un registro en memoria. Se van utilizar dos números después de esta instrucción, estos números están en hexadecimal– D8h, el cual se refiere a la dirección del registro STATUS, y el número 5 que corresponde al número de bit. Por lo tanto, la instrucción dice: "pon a 1 el bit 5 de la dirección de memoria 03h", esto en palabras. PASO 2. Ahora ya estamos en el banco 1 ponemos el valor binario en nuestro W, este valor se puede escribir en hexadecimal o binario. MOVLW b'00000110' MOVLW 06h Cualquiera de las dos funcionará. La instrucción MOVLW significa en inglés "Move Literal Value into W", en español, mover un valor literal directamente al registro W. 53 PASO 3. Ahora necesitamos poner este valor en el registro TRISB para configurar el puerto: MOVWF 93h Esta instrucción significa "poner los contenidos de W en el registro cuya dirección viene a continuación", en este caso la dirección 93h, que apunta a TRISB. Nuestro registro TRISB ahora tiene el valor 00000110 o mostrado gráficamente: Pin del Puerto B RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0 Valor Binario 0 0 0 0 0 1 1 0 Entrada/Salida S S S S S E E S PASO 4. Ahora tenemos que configurar los pines del Puerto B, y para ello necesitamos volver al banco 0 para manipular cualquier dato. BCF D8h, 5 Esta instrucción hace lo contrario a BSF. Significa en ingles "Bit Clear F" que quiere decir “poner a 0 un bit de la memoria”. Los dos números que le siguen son la dirección del registro, en este caso del registro STATUS, y el 54 número de bit, es este caso el 5. Así que lo que hemos hecho ahora es poner a 0 el bit 5 del registro STATUS. Ahora ya se está de vuelta en el banco 0. Aquí está el código en un solo bloque: BSF MOVLW MOVWF BCF D8h, 5 06h 93h D8h, 5 ; Ve al banco 1 ; Pon 0000 0110 en W ; Mueve lo que tiene W a TRISB ; Vuelve al Banco 0 Ahora, entendiendo lo anterior, se puede realizar un programa sencillo, que encienda y apague un LED. Lo primero que se tiene que hacer es definir qué puerto y que bit del puerto será el que este parpadeando, para esto utilizamos lo anteriormente aprendido, usaremos el bit 1 del puerto B. bsf movlw movwf bcf D8h,5 00h 93h D8h,5 ;Ir al Banco 1 ;Pone 00000000 en W ;Todo el puerto a como salida ;volver al Banco 0 Teniendo configurado el puerto que vamos a utilizar, solo falta mandar la señal al LED, esto lo se hace poniendo en alto o bajo el bit que se desea encender, en este caso el bit 2 del puerto B. movlw 02h ; Escribe en W 0000 0001, poniendo el bit 1 en alto y los ;demás en su estado bajo movwf 81h ; EL puerto B toma el valor de W, el puerto B está en la ;dirección 81h En este punto el LED va a estar encendido, lo que se quiere ahora es apagarlo y esto se hace poniendo el puerto B en 0000 0000. 55 movlw movwf 00h 81h ; Escribe 00h en el registro W. Esto pone a 0 todos los pines. ; Apaga el puerto B Lo que se hizo fue encender y apagar el LED una vez, lo que se quiere es hacerlo pero manera continua, es para esto que se usa un GOTO y una etiqueta, el GOTO, te manda a la etiqueta que se le indique, y si se pone la etiqueta al inicio del programa y el GOTO después de apagar el LED lo que se obtendrá será un ciclo continuo del LED encendiendo y apagando. INICIO movlw movwf movlw movwf goto 01h 81h 00h 81h INICIO ;Regresa a la etiqueta de inicio Como se logra notar el programa sin las etiquetas es bastante confuso, porque solamente se aprecian letras y números, existe una función llamada EQU, que nos sirve para declarar con nombres a los números, esta instrucción no es del propio PIC, sino del lenguaje ensamblador. STATUS EQU TRISB EQU PORTB EQU D8h 93h 81h ; Este asigna a la palabra STATUS el valor D8h ; Este asigna a la palabra TRISA el valor 93h ; Este asigna a la palabra PORTB el valor de 81h Ahora será más fácil entender el programa aunque no se usen muchas etiquetas, y con esta nueva instrucción el programa quedara de la siguiente manera: STATUS EQU TRISB EQU PORTB EQU D8h 93h 81h ; Este asigna a la palabra STATUS el valor D8h ; Este asigna a la palabra TRISA el valor 93h ; Este asigna a la palabra PORTB el valor de 81h 56 bsf movlw movwf bcf INICIO movlw movwf movlw movwf goto STATUS,5 00h TRISB STATUS,5 02h PORTB 00h PORTB INICIO En teoría se tiene un programa que prende y apaga un LED, el programa comprende de 5 instrucciones y si tomamos en cuenta que cada una dura un ciclo de instrucción, entonces el tiempo de encendido y apagado será muy rápido para distinguirlo o verlo. La fórmula para determinar un ciclo de instrucción es la siguiente: ( )*4= CI Entonces, si tenemos un cristal de 20MHz un ciclo de maquina dura .2 microsegundos y si tenemos 5 instrucciones quiere decir que prendera y apagara el LED en 1 microsegundo, lo cual es imposible de ver para el ojo humano, es por eso que se deben de crear retardos o delays para hacer que tarde más tiempo en la realización de una operación El principio para retardo es el de contar hacia atrás o hacia adelante desde un número previamente establecido y cuando llegue a cero, paramos de contar. El valor cero indica el fin del retardo y continuamos nuestro camino a través del programa. Así que lo primero que se necesita hacer es definir una 57 constante que se usara como contador. La llamaremos CONTADOR. Lo siguiente se necesita decidir el tamaño del número desde el que contador y se debe considerar que el número mayor que se puede tener es 255 o FFh en hexadecimal. Ahora, como hemos mencionado en el apartado anterior, la instrucción EQU asigna una palabra a una localización de un registro de memoria. Esto significa que cualquiera que sea el número que asignemos a CONTADOR, será igual al contenido de un registro. Si se prueba y asignamos el valor FFh, el compilador entenderá que se está asignando la dirección de memoria FFh a la constante, y se obtendrá un error cuando se vaya a compilar el programa. Esto es debido a que la localización FFh está reservada, y por tanto no se puede acceder a ella.. Si se asigna a nuestro CONTADOR, por ejemplo, a la dirección 08h, este apuntará a un registro de propósito general. Las posiciones de memoria tienen un valor por defecto de FFh. De este modo, si CONTADOR apunta a 08h, tendrá un valor de FFh la primera vez que lo se asigne. Si queremos que CONTADOR tenga un valor de 93h, no podemos decir 'CONTADOR EQU 93h' porque esta es la localización del registro del puerto B (TRISB). Lo que hacemos es esto: movlw 93h ; Primero, ponemos el valor 93h en el registro W. movwf 08h ; Ahora lo movemos a nuestro registro 08h. 58 Ahora, se puede decir 'CONTADOR equ 08h', CONTADOR será igual al valor 93h. Así que lo primero definimos nuestra constante: CONTADOR equ 08h A continuación es necesario disminuir este CONTADOR en 1 hasta que alcance cero. Este lenguaje cuenta con una instrucción que hace el decremento y con ayuda de otra llamada GOTO, hacemos que el proceso se repita hasta que llegue el valor a 0. decfsz CONTADOR,1 Esta instrucción dice "resta 1 al registro (en esta caso CONTADOR). Si llegamos a cero, salta 2 lugares hacia delante, si no llega a cero se ira a la instrucción GOTO que lo llevara nuevamente a realizar el decremento. CONTADOR equ ETIQUETA decfsz CONTADOR,1 goto 08h ETIQUETA ;Continua por aquí. Lo que se hizo fue primero poner nuestra constante CONTADOR a 255. La siguiente línea pone una etiqueta, llamada ETIQUETA seguida de nuestra 59 instrucción decfsz. La instrucción decfsz CONTADOR,1 disminuye el valor de CONTADOR en 1, y almacena el resultado de vuelta en CONTADOR. También comprueba si CONTADOR tiene un valor de 0. Si no lo tiene, hace que el programa salte a la siguiente línea. Aquí tenemos una instrucción de 'goto' que nos envía de vuelta a nuestra instrucción decfsz. Si el valor de CONTADOR es igual a cero, entonces la instrucción decfsz hace que el programa salte dos lugares hacia adelante, y se sitúe donde se ha escrito "Continua por aquí". Así que, como se puede ver, se ha hecho que el programa permanezca en un lugar durante un tiempo predeterminado antes de seguir adelante. Esto se llama bucle de retardo. Si necesitamos un retardo mayor, podemos poner un bucle detrás de otro. Cuantos más bucles pongamos, mayor será el retardo. Nosotros vamos a necesitar por lo menos dos, si queremos ver parpadear al LED. Vamos a poner estos bucles de retardo en nuestro programa, y terminaremos haciendo un programa real añadiendo los comentarios: ;*****Establecimiento constantes **** STATUS equ D8h ; Dirección del registro STATUS TRISA equ 85h ; Dirección del registro Puerto B PORTA equ 05h ; Dirección del Puerto A. CONTADOR1 equ 08h ; Primer contador retardo. CONTADOR2 equ 09h ; Segundo contador para retardo. ; ;****Configuración del Puerto**** bsf STATUS,5 ; Cambiamos al banco 1Switch to Bank 1 movlw 00h ; Ponemos los pines del puerto A ... movwf TRISB ; como salidas. bcf STATUS,5 ; Volvemos al Banco 0. ; ;****Encendido del LED **** 60 Inicio movlw 02h ; Encendemos el LED poniendo primero el valor movwf PORTB ; en el registro w y después al puerto ; ;****Inicio del retardo 1**** Bucle1 decfsz CONTADOR1,1 ; Restamos 1 a 255. goto Bucle1 ; Si CONTADOR es cero, continuamos. decfsz CONTADOR2,1 ; Restamos 1 a 255 goto Bucle1 ; Volvemos al inicio de nuestro bucle ; Este retardo cuenta hacia atrás ... ;.desde 255 a 0, 255 veces. ; ;****Retardo terminado, ahora apagamos el LED **** movlw 00h ; Apaga el LED poniendo primero el valor ... movwf PORTB ; en el registro w y después al puerto ; ;****Añadimos otro retardo**** Bucle2 decfsz CONTADOR1,1 ; Este segundo bucle mantiene el LED goto Bucle2 ; apagado el tiempo suficiente decfsz CONTADOR2,1 ; para que lo veamos goto Bucle2 ; ;****Ahora volvemos al inicio del programa goto Inicio ; Vuelve al principio y enciende el LED... ;de nuevo. ;****Termina el Programa**** end ; Algunos compiladores necesitan esta instrucción. ;y también por si acaso olvidamos poner... ;la instrucción 'goto'. Para hacer un retardo con un tiempo específico en necesario saber la frecuencia del cristal, ya que con este se determina el tiempo de un ciclo de instrucción, esto es igual a (1/cristal)x4, exceptuando aquellas que como CALL, RETURN, GOTO, RETLW, BTFSC, INCFSZ, DECFSZ, que duran el doble, otro factor que determina la duración del retardo es el valor que tenga la variable, este está comprendido de 0 a 255, y también tomar en cuenta si se decrementa 61 o incrementar la variable, por ejemplo si tenemos un cristal de 20MHz, la variable tiene un valor de 125 y se decrementa. Un ciclo de instrucción (CI) = (1/20Mhz)x4 = .2µs movlw .125 movwf CONTADOR Bucle decfsz CONTADOR, 1 Goto Bucle ;Continua con el programa Entonces, el tiempo es determinado por el Ciclo de instrucción multiplicado por el valor de la variable (tomando en cuenta si a la variable se decrementa o incrementa) y a su vez esto multiplicado por la suma de la cantidad de ciclos de instrucción de las instrucciones dentro del dentro del retardo. CI x CONTADOR x (2+1)= Tiempo1 (.2µs)x(125)x3 = .075ms Si se requiriera un valor mayor de tiempo, esto se hace metiendo este bucle o ciclo dentro de un segundo, y si el tiempo aun no fuera suficiente, se puede repetir el proceso N veces hasta alcanzar tiempo requerido. Bucle2 Bucle1 movlw movwf movlw movwf decfsz Goto .100 CONTADOR2 .125 CONTADOR1 CONTADOR1, 1 Bucle1 62 decfsz CONTADOR2, 1 Goto Bucle2 ;Continua con el programa Para esto se tiene la siguiente formula (Tiempo1)x(CONTADOR2)+(2CIxCONTADOR2)= Tiempo2, y para determinar el tiempo de un tercer bucle o anidamiento seria (Tiempo2)x(CONTADOR3)+(2CIxCONTADOR3)= Tiempo3, y así N veces. Anteriormente se realizó un programa que hace el parpadeo de un LED, ahora se verá la manera de encender y apagar un LED usando un interruptor, para esto es necesario leer los puertos, para esto es necesario configurar los puertos o al menos un bit de un puerto como entrada, la cual será leída. bsf movlw movwf bcf STATUS,5 07h TRISA STATUS,5 ; Va al Banco 1. ; Para configurar el pin 7 del Puerto B ; como entrada. ; Vuelve al Banco 0. Ahora hemos puesto el bit 0 del puerto A como entrada. Lo que necesitamos hacer ahora es comprobar si el pin está a nivel alto o a nivel bajo. Para ello, podemos usar una de estas dos instrucciones: BTFSC y BTFSS. La instrucción BTFSC significa "Haz una comprobación de bit en el registro y bit que especificamos. Si es un 0, entonces sáltate la siguiente instrucción". La instrucción BTFSS significa "Haz una comprobación de bit en el registro y bit que especificamos. Si es un 1, entonces sáltate la siguiente instrucción". 63 La que se use dependerá de cómo se quiera que nuestro programa reaccione cuando lea la entrada. Por ejemplo, si simplemente se está esperando que la entrada sea 1, entonces se podría utilizar la instrucción BTFSS de este modo: ;Aquí el código BTFSS Goto PORTB, 7 Inicio ;Continua por aquí Entonces es muy sencillo hacer un programa que prenda un LED con un interruptor externo, como siempre es necesaria la configuración de los puertos. bsf movlw movwf bcf STATUS,5 1000 0000 TRISB STATUS,5 ; Va al Banco 1 ; Para configurar el bit 7 del Puerto B ; como entrada ; Vuelve al Banco 0 Aquí se está poniendo el bit 7 del puerto B como entrada, y todos los demás se quedan como salidas, ahora preguntamos si el bit 7 está en alto o en bajo, para prender o apagar el LED, para esto se utiliza el BTFSS para que cuando este activo el bit 7 salte a la opción de encender, mientras tanto que se mantenga apagado. CHECA Btfss goto PORTB, 7 CHECA ;Puerto B bit 7 Activado? ;si no lo está sigue preguntando 64 Bsf PORTB,0 Cuando está activo enciende el bit 0 del ;puerto B Y así de sencillo es una manera de leer la entrada de los puertos y con respecto al estado de esta señal, sea en alto o en bajo, tomar una decisión, saltar a otra parte del programa, hacer una interrupción, realizar alguna operación, etc. Operadores Aritméticos ADD Esta función lo que hace es sumar dos números. Si el resultado de sumar dos números excede de 8 bits o de 255, entonces se activará un flag llamado CARRY, el CARRY se trata de 1 bit que se ubica en un registro en concreto de la memoria del PIC, el CARRY está localizado en el bit 0 de la dirección de memoria 03h. Si este bit se activa, quiere decir que la suma de los 2 números excedió los 255. Si es 0, entonces el resultado queda dentro de los 8 bits. También, el PIC nos da dos modalidades de ADD, que son ADDLW y ADDWF. Como puedes suponer, es muy similar a la función anterior. ADDLW añade los contenidos del registro W con un número que le especifiquemos. ADDWF añadirá los contenidos del registro W y cualquier otro registro que le especifiquemos. SUB 65 La instrucción SUB es una substracción o resta. Una vez más el PIC da dos modalidades: SUBLW y SUBWF. La sintaxis es exactamente la misma que para la función ADD. Ahora se mostrara como hacer un convertidor de BCD a 7 segmentos utilizando las instrucciones SUB y ADD, es decir, hacer una conversión de 8 bits y desplegar el número en decimal en tres displays, para esto es necesario seleccionar un puerto como como entradas, otro puerto para los displays y 3 salidas más para multiplexar. La multiplexación consiste en elegir el display que se va a activar, más adelante se entenderá mejor, empezaremos configurando los puertos: ;;;;;;;;;;;Configuración de puertos;;;;;;;;;;;;; bsf clrf clrf movlw movwf bcf STATUS,5 TRISC TRISA b'11111111' TRISB STATUS,5 ;Se mueve el Banco 1 ;Puerto C como salida de displays ;Puerto A como salida de multiplexar ;1111 1111 movidos a W ;Puerto B como entrada de 8 bits ;Regresa al Banco 0 La conversión se hará de la siguiente manera, se adquiere el dato del puerto B, a este dato en decimal equivale a 255, entonces se empezara sacando centenas, decenas y unidades, también debemos tomar en cuenta que el lenguaje ensamblador no hace divisiones, por lo que se harán restas. Primero se guarda el valor del puerto en una variable y se le hará una resta de 100, si el 66 valor es mayor a 100 se incrementara el valor de otra variable llamada cent, de no ser así se provocara un acarreo o CARRY y se volverá a sumar los 100 para regresarlo a su valor original y pasara a determinar el número de centenas que tiene y se hará lo mismo que en las centenas, solamente que en lugar de substraer 100 se substraerá 10 y se irán guardando en otra variable llamada dec, se entenderá mejor con la siguiente parte del código. ;;;;;;;;;;;;;;Adquisición de dato;;;;;;;;;;;;;; movf PORTB,0 ;coloca lo que está en el puerto B en W movwf DIVIDENDO ;Lo q esta en W lo mueve a DIVIDENDO ;;;;;;;;;;;;;;Obtener Centenas;;;;;;;;;;;;;;;;; CENTENAS movlw .100 ;W toma el valor de 100d valor en decimal subwf DIVIDENDO,f ;se hace la resta de k-w, es decir, ;DIVIDENDO - 100 btfss STATUS,0 ;Pregunta por el carry, si se produjo goto SUMA_100 ;el número dio negativo se suma lo q se resto incf cent,f ; incrementa en 1 la varia de centenas goto CENTENAS ;repite el proceso hasta q ya no se puedan ;extraer centenas SUMA_100 movlw .100 addwf DIVIDENDO,f ;se suman los 100 que se le restaron ;para regresar a su valor y devolver el carry ;;;;;;;;;;;;;;Obtener centenas;;;;;;;;;;;;;;;;; DECENAS movlw .10 ;W tomo el valor de 10d subwf DIVIDENDO,f ;y se la substrayendo al DIVIDENDO btfss STATUS,0 ;pregunta si se produjo el CARRY goto SUMA_10 ;Va a la rutina para devolver los 10 incf dec,f ;si no se incrementa en 1 las decenas goto DECENAS ;y se repite el ciclo hasta q ya no entre SUMA_10 movlw .10 addwf DIVIDENDO,f ;si al hacer la resta dio un numero negativo ;se produce un carry? 67 goto UNIDADES ;y se le hace una suma devolviendo al valor ;anterior ;;;;;;;;;;;;;;Obtener Unidades;;;;;;;;;;;;;;;;; UNIDADES movf DIVIDENDO,0 movwf uni ;el valor que queda al DIVIDENDO ;se pone en las unidades Hasta aquí ya se han sacado las centenas, decenas y unidades del puerto B, que se ha llamado DIVIDENDO, ahora hay que mandarlas a los display, hay que recordar que los 3 display están conectados a la mismas salidas, entonces si se mandan las centenas y los display están activos, los 3 desplegaran el mismo número, es por eso que se usa la multiplexación, cuando se quieran mandar las decenas se manda un pulso del puerto A al display de las centenas y al mismo tiempo se manda el valor de las centenas, lo mismo para las decenas y unidades y así cada uno mostrara el número correspondiente. ;;;;;;;;;MANDAR CENTENAS;;;;;;;;;;;;; movf cent,0 ;Guarda una copia de cent en W movwf COMPARA ;adquiere el valor q tiene W (cent) bSf PORTA,0 ;Activa el bit 0 del puerto A (para multiplexar) call NUMEROS ;Se mueve a la tabla para comparar el valor q ;tenia cent bCf PORTA,0 ;Desactiva el bit 0 de las centenas ;;;;;;;;;MANDAR DECENAS;;;;;;;;;;;;; movf dec,0 ;Guarda en W una copia de dec Movwf COMPARA ;mueve el valor de dec a compara bSf PORTA,1 ;activa bit 1 del puert0 A para el display de decenas 68 call NUMEROS ;Compara el dato con una tabla bCf PORTA,1 ;Regresa y apaga el display de decenas ;;;;;;;;;MANDAR UNIDADES;;;;;;;;;;;;; movf uni,0 ;lo que vale uni lo guarda en W movwf COMPARA ;W se guarda en COMPARA bSf PORTA,2 ;Activa el bit 2 del puerto A para las unidades call NUMEROS ;llama a una tabla y verifica el numero q es bCf PORTA,2 ;regresa y desactiva las unidades Se tiene que crear una tabla de comparación, esta tabla sirve dentro de nuestro programa para comparar las centenas, decenas y unidades y con respecto al número que se tenga mandar a activar los bits necesarios para hacer el número correspondiente en el display, la comparación se hace en binario, es por eso que debemos de saber que bit son necesarion poner en alto o bajo (dependiendo del tipo de display) obtener el numero deseado, en la siguiente imagen se muestra como están conectados los display con el microcontrolador: 69 Así que lograr los de manera gráfica en el display el numero esta la siguiente tabla representativa para un cátodo común. Número Valor del Puerto C 1 b'01000001' = 41h 2 b'00111011' = 3Bh 3 b'01101011' = 6Bh 4 b'01001101' = 4Dh 5 b'01101110' = 6Eh 6 b'01111110' = 7Eh Display 70 7 b'01000011' = 43h 8 b'01111111' = 7Fh 9 b'01101111' = 6Fh 0 b'01110111' = 77h Para poder comparar el valor del número obtenido con respecto al número que se tiene que desplegar en el display es necesario utilizar las instrucciones anteriores, y con respecto al resultado tomar la decisión de mandar el número o seguir buscando a cual corresponde. ;;;;;;;;;;Tabla De Comparación;;;;;;; NUMEROS ;;;;;;;;;;CERO;;;;;;;;;;; MOVF COMPARA,0 SUBLW b'00000' BTFSC STATUS,2 CALL CERO ;W igual al Puerto B ;Se resta COMPRAR con 0 ;Si el resultado es CERO manda ;llamar al numero ;en este caso a CERO, sino, brinca a ;comparar otro numero 71 ;;;;;;;;;;UNO;;;;;;;;;; MOVF COMPARA,0 SUBLW b'00001' ; Este número binario equivale a ;número en decimal BTFSC STATUS,2 CALL UNO Y se repite prácticamente las mismas instrucciones para cada una de las comparaciones, solamente cambia el valor contra el cual compara. ;;;;;;;;;;OCHO;;;;;;;;;; MOVF COMPARA,0 SUBLW b'01000' BTFSC STATUS,2 CALL OCHO ;;;;;;;;;;NUEVE;;;;;;;;;; MOVF COMPARA,0 SUBLW b'01001' BTFSC STATUS,2 CALL NUEVE Solamente falta la dichosa falta de los números que desplegara en el diplsay, la cual viene a continuación ;;;;;;;;;Tabla de Numeros;;;;;;;;;;;;;; CERO UNO MOVLW MOVWF RETURN MOVLW MOVWF RETURN b'01110111 PORTC b'01000001' PORTC Y este proceso se repite hasta el número nueve, cambiando los bits que se activaran en el Puerto C, este número se muestra en la tabla mostrada anteriormente. OCHO NUEVE MOVLW MOVWF RETURN MOVLW b’01111111 PORTC b'01101111 72 MOVWF RETURN PORTC Y con esto se tiene se tiene el programa terminado de conversión. Claro que existen más funciones y mejores formas de realizar los programas, aquí solo se muestra de una manera sencilla el alcance que puede tener, la limitante ahora es el Microcontrolador y el programador. El LCD La pantalla de cristal líquido o LCD (Liquid Crystal Display) es un dispositivo microcontrolado de visualización grafico para la presentación de caracteres o símbolos, en este caso dispone de 2 filas de 16 caracteres cada una, y cada carácter dispone de una matriz de 5x7 puntos (pixels). Características principales: Pantalla de caracteres ASCII, además de los caracteres Kanji y Griegos. Desplazamiento de los caracteres hacia la izquierda o la derecha. Memoria de 40 caracteres por línea de pantalla. Movimiento del cursor y cambio de su aspecto. Permite que el usuario pueda programar 8 caracteres. Conexión a un procesador usando un interfaz de 4 u 8 bits 73 El LCD cuanta con pines, y además un juego de instrucciones y comandos utilizados para configurar el LCD, adelante se muestra una tabla con los pines. Clear Display Borrar y colocar el cursor en la primera posición (dirección 0). Pone el bit I/D a 1 por defecto. RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 0 0 0 0 0 0 0 1 Home 74 Colocar el cursor en la posición de inicio (dirección 0) y hacer que el display comience a desplazarse desde la posición original. El contenido de la memoria RAM de datos de visualización (DD RAM) permanece invariable. RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 0 0 0 0 0 0 1 X Entry Mode Set Establecer la dirección de movimiento del cursor y especificar si la visualización se desplaza a la siguiente posición de la pantalla o no.. Para visualizar normalmente se debe poner el bit S=0. RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 0 0 0 0 0 1 I/D S Display ON/OFF Control Activar o desactivar poniendo en ON/OFF tanto el LCD (D) como el cursor (C) y establecer si este último debe o no parpadear (B). RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 0 0 0 0 1 D C B Cursor or Display Shift Mover el cursor y desplazar el LCD sin cambiar el contenido de la memoria de datos de visualización DD RAM. 75 RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 0 0 0 1 S/C R/L X X Function Set Establecer el tamaño de interface con el bus de datos (DL), número de líneas del LCD (N) y tipo de carácter (F). RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 0 0 0 0 1 DL N F X X Set the CG RAM Address El módulo LCD además de tener definidos todo el conjunto de caracteres ASCII permite al usuario definir 4 u 8 caracteres. La composición de estos caracteres se va guardando en una memoria llamada CG RAM con capacidad para 64 bytes. Cada carácter definido por el usuario se compone de 16 u 8 bytes que se almacenan en consecutivas en posiciones de la CG RAM. Mediante esta instrucción se establece la dirección de memoria CG RAM a partir de la cual se irán almacenando los bytes que definen un carácter. Ejecutando este comando todos los datos que se lean o escriban posteriormente lo harán desde esta memoria CG RAM. RS R/W DB7 DB6 DB5 DB4 DB3 DB2 0 0 0 1 Dirección de la CG RAM DB1 DB0 76 Set the DD RAM Address Los caracteres o datos a visualizar se almacenan en una memoria llamada DD RAM para luego pasar a la pantalla. Mediante esta instrucción se establece la dirección de la memoria DD RAM a partir de la cual se almacenarán los datos a visualizar. Ejecutando este comando todos los datos que se escriban o lean posteriormente lo harán desde esta memoria DD RAM. Las direcciones 80h a 8Fh corresponden a los 16 caracteres del primer renglón y las direcciones C0h a CFh a los 16 caracteres del segundo renglón, para este modelo de LCD. RS R/W DB7 DB6 DB5 DB4 DB3 0 0 1 Dirección de la DD RAM DB2 DB1 DB0 Read Busy Flag and Address El módulo LCD tarda un cierto tiempo para ejecutar las instrucciones, tiempo en que no se debe enviar otra instrucción. Para ello dispone de un flag BUSY (ocupado) que indica que se está ejecutando una instrucción. Esta instrucción de lectura informa del estado de dicho flag además de proporcionar el valor del contador de direcciones de la CG RAM o de la DD RAM según la última que se haya empleado. RS R/W DB7 DB6 DB5 DB4 DB3 DB2 0 1 BF Dirección de la CG RAM o DD RAM DB1 DB0 Writ 77 e data to CG or DD RAM Comando para escribir en la memoria DD RAM los datos que se quieren presentar en pantalla, en código ASCII. Igualmente se escribe en la memoria CG RAM los bytes para generar caracteres definidos por el usuario. Previamente se direcciona la memoria DD RAM o la memoria CG RAM en la que se quiere escribir datos. RS R/W DB7 DB6 DB5 DB4 DB3 DB2 1 0 Código ASCII o byte del carácter gráfico DB1 DB0 Read Data from CG RAM or DD RAM Comando para leer los datos almacenados en la memoria DD RAM, en código ASCII. Igualmente se lee de la memoria CG RAM los bytes de los caracteres definidos por el usuario. Previamente se direcciona la memoria DD RAM o la memoria CG RAM de la que se quiere leer los datos. RS R/W DB7 DB6 DB5 DB4 DB3 DB2 1 1 Código ASCII o byte del carácter gráfico DB1 DB0 Para comenzar a trabajar con un LCD es necesario hacer una configuración inicial, definiendo los parámetros del cursor, su posición inicial, la manera de desplegar los datos, el tamaño del dato y la manera de recibirlo, esto usando las instrucciones anteriormente mencionadas, bueno sin olvidar las 78 configuraciones iniciales que debe llevar todo programa en lenguaje ensamblador, que son la definición de puertos de entrada y salida y variables. La configuración de los puertos se muestra a continuación: RS Equ 0x04 ;El registro de control es toma el valor de 04 RW Equ 0x06 ;El modo lectura/escritura tomo el valor de 06 E Equ 0x07 ;El Habilitador o Enable toma el valor de 07 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Facilitara La escritura y comprensión del programa;;;;;;;;;;; ORG 0X00 ;;;;;;;;Configuración De Puerto;;;;;;;; BSF STATUS,5 ;Cambia al banco 1 CLRF TRISB ;Puerto B como salida BCF STATUS,5 ; Regresa banco 0 CLRF PORTB ;Pone el Puerto B en Cero Los parámetros que se configuran habitualmente son el CLEAR DISPLAY, SET DISPLAY SHITF, SET DISPLAY CHARACTER MODE y SET DISPLAY ON/OFF AND CURSOS COMMAND, lo más recomendable en este orden: 79 La parte del código que corresponde a la inicialización de configuración del LCD es la siguiente: ;;;;;;;;;;;;;;;;RUTINA PARA CONFIGURAR LCD;;;;;;;;;;;;;;;;;;;;;;;;;;;; CONF_LCD CALL LCD_BUSY call LCD_Clr ;Borra el display call DELAY_2MS movlw 0x20 ;0010 0000 call LCD_Cmd call DELAY_40us movlw 0x28 ;0010 1000 Set display shift call LCD_Cmd call DELAY_40us movlw 0x06 ;0000 0110 Set display character mode call LCD_Cmd call DELAY_40us movlw 0x0c ;0000 1100 Set display on call LCD_Cmd ;Set cursor off call DELAY_40us call LCD_Clr ;clear display call DELAY_2MS retlw 0x00 Cabe aclarar que en esta parte del programa aparecen subrutinas que aún no se han nombrado, como LCD_Cmd que se encarga de enviar el dato, los retardos y el LCD_BUSY. El LCD_Busy es la manera de revisar que el LCD no esté realizando alguna otra operación, tanto como de escritura o lectura, para realizar esta revisión se debe a leer el bit 7 de datos del LCD y habilitar el Enable (E) y preguntar si está en estado alto o bajo, si está en estado alto quiere decir que está realizando una operación y entonces se queda esperando hasta que haya terminado, cuando termina regresa el Enable a esta do bajo y se regresa al 80 modo de escritura y al modo de control, con el siguiente diagrama de flujo se entenderá mejor: Entonces la parte de este código quedaría de la siguiente manera: LCD_BUSY bsf clrf bcf bcf bsf call OCUPADO btfsc goto bcf bsf STATUS,5 TRISB STATUS,5 PORTB, RS PORTB, RW PULSE_E MEMORIA2, 7 OCUPADO PORTB, RW STATUS, 5 ;banco 1 ;Puerto como salida ;regresa al banco 0 ;modo registro de control ;modo lectura ;Deja entra salir los datos ; bit 7 activo? ;checa hasta q se desocupe ;se desocupa y habilita modo lectura ;banco 1 81 movlw 0x00 movwf TRISB bcf STATUS, return ;configura como salida puerto b 5 ;regresa banco 0 La manera de enviar datos aria con respecto si se configuro de un bus de 4 bits o uno de 8 bits, la manera más cómoda seria de 8 bits, pero la manera más práctica es de un bus de 4 bits, ya que se dejan pines disponibles del Microcontrolador, este programa está configurado para un bus de 4 bits, para un bus de 4 bits es necesario primero poner R/W en modo de escritura, RS va a variar dependiendo si se quiere mandar un dato o un comando o instrucción de configuración, un 1 para datos y 0 para comando, después revisar con el LCD_Busy si está ocupado el LCD o no, activar el Enable y posteriormente dividir este dato o comando, según sea el caso, en dos, para así mandar primero los niveles bajos y después los niveles altos. La parte de este programa corresponde a las siguientes líneas: ;;;;;;;;;;;;RUTINA PARA CARACTER DE 4 BITS;;;;;;;;;;;;;;;;;;;;; LCD_Char call LCD_BUSY movwf MEMORIA1 swapf MEMORIA1,w andlw 0x0f movwf PORTB bsf PORTB, RS call PULSO_E movf MEMORIA1,w andlw 0x0f movwf PORTB bsf PORTB, RS call PULSO_E ;GUARDA EL VALOR DE MEMORIA1 A W ;CAMBIA LOS NIVELES ALTOS ;BORRA LOS VALORES ALTOS ;MANDA LOS BITS BAJOS ;PONE EL REGISTRO DE CONTROL ;MANDA UN PULSO PARA LEER ;MANDAR NIVELES BAJOS ;BORRA LOS NIVELES ALTOS ;Y LOS MANDA POR EL PUERTO B ;RS line to 1 ;HABILITA UN PULSO DE ENABLE 82 call LCD_BUSY retlw 0x00 ;;;;;;;;;;;;;;;; RUTINA PARA MANDAR COMANDOS;;;;;;;;;;;;;;;;;;;;; LCD_Cmd call LCD_BUSY movwf MEMORIA1 swapf MEMORIA1,w andlw 0x0f movwf PORTB bcf PORTB, RS call PULSO_E movf MEMORIA1,w andlw 0x0f movwf PORTB bcf PORTB, RS call PULSO_E call LCD_BUSY retlw 0x00 ;GUARDA EL VALOR DE MEMORIA1 A W ;CAMBIA LOS NIVELES ALTOS ;BORRA LOS VALORES ALTOS ;MANDA LOS BITS BAJOS ;Modo de comandos ;MANDA UN PULSO PARA LEER ;Manda los niveles bajos ;Borra los 4 bit más significativos ;Manda niveles bajos por el Puerto B ;RS line to 0 ;Activa la entrada de datos ;revisa que no este ocupado el LCD ;regresa con el valor de 0 Ya se tiene la parte de la configuración del PIC, el LCD_Busy que revisa que no este ocupado, la forma de mandar datos y comandos, solo falta la parte central del programa que depende directamente de todo lo anterior: ;;;;;;;;;;;;;; PROGRAMA ;;;;;;;;;;;;;;;; clrf CONTADOR ;PONE EN 0 EL CONTADOR MENDAJE movf CONTADOR, w call TEXTO xorlw 0x00 btfsc STATUS, 2 goto fin call LCD_Char incf CONTADOR, f goto MENSAJE fin goto fin ;;;;;;;;;;;;;;;;TEXTO;;;;;;;;;;;;;;;;;;; TEXTO addwf PCL, f ;PONE EL VALOR DEL CONTADOR EN W ;VA A LA TABLA DONDE ESTA EL TEXTO ;ES IGUAL A 0? ;pregunta por el resultado de la operación ;si es cero termina, sino… ;Va a la rutina para insertar carácter ;incrementa en 1 el contador ;Regresa para adquirir el mensaje ;termina 83 retlw retlw retlw retlw retlw retlw retlw retlw retlw retlw retlw retlw retlw retlw retlw retlw b'00010100' b'01100100' b'00011100' b'00010100' b'00010100' b'00101110' b'00010100' b'00100100' b'00010100' b'00100100' b'00010100' b'00100100' b'01000001' b'01000010' b'01000001' 0x00 ;Los caracteres son ingresados ;mediante código binario ;este valor es sacado de la tabla de caracteres ;aunque también puede escribirse la letra ;y el programa generare el código binario ;correspondiente Lo que hace el programa es que lleva una cuenta de la veces que se repite el ciclo, para que cuando mande a la subrutina TEXTO este valor de CONTADOR va a ser los renglones que va a saltar hacia abajo, y así ira escribiendo las letras previamente cargadas, también compara el valor 0x00 para determinar si ya se terminó la tabla, y manda el dato con la subrutina LCD_Char. Recomendaciones: La única manera de aprender a programar, es programando, con la práctica encontraras las particularidades de cada micro y desarrollarlas tu propia forma de la resolución y análisis de problemas, la única limitante en el desarrollo de programas el que los realiza, es decir la imaginación que se tiene para solucionar los problemas. 84