Descarga la aplicación para disfrutar aún más
Vista previa del material en texto
Nº DE COLECCIÓN 153 - Rep. Argentina: $99,99 - México: $120 M/N - Otros Países: u$s 8 pCreatronica 349.qxd:Maquetación 1 21/4/16 12:11 p.m. Página 1 4ª forros.qxd:Maquetación 1 15/10/13 10:37 Página 1 MICROCONTROLADORES PIC PROGRAMACIÓN BÁSICA M. en C. Ismael Cervantes de Anda Ing. Alberto Jesús Alcántara Méndez Docentes de la Escuela Superior de Cómputo (ESCOM) Instituto Politécnico Nacional (IPN) México 2 CONTENIDO CONTENIDO ........................................................................................................................ 2 CAPÍTULO I. RUTINAS BÁSICAS ..................................................................................... 3 1.1 CONFIGURACIÓN DE LOS PUERTOS COMO ENTRADA O SALIDA ...................... 3 1.2 LECTURA DE DATOS DE UN PUERTO ........................................................................... 5 1.3 ESCRITURA DE DATOS EN UN PUERTO ..................................................................... 11 1.4 ASIGNACIÓN DE DATOS A UN REGISTRO ................................................................. 16 1.5 INCREMENTO Y DECREMENTO DE DATOS DE LOS REGISTROS ...................... 23 1.5.1 Incremento o Decremento del dato de un registro en una unidad ....................................................23 1.5.2 Incremento o Decremento del dato de un registro en valores diferentes a la unidad .......................24 1.6 DISEÑO DE UN CONTADOR ............................................................................................ 25 1.6.1 Contador Ascendente .......................................................................................................................27 1.6.2 Contador Descendente .....................................................................................................................30 1.7 DISEÑO DE UN RETARDO BÁSICO POR BUCLES ..................................................... 32 1.8 SUMA ARITMÉTICA .......................................................................................................... 40 1.9 RESTA ARITMÉTICA ........................................................................................................ 51 1.10 MULTIPLICACIÓN ARITMÉTICA ............................................................................... 64 1.11 DIVISIÓN ARITMÉTICA ................................................................................................. 68 CAPÍTULO II. RUTINAS INTERMEDIAS ...................................................................... 73 2.1 FUNCIÓN LÓGICA AND Y SUS APLICACIONES ........................................................ 73 2.2 FUNCIÓN LÓGICA OR Y SUS APLICACIONES .......................................................... 77 2.3 FUNCIÓN LÓGICA XOR Y SUS APLICACIONES ....................................................... 82 2.4 FUNCIONES LÓGICAS DE COMPARACIÓN ENTRE REGISTROS (=, <, >) .......... 85 2.4.1 Comparación IGUAL (=) ó DIFERENTE (≠) .................................................................................86 2.4.2 Comparación MENOR QUE (<) ó MAYOR O IGUAL QUE (≥)...................................................92 2.4.3 Comparación MAYOR QUE (>) ó MENOR O IGUAL QUE (≤)...................................................98 2.5 LECTURA DE UN TECLADO MATRICIAL ................................................................. 103 2.6 CONFIGURACIÓN DE LAS INTERRUPCIONES ....................................................... 114 2.7 IMPLEMENTACIÓN DE UN RETARDO POR TIMER .............................................. 120 2.7.1 El TIMER de 8 bits (TMR0) ..........................................................................................................122 2.7.2 El TIMER de 16 bit s (TMR1) .......................................................................................................128 2.8 CONFIGURACIÓN DE LA USART ................................................................................ 136 2.8.1 USART en modo Transmisión (Tx) ..............................................................................................138 2.8.2 USART en modo Recepción (Rx) .................................................................................................146 3 CAPÍTULO I. RUTINAS BÁSICAS 1.1 CONFIGURACIÓN DE LOS PUERTOS COMO ENTRADA O SALIDA El primer ejercicio que se realiza con un microcontrolador es la de leer o escribir datos discretos (digitales) a través de sus puertos, por lo tanto, la primera actividad que tiene que realizarse, es la de configurar sus respectivos puertos ya sean como de entrada o de salida de datos. Todos los microcontroladores poseen puertos que dependiendo de su estructura física relacionada con la cantidad de terminales, pueden poseer una cantidad de puertos igual a 1 ó 2 ó 3, etc. Figura 1 Diversos microcontroladores PIC. 2 A continuación describiremos la manera en que tienen que ser configurados los puertos de un microcontrolador PIC, y para ello, nos basaremos en 4 microcontroladores PIC de diferentes tamaños, los cuales tomaremos como modelo y a partir de estos, podremos realizar cualquier aplicación, no importando la cantidad de terminales que posean los microcontroladores, ya que lo importante es aprender a configurarlos y obtener el máximo beneficio de sus herramientas internas. Para configurar los puertos de entrada o salida de datos digital de los microcontroladores, se tiene que guardar un valor en el respectivo registro de configuración del puerto a ser empleado. El registro de configuración debe ser manipulado en el llamado ―tris‖, que dependiendo del puerto se complementa el nombre del registro a ―trisa‖ si se trata del puerto A, o ―trisb‖ si se trata del puerto B, o ―trisc‖ si se trata del puerto C, etc. Normalmente la mayor cantidad de puertos que posee un microcontrolador PIC es de 5 por lo que solo llegaría hasta el puerto E. Cabe aclarar, que los microcontroladores que cuentan con un solo puerto como es el caso del PIC12F629, el registro de configuración de su puerto correspondiente, tan solo recibe el nombre de ―trisio‖, ya que no es necesario especificarle de que puerto se trata, por el hecho de que solo posee uno. Los registros de configuración de los diferentes puertos de los microcontroladores PIC, se encuentran en el banco 1 del mapa de memoria de datos, siendo las localidades específicas para cada registro de configuración las siguientes: 3 Matrícula del PIC Registro de Configuración trisa trisb trisc Trisd trise trisio PIC12F629 ---- ---- ---- ---- ---- 85h PIC16F628A 85h 86h ---- ---- ---- ---- PIC16F876 85h 86h 87h ---- ---- ---- PIC16F877 85h 86h 87h 88h 89h ---- Tabla 1. Ubicación de los registros de configuración de algunos microcontroladores PIC. Todos los registros tris (configuración de puertos) de los diferentes puertos que poseen los microcontroladores PIC, se encuentran conformados por 8 bits, los cuales dependiendo del estado lógico en el que se encuentren, será la forma de como se configure su correspondiente puerto, ya sea como entrada o salida. Para que un puerto de algún microcontrolador PIC sea configurado como entrada, en su correspondiente registro tris se debe de alojar un dato el cual debe estar compuesto por 1’s lógicos. Expresado de otra manera, sí se requiere que todos los bits de un puerto sean configurados como entradas, entonces a cada bit del correspondiente registro tris del puerto en cuestión se le tendrá que colocar en 1 lógico. Tal como se muestra a continuación: Registro tris = 11111111(binario) ó tris = FF(hexadecimal) ó tris = 255(decimal) De manera contraria, para que un puerto de algún microcontrolador PIC sea configurado como salida, en su correspondiente registro tris se debe de alojar un dato el cual debe estar constituidopor 0’s lógicos. Expresando lo anterior de otra manera, sí se requiere que todos los bits de un puerto sean configurados como salidas, entonces a cada bit del correspondiente registro tris del puerto en cuestión se le tendrá que colocar en 0 lógico. Tal como se muestra a continuación: Registro tris = 00000000(binario) ó tris = 00(hexadecimal) ó tris = 000(decimal) Por otra parte, no es requisito indispensable configurar los bits de todo 4 un puerto ya sea como entrada o como salida, si no dependiendo de la aplicación un mismo puerto puede ser configurado por ejemplo mitad como entrada y mitad como salida, por lo tanto el registro tris podría quedar como: Registro tris = 00001111(binario) ó al revés tris = 11110000(binario) De manera general, la cantidad de bits de entrada o salida que se pueden configurar en un puerto, depende de las necesidades de la aplicación, pero lo que si debe de tomarse en cuenta es que los puertos cuentan con máximo 8 bits, los cuales deben ser distribuidos de manera adecuada, para considerar que microcontrolador es el que debemos de adquirir. Para acceder a cualquiera de los registros tris se tiene que apuntar en primera instancia al banco 1 del mapa de memoria de datos, para ello se tienen que manipular los bits rp0 y rp1 del registro ―status‖. Por otra parte suponga que se requiere configurar al puerto A como entrada y en el puerto B el nible superior como entrada y el nible inferior como salida. A continuación se muestra a manera de sugerencia el código para realizar las acciones antes descritas, sobre microcontroladores que cuentan con más de un puerto. bsf status,rp0 ;cambia al banco 1 bcf status,rp1 movlw b’11111111’ ;configura al puerto A como entrada movwf trisa movlw b’11110000’ ;configura al puerto B bits del 0 a 3 como salida movwf trisb ;bits del 4 a 7 como entrada Para microcontroladores que solo tienen un puerto, y además necesitamos que los bits 0,1 y 2 sean configurados como entradas, y los bits 3, 4 y 5 sean configurados como salidas, tomando en cuenta que el microcontrolador de un solo puerto puede ser el PIC12F629, se presenta el fragmento de código para configurar el puerto. bsf status,rp0 ;cambia al banco 1 movlw b’00000111’ ;configura los bits del 0 al 2 como entrada, y los bits del 3 al 5 ;como salida del único puerto. movwf trisio 5 Aunque todos los registros de configuración tris son de 8 bits, en el PIC12F629 solo son empleados los 6 bits de más bajo peso, por lo que los bits 6 y 7 los colocamos en ―0‖ (de todas maneras son colocados en el estado lógico ―0‖ de manera automática). Para finalizar el tema de la configuración de los registros de los puertos, podemos decir que es a través de los registros de configuración tris por donde se configuran los puertos de un microcontrolador, por lo tanto, son los primeros registros que deben ser manipulados cuando se diseña un programa. 1.2 LECTURA DE DATOS DE UN PUERTO No importando la cantidad de bits que conformen a un puerto, este puede ser configurado para que pueda ―leer‖ algún dato del exterior, para ello, una vez que se tiene el correspondiente circuito de aplicación, se graba en el microcontrolador PIC el programa por medio del cual realizara la tarea de ingresar un dato digital al microcontrolador. 6 ; Programa de prueba para leer el puerto B LIST P=PIC16F876 ;Aquí se coloca la matricula del microcontrolador ;que vaya a emplearse ;============================================================= ; Declaración de registros ;============================================================= portb equ 0x06 status equ 0x83 trisb equ 0x86 temporal equ 0x20 ;============================================================= ; Declaración de bits ;============================================================= rp0 equ 0x05 rp1 equ 0x06 ;============================================================= ; Vector del reset ;============================================================= reset org 0 goto inicio ;============================================================= ; Inicio del programa principal ;============================================================= inicio bsf status,rp0 ;cambia al banco 1 bcf status,rp1 movlw b’11111111’ ;configura al puerto B como entrada movwf trisb bcf status,rp0 ;cambia al banco 0 bcf status,rp1 movf portb,0 ;el dato del puerto es cargado al registro W movwf temporal ;el valor del registro W se aloja en el registro ;temporal. goto inicio Tabla 2. Utilización del puerto B de cualquier microcontrolador PIC para leer datos. Para poder emplear un puerto como entrada en los microcontroladores PIC, se tiene que comenzar con la configuración del correspondiente registro ―tris‖, colocando todos sus bits en unos ―lógicos‖ (1’s). Posteriormente a la configuración del registro tris, se tiene que emplear el registro denominado ―port‖, llamando al puerto A como ―porta‖, al puerto B como ―portb‖, al puerto C como ―portc‖ y así sucesivamente para cada uno de los puertos con que cuente el microcontrolador. 7 ; Programa de prueba para leer el puerto A LIST P=PIC16F628A ;Aquí se coloca la matricula del microcontrolador ;que vaya a emplearse ;============================================================= ; Declaración de registros ;============================================================= porta equ 0x05 cmcon equ 0x1f status equ 0x83 trisa equ 0x85 temporal equ 0x20 ;============================================================= ; Declaración de bits ;============================================================= rp0 equ 0x05 rp1 equ 0x06 ;============================================================= ; Vector del reset ;============================================================= reset org 0 goto inicio ;============================================================= ; Inicio del programa principal ;============================================================= inicio bsf status,rp0 ;cambia al banco 1 bcf status,rp1 movlw b’11111111’ ;configura al puerto A como entrada movwf trisa bcf status,rp0 ;cambia al banco 0 bcf status,rp1 movlw b’00000111’ ;selecciona 0 (cero) comparadores en el movwf cmcon ;registro cmcon (deshabilita los ;comparadores) movf porta,0 ;el dato del puerto es cargado al registro W movwf temporal ;el valor del registro W se aloja en el registro ;temporal. goto inicio ; Programa de prueba para leer el puerto A LIST P=PIC16F876 ;Aquí se coloca la matricula del microcontrolador ;que vaya a emplearse ;============================================================= ; Declaración de registros ;============================================================= porta equ 0x05 status equ 0x83 trisa equ 0x85 adcon1 equ 0x9f temporal equ 0x20 ;============================================================= ; Declaración de bits ;============================================================= rp0 equ 0x05 rp1 equ 0x06 ;============================================================= ; Vector del reset ;============================================================= reset org 0 goto inicio ;============================================================= ; Inicio del programa principal ;============================================================= inicio bsf status,rp0 ;cambia al banco 1 bcf status,rp1 movlw b’11111111’ ;configura al puerto A como entrada movwf trisa movlw b’00000111’ ;selecciona 0 (cero) comparadores en el movwf adcon1 ;registro adcon1 (deshabilita los ADC) bcf status,rp0;cambia al banco 0 bcf status,rp1 movf porta,0 ;el dato del puerto es cargado al registro W movwf temporal ;el valor del registro W se aloja en el registro ;temporal. goto inicio Tabla 3. Utilización del puerto A para leer datos de los microcontroladores PIC16F628A y PIC16F876. Los registros ―port‖ prácticamente se comportan como un reflejo del estado lógico que se presenta en las terminales físicas del microcontrolador, siendo más específicos, diremos que el dato que alojemos en algún registro port, se transmitirá a las terminales que se encuentran relacionadas con el registro port correspondiente, recordando que el registro tris consecuente debe encontrarse configurado de tal forma que el puerto se comporte como entrada. Todos los registros port se encuentran constituidos por 8 bits, los cuales indican el estado lógico en que se encuentran las terminales físicas del puerto en cuestión del microcontrolador PIC. Para leer todos los bits de un puerto se puede emplear el comando de lectura de un registro, indicando en la instrucción el puerto que tendrá que ser intervenido, para una mayor referencia observe el 8 ejemplo que se ilustra en la tabla 2. Este código es valido para todos los puertos exceptuando al puerto A de los microcontroladores PIC, por otra parte también se indica el direccionamiento del banco donde se encuentran los registros que serán empleados, actividad que se implementa por medio de la manipulación de los bits ―rp0‖ y ―rp1‖ del registro ―status‖. En las terminales del puerto A de los microcontroladores PIC dependiendo de su estructura interna, pueden poseer ya sea convertidores analógico a digital (ADC), ó comparadores de voltaje, motivo por el cual como parte de la rutina de inicialización de los registros de los microcontroladores, se les tiene que indicar de manera adicional, que se van a emplear las terminales del puerto A para realizar lecturas de naturaleza digital. Posterior a la aplicación de un reset, las terminales del puerto A se configuran de manera predeterminada para que sean activados ya sea el ADC ó los comparadores de voltaje, por lo tanto, tendremos que recurrir al registro en donde se configura la cantidad de ADC’s o comparadores que serán empleados, pero en esta ocasión para deshabilitarlos. Para realizar la actividad de deshabilitación de ADC ó comparadores, basta con seleccionar 0 (cero) ADC’s ó 0 (cero) comparadores de voltaje, tal como se ilustra en la código del programa de la tabla. Hasta este punto hemos revisado de qué manera se leen los puertos A ó B ó C, etc., de microcontroladores que poseen más de un puerto (el PIC16F628A cuenta con 2 puertos y el PIC16F876 cuenta con 3 puertos) como entrada, pero también podemos encontrarnos con microcontroladores que posean tan solo un puerto único, por lo tanto debemos de ser capaces de poder trabajar con el microcontrolador de un solo puerto. 9 ; Programa de prueba para leer el puerto de un PIC de 8 terminales LIST P=PIC12F629 ;Aquí se coloca la matricula del microcontrolador ;que vaya a emplearse ;============================================================= ; Declaración de registros ;============================================================= w equ 00h status equ 0x03 gpio equ 0x05 cmcon equ 0x19 trisio equ 0x85 osccal equ 0x90 var1 equ 0x20 ;============================================================= ; Declaración de Bits ;============================================================= c equ 0 ;carry (acarreo) z equ 2 ;bit del cero rp0 equ 5 ;registro de selección de banco ;============================================================= ; Inicio ;============================================================= reset org 0 goto inicio ;============================================================= ; programa principal ;============================================================= inicio bcf status,rp0 ;cambiar al banco 0 movlw b’00000111’ ;selecciona 0 (cero) comparadores en el movwf cmcon ;registro cmcon (deshabilita los comparadores) bsf status,rp0 ;cambiar al banco 1 movlw b'00111111' ;configura los bits 0, 1, 2 , 3, 4 y 5 del puerto GPIO movwf trisio ;como entradas (solo contiene 6 bits). movlw b'11111100' ;configura el oscilador interno en su velocidad movwf osccal ;máxima (4 Mhz). ciclo bcf status,rp0 ;cambiar al banco 0 movf gpio,w movwf var1 goto ciclo Tabla 4. Utilización del puerto GPIO de un PIC de 8 terminales para leer datos. Dentro de los microcontroladores PIC, uno de los que cuenta con un solo puerto es el que se identifica por medio de la matricula PIC12F629, el cual posee 8 terminales de las cuales 2 son para alimentación, por lo que sobra un puerto de tan solo 6 bits. En este caso se trata de un microcontrolador que podemos considerar como ―enano‖ pero no por ello restringido en su operación, por el contrario todo depende de la aplicación que queramos realizar, y si esta no 10 requiere de muchas terminales de entrada, el PIC12F629 es muy adecuado. Para emplear el puerto del microcontrolador PIC12F629 tenemos en primera instancia que configurar los bits de su correspondiente registro ―trisio‖ de tal manera que pueda leer datos, siguiendo la misma mecánica que se realizo para los demás microcontroladores, por lo tanto se debe de colocar unos (1´s) en los respectivos bits donde se pretende que la correspondiente terminal del microcontrolador sea configurada como entrada. Se tiene que considerar que la terminal identificada como GP3 (refiérase a la figura 1), siempre debe ser configurada como de entrada, ya que la arquitectura del microcontrolador PIC12F629 así la tiene diseñada. En la tabla 4 se ilustra un fragmento de código para configurar al único puerto con el que cuenta un microcontrolador PIC de 8 terminales (en este caso un PIC12F629). En el registro ―trisio‖ se cargan 1’s en los bits 0, 1, 2, 3, 4 y 5 porque son los que se encuentran disponibles para el PIC12F629, los bits 6 y 7 no se encuentran disponibles para este PIC. Una vez que fue configurado el registro trisio, se procede a emplear el registro ―gpio‖ para ingresar el dato que se encuentra en las terminales del microcontrolador. Para emplear la totalidad de las terminales del PIC12F629, es necesario habilitar al oscilador interno del PIC, para que se puedan emplear las 2 terminales dedicadas al oscilador como entradas discretas (GP4 y GP5), además de deshabilitar la terminal del reset externo denominado MCLR, para contar con la terminal GP3 exclusivamente como entrada. Por otra parte, cuando se habilita al oscilador interno, se tiene que seleccionar la frecuencia de operación, por lo que en el registro ―osccal‖ se ingresa el valor binario ―11111100‖ que selecciona la frecuencia máxima de operación que es de 4 Mhz. El PIC12F629 en las terminales identificadas como GP0 y GP1 cuentan a la vez con comparadores de voltaje, mismos que tienen que ser deshabilitados para emplear dichas terminales como entradas digitales, siendo mediante la carga del valor binario ―00000111‖ en el registro ―cmcon‖. Por último se tiene que recordar que para interactuar con algún registro, se 11 tiene que direccionar al banco adecuado. El PIC12F629 solo cuenta con 2 bancos, por lo tanto basta con manipular el bit ―rp0‖ del registro status para acceder al banco adecuado. 1.3 ESCRITURA DE DATOS EN UN PUERTO Sin tomar en cuenta la cantidad de bits que conforman a los puertos de los microcontroladores PIC, estos pueden ser configurados para que se pueda ―escribir‖ algún dato hacia el exterior del microcontrolador, para ello, una vez que se tiene el correspondiente circuito de aplicación debidamente configurado, se graba en el microcontrolador PIC el programa por mediodel cual realizara la tarea de enviar un dato digital hacia el exterior del microcontrolador. Para poder utilizar cualquiera de los puertos de un microcontrolador PIC como salida, se tiene que considerar como primer paso el de la configuración del correspondiente registro ―tris‖, colocando todos sus bits en ceros ―lógicos‖ (0’s). Una vez que fue configurado el registro tris, se tiene que proceder con el empleo del registro denominado ―port‖, y de acuerdo al puerto que se tenga que emplear se podrá seleccionar desde el puerto A como ―porta‖, al puerto B como ―portb‖, al puerto C como ―portc‖ y así sucesivamente para cada uno de los puertos con que cuente el microcontrolador. Los registros denominados ―port‖ prácticamente se comportan como un reflejo del estado lógico que se presenta en las terminales físicas del microcontrolador, siendo más específicos, diremos que el dato que alojemos en algún registro port, se transmitirá a las terminales que se encuentran relacionadas con el registro port correspondiente, recordando que el registro tris consecuente debe encontrarse configurado de tal forma que el puerto se comporte como salida. En los microcontroladores PIC todos los registros port se encuentran constituidos por 8 bits, los cuales indican el estado lógico en que se encuentran las terminales físicas del puerto en cuestión del microcontrolador PIC. 12 ; Programa de prueba para escribir en el puerto B LIST P=PIC16F876 ;Aquí se coloca la matricula del microcontrolador ;que vaya a emplearse ;============================================================= ; Declaración de registros ;============================================================= portb equ 0x06 status equ 0x83 trisb equ 0x86 temporal equ 0x20 ;============================================================= ; Declaración de bits ;============================================================= rp0 equ 0x05 rp1 equ 0x06 ;============================================================= ; Vector del reset ;============================================================= reset org 0 goto inicio ;============================================================= ; Inicio del programa principal ;============================================================= inicio bsf status,rp0 ;cambia al banco 1 bcf status,rp1 movlw b’00000000’ ;configura al puerto B como salida movwf trisb bcf status,rp0 ;cambia al banco 0 bcf status,rp1 movf temporal,0 ;el dato del registro temporal es cargado a W movwf portb ;escribe el dato de W en el puerto B goto inicio Tabla 5. Utilización del puerto B de cualquier microcontrolador PIC para escribir datos. Para escribir un dato en todos los bits de un puerto se puede emplear el comando de escritura sobre un registro, indicando en la instrucción el puerto que tendrá que ser intervenido, para una mayor referencia observe el ejemplo que se ilustra en la tabla 5. El código de la tabla 5 es valido para intervenir todos los puertos de un microcontrolador PIC exceptuando al puerto A de los PIC, por otra parte también se indica el direccionamiento del banco donde se encuentran los registros que serán empleados, por medio de la manipulación de los bits ―rp0 y rp1‖ del registro ―status‖, que de acuerdo al banco donde se ubiquen los diferentes registros de configuración, se tendrá que colocar la combinación adecuada en los bits rp0 y rp1. 13 ; Programa de prueba para escribir un dato en el puerto A LIST P=PIC16F628A ;Aquí se coloca la matricula del microcontrolador ;que vaya a emplearse ;============================================================= ; Declaración de registros ;============================================================= porta equ 0x05 cmcon equ 0x1f status equ 0x83 trisa equ 0x85 temporal equ 0x20 ;============================================================= ; Declaración de bits ;============================================================= rp0 equ 0x05 rp1 equ 0x06 ;============================================================= ; Vector del reset ;============================================================= reset org 0 goto inicio ;============================================================= ; Inicio del programa principal ;============================================================= inicio bsf status,rp0 ;cambia al banco 1 bcf status,rp1 movlw b’00000000’ ;configura al puerto A como salida movwf trisa bcf status,rp0 ;cambia al banco 0 bcf status,rp1 movlw b’00000111’ ;selecciona 0 (cero) comparadores en el movwf cmcon ;registro cmcon (deshabilita los ;comparadores) movf temporal,0 ;el dato del registro temporal es cargado a W movwf porta ;escribe el dato de W en el puerto A goto inicio ; Programa de prueba para escribir un dato en el puerto A LIST P=PIC16F876 ;Aquí se coloca la matricula del microcontrolador ;que vaya a emplearse ;============================================================= ; Declaración de registros ;============================================================= porta equ 0x05 status equ 0x83 trisa equ 0x85 adcon1 equ 0x9f temporal equ 0x20 ;============================================================= ; Declaración de bits ;============================================================= rp0 equ 0x05 rp1 equ 0x06 ;============================================================= ; Vector del reset ;============================================================= reset org 0 goto inicio ;============================================================= ; Inicio del programa principal ;============================================================= inicio bsf status,rp0 ;cambia al banco 1 bcf status,rp1 movlw b’00000000’ ;configura al puerto A como salida movwf trisa movlw b’00000111’ ;selecciona 0 (cero) comparadores en el movwf adcon1 ;registro adcon1 (deshabilita los ADC) bcf status,rp0 ;cambia al banco 0 bcf status,rp1 movf temporal,0 ;el dato del registro temporal es cargado a W movwf porta ;escribe el dato de W en el puerto A goto inicio Tabla 6. Utilización del puerto A para escribir datos en los microcontroladores PIC16F628A y PIC16F876. Sobre las terminales del puerto A de cualquiera de los microcontroladores PIC dependiendo de su estructura interna, pueden contar con convertidores analógico a digital (ADC), ó comparadores de voltaje, precedente para que sea implementada la correspondiente rutina de inicialización de los registros de los microcontroladores, para que de manera adicional se le indique a las terminales del puerto que serán empleadas para realizar la escritura de datos digitales en el puerto A. Cuando se aplica un reset, las terminales del puerto A se configuran siempre de manera predeterminada para que estas sean habilitadas como ADC ó los comparadores de voltaje, por lo tanto, se tendrá que recurrir al registro en donde se configura la cantidad de ADC’s o comparadores que serán empleados, pero en esta ocasión se tendrán que deshabilitar. 14 Para realizar la actividad de deshabilitación de ADC ó comparadores, basta con seleccionar 0 (cero) ADC’s ó 0 (cero) comparadores de voltaje, tal como se ilustra en los fragmentos de código de los programas de la tabla. Hemos revisado la manera de escribir datos sobre los puertos A ó B ó C, etc., de microcontroladores que cuentan con más de un puerto (el PIC16F628A cuenta con 2 puertos y el PIC16F876 cuenta con 3 puertos), pero también podemos encontrarnos con microcontroladores que poseen tan solo un puerto único, por lo tanto se debe de contar con el conocimiento de podertrabajar con algún microcontrolador de un solo puerto. Dentro de la familia de los microcontroladores PIC, uno de los que cuenta con un solo puerto es el que se identifica por medio de la matricula PIC12F629, el cual posee 8 terminales de las cuales 2 son para que sea energizado (terminales Vdd y Vss), por lo que sobra un puerto de tan solo 6 bits. En este caso se trata de un microcontrolador pequeño que pudiera ser considerado como restringido en cuanto a su cantidad de terminales, pero no en su operación, por el contrario todo depende de la aplicación que se tenga que realizar, ya que si esta no requiere de muchas terminales de salida, el PIC12F629 es un microcontrolador muy adecuado. Para emplear el puerto del microcontrolador PIC12F629 tenemos en primera instancia que configurar los bits de su correspondiente registro ―trisio‖ de tal manera que se pueda escribir algún datos, siguiendo la misma mecánica que se realizo para los demás microcontroladores, por lo tanto, se debe de colocar ceros (0´s) en los respectivos bits donde se pretende que la correspondiente terminal del microcontrolador sea configurada como salida. Se tiene que considerar que de las terminales con que cuenta el PIC12F629, identificada como GP3 (refiérase a la figura 1), siempre tiene que ser configurada como de entrada, ya que la arquitectura del microcontrolador PIC12F629 así la tiene diseñada. 15 ;Programa de prueba para escribir datos en un PIC de 8 terminales LIST P=PIC12F629 ;Aquí se coloca la matricula del microcontrolador ;que vaya a emplearse ;============================================================= ; Declaración de registros ;============================================================= w equ 00h status equ 0x03 gpio equ 0x05 cmcon equ 0x19 trisio equ 0x85 osccal equ 0x90 var1 equ 0x20 ;============================================================= ; Declaración de Bits ;============================================================= c equ 0 ;carry (acarreo) z equ 2 ;bit del cero rp0 equ 5 ;registro de selección de banco ;============================================================= ; Inicio ;============================================================= reset org 0 goto inicio ;============================================================= ; programa principal ;============================================================= inicio bcf status,rp0 ;cambiar al banco 0 movlw b’00000111’ ;selecciona 0 (cero) comparadores en el movwf cmcon ;registro cmcon (deshabilita los comparadores) bsf status,rp0 ;cambiar al banco 1 movlw b'00001000' ;configura todos los bits (con excepción del 3) del movwf trisio ;puerto como salidas (solo contiene 6 bits). movlw b'11111100' ;configura el oscilador interno en su velocidad movwf osccal ;máxima (4 Mhz). ciclo bcf status,rp0 ;cambiar al banco 0 movf var1,w movwf gpio goto ciclo Tabla 7. Utilización del puerto GPIO de un PIC de 8 terminales para escribir datos. En la tabla 7 se ilustra un fragmento de código para configurar al único puerto con el que cuenta un microcontrolador PIC de 8 terminales (en este caso un PIC12F629) como salida. En el registro ―trisio‖ se cargan 0’s en los bits 0, 1, 2, 4 y 5 porque son los que se encuentran disponibles para el PIC12F629, los bits 6 y 7 no se encuentran disponibles para este PIC. Una vez que fue configurado el registro trisio, se procede a emplear el 16 registro ―gpio‖ para enviar hacia el exterior del microcontrolador algún dato, para que se refleje en las terminales del microcontrolador. Para emplear la totalidad de las terminales del PIC12F629, es necesario habilitar al oscilador interno del PIC, para que se puedan emplear las 2 terminales dedicadas al oscilador como salidas discretas (GP4 y GP5), además de deshabilitar la terminal del reset externo denominado MCLR, para contar con la terminal GP3 exclusivamente como ―entrada‖. Por otra parte, cuando se habilita al oscilador interno, se tiene que seleccionar la frecuencia de operación, por lo que en el registro ―osccal‖ se ingresa el valor binario ―11111100‖ que selecciona la frecuencia máxima de operación que es de 4 Mhz. El PIC12F629 en las terminales identificadas como GP0 y GP1 cuentan a la vez con comparadores de voltaje, mismos que tienen que ser deshabilitados para emplear dichas terminales como salidas digitales, siendo mediante la carga del valor binario ―00000111‖ en el registro ―cmcon‖. Por último se debe de tomar en cuenta que para interactuar con algún registro, se tiene que direccionar al banco adecuado. El PIC12F629 solo cuenta con 2 bancos, por lo tanto, basta con manipular el bit ―rp0‖ del registro status para acceder al banco adecuado. 1.4 ASIGNACIÓN DE DATOS A UN REGISTRO Una de las tareas que tiene que realizar un microcontrolador, es la de ir almacenando datos, ya sea en sus registros de configuración, o en cualquier registro de memoria RAM, que es en donde finalmente se alojan los datos que resultan de una operación, o la lectura de un puerto, etc. Si la aplicación así lo requiere, se tiene que manipular el dato de más de un registro, para ello, se tienen que distribuir todos los registros involucrados en el proyecto, para que en primera instancia se tengan que ubicar sobre los espacios de memoria RAM, que se encuentran constituidos sobre la memoria de datos, por lo tanto, se debe de conocer sobre que banco de memoria es sobre el que se alojara el dato en un registro. 17 Para comenzar a trabajar con los registros, la primera actividad a desarrollar es la que lleva por nombre ―declaración‖ de registros, o sea se le tiene que indicar al programa editor (que en el caso de los microcontroladores PIC es el MPLAB) que se va emplear por ejemplo el registro ―trisa‖. w equ 00h status equ 0x03 trisa equ 0x85 trisb equ 0x86 porta equ 0x05 portb equ 0x06 cmcon equ 0x1f var1 equ 0x20 var2 equ 0x21 var3 equ 0x22 var4 equ 0x23 var5 equ 0x24 var6 equ 0x25 var7 equ 0x26 var8 equ 0x27 var9 equ 0x28 var10 equ 0x29 var11 equ 0x2a var12 equ 0x2b var13 equ 0x2c var14 equ 0x2d var15 equ 0x2e var16 equ 0x2f var17 equ 0x30 Tabla 8. Declaración de registros, para su empleo posterior. Recordemos que se pueden clasificar de forma general en 2 conjuntos los registros que emplearemos, los cuales conocemos como registros de configuración y registros de propósito general, estos últimos también tienen la tarea de almacenar datos ya que se trata de registros que se encuentran implementados sobre memoria RAM. A continuación marcaremos un mayor énfasis sobre los registros de propósito general, sin olvidar a los registros de configuración. Una vez que fueron declarados los registros con los que trabajaremos, ya los podemos emplear para escribirles o leerles el dato que contengan, por lo tanto, en el ejemplo que se muestra sobre un listado en el fragmento de programa descrito en la tabla 8, se declaran los registros que serán empleados, resaltando de 18 una manera particular a los registros de propósito general que son los que funcionaran como localidades de memoria RAM. De la tabla 8 se observa que se tienen que declara una serie de registros que se denominan ―var1‖, ―var2‖, ―var3‖, etc. Lo importante es que ocupan las localidades de los registros que van de la 20h a la 30 h, además de que son localidades continuas. Se debe de tener en cuenta que si por alguna razón se requiere insertar un nuevo registro por ejemplo entre los identificados como var7 y var8, posteriormente se tienen que enumerar nuevamente las localidades recorriendo los números de registro que a cada una le corresponde de tal manera, que de nueva cuenta queden ordenadas. w equ 00h status equ0x03 trisa equ 0x85 trisb equ 0x86 porta equ 0x05 portb equ 0x06 cmcon equ 0x1f CBLOCK 0x20 ;Define donde comienza la declaración de registros var1 var2 var3 var4 var5 var6 var7 var8 var9 var10 var11 var12 var13 var14 var15 var16 var17 ENDC ;Define donde termina la declaración de registros Tabla 9. Declaración de un bloque de registros, para asignación automática de localidades. En la tabla 9 se muestra una manera mucho más práctica en lo correspondiente a la declaración de registros, en donde puede observarse que a partir del registro var1, nos olvidamos de indicar por medio de la directiva 19 ―equ‖ la localidad que le corresponde a cada registro. Tan solo tenemos que enumerar a todos los registros que tenemos que emplear y al comienzo del bloque le colocamos el comando ―CBLOCK‖, indicándole cual será la primera localidad que tendrá que ocuparse, tal como se muestra en la ejemplo ―CBLOCK 0x20‖, tal como aparece en la tabla 9. LIST P=PIC16F628A ;========================================= ; Declaración de registros ;========================================= w equ 0x00 status equ 0x03 porta equ 0x05 portb equ 0x06 trisa equ 0x85 trisb equ 0x86 cmcon equ 0x1f CBLOCK 0x20 ;define donde comienza la declaración de registros var1 var2 var3 var4 var5 var6 var7 var8 var9 var10 var11 var12 var13 var14 var15 var16 var17 ENDC ;define donde termina la declaración de registros ;========================================== ; Declaración de bits ;========================================== rp0 equ 0x05 rp1 equ 0x06 ;========================================== ; Vector del Reset ;========================================== org 0x00 goto inicio ;========================================== ; Programa principal ;========================================== inicio bcf status,rp1 ;direcciona el banco 1 bsf status,rp0 movlw 0xff movwf trisa ;los bits del Puerto a como entradas bcf status,rp1 ;direcciona el banco 0 bcf status,rp0 movlw 0x07 movwf cmcon ciclo bcf status,rp1 ;direcciona el banco 0 bcf status,rp0 movf porta,0 movwf var1 movwf var2 movwf var3 movwf var4 movwf var5 movwf var6 movwf var7 movwf var8 movwf var9 movwf var10 movwf var11 movwf var12 movwf var13 movwf var14 movwf var15 movwf var16 movwf var17 goto ciclo end Tabla 10. Empleo de los registros una vez declarados. Para indicar en donde termina la declaración de registros, se tiene que colocar el comando ―ENDC‖ y hasta allí termina de realizar las declaraciones, por lo tanto, si se tiene que agregar un nuevo registro, tan solo se tiene que escribir 20 dentro del bloque y de manera automática le proporcionara una localidad. Cuando ya fueron declarados los registros, posteriormente se procede a su empleo ya sea para guardarles un dato, o para leer el dato que contengan, en la tabla 10 se muestra un ejemplo en donde se emplea una gran cantidad de registros, los cuales durante el presente ejercicio serán empleados para alojarles un dato. El dato será leído a través del puerto A, posteriormente se guardara en el registro de trabajo ―W‖, y por último el dato que se encuentre en el registro W será colocado en todos los registros que van de var1 a var17, aquí es muy importante resaltar el hecho de que la declaración de los registros fue realizada mediante un bloque. En el ejemplo mostrado en la tabla 10 se observa en la sección ―programa principal‖ después de la etiqueta ―ciclo‖, que de manera ordenada se tienen que ir alojando valores en cada uno de los registros identificados como ―var‖, mediante el empleo de una instrucción para cada uno de los registros, que en este caso se trata tan solo de 17; para cada uno de los registros se esta empleando un direccionamiento directo. Supóngase el caso en el que se requiera el manejo de 80 registros (no solo 17), la pregunta seria ¿se pondrán a escribir 80 instrucciones para cada uno de los registros? Seria una cuestión de nunca acabar, por lo que mejor recurrimos al método de direccionamiento indirecto, en el cual tan solo tenemos que indicar donde comienza la localidad de los registros que serán intervenidos, y controlar mediante un contador el acceso al siguiente registro, tal como es ilustrado en el ejemplo de la tabla 11. El código del programa ilustrado en la tabla 11 es idéntico en cuanto a la actividad que realiza el programa que se muestra en la tabla 10, pero se tiene un cambio a la manera de guardar los datos en los registros, si observa detenidamente ambos programas, el que corresponde a la tabla 11, posee menos líneas de código porque se implemento en este el método de direccionamiento indirecto, para manipular a todos los registros. 21 LIST P=PIC16F628A ;========================================= ; Declaración de registros ;========================================= w equ 0x00 indf equ 0x00 status equ 0x03 fsr equ 0x04 porta equ 0x05 portb equ 0x06 trisa equ 0x85 trisb equ 0x86 cmcon equ 0x1f CBLOCK 0x20 ;Define donde comienza la declaración de registros var1 var2 var3 var4 var5 var6 var7 var8 var9 var10 var11 var12 var13 var14 var15 var16 var17 ENDC ;Define donde termina la declaración de registros ;========================================== ; Declaración de bits ;========================================== z equ 0x02 rp0 equ 0x05 rp1 equ 0x06 ;========================================== ; Vector del Reset ;========================================== org 0x00 goto inicio ;========================================== ; Programa principal ;========================================== inicio bcf status,rp1 ;Direcciona el banco 1 bsf status,rp0 movlw 0xff movwf trisa ;Los bits del Puerto a como entradas movlw 0x00 movwf trisb ;Los bits del Puerto b como salidas bcf status,rp1 ;Direcciona el banco 0 bcf status,rp0 movlw 0x07 movwf cmcon otro bcf status,rp1 ;Direcciona el banco 0 bcf status,rp0 movlw 0x20 ;indica la primera localidad a manipular movwf fsr ciclo movf porta,w ;lee un dato del puerto a movwf indf ;aloja el dato en el registro indirecto movlw 0x30 ;verifica si se trata del ultimo registro xorwf fsr,w btfsc status,z goto otro incf fsr,1 goto ciclo end Tabla 11. Empleo de los registros mediante direccionamiento indirecto. El direccionamiento indirecto consiste en obtener la dirección de una localidad de memoria (memoria RAM), por medio de otro registro (File Select Register ―FSR‖) que de manera intermedia es el primero que tiene que ser consultado. El direccionamiento indirecto en los microcontroladores PIC se realiza por medio del empleo de los registros denominados en primer termino como: ―FSR‖ que es el que contendrá como dato a la localidad de memoria RAM que será manipulada, e ―INDF‖ que es el registro en el cual se encuentra la información 22 que será escrita o leída de la localidad de memoria RAM que se esta direccionando por medio del registro FRS. Para una mejor comprensión observe la figura 2, en la cual se muestra que con los bits del 0 al 6 del registro FSR se direcciona una localidad de memoria RAM, mientras que la combinación generada mediante los bits 7 del registro FSR y el bit IRP del registro STATUS se puede acceder a cualquiera de los 4 bancos de memoria que posee un microcontrolador PIC. Figura 2. Direccionamiento Directo e Indirecto en un PIC. Regresando de nuevamente al ejemplo de programa mostrado en la tabla 11, revisemos el fragmentode código que a continuación se muestra: ciclo movf porta,w ;lee un dato del puerto a movwf indf ;aloja el dato en el registro indirecto movlw 0x30 ;verifica si se trata del ultimo registro xorwf fsr,w btfsc status,z goto otro incf fsr,1 goto ciclo Para poder emplear los registros ―indf‖ y ―fsr‖ tuvieron que ser declarados mediante el comando ―equ‖ con su respectiva localidad en el mapa de 23 memoria de registros del microcontrolador PIC, que para el registro ―indf‖ se trata de la localidad 00h, y para el registro ―fsr‖ de la localidad 04h. Cuando se requiere alojar un dato de manera consecutiva en los registros de memoria RAM, se emplea la instrucción ―movwf indf‖ (previamente tuvo que ser cargado el dato en el registro de trabajo W) tal como se muestra en el programa de la tabla 11, pero cuando se requiere realizar la operación inversa, o sea leer de manera cíclica a los registros de memoria RAM, entonces la instrucción que tiene que ser empleada es ―movf indf,0‖ para que el dato que contenga la localidad de memoria RAM sea colocado en el registro de trabajo W. En cualquiera de los casos ya sea de escritura o lectura de una localidad de memoria RAM, lo primero que tiene que hacerse es ingresar en el registro FSR la localidad a ser intervenida. 1.5 INCREMENTO Y DECREMENTO DE DATOS DE LOS REGISTROS Incrementar o decrementar los datos de los registros, es una actividad que dependiendo de la aplicación se realiza con mucha frecuencia dentro de un programa, por ello, es que se tienen que revisar las diversas maneras de manipular la información que se encuentra alojada en los registros. 1.5.1 INCREMENTO O DECREMENTO DEL DATO DE UN REGISTRO EN UNA UNIDAD Para incrementar o decrementar el dato de un registro en una unidad, se tienen las instrucciones ―incf‖ y ―decf‖ respectivamente, los cuales de manera simple realizan la operación que les corresponde, normalmente cuando observamos de manera aislada a este tipo de operaciones, en muchas ocasiones las consideramos como actividades triviales, pero debemos de estar seguros que si las empleamos de manera correcta, nuestros programas serán muy eficientes, la sintaxis completa de las instrucciones ―incf‖ y ―decf‖ son las siguientes: 24 a) incf registroX,1 ;Incrementa en una unidad el dato del registro X alojando el resultado final dentro del mismo registro X1. b) decf registroX,1 ;Decrementa en una unidad el dato del registro X alojando el resultado final dentro del mismo registro X1. Existen otras instrucciones que a parte de realizar la tarea de incrementar o decrementar en una unidad al valor del dato de algún registro, también verifican si el resultado de la operación fue cero, teniéndose la posibilidad de diseñar un contador con pocas líneas de código, y para ello se emplean las instrucciones que se muestran con su respectiva sintaxis de manera completa a continuación: a) incfsz registroX,1 ;Incrementa en una unidad el dato del registro X alojando el resultado final dentro del mismo registro X1, y brinca si el resultado fue 0 (cero). b) decfsz registroX,1 ;Decrementa en una unidad el dato del registro X alojando el resultado final dentro del mismo registro X1, y brinca si el resultado fue 0 (cero). En los capítulos siguientes se mostraran ejemplos a cerca del empleo de estas instrucciones, en los cuales se muestran en aplicaciones prácticas. 1.5.2 INCREMENTO O DECREMENTO DEL DATO DE UN REGISTRO EN VALORES DIFERENTES A LA UNIDAD En diversas ocasiones se necesita que se manipule el dato de un registro, para controlar una cierta variable, para lo cual los incrementos deben ser valores diferentes de la unidad, o simplemente se tiene que sumar o restar un valor de acuerdo con la aplicación que se esta implementando, pues bien, para incrementar o decrementar el dato de algún registro con valores diferentes de la 1 Refiérase a la explicación de las instrucciones que se encuentra en el capitulo ―instrucciones orientadas al control de registros dentro del Modulo I. 25 unidad, se tienen las instrucciones de suma o resta respectivamente, las cuales se muestran junto con su sintaxis completa: a) addwf registroX,1 ;Suma el valor alojado en el registro W con el dato del registro X guardando el resultado final dentro del mismo registro X2. b) subwf registroX,1 ;Resta el valor alojado en el registro W al dato del registro X guardando el resultado final dentro del mismo registro X2. 1.6 DISEÑO DE UN CONTADOR Un contador es una de las primeras aplicaciones básicas que tienen que emplearse, por lo que en el desarrollo del presente capitulo se explicara la manera en que puede ser creado el código de un programa en le cual se tenga implementado un contador básico partiendo de registros de 8 bits, en el caso de que se requieran contadores de mas de 8 bits, la metodología mostrada en el presente capitulo será valida, pero se tendrá que recurrir a la suma o resta de registros con mas de 8 bits, y cuyas explicaciones se encuentran en los respectivos capítulos llamados ―suma aritmética‖ y ―resta aritmética‖ que se ubican dentro del presente capítulo. La estructura de un contador se ilustra en el diagrama de flujo de la figura 3, en la cual se muestra que se tiene que guardar un dato en un registro, que será el que fungirá como el control del contador, el valor que se alojara en el registro contador dependerá de cómo se tiene que inicializar dicho contador. Ya inicializado el registro contador, se procede a realizar la actividad que tiene que controlar el contador, esto es, se realiza la actividad sustancial que por ejemplo puede una serie de sumas, una serie de lecturas a través de un puerto, etc. Posteriormente a la realización de la actividad que controla el contador, se tiene que incrementar el valor del dato que se encuentra en el registro contador, para contabilizar la cantidad de eventos que se han realizado. Por último, se tiene 2 Refiérase a la explicación de las instrucciones que se encuentra en el capitulo ―instrucciones orientadas al control de registros dentro del Modulo I. 26 que revisar que no se haya rebasado la cantidad de eventos a realizarse, por lo que ahora, la actividad siguiente es la de comparar el valor que se encuentra dentro del registro contador, con el valor máximo de eventos que tienen que realizarse. Si el valor que se encuentra alojado en el registro contador, aun no alcanza el valor máximo, entonces el proceso tiene que repetirse una vez más, por lo tanto, se tendrá que realizar nuevamente el evento de la actividad que se esta controlando. De otra manera, si el valor del registro contador es igual al valor máximo de los eventos que tienen que realizarse, entonces el programa tendrá que realizar una actividad diferente de la que estaba controlado con el contador, dando por terminado el contador y accediendo a un nuevo proceso. Figura 3. Diagrama de flujo de un contador. En el diagrama de flujo del contador de la figura 3, los bloques que corresponden al control del contador son resaltados, para tener presente donde se realiza el control del contador. Los contadores pueden desarrollarse en forma general de dos maneras, dependiendo de si el contador se configurará como un ―contador ascendente‖ o un ―contador descendente‖, pero en ambos casos la 27 estructura del contador es la misma que se ha mostrado previamente, y a continuación se muestra la estructura de los distintos tipos de contador. 1.6.1 CONTADOR ASCENDENTE El contador ascendente tiene como característica principal la de llevar un conteo ascendente en el registro contador, razón por la cual el registro contadorse inicializa con un valor ―pequeño‖ que puede ser inclusive 0 (cero), dicho valor tiene que ser menor al valor máximo de eventos que tiene que controlar el contador. Figura 4. Diagrama de flujo de un contador ascendente. Después de haber realizado la actividad que corresponde al evento que se esta controlando, el registro contador tiene que ser incrementado para precisamente llevar a cabo el conteo de la cantidad de eventos que han sido efectuados, normalmente el incremento que se aplica al registro contador es de una unidad, pero en realidad se tiene que incrementar de acuerdo a la aplicación que se esta desarrollando. 28 LIST P=PIC16F628A ;========================================= ; Declaración de registros ;========================================= w equ 0x00 status equ 0x03 porta equ 0x05 portb equ 0x06 trisa equ 0x85 trisb equ 0x86 cmcon equ 0x1f contador equ 0x20 ;========================================= ; Declaración de bits ;========================================= z equ 0x02 rp0 equ 0x05 rp1 equ 0x06 ;========================================= ; Vector del Reset ;========================================= org 0x00 goto inicio ;========================================= ; Programa principal ;========================================= inicio bcf status,rp1 ;Direcciona el banco 1 bsf status,rp0 movlw 0xff movwf trisa ;Los bits del Puerto a como entradas movlw 0x00 movwf trisb ;Los bits del Puerto b como salidas bcf status,rp1 ;Direcciona el banco 0 bcf status,rp0 movlw 0x07 movwf cmcon otro bcf status,rp1 ;Direcciona el banco 0 bcf status,rp0 movlw 0x00 ;inicia el registro contador movwf contador conteo movf porta,w ;lee un dato del puerto a movwf portb incf contador,1 ;incrementa registro contador movlw 0x05 ;verifica el valor máximo del contador xorwf contador,w btfsc status,z goto otro goto conteo end LIST P=PIC16F628A ;========================================= ; Declaración de registros ;========================================= w equ 0x00 status equ 0x03 porta equ 0x05 portb equ 0x06 trisa equ 0x85 trisb equ 0x86 cmcon equ 0x1f contador equ 0x20 ;========================================== ; Declaración de bits ;========================================== z equ 0x02 rp0 equ 0x05 rp1 equ 0x06 ;========================================== ; Vector del Reset ;========================================== org 0x00 goto inicio ;========================================== ; Programa principal ;========================================== inicio bcf status,rp1 ;Direcciona el banco 1 bsf status,rp0 movlw 0xff movwf trisa ;Los bits del Puerto a como entradas movlw 0x00 movwf trisb ;Los bits del Puerto b como salidas bcf status,rp1 ;Direcciona el banco 0 bcf status,rp0 movlw 0x07 movwf cmcon otro bcf status,rp1 ;Direcciona el banco 0 bcf status,rp0 movlw 0x00 ;inicia el registro contador movwf contador conteo movf porta,w ;lee un dato del puerto a movwf portb movlw 0x01 addwf contador,1 ;incrementa registro contador movlw 0x05 ;verifica el valor máximo del contador xorwf contador,w btfsc status,z goto otro goto conteo end Tabla 12. Ejemplos de programa para un contador ascendente. Una vez que se ha incrementado el valor del registro contador, se procede a comparar el valor del registro contador con el valor máximo de la cantidad de eventos que tienen que desarrollarse, este valor puede encontrarse dentro de un registro al que podemos llamar ―Valormaximo‖. Si después de 29 ―incrementar‖ el dato del valor del registro contador aun no es igual al valor máximo, entonces se tiene que aplicar un nuevo incremento al registro contador, y así sucesivamente hasta que alcance su valor total. En los ejemplos de programa ilustrados en la tabla 12, se propone el empleo de un microcontrolador PIC16F628A, pero en realidad por el momento no es relevante el microcontrolador PIC que sea empleado, ya que el código para realizar el conteo es valido para cualquier PIC. Los programas mostrados en la tabla 12 controlan un contador ascendente, realizando ambos programas idénticas funciones, teniendo solo un cambio en cuanto a las líneas de sus respectivos códigos. El cambio existente entre los programas radica en la instrucción que efectúa el incremento del registro contador. En un programa se emplea la instrucción ―incf contador,1‖ la cual indica que se incremente en una unidad el valor del registro ―contador‖ guardando el resultado en el mismo registro. Por otra parte en el segundo programa que también se encuentra en la tabla 12, se emplea el par de instrucciones ―movlw 0x01‖ y ―addwf contador,1‖, las cuales en primer instancia cargan el registro de trabajo W con el valor al cual tendrá que ser incrementado el registro contador, siendo el valor de 01h para el presente ejemplo, mientras que por medio de la instrucción addwf, se realiza la suma del registro contador con el valor que fue cargado en el registro de trabajo W, guardando el resultado de la suma en el mismo registro contador; si fuera necesario que el incremento que será sumado al registro contador sea diferente de 01h, tan solo se tiene que cargar el valor correspondiente en el registro de trabajo W. Posterior al incremento del registro contador se tiene que verificar si ya se llego al valor máximo de eventos realizados, para el presente ejemplo el incremento se tiene que realizar hasta que se alcanza el valor máximo de 5 (el proceso de comparación será mostrado con detalle en el capitulo de funciones lógicas que se encuentra dentro del presente capítulo). El evento que se esta controlando es el de leer el un dato a través del puerto a, y escribir ese mismo dato en el puerto b. 30 1.6.2 CONTADOR DESCENDENTE El contador descendente a deferencia del contador ascendente, realiza el control del contador a través de un conteo descendente, tal como es ilustrado en la figura 5. Figura 5. Diagrama de flujo de un contador descendente. Se observa gráficamente en el diagrama de flujo de la figura 5 que cuando se inicializa el registro contador, tiene que ser con el valor del total de los eventos que tendrán que efectuarse. A continuación se realiza la actividad del evento que se esta controlando, para posteriormente realizar un decremento en el valor del registro contador, recordando que el valor inicial que se encuentra dentro del registro contador es el valor máximo de eventos. El decremento que se realiza en el registro contador puede ser de unidad en unidad conforme se vayan ejecutando los eventos uno a uno, por lo tanto, cuando se realice el último evento, el valor que debe encontrarse alojado en el registro contador es igual a 0 (cero). El decremento puede ser de unidad en unidad, o un valor diferente de 1 lo que da origen el empleo de las 31 instrucciones ―decf‖ o ―subwf‖ respectivamente. LIST P=PIC16F628A ;========================================= ; Declaración de registros ;========================================= w equ 0x00 status equ 0x03 porta equ 0x05 portb equ 0x06 trisa equ 0x85 trisb equ 0x86 cmcon equ 0x1f contador equ 0x20 ;========================================= ; Declaración de bits ;========================================= z equ 0x02 rp0 equ 0x05 rp1 equ 0x06 ;========================================= ; Vector del Reset ;========================================= org 0x00 goto inicio ;========================================= ; Programa principal ;========================================= inicio bcf status,rp1;Direcciona el banco 1 bsf status,rp0 movlw 0xff movwf trisa ;Los bits del Puerto a como entradas movlw 0x00 movwf trisb ;Los bits del Puerto b como salidas bcf status,rp1 ;Direcciona el banco 0 bcf status,rp0 movlw 0x07 movwf cmcon otro bcf status,rp1 ;Direcciona el banco 0 bcf status,rp0 movlw 0x05 ;inicia el registro contador movwf contador conteo movf porta,w ;lee un dato del puerto a movwf portb decf contador,1 ;decrementa registro contador movlw 0x00 ;verifica el valor mínimo del contador xorwf contador,w btfsc status,z goto otro goto conteo end LIST P=PIC16F628A ;========================================= ; Declaración de registros ;========================================= w equ 0x00 status equ 0x03 porta equ 0x05 portb equ 0x06 trisa equ 0x85 trisb equ 0x86 cmcon equ 0x1f contador equ 0x20 ;========================================== ; Declaración de bits ;========================================== z equ 0x02 rp0 equ 0x05 rp1 equ 0x06 ;========================================== ; Vector del Reset ;========================================== org 0x00 goto inicio ;========================================== ; Programa principal ;========================================== inicio bcf status,rp1 ;Direcciona el banco 1 bsf status,rp0 movlw 0xff movwf trisa ;Los bits del Puerto a como entradas movlw 0x00 movwf trisb ;Los bits del Puerto b como salidas bcf status,rp1 ;Direcciona el banco 0 bcf status,rp0 movlw 0x07 movwf cmcon otro bcf status,rp1 ;Direcciona el banco 0 bcf status,rp0 movlw 0x05 ;inicia el registro contador movwf contador conteo movf porta,w ;lee un dato del puerto a movwf portb movlw 0x01 subwf contador,1 ;decrementa registro contador movlw 0x00 ;verifica el valor mínimo del contador xorwf contador,w btfsc status,z goto otro goto conteo end Tabla 13. Ejemplos de programa para un contador descendente. En la tabla 13 se muestran 2 programas que tienen implementados un contador descendente cada uno, de los cuales la diferencia radica en que en un programa el decremento se realiza mediante una instrucción que 32 decrementa unidad por unidad (decf), mientras que en el segundo programa el decremento se realiza mediante una instrucción de resta (subwf), en la cual se puede definir el valor del decremento, mediante un dato que se guarda previamente en el registro de trabajo W. 1.7 DISEÑO DE UN RETARDO BÁSICO POR BUCLES Una de las aplicaciones que se requiere implementar para controlar el tiempo de un proceso, es una rutina a base de un contador en el cual se toma en consideración el tiempo que emplea una instrucción en ejecutarse. Figura 6. Diagrama de flujo de un retardo. La implementación de un retardo por bucles (también llamado temporizador) toma como base la estructura de un contador, por lo que en primera instancia se tiene que definir el tipo de contador que será empleado. Normalmente se trata de utilizar contadores descendentes, porque es más fácil definir un valor inicial a partir del cual se tendrá que ir decrementando hasta llegar a cero, en la figura 6 se ilustra el diagrama de flujo de un contador descendente, a través del 33 cual esta implementado el retardo. La diferencia entre un temporizador y un contador es que al evento que controla el temporizador, se encuentra relacionado con la función de decrementar el dato del registro que se emplea para contabilizar el tiempo que esta transcurriendo. La temporización se termina en el momento que el registro decrementado llega a cero. A partir del diagrama de flujo de la figura 6, se obtiene el código que corresponde con el programa de un temporizador, el cual a su vez se muestra en la tabla 14. Las líneas del programa que se encuentran relacionadas de manera directa con la función del temporizador son las que se muestran en la tabla 14. movlw 0x02 ;se carga el valor de 02h en el registro de trabajo W. movwf contador ;el valor W se carga en el registro ―contador‖. bucle decfsz contador,1 ;decrementa el valor del registro contador en una ;unidad, y si el registro contador es igual a cero. ;Se genera un salto saliendo del ciclo del ;decremento. goto bucle instrucciones de un proceso siguiente . . . end Tabla 14. Estructura básica de un temporizador. Del fragmento de programa mostrado en la tabla 14, se observa que un registro llamado ―contador‖ es el que mantiene el control de la temporización, ya que en el programa este registro va decrementando su valor, mientras se ejecutan las instrucciones que conforman al código del temporizador. Se observa también que el dato que se encuentra alojado en el registro ―contador‖, se decrementará hasta que llegue a cero. Cuando el valor del registro ―contador‖ llegue a cero la temporización habrá terminado, mientras esto sucede, 34 el microcontrolador se quedara cautivo realizando la actividad de controlar al temporizador. Hemos observado que la ejecución del programa que se encuentra en la tabla 14, controla el tiempo de un temporizador, pero la pregunta natural que surge a continuación es: ¿De que manera podemos controlar el tiempo en un programa temporizador? La respuesta es la siguiente, si echamos un vistazo al listado de instrucciones del microcontrolador PIC, encontraremos que la ejecución de las instrucciones (cualquiera que sea) tienen implícito el consumo de un tiempo, que es el que se tarda la instrucción en llevarse a cabo (ejecutarse). Para determinar el tiempo que tarda una instrucción en ejecutarse, se hace referencia a un término que nos auxilia en la determinación de dicho tiempo. El término es el denominado ―ciclo de instrucción‖ o simplemente ―ciclo‖, este ciclo a su vez se encuentra relacionados con la frecuencia a la cual se ejecutan las instrucciones en el microcontrolador, recordando que se debe de disponer de un circuito oscilador para que el microcontrolador. En el listado de instrucciones de los microcontroladores PIC, se indican la cantidad de ciclos que consume la ejecución de cada una de las instrucciones que componen al listado. Los ciclos de instrucción o ciclos en un microcontrolador PIC, equivalen a la cuarta parte de la frecuencia que proporciona el circuito oscilador. En la tabla 15 se muestra el programa que controla a un temporizador, en el se observa que de acuerdo con el listado de instrucciones de un microcontrolador PIC, la cantidad de ciclos que consume cada una de las instrucciones que conforman al programa del temporizador. Teniéndose en cuenta que casi todas las instrucciones requieren de un solo ciclo para que la instrucción se ejecute completamente, y en algunos casos las instrucciones requieren de 2 ciclos para que estas sean ejecutadas, y en otros casos especiales, tal como es la instrucción ―decfsz‖ requieren ya sea de 1 ó 2 ciclos, a continuación se explica la manera en como trabaja la instrucción y dependiendo de la situación la cantidad de ciclos que consume. 35 movlw 0x02 movwf contador bucle decfsz contador,1 ; 1 ó 2 ciclos. goto bucle ; 2 ciclos. instrucciones de un proceso siguiente . . . end Tabla 15. Cantidad de ciclos que consumen las instrucciones de un temporizador. La instrucción ―decfsz‖ lleva a cabo el decremento del valor de un registro, y mientras no llegue a cero el valor del registro decrementado, se ejecuta la instrucción que se encuentra expresada debajo de decfsz, consumiendo esta actividad 1 ciclo. Pero si al ejecutar la instrucción decfsz el valor delregistro decrementado alcanzo el valor de cero, se provoca un brinco, por lo tanto, el microcontrolador omitirá la ejecución de la instrucción siguiente, pasando a la que se encuentra en segundo término después de decfsz, teniéndose en esta actividad el consumo de 2 ciclos. En la tabla 15 se muestran las cantidades de ciclos que consumen cada una de las instrucciones de un temporizador, por lo tanto, en principio con estos datos se deben de contabilizar la cantidad total de ciclos, que fueron consumidos desde que se da inicio con la rutina de temporización, hasta que el valor del registro contador llega a cero, para ello refiérase a la tabla 16, en donde se muestra detalladamente la manera en que se lleva a cabo el conteo de los ciclos totales. El ejemplo mostrado en la tabla 16 nos indica que en el paso 1 las 2 primeras instrucciones que son ejecutadas, cargan en el registro ―contador‖ el valor 02h, por lo tanto ya se tiene el valor en el registro que se encargara de controlar al temporizador; como paso siguiente se tiene la instrucción ―decfsz contador,1‖ que al ejecutarse decrementa el valor del registro contador a la vez guarda el resultado en el mismo registro; se tiene que recordar que el valor inicial del registro 36 ―contador‖ es 02h, por lo que después de ejecutar la instrucción, el valor que ahora se encontrara en el registro contador será el de 01h; como el resultado en el registro contador no fue cero, la ejecución de la instrucción ―decfsz contador,1‖ será de 1 ciclo; posteriormente se lleva a cabo la ejecución de ―goto bucle‖, esta instrucción consume 2 ciclos, y provoca que se lleve a cabo un brinco al lugar donde se encuentra la etiqueta bucle, preparando una nueva secuencia en el control del temporizador; de manera acumulada en esta etapa se tiene un total de 3 ciclos. PASO 1 movlw 0x02 ;contador = 02h movwf contador bucle decfsz contador,1 ; 1 ciclo. goto bucle ; 2 ciclos. instrucciones de un proceso siguiente . . . end contador = 01h ciclos = 3 PASO 2 movlw 0x02 movwf contador bucle decfsz contador,1 ; 2 ciclos. goto bucle ; no se ejecuta instrucciones de un proceso siguiente . . . end contador = 00h ciclos = 2 PASO 1 ciclos = 3 + PASO 2 ciclos = 2 Ciclos totales = 5 Tabla 16. Ejecución del programa temporizador. En el paso 2 del programa de la tabla 16, las instrucciones son ejecutadas a partir de la ubicación de la etiqueta bucle, por lo que a continuación toca el turno nuevamente de la instrucción ―decfsz contador,1‖, que al ser procesada proporcionará como resultado el decremento del valor del registro ―contador‖, que al inicio del paso 2 se encontraba con un valor igual a 01h, y después de ejecutar la instrucción del decremento, el valor que se encontrara en el registro ―contador‖ será igual con cero, trayendo como consecuencia que en el paso 2 la instrucción decfsz consuma 2 ciclos, además de que la instrucción ―goto bucle‖ no será ejecutada, pasando a la instrucción que continua después de goto, dando por 37 terminado el proceso del temporizador; el paso 2 proporciona un total de 2 ciclos. La suma de los ciclos totales del paso 1 con los del paso 2, dan un total de 5 ciclos que son los que se consumen en el temporizador, observe la tabla 16. Para determinar el tiempo que se consumió con la ejecución de los 5 ciclos del programa temporizador, se debe calcular el tiempo que consume cada ciclo de manera independiente, para ello nos basaremos en las relaciones que son mostradas en la tabla 17. Ciclo de instrucción o ciclo = 4 Foscilador Si la frecuencia del oscilador es de 4 MHz, entonces: Ciclo de instrucción o ciclo = 4 4Mhz = 1 MHz. El tiempo que tarda cada ciclo de instrucción es = ninstrucciódeCiclo __ 1 El tiempo de cada ciclo es = MHz1 1 = 1 μseg. Por lo tanto para 5 ciclos se tiene un tiempo de: (5 Ciclos) * (1 μseg) = 5 μseg. Tabla 17. Relaciones matemáticas para calcular el tiempo. Del cálculo que se mostrado en la tabla 17 se observa que el tiempo resultante es muy pequeño, por lo tanto, si lo que se requiere es implementar un temporizador para un valor de tiempo más amplio, se tiene que colocar un valor más grande al registro ―contador‖, para que a su vez el número de ciclos se incremente, tal como se ilustra en el programa de la tabla 18. En el programa mostrado en la figura 18, se observa que las 2 primeras instrucciones del paso 1 se emplean para cargar el valor 16610 en el registro ―contador‖. Por otra parte, mientras el valor del registro contador sea mayor que cero, cada vez que es decrementado el valor del registro ―contador‖ mediante la instrucción decfsz, esta consume 1 ciclo, más los 2 ciclos que aporta la 38 instrucción goto. Esto último significa que los 3 ciclos resultantes se repetirán 165 veces, porque el dato que esta guardado en el registro ―contador‖ se estará decrementando unidad por unidad, comenzando por valor de 16610 hasta llegar a 110. En la tabla 18 se muestra en la parte correspondiente al paso 1 la cantidad de ciclos que se acumulan mientras en valor en el registro ―contador‖ es mayor que cero. PASO 1 movlw .166 ;contador = 16610 movwf contador bucle decfsz contador,1 ; 1 ciclo. goto bucle ; 2 ciclos. instrucciones de un proceso siguiente . . . end Después de decrementar 165 veces el valor del registro ―contador‖; contador = 110 ciclos = (165) * 3 = 495 PASO 2 movlw .166 movwf contador bucle decfsz contador,1 ; 2 ciclos. goto bucle ; no se ejecuta instrucciones de un proceso siguiente . . . end contador = 00h ciclos = 2 PASO 1 ciclos = 495 + PASO 2 ciclos = 2 Ciclos totales = 497 Tabla 18. Tiempo base para un temporizador de 0.5mseg Para acceder al paso 2 en el programa de la tabla 18, el valor en el registro ―contador‖ debe ser cero, por lo que se tendrá que la ejecución de la instrucción decfsz es de 2 ciclos. El total de ciclos se obtiene de la suma de los generados en el paso 1 y en el paso 2, dando un total de 497 ciclos. Para calcular el tiempo en el que se ejecutan los 497 ciclos, se hace referencia a las relaciones matemáticas de la tabla 17, por lo que supongamos que se tiene un oscilador de 4 Mhz, con el que nos arrojara un término de 1 μseg, para cada ciclo que es ejecutado, por lo tanto, los 497 ciclos son ejecutados en 497 μseg, que a su vez es un valor muy cercano a 500 μseg, que también puede 39 interpretarse como 0.5 mseg. El tiempo de 0.5 mseg lo podemos tomar como base para a partir de este valor generar temporizadores más grandes, tal como se muestra en los ejemplos de la tabla 19. EJEMPLO 1 movlw .08 ;repite 8 veces la base de tiempo. movwf var2 ciclo_2 movlw .166 movwf var1 ciclo_1 decfsz var1,1 ;base de tiempo de 0.5 mseg. goto ciclo_1 decfsz var2,1 goto ciclo_2 ….…. otras instrucciones 0.5 mseg * 8 veces = 4 mseg EJEMPLO 2 movlw .255 ;repite 255 veces la temporIzación movwf var3 ;de 4 mseg. ciclo_3 movlw .08 movwf var2 ciclo_2 movlw .166 movwf var1 ciclo_1 decfsz var1,1 ;base de 0.5 mseg. goto ciclo_1 decfsz var2,1 goto ciclo_2 decfsz var3,1 goto ciclo_3 ….…. otras instrucciones 4 mseg * 255 veces = 1 seg Tabla 19. Ejemplos con distintos valores de temporización. En los ejemplos mostrados en la tabla 19 se muestra que se puede realizar un conteo largo de tiempo, y para ello basta con generar una estructura de contadores descontentes anidados unos en otros, esto
Compartir