curso internet microcontroladores pic

119
Microcontroladores PIC Esta web nació con el propósito de facilitar la transición de los PIC hacia los AVR. Pero debido a la redundancia que surgía al tocar temas similares en la teoría de ambos Microcontroladores, curso micros se decantó por dedicarse casi en exclusiva a los AVR. La poca información relacionada con los PIC que todavía permanece aquí es un pequeño legado de lo antes fue cursomicros. ¿Por qué prefiero los AVR y no los PIC? Un seguidor preguntaba en facebook por qué la web ahora se enfocaba a los AVR y ya no a los PIC, si era acaso porque los PIC habían quedado descontinuados o si había otros microcontroladores que eran mejores. Yo no creo que los AVR sean mejores que los PIC y menos en lo contrario. Siempre digo que todo lo que puedes hacer con un PIC también lo puedes hacer con un AVR y viceversa, buscando los modelos adecuados por supuesto. Pienso que si las personas usamos uno u otro microcontrolador se debe principalmemte a preferencias personales. En mi experiencia particular, empecé con los PIC porque eran los únicos difundidos entonces. Todos los libros que encontraba en las bibliotecas solo hablaban de ellos. Digamos que no tuve opción. Luego en la universidad aprendí también otros microcontoladores como el 68HC11 y otros chips tan antiguos como los que mis profesores habían aprendido en su juventud. Esos sí estaban descontinuados. A mí me daba igual. Solo me gustaba experimentar con todo tipo de hardware y software que encontraba pero sin ninguna predilección por algún microcontrolador. Fue recién cuando conocí de Dale Heatherington que mi camino dio un giro de 180 grados. Al inicio él también usaba los PIC, pero luego se pasó a los AVR. Como yo seguía con admiración todos sus trabajos , también tuve que estudiar los AVR. No había nada de información en castellano pero estudiarlos aunque sea en otro idioma es más fácil para quien ya conoce de otros microcontroladores. Mi preferencia por los AVR se acentuó al descubrír webs como AVRfreaks donde la gente compartía su trabajo como no había visto en la comunidad PIC. Me parecía que a muchos PIC aficionados les gustaba esconder sus códigos así fueran de LEDs parpadeantes. Las toneladas de proyectos que había en esta web me hacían pensar que los fans de los AVR competían por quién compartía más. Claro que también hay seguidores de los PIC que comparten pero la gran diferencia está en que sus códigos no son tan portables. Algunos trabajan con CCS C , otros con Mikro C , otros con Hitech C , otros con SDCC , otros con MPLAB C18, C30 o C32 y con otros compiladores más (sin mencionar los que prefieren el Basic). Al inicio la pasé muy bien probando todas esas herramientas, pero al final terminé renegando de sus divergencias. En el mundo de los AVR en cambio casi todos sus habitantes programan con AVR GCC . No podemos estar más unidos. Hablamos el mismo lenguaje, literalmente. Otro motivo que consolidó mi predilección por los AVR fueron los proyectos publicados por los alumnos de Bruce Land, de la Universidad de Cornell. Puedes revisarlos en esta sección . Después supe que los AVR eran usados también en la mayoría de las universidades de los Estados Unidos. Me apena que en casi todas las instituciones educaticas de habla española todavía sigan enseñando con los PIC. Entiendo que también

Upload: makoko-medina

Post on 28-Dec-2015

165 views

Category:

Documents


25 download

TRANSCRIPT

Page 1: CURSO INTERNET Microcontroladores PIC

Microcontroladores PIC

Esta web nació con el propósito de facilitar la transición de los PIC hacia los AVR. Pero debido a la redundancia que surgía al tocar temas similares en la teoría de ambos Microcontroladores, curso micros se decantó por dedicarse casi en exclusiva a los AVR.

La poca información relacionada con los PIC que todavía permanece aquí es un pequeño legado de lo antes fue cursomicros.

¿Por qué prefiero los AVR y no los PIC?

Un seguidor preguntaba en facebook por qué la web ahora se enfocaba a los AVR y ya no a los PIC, si era acaso porque los PIC habían quedado descontinuados o si había otros microcontroladores que eran mejores. Yo no creo que los AVR sean mejores que los PIC y menos en lo contrario. Siempre digo que todo lo que puedes hacer con un PIC también lo puedes hacer con un AVR y viceversa, buscando los modelos adecuados por supuesto. Pienso que si las personas usamos uno u otro microcontrolador se debe principalmemte a preferencias personales.

En mi experiencia particular, empecé con los PIC porque eran los únicos difundidos entonces. Todos los libros que encontraba en las bibliotecas solo hablaban de ellos. Digamos que no tuve opción. Luego en la universidad aprendí también otros microcontoladores como el 68HC11 y otros chips tan antiguos como los que mis profesores habían aprendido en su juventud. Esos sí estaban descontinuados. A mí me daba igual. Solo me gustaba experimentar con todo tipo de hardware y software que encontraba pero sin ninguna predilección por algún microcontrolador.Fue recién cuando conocí de Dale Heatherington que mi camino dio un giro de 180 grados. Al inicio él también usaba los PIC, pero luego se pasó a los AVR. Como yo seguía con admiración todos sus trabajos, también tuve que estudiar los AVR. No había nada de información en castellano pero estudiarlos aunque sea en otro idioma es más fácil para quien ya conoce de otros microcontroladores.Mi preferencia por los AVR se acentuó al descubrír webs como AVRfreaks donde la gente compartía su trabajo como no había visto en la comunidad PIC. Me parecía que a muchos PIC aficionados les gustaba esconder sus códigos así fueran de LEDs parpadeantes. Las toneladas de proyectos que había en esta web me hacían pensar que los fans de los AVR competían por quién compartía más. Claro que también hay seguidores de los PIC que comparten pero la gran diferencia está en que sus códigos no son tan portables. Algunos trabajan con CCS C, otros con Mikro C, otros con Hitech C, otros con SDCC, otros con MPLAB C18, C30 o C32 y con otros compiladores más (sin mencionar los que prefieren el Basic). Al inicio la pasé muy bien probando todas esas herramientas, pero al final terminé renegando de sus divergencias. En el mundo de los AVR en cambio casi todos sus habitantes programan con AVR GCC. No podemos estar más unidos. Hablamos el mismo lenguaje, literalmente.Otro motivo que consolidó mi predilección por los AVR fueron los proyectos publicados por los alumnos de Bruce Land, de la Universidad de Cornell. Puedes revisarlos en esta sección. Después supe que los AVR eran usados también en la mayoría de las universidades de los Estados Unidos. Me apena que en casi todas las instituciones educaticas de habla española todavía sigan enseñando con los PIC. Entiendo que también deben tener sus razones. Solo espero que no sea porque no conocen mucho de otros microcontroladores, como pasaba en mi entorno.Finalmente quiero mencionar la razón que casi no me deja tiempo para los PIC. Se llama Arduino. Algunos creen que es otro tipo de microcontrolador, pero en realidad el Arduino no es más que un "AVR disfrazado".De vez en cuando todavía doy clases de programación de PICs. No tanto porque yo lo desee sino porque es la demanda.

Page 2: CURSO INTERNET Microcontroladores PIC

Compiladores C para PICs

En primer lugar, aparte del lenguaje, nada tiene que ver un compilador para computadoras con los compiladores para microcontroladores. Poco tiene que ver un compilador para PICs que otro para otros microcontroladores. Inclusive, poco tiene que ver un compilador de PICs de una compañía con otro de otra compañía.

Veamos grosso modo algunos aspectos de los compiladores de PICs más conocidos.Hi-tech C. Es uno de los compiladores producidos por la empresa htsoft. Es quizá el más eficiente y el que mejor soporta el lenguaje C estándar. Su entorno IDE también incluye el mejor depurador ICD. Como contraparte, su apego al hardware del microcontrolador le resta algo de portabilidad. Tampoco luce librerías incorporadas como otros productos. Pero su principal desventaja es su elevado precio. Y, por si fuera poco, el compilador para la familia de partes PIC18 se vende por separado.IAR C. Los compiladores C de la compañía iar systems tienen básicamente las mismas características mencionadas de los compiladores de htsoft, incluyendo sus propios depuradores. Así mismo, las versiones para los PIC16 y PIC18 se distribuyen por separado. Actualmente, no sé por qué, ya no está disponible la primera versión.CCS C. La empresa ccsinfo decidió dotar a sus compiladores C una capa extra que aísla al programador de los recursos intrínsecos del microcontrolador. Esto puede afectar la portabilidad de sus códigos a otros compiladores, pero resulta inmejorable, si solo se trabaja en el lenguaje de CCS C, para transportar los códigos de un PIC a otro (de cualquier familia) con un esfuerzo sin comparación. Además, incluye en un solo paquete los compiladores para los PICs de las familias Baseline, Midrange (PIC16 básicamente) y High performance (PIC18). Se dispone también de un compilador para los PIC de 16 bits. Todavía no hay soporte para los PICs de 32 bits.Al igual que los softwares anteriores, sus librerías estándar, como stdlib.h, stdio.h, string.h y math.h, son muy completas y potentes; pero CCS C supera a sus rivales al incorporar librerías para controlar todos los módulos internos del PIC y también muchísimos dispositivos externos.Mikro C. La compañía Mikroelektronika vende compiladores para PICs en los lenguajes C (MikroC), Basic (MikroBasic) y Pascal (MikroPascal).Yo diría que el estilo de Mikro C se parece al de Hi-tech C y sus facilidades tratan de acercarse a las de CCS C: aunque en muchos casos aún es necesario acceder a los registros internos del PIC, cuenta con librerías para controlar sus módulos internos. También tiene una apreciable cantidad de librerías para interfacear dispositivos externos. Lo malo es que todas ellas están precompiladas y no se podrían modificar, en caso de ser necesario.Mikroelektronika y CCS también comercializan sus propias tarjetas de entrenamiento para el aprendizaje de sus productos. Para más información puedes visitar sus sitios web.MPLAB C18, C30 y C32. Excelentes compiladores desarrollados por los ingenieros de Microchip. No es gratuito como el MPLAB, pero creo que es el que ofrece la versión demo más generosa: es 100 % funcional por 60 días. Lamentablemente, como sugiere su nombre, solo trabaja con las partes PIC18. Quizá lo probemos en otro momento.Otros. Aún hay otros compiladores C (como Bytecraft, BoostC y FedC) que algo menos reconocidos como los anteriores, lo que no significa que sean malos.

Page 3: CURSO INTERNET Microcontroladores PIC

PROGRAMACION

INTRODUCCION

Como a lo largo de este curso se tratará de llevar un avance progresivo, empezaremos con la parte práctica más fácil, que es la grabación de PICs, proceso a veces llamado como “quemado del PIC”. Conoceremos las herramientas requeridas, construiremos el popular programador TE20 y al final lo pondremos en acción. Dado que aún no sabemos desarrollar programas, tomaremos archivos *.hexpre elaborados para quemar el PIC.

El proceso de grabación de los PICs varía de acuerdo con los equipos de programación con que se cuenten, aunque el resultado final es, si se quiere, el mismo.

Hardware para la programación de PICs

De la enorme cantidad de programadores que existe destacaremos que, en general, los podemos dividir según su interface de conexión a la computadora. Algunos aún utilizan el casi extinto puerto paralelo (como el ProPic programmer), otros se conectan mediante el puerto serie (como los programadores JDM o el PICSTART Plus) y los más sofisticados presentan una interface USB. Por supuesto, la calidad siempre irá de la mano con el precio.

Page 4: CURSO INTERNET Microcontroladores PIC

Software para la programación de PICs

Casi todas las tarjetas de los programadores profesionales (en especial los de interface USB) también traen consigo su propio software controlador. Los programadores patentados por Microchip (como elPICSTART Plus, PRO MATE II, o el PM3) son controlados por utilidades incluidas en el MPLAB IDE. Los dos últimos citados incluso pueden operar en modo Stand-Alone, es decir, sin conexión a la computadora.Por otro lado, hay programadores como el JDM y ProPic, entre otros, que funcionan con softwares de programación generales. Uno de ellos es el IC-PROG, que es de libre distribución.Otro software gratuito, y que supera al IC-PROG –al menos para mí–, es WinPic800. Este programa lo puedes descargar desde su web http://www.WinPic800.com. Allí también podrás hallar todos los planos para la construcción de su hardware programador con interface USB, pero el firmware del microcontrolador (el principal elemento) tiene un precio.WinPic800 también ofrece soporte para múltiples modelos de programadores, incluido el TE-20. Así que, a no ser que cuentes con mejores herramientas, nosotros emplearemos un TE-20 y como software, el WinPic800 será el elegido.

EL PROGRAMADOR TE-20

Si está dentro de tus posibilidades conseguir un programador profesional, ¡enhorabuena! Lo cierto es que no todos podrán hacerlo debido a su precio. Para ellos una buena alternativa puede ser el programador TE-20, una variante mejorada del hiperfamoso programador JDM.

Al igual que su “padre”, el programador TE-20 tiene la notable y peculiar característica de operar sin alimentación externa. Pero como nada es gratis en la vida, este mismo detalle da pie a un relativo defecto: algunas laptops no disponen de mucha corriente en sus puertos, por lo que pueden tener dificultades al controlar un TE-20.

Page 5: CURSO INTERNET Microcontroladores PIC

 Construcción de un programador TE-20

Por su popularidad, los programadores TE-20 se pueden hallar fácilmente en las tiendas de electrónica. Pero para los que tienen la afición (u obsesión) de hacerlo todo por ellos mismos, aquí les muestro cómo.

Antes de seguir, quiero aclarar que en su versión original el TE-20 incorpora soporte para PICs de 18 y 28 pines, y un circuito para programar memorias EEPROM I2C. (Ver Figura de arriba.) Lo único que hice en esta versión fue sustituir el zócalo de 28 pines por uno de 40. No quise incluir el zócalo de 28 pines para no complicar el PCB y porque yo veo que es más común emplear los PICs de 40 pines que los de 28. Como sea, digamos que tiene todo lo necesario para nuestro trabajo con PICs en este curso.

Lista de componentes

Para el grabador con zócalos simples los componentes son:

1  Conector DB9 hembra para placa impresa

1  Diodo zener de 5.1 Voltios (1N4733A)

1  Diodo zener de 8.2 Voltios (1N4738A)

4  Diodos 1N4148

1  Capacitor de 220 µF, 16 Voltios

1  Capacitor de 47 µF, 16 Voltios. (Mejor, si también es de 220 µF.)

2  Transistores BC547 (o BC548)

1  Transistor BC557 (o BC558)

1  Resistencia de 100 K

1  Resistencia de 1.5 K

1  Resistencia de 10 K

1  Resistencia de 1 K

Page 6: CURSO INTERNET Microcontroladores PIC

1  Zócalo de 8 pines

1  Zócalo de 18 pines

1  Zócalo de 40 pines

1  Plaqueta de circuito impreso (preferentemente de fibra de vidrio) de 5 cm x 10 cm

Nota: los capacitores de 220 µF antiguos son más gorditos que los de hoy. No compres de esos porque no va a caber en la placa impresa. Así mismo, es preferible conseguir transistores que tengan las patitas en disposición colineal en lugar de los que vienen en forma de trípode.

Esquema del circuito

 La placa PCB

Esta imagen no está precisamente a escala. En la web puedes encontrar todos los planos necesarios por separado para la construcción de este TE-20.

Page 7: CURSO INTERNET Microcontroladores PIC

 

Descripción del circuito del TE-20

Una breve explicación de las principales señales del TE-20 nos permitirá conocerlo mejor y quizá te pueda servir para cuando quieras hacerle algunas modificaciones o tomar sus señales para programar un PIC que no quepa en los zócalos.Son 5 las líneas de datos y de control para la programación de los PICs. (Ver circuito del TE20   .)

VPP. Es la tensión de programación. En modo programación su valor es de 13 V más o menos. Siempre corresponde a la patita MCLR de los PICs.

VDD o VCC. Como siempre, es la tensión de alimentación. Debe valer entre 4.5 V y 5.5 V. En algunos PICs hay más de un pin VDD. Si se pueden conectar todos, mejor. Corresponde a los pines del mismo nombre en el PIC.

GND. Ésta es la tierra y vale 0 V solo si es visto desde el circuito del PIC. Observa que en el circuito del TE-20 no es la misma GND del conector DB9 (pin 5). Debe ir a los a los pines del mismo nombre en el PIC.

CLOCK. Es la señal de reloj que debe tener toda comunicación síncrona. Corresponde al pin RB6del PIC.

DATA. Es una línea bidireccional para transmitir y recibir los datos del PIC. Siempre corresponde al pin RB7 del PIC.

Como se sabe, una singularidad del TE-20 es que no requiere de fuente de alimentación externa: la obtendrá a partir de las líneas del mismo puerto serie.

El pin MCLR del PIC determina el modo de funcionamiento del mismo.

Cuando la tensión en MCLR vale GND (0 V), el PIC permanece en estado de RESET.

Cuando MCLR vale VDD (típicamente 5 V), el PIC ejecuta el programa grabado en su memoria.

Si MCLR vale VPP (cerca de 13 V), entonces el PIC pasa al estado de programación y espera los datos del programa a grabarse.

El valor de VPP en el circuito del TE-20 subirá a cerca de 13 V cuando haya actividad en la línea TXD. Solo el pin MCLR del PIC puede soportar tranquilamente estos niveles de tensión. Así que siempre debes ser muy cuidadoso al colocar el PIC en el zócalo del TE-20.

Descarga de archivos PDF del programador TE-20

Placa PCB

Page 9: CURSO INTERNET Microcontroladores PIC

Práctica  Uso del programador TE-20 y el WinPic800

Ahora veremos de lo que se trata esto de manejar circuitos con PICs. En esta práctica solo aprenderemos a grabar un PIC. Como aún no sabemos programar, lo haremos con un archivo*.hex pre creado. No es necesario ver el código, nos bastará con saber que muestra en la pantalla del LCD un mensaje en movimiento, mientras que en los 8 pines del puerto B visualiza un juego de luces con tres efectos diferentes. Un botón conectado al pin RA4 permite cambiar de efecto.

Los archivos de ésta como los de todas las prácticas del curso están disponibles en la web.

 

Circuito de la práctica

Este circuito, al igual que todos los del curso, se puede montar sobre un breadboard. Se asume que la fuente de alimentación es externa y su diagrama no será incluido aquí ni en ningún circuito. Esta fuente debe ser lo más precisa y estable posible. Como en todo circuito digital, debe entregar una tensión de VCC = 5 V. Con una fuente basada en el regulador 7805 será suficiente.

Si bien en esta práctica se podría prescindir del LCD, en el Módulo 2 nos será muy útil. Así que si lo vas a conseguir éste puede ser un buen momento. Solo debes verificar que tenga un controlador interno HD44780 o compatible. Puede ser de dos líneas con 16 ó 20 caracteres cada una.

Sobre el PIC16F84A, si tienes este mismo modelo, ¡genial! Si recién lo vas a comprar, que sea el PIC16F84A (con la F y la A). En este modelo aún hay especificaciones de frecuencia. Los PIC16F84A-04 trabajan a 4MHz y los PIC16F84A-20, a 20MHz. La inscripción final dice /P o I/P, que indican operación

Page 10: CURSO INTERNET Microcontroladores PIC

a temperatura comercial (de 0 °C a +70 °C) y temperatura industrial (de –40 °C a +85 °C), respectivamente, ambos en empaque PDIP.Finalmente, también nos hará falta un cable con conectores DB9 para el puerto serial de la computadora, aun cuando el pequeño tamaño de nuestro TE-20 le permite conectarse directamente.

 

Procedimiento

Colocar el PIC en el zócalo adecuado del TE-20 y con la orientación indicada por las muescas del PIC y del zócalo.

Conectar el TE-20 al puerto serie del PC, mediante el cable serial si fuera necesario. Fíjate en a cuál puerto serie lo conectas en caso de tener más de uno.

Ejecutar el programa WinPic800. Si aún no lo tienes instalado, lo puedes descargar desde su web www.WinPic800.com e instalarlo sin ninguna remarcación en especial: solo le das a aceptar y siguiente, siguiente, siguiente...

En el entorno de WinPic800 ve al menú Configuración > Hardware para seleccionar el TE20 como hardware de programador y un puerto COM disponible. (Nota que yo escogí el COM1.)

En caso de tener más de un ítem COM en la lista, debes seleccionar aquél donde hayas conectado el TE-20.

Esta configuración permanecerá hasta que se vuelva a cambiar.

Seleccionar el dispositivo a programar. Para nuestro PIC16F84A primero el grupo del PIC (PIC16F) luego el PIC16F84A. Esta opción se mantendrá hasta que se vuelva a cambiar.

Page 11: CURSO INTERNET Microcontroladores PIC

Recién ahora se revelan las opciones Detectar Dispositivo   y Leer ID-REV  , que dan casi lo mismo. Aunque un poquito tarde, nos valdrán para ver si nuestro TE-20 está conectado y respondiendo adecuadamente. Así que clica cualquiera y a ver:

Ya viste que a mi me fue muy bien. Si tú no corriste igual suerte, sería bueno que regreses al cuarto paso a ver si tomaste un puerto COM adecuado o que chequees si el TE-20 está bien conectado. De continuar sin resultados, podría ser que tu puerto serie no responde adecuadamente (pasa en algunas laptops) o “simplemente” no responde (puerto serie quemado quizá), o que el TE-20 tenga fallas, o que el PIC esté dañado.

Abrir el archivo *.HEX a grabar.

Una vez cargado el programa, haremos un pequeño alto aquí para ver los datos que se grabarán en el PICmicro.

En la ficha Código aparece gran parte del archivo que abrimos. Es el verdadero código que ejecutará el PICmicro. A menos que sepas lo que haces, jamás deberías cambiar estos códigos.

Page 12: CURSO INTERNET Microcontroladores PIC

La ficha Datos representa el contenido inicial que tendrá la EEPROM interna del PIC. Esto es más importante: a mucha gente le gusta meter las manos en la ficha Config. para modificar el

valor de los bits de configuración. Hablaremos de su significado en el siguiente capítulo. Por ahora diré que dichos valores también pueden ser cargados desde el mismo archivo *.hex. Al menos todos los programas de este curso están lo suficientemente completos como para no tener que tocar esta ventana.

Ahora a grabar. Para ello selecciona Dispositivo > Programar Todo o el botón   de la barra de herramientas o Ctrl + P desde el teclado

No podía faltar una comprobación de la grabación. Para ello clica Verificar Todo   o, a veces más rápido, tipea Ctrl + V desde el teclado.

Ok, ok, ok y ok. Eso es lo que nos gusta a todos.

Desconectar el TE-20 y retirar el PIC. Ahora el PIC está listo para ser colocado en el circuito.

Page 13: CURSO INTERNET Microcontroladores PIC

Al principio parece un procedimiento largo; sin embargo, dado que la configuración adoptada se mantendrá las siguientes veces que se arranque WinPic800, verás que muchos de los pasos dados ya no serán necesarios y todo se reducirá a cargar el programa y grabar.WinPic800 también ofrece otras opciones que pueden resultar utilísimas. No son muchas, por lo que te será fácil descubrirlas por tu cuenta. Una que me ayuda mucho es Cargar el último programa accedido.

Programadores USB para PIC

A continuación tienes algunos programadores USB que los puedes construir libremente. Tanto el firmware como los planos de diseño están a libre disposición en sus respectivos sitios web. Son programadores que utilizan un PIC, específicamente un PIC18F2550, como su controlador por lo que será necesario grabarlo previamente. Para ello puedes armar provisionalmente un programador sencillo como el programador te-20 u otro.

Hay algunos factores en el programador que debes considerar a la hora de evaluar cuál te conviene.La principal diferencia entre ellos está en las series de PICs que pueden programar, entre los PIC10,PIC12, PIC16, PIC18, PIC24F, PIC24H, dsPIC30,dsPIC33 y PIC32. La programación de los PIC es muy sensible a sus variaciones: que un programador soporte un PIC de una serie no necesariamente significa que vaya a poder con los demás miembros del grupo.

Familias de Microcontroladores PIC

Todas estas familias a su vez pueden dividirse en dos grandes grupos: Los que trabajan con hasta 5V de alimentación, que son la mayoría de los PIC de 8 bits y parte de los de 16 bits y los que por su velocidad superior trabajan con alimentación de hasta 3.3V, que son el resto, como todos los PIC32.Todos los programadores pueden grabar los PIC de 5V, la cuestión está en los PIC de 3.3V. Un programador debe sintonizar con el circuito del PIC de 3.3V para que pueda comunicarse con él. El primer factor aquí es la tensión de alimentación. Si el circuito trabaja con su propia alimentación gran parte del obstáculo queda salvado, de otro modo el programador deberá ser capaz de proveer los 3.3V al PIC programado. El USBPICProg por ejemplo necesita de un adaptador externo para esta función.

Page 14: CURSO INTERNET Microcontroladores PIC

Así mismo, en el programador las líneas de interface de la programación deben manejar niveles de tensión compatibles con los del PIC a grabar. Muchos PIC diseñados para operar a 3.3 V soportan tranquilamente voltajes de hasta 5V pero otros son más sensibles y necesitarán de elementos interpuestos que en algunos casos puede bastar con simples resistencias. El programador PICkit 2original en este sentido usa un buen circuito de adaptación que la mayoría de sus clones mutilan por simplificar el hardware.

Programador USBPICProg

Este es un programador Open Source iniciado por Frans Schreuder. Puedes visitar su webusbpicprog.org para conocer todas sus características. Allí también encontrarás todos los esquemas para construirlo. Pero si deseas también se encuentra disponible una versión comercial como la que se muestra en la figura de abajo.

programador USBPICProg

Anverso y reverso del programador de PIC USBPICProg (fuente: usbpicprog.org).Muchas personas prefieren los diseños de agujero pasante y como los circuitos son libres han hecho sus propias adaptaciones del hardware. Abajo se muestra un ejemplo realizado por Francesco Montorsi.

Programador de PIC USBPICProg en versión de agujero pasante (fuente: usbpicprog.org).

Yo por mi parte prefiero la simetría y el conector USB tipo B. Así que probé modificarlo y el resultado me quedó como se ve abajo. También removí el conector ICSP del PIC18F2550 y cambié la disposición de los pines en el conector ICSP principal para que sea compatible con el del PICkit 2.

Programador de PIC USBPICProg

 

Page 15: CURSO INTERNET Microcontroladores PIC

Programador GPIC USB SE

Es la segunda versión del programador USB de Guillermo Presa disponible en www.sitionica.com.ar. El software programador solo corre bajo Windows. La placa tiene un muy bonito acabado. El hardware provee la interface para programar los PIC de 3.3V.

Programador de PIC GPIC USB SE (fuente: sitionica.com.ar)

 

Programador PICkit 2

Este es el programador oficial de Microchip. Bueno, uno de los varios. Su pariente superior es el PICkit 3; cuesta como un 30% más pero parece que sus nuevas características no lo justifican. Así que en general para muchos el PICkit 2 y PICkit 3 son casi lo mismo. No podemos discutir sus limitaciones pues simplemente programan todos los PIC. Además de un software independiente que no requiere drivers adicionales por trabajar en modo HID, pueden operar desde el entorno de MPLAB X.

Programador de PIC PICkit 2 (fuente: microchip.com).El circuito del programador PICkit 2 siempre ha estado presente en su manual y tiempo después Microchip ha decidido liberar también el firmware del PIC18F2550 que lleva como cerebro tanto en archivo HEX como en código fuente. Muchas personas y hasta entes comerciales han aprovechado

Page 16: CURSO INTERNET Microcontroladores PIC

esta oportunidad para crear sus adaptaciones denominadas clones del PICkit 2 en general simplificando el circuito para facilitar su implementación o reducir su costo, aunque muchas veces en desmedro de su funcionalidad.programador USBPICProg

Clones del programador PICkit 2, de mcuhobby.com y canakit.com.Si buscas en Internet, vas a encontrar muchos otros clones del programador PICkit 2. Cada quien reduce o ajusta el circuito sus necesidades. Al elegir uno recuerda tener en cuenta las características mencionadas al inicio de esta página. Y si esperas un consejo mío, te recomiendo que te compres uno oficial.

Características del PIC16F84A y PIC16F87xA

CPU RISC de Alta Performance:

Solo 35 instrucciones que aprender

Velocidad de operación de hasta 20 MHz (modelo PIC16F84A-20)

1024 palabras de memoria de programa (FLASH)

68 bytes de RAM de Datos estática

64 bytes de EEPROM de Datos

Pila hardware de 8 niveles

Cuatro fuentes de interrupción:Características de los Periféricos:

13 pines de E/S con control de dirección individual

Suministro de hasta 25 mA de corriente por pin en los puertos TMR0: temporizador/contador de 8-bits con prescaler programable

Características Especiales del Microcontrolador:

Memoria de programa FLASH para 10 000 ciclos de borrado/escritura típicamente

Memoria EEPROM para 10 000 000 de ciclos de borrado/escritura típicamente Programación Serial en el Circuito, ICSP Watchdog Timer con su propio oscilador RC

Capacidad de protección de código

Modo SLEEP para ahorrar energía

Opciones para seleccionar el oscilador

Tecnología FLASH/EEPROM CMOS mejorada:

Amplio rango de voltaje de operación: 2.0 V a 5.5 V

Máxima disipación de potencia: 800 mW

Y ahora las características de los PIC16F87xA:CPU RISC de Alta Performance:

Page 17: CURSO INTERNET Microcontroladores PIC

Solo 35 instrucciones que aprender

Velocidad de operación de hasta 20 MHz (200 ns por instrucción básica)

Hasta 8 K de palabras de 14 bits de memoria de programa (FLASH)

Hasta 368 bytes de RAM de Datos estática

Hasta 256 bytes de EEPROM de Datos

Pila hardware de 8 niveles

Hasta 15 fuentes de interrupciónCaracterísticas de los Periféricos:

Hasta 33 pines de E/S con control de dirección individual

Suministro de hasta 25 mA de corriente por pin en los puertos

Timer0: temporizador/contador de 8-bits con prescaler programable

Timer1: temporizador/contador de 16-bits con prescaler programable

Timer2: temporizador de 8-bits con prescaler y postcaler programables

Dos módulos CCP, Capture, Compare, PWM. El PWM es de 10 bits

MSSP: Puerto Serie Síncrono Maestro con operaciones en modos I2C y SPI.

USART: Puerto serie Transmisor Receptor Síncrono Asíncrono Universal

PSP: Puerto Paralelo Esclavo de 8 bits y con controles RD, WR y CS.

BOR: Circuito de Detección de Bajo VoltajeCaracterísticas Especiales del Microcontrolador:

Memoria de programa FLASH para 100 000 ciclos de borrado/escritura típicamente

Memoria EEPROM para 1 000 000 de ciclos de borrado/escritura típicamente

Watchdog Timer

Capacidad de protección de código

Modo SLEEP para ahorrar energía

Opciones para seleccionar el oscilador

Programación Serial en el Circuito, ICSP

Autoprogramación por control software

Programación en bajo voltaje (5V)

Soporte ICD vía dos pinesCaracterísticas analógicas:

Conversor ADC de 10 bits de hasta 8 canales

Módulo Comparador

Page 18: CURSO INTERNET Microcontroladores PIC

Diagrama de pines del PIC16F84A y PIC16F877A/874A en encapsulado PDIP.

La memoria de programa

En los PIC16Fxxx es de tipo flash, por eso la F. Aquí es donde se aloja el programa que el CPU ejecutará. En los PIC16 la memoria de programa se cuantifica en palabras, de 14 bits cada una. Son de 14 bits porque cada instrucción es de 14 bits. Esto suele impresionar un poco al novel, quien está habituado a medir la capacidad de las memorias en bytes (8 bits).El PIC16F84A tiene 1 k (1024) palabras de memoria. En tiempo de ejecución son de solo lectura. Con 1 k puede almacenar hasta 1024 instrucciones de código ensamblador.Los PIC16F877A/876A tienen 8 k (8192) palabras de memoria de programa mientras que losPIC16F874A/873A tienen 4 k (4192). Los cuatro PICmicros ofrecen la posibilidad de escribir en su memoria de programa incluso en tiempo de ejecución. Esta función puede ser aprovechada para almacenar datos procesados por el usuario o para permitir la autoprogramación del PIC.En las siguientes figuras las memorias de programa del PIC están acompañadas por el PC (Program Counter) y la Pila (Stack). Es así porque hay una extrecha relación en su trabajo.

Page 19: CURSO INTERNET Microcontroladores PIC

Contador de Programa, Pila y Memoria de programa del PIC16F84A y PIC16F87xA.

 

El Contador de Programa, PC

El PC es un registro que indica la siguiente instrucción que debe ejecutar el CPU. Al arrancar microcontrolador, el PC vale 0x0000 y se va incrementando automáticamente, con lo que el PIC debería ejecutar una a una todas las instrucciones del programa.En los PICs de la familia Mid-Range el PC es de 13 bits, pudiendo direccionar un máximo de 8 k palabras de memoria de programa.

La Pila o STACK

Es una memoria que almacena temporalmente el valor del PC (Program Counter) cuando el programa llama a una subrutina o cuando salta al Vector de Interrupción, en una interrupción.

En los PICs de la familia Mid-Range la Pila tiene únicamente 8 niveles y se administra a nivel hardware, esto es, no hay instrucciones para acceder a ella directamente. Su operación es enteramente en background. Solo debemos cuidar de que no se llegue a desbordar.

La memoria RAM

A diferencia de las RAMs de los microcontroladores convencionales, que tienen mapa de memoria plano, la RAM de los PICs de familia Mid-range está dividida en sectores denominados bancos. Cada byte de la RAM se conoce como registro.

Page 20: CURSO INTERNET Microcontroladores PIC

Hay dos tipos de registros de RAM: los registros de función especial SFR y los registros de propósito general GPR.

No todos los registros están implementados físicamente. La escritura en dichas locaciones no significa nada y siempre se leen como 0.

El PIC16F84A es de los muy pocos que tienen 2 bancos de RAM; el resto de los PIC16F, que son la gran mayoría, tienen 4 bancos. La existencia de los bancos solo es de consideración (y un dolor de cabeza) cuando se programa en lenguaje ensamblador.

Registros de Funciones Especiales, SFR

Los registros SFR (Special Function Register) están ubicados en las primeras posiciones de cada banco de RAM, los que en la figura anterior aparecen con nombre propio, como TMR0, PORTA, etc. Su principal función es controlar las operaciones del microprocesador y de los módulos periféricos. Como se ve, algunos de esos registros aparecen duplicados en los bancos; eso es para facilitarnos su acceso porque son de uso muy frecuente o porque son un poquito más especiales, como STATUS,INTCON o PCL.

Registros de Propósito General, GPR

También son registros de 1 byte cada uno. Los registros GPR (General Purpose Register) sirven para almacenar los datos o variables que se procesan en el programa.El PIC16F84A tiene 68 registros GPR, todos ubicados en el banco 0, entre las direcciones 0x0C y 0x4F. En el banco 1 no hay registros GPR, solo hay accesos a los registros del banco 0. Dicho en otras palabras, los registros GPR del banco 1 son un reflejo de los GPR del banco 0.

Mapa de la RAM de datos del PIC16F84A.

Page 21: CURSO INTERNET Microcontroladores PIC

Los PIC16F877A/876A tienen 368 registros GPR. Los últimos 16 registros de los bancos 1, 2 y 3 son los mismos que del banco 0.Los PIC16F874A/873A tienen 192 registros GPR. Su mapa de RAM es un poco diferente debido principalmente a los accesos repetidos. Todas estas diferencias serán de preocupación solo cuando se programe en ensamblador.

Mapa de la RAM de datos de los PIC16F877A y PIC16F876A.

Page 22: CURSO INTERNET Microcontroladores PIC

Mapa de la RAM de datos de los PIC16F874A y PIC16F873A.

Page 23: CURSO INTERNET Microcontroladores PIC

Los registros GPR no tienen nombres propios, pero los compiladores de alto nivel saben cómo administrarlos para almacenar las variables del programa. Por otro lado, si se programa en ensamblador, se les debe acceder mediante sus direcciones, ya sea directamente usando números, o asignándoles nombres a las direcciones con algunas directivas, como equ o cblock.Por ejemplo, en el siguiente código se designan los nombres var1 y var2 a los registros de direcciones 0x25 y 0x30, respectivamente.var1 equ 0x25 var2 equ 0x30

Luego se podrán usar esos nombres para acceder a los registros designados. Por ejemplo, el siguiente código copia el contenido del primer registro al segundo. Movf var1, W ; Mover var1 a W Movwf var2 ; Mover W a var2

El diseñador puede elegir cualesquiera registros GPR como sus variables de programa. Para ello debe recordar siempre dónde se localizan. Según las figuras de arriba, en el PIC16F84A están mapeados a partir de la dirección 0x0C. En los PIC16F87xA empiezan en la dirección 0x20 en el banco 0; los otros bancos se usan raramente en ensamblador.

Diferencias entre los PIC16F87xA

El PIC16F876A se diferencia del PIC16F877A porque viene en empaque PDIP de 28 pines, lo que le descuenta los puertos D (de 8 pines) y E (de 3 pines). La función excluyente de estos puertos es la interface del PSP (Parallel Slave Port), del que muy pocos se acuerdan. El puerto E también provee tres canales adicionales para el conversor ADC. En consecuencia, si no vamos a utilizar estas funciones, no se presentarán problemas de compatibilidad y los programas pueden ser usados para el PIC16F877A o el PIC16F876A indistintamente, tanto en código fuente como en código ejecutable *.hex.Las mismas diferencias descritas arriba también se presentan entre los PIC16F873A y PIC16F874A. Adicionalmente, estos PICmicros se diferencian de los dos anteriores por tener menos memoria de programa FLASH, de datos RAM y de EEPROM, y en la ligera variación de disposición de los registros GPR de la RAM. Esto último puede dar origen a incompatibilidades hasta en los códigos *.hex resultantes.

La siguiente tabla resume las diferencias más evidentes entre los PICmicros citados.

Tabla Dispositivo

DispositivoMemoria de Programa 

(palabras 14-bits)RAM(bytes) EEPROM(bytes)

Pines de E/S

Canales del conversor ADC

PIC16F877A 8192 368 256 33 8

PIC16F876A 8192 368 256 22 5

PIC16F874A 4096 192 128 33 8

PIC16F873A 4096 192 128 22 5

De estos 4 PICs en este curso se utiliza el PIC16F876A, aunque los programas, que están escritos en lenguaje C, serán totalmente compatibles con los otros 3. Para cambiar de PIC solo hará falta establecerlo como PIC destino y recompilar el proyecto. El compilador se encargará de los detalles de bajo nivel.

Los Fuses de Configuración

Page 24: CURSO INTERNET Microcontroladores PIC

Los fuses se programan mediante los llamados Bits de Configuración, los cuales están contenidos en un registro de EEPROM especial denominado Configuration Word. Este registro está situado en la dirección 0x2007, aunque tiene poco sentido saberlo porque es inaccesible desde el programa en tiempo de ejecución.

El PIC16F84A tiene 4 fuses y los PIC16F87xA tienen 9. Por tanto habrá diferencias en sus palabras de configuración.Ésta es la Palabra de Configuración del PIC16F84A:

Ésta es la Palabra de Configuración del PIC16F87xA:

La Palabra de Configuración de los PIC16F87xA incluye todos los bits del PIC16F84A, aunque varíen algunos nombres. De todos modos, esos nombres son raramente usados como tal. Los fuses se suelen programar usando máscaras que los representan. Por fortuna, las máscaras sí son iguales.La Palabra de Configuración se puede cambiar en el momento de “quemar” el PIC en el IDE del software de programación, pero sería mejor que sus valores se cargaran desde el archivo *.hex junto con el código ejecutable. En seguida se muestra un ejemplo de cómo establecer los fuses en el código fuente del programa en lenguaje ensamblador, mediante la directiva __config: __config _XT_OSC & _WDT_OFF & _PWRTE_ON

Esta línea pone tres máscaras (_XT_OSC, _WDT_OFF y _PWRTE_ON) enlazadas por el operador &. Cada máscara indica el estado de un fuse. En este caso se indica: adaptar el circuito interno de oscilador para un XTAL, inhabilitar el Watchdog y habilitar el Power-up Timer. El resto de los fuses (los no citados) tendrán sus valores por defecto.

No te preocupes si el anterior parrafo se leyó extraño. A continuación se describen los 9 fuses de los PIC16F87xA. El PIC16F84A solo cuenta con los 4 primeros. También se muestran las máscaras correspondientes utilizadas en ensamblador.

Selección del oscilador

Sirve para adaptar el circuito interno del oscilador según el componente externo que se usará como fuente del reloj del sistema.

_LP_OSC = Oscilador LP. Se usa cuando el PIC va a trabajar con un cristal de baja potencia. _XT_OSC = Oscilador XT. Se usa cuando el PIC trabajará con un cristal o resonador de frecuencias

iguales o menores que 4 MHz. Es la opción que usaremos a lo largo del curso. _HS_OSC = Oscilador HS. Se usa cuando el PIC operará con un cristal o resonador de alta frecuencia,

iguales o mayores que 4 MHz. _RC_OSC = Oscilador RC. Se usa cuando el PIC va a operar con un circuito RC. Es útil para sistemas de

bajo costo aunque con frecuencias bajas y de menor nivel de estabilidad. Es la opción por defecto.

Page 25: CURSO INTERNET Microcontroladores PIC

El Watchdog

El Watchdog o WDT es un temporizador que una vez vez alcanzado su tiempo límite puede provocar un reset en el pic. El watchdog es un simple contador, que se puede reiniciar para que no llegue a desbordarse de modo que no se produzca el reset.

El watchdog está habiitado por defecto y se debe reiniciar con la instrucción de ensamblador clrwdt. En el programa el watchdog se inhabilita poniendo la máscara _WDT_OFF.

_WDT_ON = WDT habilitado. Opción por defecto. _WDT_OFF = WDT inhabilitado.

Power Up Timer

Cuando el circuito Power-up está habilitado temporizará cerca de 72 ms después de conectada la alimentación del PIC, manteniéndolo en estado de reset. Luego de este tiempo el PIC empezará a ejecutar el programa. Es útil para esperar a que la tensión de alimentación se estabilice.

_PWRTE_ON = El temporizador Power-up está habilitado. _PWRTE_OFF = El temporizador Power-up está inhabilitado. Opción por defecto.

Protección de Código

Se representa por el bit CP. Este fuse pone protección a la memoria de programa. Como sabemos, es posible leer el programa contenido en el PICmicro mediante el dispositivo programador (JDM por ejemplo). Si activamos este fuse, dicha lectura será impedida. También implica renunciar a la característica de verificación del programa; así que si lo vas a activar, no olvides reconfigurar el software de programación.

_CP_OFF = Protección de código inhabilitada. Es la opción por defecto. _CP_ON = Protección de código habilitada (PIC16F84A). _CP_ALL = Protección de código habilitada (PIC16F87xA).

Escritura en memoria de programa

Se representa con los bits WRT1 y WRT0. Los PIC16F87xA ofrecen la posibilidad de escribir en su memoria de programa Flash en tiempo de ejecución. Sin embargo, esto algunas veces puede resultar riesgoso. Así que para dotarle se seguridad adicional al programa este fuse permite configurar qué área de memoria quedará protegida y qué área no. El efecto no es siempre el mismo en los PIC16F877A/876A que en los PIC16F874A/F873A: no es lo mismo la mitad de la memoria del PIC16F876A que la mitad de memoria del PIC16F873A.

_WRT_OFF = No hay protección de la memoria de programa. Opción por defecto. _WRT_256 = Se protegen las primeras 256 palabras de la memoria de programa. _WRT_1FOURTH = Se protege el primer cuarto de la memoria de programa. _WRT_HALF = Se protege la primera mitad de la memoria de programa.

Modo ICD

Se representa con el bit DEBUG. Con el módulo ICD (In Circuit Debugger) habilitado, los PIC16F87xAmonitorizan el estado de todos sus elementos hardware internos. Los resultados serán almacenados en un área reservada de la memoria RAM y luego enviados a una computadora a través de los pines RB6 y RB7. La computadora recibirá los datos mediante algún programa que soporte el modo ICD

Page 26: CURSO INTERNET Microcontroladores PIC

Al habilitar el modo ICD se debe renunciar a los pines RB6 y RB7 como puertos de E/S convencionales, a un nivel de pila y a algo de memoria RAM.

_DEBUG_OFF = ICD inhabilitado. Opción por defecto. _DEBUG_ON = ICD habilitado, RB6 y RB7 se destinan al debugger.

Protección de la EEPROM interna

Se representa con el bit CPD. Sirve para proteger la memoria EEPROM interna de los PIC16F87xAcontra accesos mediante un dispositivo externo. Funciona similar a la protección de la memoria de programa, esto es, podrá ser accedida normalmente por el CPU en tiempo de ejecución, mas no, por ejemplo, por un programador de PICs.

_CPD_OFF = EEPROM interna desprotegida. Opción por defecto. _CPD_ON = EEPROM interna protegida.

Programación en bajo voltaje

Se representa con el bit LVP. Los PIC16F87xA también ofrecen la posibilidad de ser programados con una tensión igual a Vdd en el pin MCLR, en vez de los 12 V acostumbrados. Éste es el modo de programación ICSP (In Circuit Serial Programming) de bajo voltaje. Los pines RB6 y RB7 también deben ser sacrificados para uso exclusivo del programador y además se les suma la presencia del pin RB3 como señal del modo de programación. Dada esta interface, no debe sorprender que esta característica puede ir muy de la mano con el depurador ICD. Sin embargo, para la programación en bajo voltaje no se requiere de herramientas especializadas.Habilitado este fuse, los pines RB7, RB6 y RB3 no responderán como puertos de E/S típicos.

_LVP_ON = Programación en bajo voltaje habilitado. Opción por defecto. _LVP_OFF = Programación en bajo voltaje inhabilitado.

Brown Out Reset

El circuito Brown out del PIC detecta las caídas en la tensión de alimenación y puede generar un reset ante tal evento para evitar que el PIC siga trabajando con alimentación insuficiente. En los PIC16F el valor umbral típico del circuito Brown out es de 4V. De hecho, a tensiones aceptablemente por debajo de este nivel de tensión el PIC todavía puede tener una operación correcta pero no garantizada.

Si no se quiere correr el riesgo y se prefiere optar por que el PIC reinicie todo, se puede activar este fuse mediante su bit de configuración BOREN o mediante su máscara respectiva.

_BODEN_ON = Brown out reset habilitado. Opción por defecto. _BODEN_OFF = Brown out reset inhabilitado.

El registro STATUS

Dadas las limitaciones del ALU del PIC, los bits restantes de STATUS han sido rellenados con bits que tienen funciones completamente disímiles.

Registro STATUS

STATUS IRP RP1 RP0 TO PD Z DC C

Registro de

Page 27: CURSO INTERNET Microcontroladores PIC

IRP: Register Bank Select bit (usado para direccionamiento indirecto)

1 = Bancos 2 y 3

0 = Bancos 0 y 1

No implementado en el PIC16F84A: mantener en ‘0’

RP1:RP0: Register Bank Select bits (usado para direccionamiento directo)

11 = Banco 3

10 = Banco 2

01 = Banco 1

00 = Banco 0

El bit RP1 no está implementado en el PIC16F84A: mantener en ‘0’

TO: Watchdog Timer Enable bit

1 = Después del power-up, instrucción CLRWDT, o instrucción SLEEP

0 = Ocurrió un desbordamietno del Watchdog

PD Oscillator Selection bits

1 = Después del power-up o por la instrucción CLRWDT

0 = Por ejecución de la instrucción SLEEP

Z Zero bit

1 = El resultado de una operación aritmética o lógica es cero

0 = El resultado de una operación aritmética o lógica no es cero

DC Digit Carry /borrow bit  (para borrow, la polaridad es invertida)

1 = Ocurrió un acarreo en el bit de 4to orden del resultado

0 = No ocurrió un acarreo en el bit de 4to orden del resultado

C Carry bit o borrow (para borrow, la polaridad es invertida)

1 = Ocurrió un acarreo en el Bit Más Significativo del resultado

0 = No ocurrió un acarreo en el Bit Más Significativo del resultado

 Descripción de los Puertos

Todos los pines de los puertos son bidireccionales configurables por software.

Cuando actúan como salidas, los pines pueden entregar tensiones de hasta Vdd. Cuando actúan como entradas pueden manejar niveles de hasta 0.3V por encima de Vdd. Cada pin de puerto puede soportar hasta 25 mA de corriente.

Page 28: CURSO INTERNET Microcontroladores PIC

Diagrama de pines de los PIC16F84A y PIC16F87xA.

Page 29: CURSO INTERNET Microcontroladores PIC

El puerto B

Empezamos con el puerto B porque es el más fácil. Los nombres sencillos de sus pines revelan que no tienen muchas funciones. Los 8 pines RB0...RB7 trabajan como E/S digitales bidireccionales por igual. Es adecuado para interfaces ordinarias como el manejo de LEDs, control de LCDs, teclados, lectura de switches, pulsadores, etc.La etiqueta INT en el pin RB0/INT significa que además se puede configurar para recibir interrupciones externas. Solo en ese estado se comporta como entrada Schmitt Trigger. De hecho, los pines RB4, RB5, RB6 y RB7 también pueden responder a interrupciones. Estas interrupciones le permiten al microcontrolador atender inmediatamente a los eventos de cambios de nivel lógico en los puertos sin necesidad de estar monitorizándolos constantemente. Las interrupciones se estudian con profundidad mucho más adelante.El puerto B es el único entre los PIC16F que incluye resistencias de pull up internas. Eso nos ahorrará el tener que ponerlas externamente cuando sean requeridas, aunque lo ideal sería que hubiera pull-ups en todos los puertos, así como que todos los pines fueran Schmitt Trigger.Recordemos (del capítulo 2) que los pines RB6 y RB7 también sirven de interface para la programación del PICmicro. Solo en ese modo estos pines actúan como Schimitt Trigger, aunque tenga poca relevancia para nuestros propósitos.También recordemos (del capítulo 3) que los PIC16F87xA soportan la programación en bajo voltaje. En ese modo su pin RB3 tiene una función muy crucial. Eso explica la inscripción adicional PGM (Modo Programación). La programación en bajo voltaje se habilita/inhabilita vía los Bits de Configuración.

El puerto A

El PIC16F84A tiene un puerto A de 5 pines, desde RA0 hasta RA4. Los cuatro primeros funcionan normalmente como pines de E/S bidireccionales y también soportan niveles TTL. El pin RA4, no obstante, es un tanto especial. Como salida es de drenador abierto y requerirá de una resistencia de pull externa si se usa como tal. Es el único pin que en todo momento tiene buffer Schmitt Trigger, lo que como entrada le da una mejor performance, y el único pin que puede recibir voltajes hasta de 8.5 V.RA4 puede funcionar adicionalmente como entrada del Timer0 cuando opera en modo Contador. Por eso su etiqueta adicional T0CKI (Timer0 Clock Input). (Descuida, si por el momento no entiendes mucho de estos conceptos, esto no se aprende de la noche a la mañana.)En los PIC16F87xA el puerto A tiene 6 pines. Los cinco primeros son compatibles con los del PIC16F84A. El pin RA5 también es E/S, TTL y bidireccional. Ahora, la gran diferencia en el puerto A de los PIC16F87xA es que está multiplexado para recibir 5 de los 8 canales posibles del conversor ADC (analógico-digital) de estos PICs. Eso es lo que indican las etiquetas ANx que poseen algunos pines. Nota que el pin RA4/T0CKI no está en este grupo.Ahora un punto clave: para confusión de los que migran a los PIC16F87xA el puerto A inicia con una configuración analógica. Si se quiere usarlo para interface digital será necesario reconfigurarlo en el registro ADCON1. Más adelante se muestra cómo.

Page 30: CURSO INTERNET Microcontroladores PIC

El puerto C

Muchos (casi todos) los módulos o periféricos nuevos de los PIC16F87xA tienen salida al exterior mediante los pines de este puerto. Aquí están los pines de recepción RX y transmisión TX del puerto serie del USART; aquí están los pines de datos SDA y reloj SCL del módulo MSSP cuando funciona en modo I2C; aquí están las salidas de los dos canales de PWM CCP1 y CCP2 de los módulos del mismo nombre cuando generan ondas PWM; aquí están las entradas del Timer1 T1OSO/T1CKI y T1OSI cuando opera en modo Contador.Creo que no tiene caso seguir con la descripción porque sería casi interminable y porque nos familiarizaremos con muchos de estos pines cuando estudiemos los módulos a los que están relacionados. Por lo demás, los pines del puerto C no necesitan de configuración previa alguna para trabajar como E/S bidireccionales, compatibles con TTL.

El puerto D

Está conformado por los 8 pines RD0...RD7. Junto con el puerto E solo están presentes en los PIC16F de 40 pines y tienen la característica destacable (y quizá superflua) de ser la interface del módulo PSP o Puerto paralelo esclavo. Pero como ese módulo casi ni se usa, el puerto D podría tranquilamente reemplazar o ayudar al puerto B en las interfaces con los dispositivos fotoelectrónicos, electromecánicos, etc., dado que es también es bidireccional, configurable pin por pin y maneja señales TTL.

El puerto E

Solo tiene 3 pines RE0...RE2, que se pueden usar como analógicos o digitales. Como pines digitales son bidireccionales y también pueden funcionar como señales de control RD, WR y CS del módulo PSP.Como pines analógicos, dan ingreso a 3 de los 8 canales posibles del conversor ADC. Al igual que el puerto A, el puerto E también inicia con sus pines como entradas analógicas y habrá que configurarlos del mismo modo para que trabajen como pines de E/S digital, si así se desea.

Configuración de los puertos

Después de un reset todos los puertos inician con sus pines configurados como entradas, pero se pueden reconfigurar en cualquier punto del programa mediante los registros TRISx. Cada puerto tiene su correspondiente registro TRIS, así por ejemplo, TRISA para PORTA, TRISB para PORTB,... y TRISE para PORTE.

Si se escribe un 1 en un bit de TRISx, entonces el pin correspondiente en el puerto x será de entrada y si se le escribe un 0, el pin será de salida. Para recordar este concepto suele ser útil notar la semejanza del 0 con la o (de output) y del 1 con la i (de input).

0 → Output  = salida 1 → Input    = entrada

Por ejemplo, si escribimos el valor 00001111 en TRISB, entonces los cuatro pines de menor peso del puerto B serán entradas digitales y los cuatro pines superiores serán salidas.

Si escribimos 00000001 en TRISA, únicamente el pin RA0 será entrada y los demás serán salidas. Como el puerto A no tiene los 8 pines completos, los bits de mayor peso de PORTA y TRISA no tienen significado.

Page 31: CURSO INTERNET Microcontroladores PIC

La codificación de lo expuesto sería así:

banksel TRISB ; Cambiar al Banco de los registros TRIS movlw b'00001111' ; Mover literal 00001111 a W movwf TRISB ; Mover W a TRISB movlw b'00000001' ; Mover literal 00000001 a W movwf TRISA ; Mover W a TRISA

Otra forma de configurar los puertos es pin por pin, utilizando las instrucciones bsf (bit set file = setear bit en registro) y bcf (bit clear file = limpiar bit en registro). Por ejemplo.

banksel TRISB ; Cambiar al Banco de los registros TRIS bsf TRISB, 2 ; Setear bit 2 de TRISB bcf TRISA, 5 ; Limpiar bit 5 de TRISA

Así hemos configurado los pines RB2 para entrada y el pin RA5 para salida. El resto de los bits de los registros TRISA y TRISB conservarán sus valores anteriores.

Finalmente, el siguiente fragmento configura los puertos del PIC empleando una forma de cofidicación alternativa y a veces más ventajosa.

banksel TRISB ; Cambiar al Banco de los TRIS movlw b'00001111' ; Configurar nibble alto de PORTB como salida movwf PORTB ; y el nibble bajo como entrada bsf PORTA, 4 ; Configurar pin RA4 como entrada

La pregunta es: ¿acaso los puertos no se configuraban en los registros TRISx? Bueno, sucede que los siete primeros bits de los registros PORTx y TRISx son iguales, de modo que una vez cambiado de banco se pueden llamar por igual. Esto es extensible a todos los registros de la RAM, aunque solo resulta práctico al trabajar con los puertos.

Ahora observemos una piedra con la que todos en algún momento hemos tropezado sobre todo al portar nuestros códigos del PIC16F84A a los PIC16F87xA. Se trata de los puertos A y E. Estos puertos además de entradas inician configurados como pines analógicos (entradas del ADC). El código del programa parece tan lógico pero el PIC no funcionaba bien porque el puerto A no era digital.

Es posible establecer varias combinaciones seleccionando los pines que serán digitales y los que serán analógicos. Por ejemplo, si se quiere que todos los pines sean digitales, hay que escribir el siguiente código en ensamblador.

Banksel ADCON1 ; Cambiar al banco de ADCON1 movlw 0x06 ; Mover 0x06 a W movwf ADCON1 ; Mover W a ADCON1

O en lenguaje C: ADCON1 = 0x06; // Poner 0x06 en ADCON1

Los códigos mostrados cargan el registro ADCON1 con el valor 0x06. ADCON1 es uno de los registros que controlan el conversor ADC. Este módulo lo estudiaremos tendidamente en su momento. Por ahora nos bastará con saber que si escribimos 6 ó 7 en él, todos los pines de los puertos A y E tendrán comportamiento digital de E/S.

Page 32: CURSO INTERNET Microcontroladores PIC

Las resistencias de Pull-up

Las pull-ups solo están disponibles en los pines del puerto B. Las pull-ups se podrían equiparar con resistencias de 20 K, a calcular por la corriente que dejan fluir.

Las 8 pull ups se pueden habilitar al mismo tiempo limpiando el bit NOT_RBPU, del registro OPTION_REG. Las pull ups solo serán efectivas en los pines que actúan como entradas; en los pines RBx configurados como salidas las pull ups quedan automáticamente inhabilitadas.

La siguiente figura muestra la conexión de un pulsador al PIC aprovechando la pull-up del pin RB7. Fíjate en que las pull-ups no se pueden usar como resistencias para excitar dispositivos como LEDs, relés, etc.

Ejemplo de uso de las resistencias de pull-up.

Los siguientes códigos habilitan todas las pull-ups del puerto B, aunque solo se activarán en los pines configurados como entradas.

banksel OPTION_REG ; Cambiar al banco de OPTION_REG bcf OPTION_REG, NOT_RBPU ; Habilitar pull-ups de PORTB

O en lenguaje C

OPTION_REG.NOT_RBPU = 0; // Habilitar pull-ups de PORTB

Práctica 4-1El ineludible LED parpadeante. Es el programa por el que todo aficionado o profesional ha pasado alguna vez en su vida. La tarea consiste en prender un LED, hacer una pausa, apagar el LED, hacer otra pausa y repetir todo de nuevo, una y otra vez, indefinidamente.

Circuito de la práctica.

Page 33: CURSO INTERNET Microcontroladores PIC

Código fuente del programa

Quizá el programa éste, que solo enciende un LED, sea una trivialidad, pero no te confíes. Los µCs no entienden nuestro lenguaje humano y hay que aprender a hablarles en el suyo. Eso, como cualquier idioma nuevo, nos tomará un poquito de tiempo. Así que no te vayas a echar para atrás cuando veas el programa ni cuando leas la enorme explicación del mismo.

;****************************************************************************; FileName: BlinkLed.asm;**************************************************************************** list p = PIC16F84A ; Seleccionar procesador #include "P16F84A.inc" ; incluir archivo P16F84A.inc __config _PWRTE_ON & _WDT_OFF & _XT_OSC & _CP_OFF cont1 equ 0x0C ; Ubicar cont1 en dirección 0x0C cont2 equ 0x0D ; Ubicar cont2 en dirección 0x0D

org 0x00 ; Código ejecutable empieza aquíStart ; Iniciar bsf STATUS, RP0 ; RP0 = 1. Cambiar al Banco 1 bcf TRISB, 0 ; Configurar pin RB0 como salida bcf STATUS, RP0 ; RP0 = 0. Cambiar al Banco 0MLoop ; Bucle principal bsf PORTB, 0 ; Prender el led call pausa ; Llamar pausa bcf PORTB, 0 ; Apagar el led call pausa ; Llamar pausa goto MLoop ; Saltar a MLoop

;****************************************************************************; Subrutina pausa. Genera 325 milisegundos aprox.

Page 34: CURSO INTERNET Microcontroladores PIC

pausa movlw d'100' ; Mover 100 a W movwf cont1 ; Mover W a cont1 (cargar cont1) movlw d'255' ; Mover 255 a W movwf cont2 ; Mover W a cont2 (cargar cont2)loop1 decfsz cont1, f ; decrementar cont1, saltear si da 0 goto loop2 ; saltar a loop2 decfsz cont2, f ; decrementar cont2, saltear si da 0loop2 goto loop1 ; saltar a loop1 return ; retornar de subrutina

end ; Fin del código

Descripción del programa

Antes de nada, asumiré que jamás en tu vida viste un programa como éste. Así que lo explicaré como para un bebé.

El programa se compone básicamente por directivas, instrucciones y comentarios. Las directivas le dan alguna orden al ensamblador para realizar su trabajo. En este código aparecen en color azul. Las instrucciones son el verdadero código ejecutable y sus nombres aquí se muestran en marrón. Un comentario es el texto decorativo que sigue a un punto y coma (;) y aparece de color verde. El siguiente capítulo describe mejor estos conceptos.

La primera línea significativa es una directiva que le dice al ensamblador que estamos haciendo un programa para el PIC16F84A.

list p = PIC16F84A ; Seleccionar procesador

La siguiente línea es una directiva para decirle al ensamblador que incluya el archivo de dispositivo P16F84A.inc como parte del código. Allí se encuentran los nombres de los registros, de los fuses de configuración, etc., del PIC usado. El ensamblador sabe dónde buscarlo.

#include <P16F84A.inc> ; incluir archivo P16F84A.inc

Lo que sigue es la directiva para poner los Fuses de Configuración. Ya los conocimos en el capítulo anterior, así que no diré mucho. Solo nota que no era necesario añadir el _CP_OFF porque es la opción por defecto de ese fuse.

__config _PWRTE_ON & _WDT_OFF & _XT_OSC & _CP_OFF

Luego tenemos dos directivas más. Sirven para nombrar con cont1 y cont2 a los registros GPR de las direcciones 0x0C y 0x0D. Se usan esas direcciones porque son los primeros registros GPR del PIC16F84A. Pueden ser otros, siempre que estén en el área de los GPR.

cont1 equ 0x0C ; Ubicar cont1 en dirección 0x0C cont2 equ 0x0D ; Ubicar cont2 en dirección 0x0D

La siguiente línea es una directiva para indicarle al ensamblador a partir de qué dirección empezará a mapear el código ejecutable que sigue. Como el CPU empieza a ejecutar el código desde la dirección 0x00, la primera instrucción debería estar allí.Ahora viene el código ejecutable en sí. Es una instrucción que significa setear el bit RP0 del registro STATUS. Con esto basta para pasar al banco 1 del PIC16F84A. Querremos acceder a los registros TRISA y TRISB.

org 0x00 ; Código ejecutable empieza aquí

Page 35: CURSO INTERNET Microcontroladores PIC

Ahora viene el código ejecutable en sí. Es una instrucción que significa setear el bit RP0 del registro STATUS. Con esto basta para pasar al banco 1 del PIC16F84A. Querremos acceder a los registros TRISA y TRISB.

bsf STATUS, RP0 ; RP0 = 1. Cambiar al Banco 1

En la siguiente línea tenemos la instrucción para Limpiar el bit 0 del registro TRISB.bcf TRISB, 0 ; Configurar pin RB0 como salida

A continuación está la instrucción para Limpiar el bit RP0 de STATUS. Regresamos al banco 0, para acceder a PORTB.

bcf STATUS, RP0 ; RP0 = 0. Cambiar al Banco 0

En el siguiente código MLoop es una etiqueta. Con bsf PORTB, 0 seteamos el bit 0 de PORTB, que es el registro que representa al puerto B. Así que nuestro LED conectado al pin RB0 se prenderá.

MLoop ; Bucle principal bsf PORTB, 0 ; Prender el led call pausa ; Llamar pausa

Apenas han pasado 4 microsegundos desde la primera instrucción. No deberíamos apagar el LED ahora, tan pronto. Necesitamos un tiempo. La llamada a pausa es una instrucción con la que el programa saltará a la etiqueta pausa. Luego ejecutará todo el código que se encuentre en este bloque hasta llegar a la instrucción return.

;****************************************************************************; Subrutina pausa. Genera 325 milisegundos aprox.pausa movlw d'100' ; Mover 100 a W movwf cont1 ; Mover W a cont1 (cargar cont1) movlw d'255' ; Mover 255 a W movwf cont2 ; Mover W a cont2 (cargar cont2)loop1 decfsz cont1, f ; decrementar cont1, saltear si da 0 goto loop2 ; saltar a loop2 decfsz cont2, f ; decrementar cont2, saltear si da 0loop2 goto loop1 ; saltar a loop1 return ; retornar de subrutina

No creas que voy a explicar el flujo de esta subrutina ahora porque está más enredada que una pelea de pulpos. Puedes ver que hay saltos para adelante, para atrás, luego otra vez para adelante y así... El hecho es que todo esto le tomará al PIC cerca de 0.3 segundos. Los delays se ven con detenimiento en el siguiente capítulo. Tras ejecutar return el programa retornará al punto desde donde se hizo la llamada y continuará con la siguiente instrucción, que es

bcf PORTB, 0 ; Apagar el led

Eso es Limpiar el bit 0 de PORTB, para apagar el LED.Luego llamamos nuevamente a la rutina pausa para mantener el LED apagado durante otros 0.3 segundos.

call pausa ; Llamar pausa

En seguida se ejecutará la instrucción goto para que el programa salte a la parte del código marcada con la etiqueta MLoop. Así se volverá a ejecutar todo el código descrito y tendremos un LED que se prende y apaga constantemente hasta que le quitemos la alimentación al circuito.

Page 36: CURSO INTERNET Microcontroladores PIC

goto MLoop ; Saltar a MLoop

Al final de todo el código tenemos la última directiva que se debe poner en un programa. end es una directiva del ensamblador para decirle que nuestro código termina aquí y que ya no busque más líneas que ensamblar.

end ; Fin del código

¡Vaya! Ni yo imaginé que la explicación de un programa tan pequeño se fuera a extender tanto. Puede parecer laborioso, pero los comienzos siempre son así; ya verás que todos los programas son muy parecidos y requieren que cada vez menos explicación.

Práctica 4-2

Antes de que empieces a creer que programar PICs es una tarea formidable por la enorme explicación del anterior programa, haremos otro programa para ver que todos son muy similares entre sí.

Se trata de un secuenciador de 8 canales. Hay 8 LEDS conectados al puerto B. Solo tiene un efecto que consiste en un par de LEDS que se desplazan desde el centro hacia los costados.

Circuito de la práctica

Código fuente del programa

;****************************************************************************; FileName: SimpleSeq.asm ; Processor: PIC16F84A

Page 37: CURSO INTERNET Microcontroladores PIC

; Purpose: Uso de Puertos - salidas;****************************************************************************

list p = PIC16F84A ; Seleccionar procesador #include <P16F84A.inc> ; incluir archivo P16F84A.inc __config _PWRTE_ON & _WDT_OFF & _XT_OSC cont1 equ 0x0C ; Ubicar cont1 en dirección 0x0C cont2 equ 0x0D ; Ubicar cont2 en dirección 0x0D

org 0x00 ; Vector de ResetStart ; Iniciar bsf STATUS, RP0 ; RP0 = 1. Cambiar al Banco 1 clrf TRISB ; TRISB = 0x00. Configurar todo PORTB como salida bcf STATUS, RP0 ; RP0 = 0. Cambiar al Banco 0MLoop movlw b'00000000' ; 00000000 a W movwf PORTB ; W a PORTB call pausa ; Llamar pausa de 250 ms movlw b'00011000' ; 00011000 a W movwf PORTB ; W a PORTB call pausa ; ... movlw b'00100100' movwf PORTB call pausa movlw b'01000010' movwf PORTB call pausa movlw b'10000001' movwf PORTB call pausa

goto MLoop ; Saltar a MLoop

;****************************************************************************; Subrutina pausa. Genera 250 milisegundos.pausa movlw d'79' ; Mover 79 a W movwf cont1 ; Mover W a cont1 (cargar cont1) movlw d'196' ; Mover 196 a W movwf cont2 ; Mover W a cont2 (cargar cont2) loop1 decfsz cont1, f ; decrementar cont1, saltear si da 0 goto loop2 ; saltar a loop2 decfsz cont2, f ; decrementar cont2, saltear si da 0loop2 goto loop1 ; saltar a loop1 return ; retornar de subrutina

end ; Fin del código

Descripción del programa

Como puedes notar, hay muchas cosas del programa anterior que también se repiten aquí, así que solo explicaré las novedades. Cómo funciona el programa es tan simple como verlo. Cada 250 ms se envía al puerto B un dato que representa un ítem del secuencial.

Page 38: CURSO INTERNET Microcontroladores PIC

El prefijo 0x representa un número en formato hexadecimal, los números entre comillas simples y precedidos por una b o d indican formatos binario o decimal, respectivamente.

La instrucción clrf (Clear File), que limpia todo un registro, es más directa para configurar todo el puerto B como salida.

clrf TRISB ; TRISB = 0x00. Configurar todo PORTB como salida

La subrutina pausa es esencialmente la misma del programa anterior. Utiliza las variables cont1 y cont2 para decrementar sus valores. La subrutina termina cuando ambos registros lleguen a 0. En este programa cont2 inicia en el 196. El valor unicial de cont1 es menos significativo.

;****************************************************************************; Subrutina pausa. Genera 250 milisegundos.pausa movlw d'79' ; Mover 79 a W movwf cont1 ; Mover W a cont1 (cargar cont1) movlw d'196' ; Mover 196 a W movwf cont2 ; Mover W a cont2 (cargar cont2) loop1 decfsz cont1, f ; decrementar cont1, saltear si da 0 goto loop2 ; saltar a loop2 decfsz cont2, f ; decrementar cont2, saltear si da 0loop2 goto loop1 ; saltar a loop1 return ; retornar de subrutina

Práctica 4-3

Luego de haber trabajado manipulando los puertos del PIC para salidas, veremos que las entradas se manejan casi igual.

Según este programa, cada vez que se presione un botón (pulsador) conectado al pin RA4 el LED conectado al pin RB0 permutará, es decir, si estaba apagado, quedará prendido y si estaba encendido quedará apagado.

Circuito de la práctica

El circuito de entrada al pin RA4 constituye un filtro pasa-bajas. Servirá para filtrar los cortísimos pulsos irregulares que se pueden producir al oprimir el pulsador, conocidos como rebotes. Este filtro funciona mejor al combinarse con la etapa Schmitt Trigger del pin RA4.

Tambien se pueden implementar simples filtros software para evadir los rebotes.

Page 39: CURSO INTERNET Microcontroladores PIC

El código fuente

;****************************************************************************; FileName: TogLed.asm ; Processor: PIC16F84A; Purpose: Uso de Puertos - entradas;****************************************************************************

list p = PIC16F84A ; Seleccionar el procesador #include <P16F84A.inc> ; Incluir archivo P16F84A.inc __config _PWRTE_ON & _WDT_OFF & _XT_OSC org 0x0000 ; Vector de ResetStart bsf STATUS, RP0 ; Cambiar al Banco 1 bcf PORTB, 0 ; Establecer pin RB0 como salida bsf PORTA, 4 ; Establecer pin RA4 como entrada bcf STATUS, RP0 ; Regresar al Banco 0MLoop ; Bucle principalEsperar_Pulsado btfsc PORTA, 4 ; ¿RA4 = 0? ¿Botón Pulsado? goto Esperar_Pulsado ; No. Saltar a Esperar_Pulsado

Page 40: CURSO INTERNET Microcontroladores PIC

PermutarLed ; Sí movlw b'00000001' ; Mover literal 00000001 a W xorwf PORTB, F ; XOR entre W y PORTB. Resultado a FEsperar_Libre btfss PORTA, 4 ; ¿RA4 = 1? ¿Botón liberado? goto Esperar_Libre ; No. Saltar a Esperar_Libre goto MLoop ; Sí. Saltar a MLoop

end ; Final del código válido

Descripción del programa

Las cuatro primeras instrucciones hacen lo que indican los comentarios. Recuerda que una vez en al banco 1 también podemos referirnos a los registros TRISA y TRISB con los nombres PORTA y PORTB.

bsf STATUS, RP0 ; Cambiar al Banco 1 bcf PORTB, 0 ; Establecer pin RB0 como salida bsf PORTA, 4 ; Establecer pin RA4 como entrada bcf STATUS, RP0 ; Regresar al Banco 0

El mnemónico btfsc significa “Bit Test File and Skip if Clear”, o sea, Testear el bit 4 de PORTA y saltearse la siguiente instrucción si vale 0. RA4 es donde está nuestro pulsador y cuando no está presionado la lectura de RA4 será 1, es decir, se ejecutará goto Esperar_Pulsado, con lo que el programa quedaría dando vueltas en este bucle, esperando hasta leer un 0.

MLoop ; Bucle principal Esperar_Pulsado btfsc PORTA, 4 ; ¿RA4 = 0? ¿Botón Pulsado? goto Esperar_Pulsado ; No. Saltar a Esperar_Pulsado PermutarLed ; Sí

Ahora, una vez oprimido el botón, RA4 se leerá como 0, el programa saltará y por encima de goto Esperar_Pulsado y ejecutará el código que sigue a PermutarLed.

PermutarLed ; Sí movlw b'00000001' ; Mover literal 00000001 a W xorwf PORTB, F ; XOR entre W y PORTB. Resultado a F

Hay varias formas de permutar el estado de un bit. Particularmente, prefiero emplear la operación XOR. Recuerda que un XOR de un 1 con un bit lo invierte y un XOR de un 0 con un bit lo deja como estaba. Como ves, las dos instrucciones mostradas solo invertirán el bit 0 de PORTB, donde está nuestro LED. Por si acaso, la etiqueta PermutarLed está de adorno, solo es referencia para nosotros, no para el ensamblador.

Por último, tenemos

Esperar_Libre btfss PORTA, 4 ; ¿RA4 = 1? ¿Botón liberado? goto Esperar_Libre ; No. Saltar a Esperar_Libre goto MLoop ; Sí. Saltar a MLoop

Con las dos primeras instrucciones hacemos que el programa se quede dando vueltas aquí hasta que el pulsador sea liberado.

Page 41: CURSO INTERNET Microcontroladores PIC

btfss es el par de btfsc y significa “Bit Test File and Skip if Set”, es decir, Testear el bit indicado del registro indicado y saltearse la siguiente instrucción si vale 1. Mientras el pulsador esté presionado, RA4 se leerá como 0 y se ejecutará goto Esperar_Libre, o sea, el programa se quedará dando vueltas en este bucle esperando a que se lea un 1.

Aunque se oprima el botón instantáneamente, puedes estar seguro de que el programa dara miles y miles de vueltas en este bucle.

Una vez liberado el pulsador, el programa pasará a goto MLoop. Con esto el programa saltará a la etiqueta MLoop y se quedará en el primer bucle esperando a que se vuelta a presionar el botón.

Práctica 8-5  El Display 7 segmentos

Este programa es una adaptación del dado electrónico de David Hobday incluido en los ejemplos de su compilador BoostC http://www.SourceBoost.com. Yo lo traduje al lenguaje ensamblador y cambié los LEDs comunes por el display 7-seg.Funciona así: al presionar el botón de la jugada se muestra un tenue 6, mientras se va generando un número aleatorio basado en la duración del pulso. Después, al liberarse el botón, se comienza a mostrar pausadamente el valor incrementado de la jugada, hasta que se detiene en un valor fijo. Para marcar este hecho se encenderá un led que bien podría ser el dp del display 7-seg. Se debe incluir una pausa antirrebote para evitar múltiples jugadas con una sola pulsada.

 

El circuito

Page 42: CURSO INTERNET Microcontroladores PIC

El display 7 segmentos que vamos a emplear en esta práctica es de cátodo común. Cada LED del display está identificado por una letra entre a y g, tal como se ve en la siguiente figura.

El diagrama de flujo

Page 43: CURSO INTERNET Microcontroladores PIC

 

El código fuente

Page 44: CURSO INTERNET Microcontroladores PIC

;****************************************************************************; FileName: EDice.asm; Processor: PIC16F84A; Purpose: Display 7-segmentos (Dado electrónico);****************************************************************************

processor PIC16F84A include <P16F84A.inc> __config _XT_OSC & _WDT_OFF & _PWRTE_ON

cblock 0x0C DiceVal ; Valor actual del dado i ; Un contador endc

#define Button PORTA, 4 ; puerto del botón

org 0x000 ; Vector de ResetStart: banksel TRISA ; Bank 1 clrf PORTB ; Todo PORTB, salida bsf Button ; Pin de botón, entrada banksel PORTA ; Bank 0

DisplayOff: clrf PORTB ; Apagar DisplayWaitPressed: btfsc Button ; Esperar botón pulsado goto $ - 1 movlw d'3' call delay_x10ms ; Pausa antirrebote de 30 ms btfsc Button ; ¿Aún pulsado? goto DisplayOff ; No, tal vez fue un rebote ; SíWaitReleased: ; Esperar botón libre ; Contar dado mientras el botón está pulsado ; Genera número pseudo-aleatorio call DiceCount ; Llamar DiceCount btfss Button ; ¿Aún pulsado? goto WaitReleased ; Sí clrf i ; Inicializar control de pausaStopping: ; Detener poco a poco incf i, F ; Incrementar tiempo de pausa movf i, W ; W = i call delay_x10ms ; Pausas variables call DiceCount movf i, W ; W = i sublw d'30' ; W = 100 - W btfsc STATUS, C ; ¿C = 1?, ¿i<=30? goto Stopping ; Sí bsf PORTB, 7 ; No. Valor definitivo. Prender LED indicador goto WaitPressed ; A jugar otra vez

;****************************************************************************; Subroutine: DiceCount; Purpose: Incrementa y muestra el valor de DiceVal;****************************************************************************DiceCount: incf DiceVal, f ; Incrementar valor movf DiceVal, W ; W = DiceVal sublw d'6' ; W = 6 - W

Page 45: CURSO INTERNET Microcontroladores PIC

btfsc STATUS, C ; ¿C = 0?, ¿DiceVal > 6? goto Display ; No movlw d'1' ; Sí... movwf DiceVal ; DiceVal = 1Display: ; Mostrar en el display 7 segmentos del dado movf DiceVal, W ; W = DiceVal call BinTo7Seg ; Convertir a 7 segmentos movwf PORTB ; Mostrarlo en el display return

;****************************************************************************; Subroutine: BinTo7Seg; Purpose: Convierte un número a formato 7 segmentos; Input: W = Número a convertir; Output: W = Número en formato 7 segmentos "xgfedcba", x=don't care;****************************************************************************BinTo7Seg addwf PCL, F retlw b'00111111' ; 7-segment code of 0 retlw b'00000110' ; 7-segment code of 1 retlw b'01011011' ; 7-segment code of 2 retlw b'01001111' ; 7-segment code of 3 retlw b'01100110' ; 7-segment code of 4 retlw b'01101101' ; 7-segment code of 5 retlw b'01111101' ; 7-segment code of 6

;****************************************************************************; Subroutine: delay_x10ms; Purpose: Genera decenas milisegundos según el valor de entrada; Input: W = decenas de ms a producir;**************************************************************************** cblock del0, del1, del2 endc

delay_x10ms

movwf del2 ; del2 = Wldel movlw d'8' movwf del1 movlw d'207' movwf del0 decfsz del0, f goto $ + 2 decfsz del1, f goto $ - 3 decfsz del2, F goto ldel return end

Page 46: CURSO INTERNET Microcontroladores PIC

Descripción del programa

La subrutina BinTo7Seg es una tabla que contiene los códigos 7-seg de los números del 1 al 6. De acuerdo con el circuito, el display está conectado a los 7 primeros pines de PORTB del PIC (a con 0, b con 1... y g con 6). Ya que el bit 7 quedaba libre, decidí dejarlo en cero para utilizarlo luego como el LED que señaliza el fin de la jugada.Se llama tabla de búsqueda a un conjunto de datos grabados en locaciones contiguas de la memoria de programa del microcontrolador. Las tablas en los PICmicros se confeccionan mediante la instrucciónretlw y se accede a sus elementos llamándolas como si fueran subrutinas.

;****************************************************************************; Subroutine: BinTo7Seg; Purpose: Convierte un número a formato 7 segmentos; Input: W = Número a convertir; Output: W = Número en formato 7 segmentos "xgfedcba", x=don't care;****************************************************************************BinTo7Seg addwf PCL, F retlw b'00111111' ; 7-segment code of 0 retlw b'00000110' ; 7-segment code of 1 retlw b'01011011' ; 7-segment code of 2 retlw b'01001111' ; 7-segment code of 3 retlw b'01100110' ; 7-segment code of 4 retlw b'01101101' ; 7-segment code of 5 retlw b'01111101' ; 7-segment code of 6

Retlw (RETurn with Literal in W) es una instrucción de retorno similar a return, con la diferencia de que al regresar de la subrutina cargará en W el valor de la constante que tiene al lado. Si te estás preguntando porque tantas instrucciones retlw, es porque cada vez que llamemos a esta subrutina se ejecuta una y solo una de ellas. ¿Cómo así?El curso de ejecución del programa se rige por el contador de programa PC. El PC está representado por dos registros especiales: PCL (Program Counter Low), que contiene los 8 bits de menor peso del PC y PCLATH (Program Counter Latch High), que representa los 5 bits de mayor peso. Así que podemos provocar desvíos y saltos a diversos puntos del código alterando el valor de estos registros.En el caso más sencillo solo será necesario emplear el registro PCL para diseñar tablas de hasta 256 elementos. Como la instrucción addwf  PCL, F suma el valor de W al PC, el programa saltará tantas posiciones como valga de W. Por ejemplo, si llamamos a la subrutina BinTo7Seg de arriba habiendo cargado 2 en W, con la ejecución de addwf  PCL, F se dará un salto a retlw b'01011011' y se retornará con b'01011011' en W. Por si acaso hubiera alguna duda, te sugiero apreciar esta operación en un simulador, como MPLAB SIM o Proteus.

Instalación del MPLAB IDE

Page 47: CURSO INTERNET Microcontroladores PIC

Puedes descargar el MPLAB libremente desdehttp://www.microchip.com. Pesa algo más de 100 MB.Bien, una vez descargado, se instalar como cualquier programa de Windows.

En esta ventana eliges instalación completa o personalizada. Aparte del espacio en el disco duro e idea de que no te perderás de nada si escoges Complete, debes saber que al final de ese camino nos pedirán confirmar la instalación del Compilador Hitech-PICC. Es un programa independiente de htsoftque se instala desde Internet, si tienes conexión. No afectará en nada al MPLAB si rechazas dicha confirmación. De todos modos, si en algún futuro te interesara, podrías instalarlo por separado.

En cambio, si eliges Custom (Personalizada), tendrás la oportunidad de seleccionar solo las utilidades de MPLAB que vayas a utilizar. Allí verás que la invocación a Hi-tech PICC está desmarcada. De hecho, con la configuración presentada suele ser suficiente.

Cualquiera que sea tu decisión, clicas Next, next... y te pones a esperar a que termine la instalación.

Page 48: CURSO INTERNET Microcontroladores PIC

Creación y construcción del proyecto

Aquí aprenderemos a crear un proyecto, editar los códigos fuente y construir el proyecto. Se entiende por construir (build) a un conjunto de procesos, como el linkado y ensamblado, que nos darán los archivos finales para grabar el PIC (*.hex), depurar el programa (*.cof), entre otros. Aunque se vea raro, es más simple de lo que parece.

Basaremos el proyecto en el programa de la práctica 4-2 de este módulo; de modo que no haya nada que explicar al respecto. Con todo, solo para no perder la perspectiva, aquí tenemos de nuevo el circuito y el código fuente:

;****************************************************************************; Program: SimpleSeq.asm;**************************************************************************** list p = PIC16F84A ; Seleccionar procesador #include <P16F84A.inc> ; incluir archivo P16F84A.inc __config _PWRTE_ON & _WDT_OFF & _XT_OSC & _CP_OFF cont1 equ 0x0C ; Ubicar cont1 en dirección 0x0C cont2 equ 0x0D ; Ubicar cont2 en dirección 0x0D

org 0x00 ; Vector de ResetStart ; Iniciar bsf STATUS, RP0 ; RP0 = 1. Cambiar al Banco 1 clrf TRISB ; TRISB = 0x00. Configurar todo PORTB como salida bcf STATUS, RP0 ; RP0 = 0. Cambiar al Banco 0MLoop movlw b'00000000' ; 00000000 a W movwf PORTB ; W a PORTB call Pausa ; Llamar pausa de 250 ms movlw b'00011000' ; 00011000 a W movwf PORTB ; W a PORTB call Pausa ; ... movlw b'00100100' movwf PORTB call Pausa movlw b'01000010' movwf PORTB

Page 49: CURSO INTERNET Microcontroladores PIC

call Pausa movlw b'10000001' movwf PORTB call Pausa

goto MLoop ; Saltar a MLoop

;****************************************************************************; Subrutina pausa. Genera 250 milisegundos.Pausa movlw d'79' ; Mover 79 a W movwf cont1 ; Mover W a cont1 (cargar cont1) movlw d'196' ; Mover 196 a W movwf cont2 ; Mover W a cont2 (cargar cont2) loop1 decfsz cont1, f ; decrementar cont1, saltear si da 0 goto loop2 ; saltar a loop2 decfsz cont2, f ; decrementar cont2, saltear si da 0loop2 goto loop1 ; saltar a loop1 return ; retornar de subrutina

end ; Fin del código

La forma más sencilla de crear un proyecto es con ayuda del Wizard. El procedimiento es el siguiente:

Ejecutar el MPLAB. Al inicio debemos tener una pantalla como la mostrada abajo. El MPLAB puede administrar más de un proyecto a la vez y para no confundirnos sería recomendable trabajar con uno solo. Por eso en caso de que hubiera otro proyecto presente lo tendríamos que cerrar yendo a Project > Close > ...

Empezamos a crear un nuevo proyecto yendo al menú Project > Project Wizard . Tendremos esta ventana de bienvenida.

Page 50: CURSO INTERNET Microcontroladores PIC

Luego seleccionamos el PICmicro (PIC16F84A en nuestro caso), clicamos Siguiente y seguimos...

Archivos generados por el MPLAB

Page 51: CURSO INTERNET Microcontroladores PIC

De la configuración por defecto los principales archivos creados por el MPLAB son:

*.mcp, de microchip mplab project. Es un archivo de texto que contiene información sobre los archivos que conforman el proyecto. Sobra decir que para editar un proyecto es aconsejable empezar por abrir este achivo.

*.mcw, de microchip mplab workspace. Este archivo almacena datos del espacio de trabajo, como la posición de las ventanas o los datos transitorios generados durante la simulación del proyecto, tema que veremos luego.

*.lst, de listing. Es un archivo de texto que reúne los códigos fuente de todos los archivos de programa y además muestra las instrucciones junto con sus respectivos códigos de operación y sus direcciones en la memoria de programa. También nos informa sobre los recursos utilizados del PICmicro, como la cantidad de memoria utilizada por el programa. Convendrá revisarlo de vez en cuando.

*.err, de error. Lista los errores, los mensajes y las advertencias del proyecto, como lo presentado en la ventana Output tras la construcción de un proyecto. A propósito, ¿recuerdas la directiva errorlevel?

*.hex, de hexadecimal. Qué puedo decir!, es el archivo requerido para grabar el PIC. *.cof, de code object file format. Es generarado para fines de simulación o depuración software

del programa. Nos será muy útil cuando trabajemos con programas como Proteus VSM.

PWM

Introducción

No voy a mencionar la utilidad que tienen las señales con Modulación por Ancho de Pulso PWM en el control de dispositivos como los motores DC. Realizar un PWM software es una labor que consume demasiados ciclos de CPU y no siempre se alcanza la frecuencia deseada. Podemos sentirnos aliviados al saber que los PICmicros tienen incorporados los módulos CCP1 y CCP2. Cada uno de estos periféricos puede trabajar en tres modos:

Modo de CompaComparaciónción Modo de Captura Modo PWM

En lo referente a los modos Captura o Comparación algunas típicas aplicaciones son la generación de un pulso de ancho programado o medida del ancho de un pulso externo. En ambos casos los módulos CCP1 y CCP2 trabajan con el Timer1. Nuestro interés por ahora es el estudio del modo PWM.

El modo PWM tiene una operación y un control que son compatibles en todos los PIC16 con módulos CCPx y se conoce como Standard PWM. Los PWM en los PIC18 son más potentes y variados, destacando el llamado Enhanced PWM. Con todo, en muchos casos todavía cuentan con el Standard y en otros, un modo compatible con él.

Cada módulo CCPx puede generar una onda PWM de hasta 10 bits de resolución con una frecuencia y duty cycle configurables. Ambas ondas son semi independientes, esto es, pueden tener diferente duty cycle pero comparten la misma frecuencia. Cada CCPx se puede habilitar o inhabilitar

Page 52: CURSO INTERNET Microcontroladores PIC

independientemente. La salida PWM del módulo CCP1 es el pin RC2/CCP1 y del módulo CCP2 es el pin RC1/CCP2. Dichos pines deben ser configurados como salidas.

 

Registros de los módulos CCPx

Los registros de duty cycle presentados en seguida tienen diferente función en los modos Captura o Comparación. El Timer2 se alía con los módulos CCPx solo en modo PWM.

CCP1CON y CCP2CON. Registros para la configuración de los módulos CCP1 y CCP2 respectivamente en modo Captura, Comparación o PWM. Son gemelos.

CCPR1L y CCPR2L. Registros para controlar los duty cycle de cada onda PWM. Son gemelos.

CCPR1H y CCPR2H. Funcionan como registros imagen de los dos anteriores. No deben se accedidos directamente.

TMR2, PR2 y T2CON. Son los conocidos registros del Timer2. Sirven para establecer el periodo, o la frecuencia, de los dos canales PWM. El Timer2 no pierde ninguna de sus capacidades que conocemos, o sea que podemos seguir temporizando, utilizando sus interrupciones, etc.

Dado que en modo PWM ambos módulos CCPx son completamente idénticos en control y configuración, estaría de más describir cada módulo por separado o al mismo tiempo. Bastará con discutir la operación de CCP1 y se entenderá que lo mismo es válido para CCP2.

Empecemos entonces: para configurar el módulo CCP1 en modo PWM, podemos escribir 0x0C en el registro CCP1CON. Eso es todo respecto a la configuración. En lo que resta de este capítulo estaremos hablando casi en exclusiva del control del duty cycle de la onda.

Éste es el mapa de bits del registro CCP1CON.

Registro CCP1CON

CCP1CON --- --- CCP1X CCP1Y CCP1M3 CCP1M2 CCP1M1 CCP1M0

CCP1X: CCP1Y:

PWM Least Significant bit

Válidos solo en modo PWM:

Estos son los dos bits menos significativos del Duty Cycle del PWM Los ocho bits más significativos se encuentran en el registro CCPR1L

Page 53: CURSO INTERNET Microcontroladores PIC

CCP1M3: CCP1M0:

CCP1 Mode Select bits

0000 = Modo Captura/Comparación/PWM inhabilitados (resetear módulo CCP1)

0100 = Modo Captura, cada flanco de bajada

0101 = Modo Captura, cada flanco de subida

0110 = Modo Captura, cada 4 flancos de subida

0111 = Modo Captura, cada 16 flancos de subida

1000 = Modo Comparación, setear salida en coincidencia (el bit CCP1IF se setea)

1001 = Modo Comparación, limpiar salida en coincidencia (bit CCP1IF se setea)

1010 = Modo Comparación, generar interrupción software en coincidencia (el bit CCP1IF se setea, el pin de CCP1 no se afecta)

1011 = Modo Comparación, disparar evento especial (el bit CCP1IF se setea, el pin de CCP1 no se afecta); CCP1 resetea TMR1; CCP2 resetea TMR1 e inicia una conversión del ADC (si el ADC está habilitado)

11xx = Modo PWM

Generación de ondas PWM de 8 bits

Los módulos CCPx pueden generar ondas PWM de hasta 10 bits de resolución. En el enfoque seguido en este capítulo se estudia el módulo CCP1 asumiendo primero que genera ondas PWM de 8 bits. Esto se consigue cortando los dos bits menos significativos. Luego se extiende la operación a los 10 bits completos.

Los dos módulos CCPx emplean el Timer2 como contador principal. El Timer2 funciona de la forma que conocemos: su registro TMR2 corre libremente desde 0x00 hasta el valor del registro PR2 y después de la coincidencia se resetea para volver a contar desde 0x00. Ese tiempo cíclico será el período de la onda PWM.

Para establecer el duty cycle se emplea el registro CCPR1L del siguiente modo: cuando TMR2 sea igual a CCPR1L el pin RC2/CCP1 se limpiará y cuando TMR2 alcance el valor de PR2, el pin RC2/CCP1 se seteará en el próximo ciclo. Estas operaciones están graficadas en la siguiente figura:

Generación de ondas PWM del módulo CCP1.

Page 54: CURSO INTERNET Microcontroladores PIC

 Periodo y frecuencia y de la onda PWM

Ya vimos que el periodo de la onda PWM está determinado por el tiempo que dura el conteo del TMR2 desde 0 hasta el valor del registro PR2. Esto es:

Donde:

PR2 = Valor del registro PR2 (entre 0 y 255).

Fosc = Frecuencia del XTAL.

Prescaler = Prescaler del Timer2 (1, 4 ó 16). Se configura en el registro T2CON.

Recordemos que el Timer2 también tiene un Postscaler, pero es una etapa posterior y no interviene directamente en el avance del Timer2.

En la práctica es mucho más habitual hablar de la frecuencia del PWM. Como ésta es la inversa del periodo, de la fórmula anterior surge la siguiente:

Duty cycle de la onda PWM

El duty cycle es la cantidad de tiempo que en un periodo la salida PWM permanece en estado alto. Este tiempo queda determinado por el valor del registro CCPR1L. Mientras TMR2 sea menor que CCPR1L la salida PWM será un 1 lógico. Apenas TMR2 alcance a CCPR1L, la salida será 0. En caso de que este tope sea superior al periodo, la salida ya no conmutará a 0.

En consecuencia, el duty cycle se controla variando el valor del registro CCPR1L. La fórmula que da su valor en tiempo es:

Donde:

CCPR1L = Valor del registro CCPR1L (entre 0 y 255).

Fosc = Frecuencia del XTAL.

Prescaler = Prescaler del Timer2 (1, 4 ó 16).

Page 55: CURSO INTERNET Microcontroladores PIC

También es mucho más ilustrativo hablar del duty cycle en términos de porcentajes. Un 0% significa que la salida es siempre bajo, 100% es un alto continuo, un 50% significa una onda cuadrada simétrica, y así. Para esto solo hay que dividir el duty cycle (en tiempo) entre el periodo y multiplicarlo por 100%. Realizando esta operación con las fórmulas presentadas anteriormente llegaremos a:

Esta fórmula es fácil de interpretar: el numerador CCPR1L representa al duty cycle y el denominador PR2+1, al periodo. La siguiente figura indica que cada periodo se divide en PR2+1 tramos equitativos y que CCPR1L es la cantidad de tramos que están en alto. Eso es una PWM.

Duty cycle de la onda PWM.

Práctica 1 PWM de 8 bits

Se generará una onda PWM de 10 kHz. El Duty cycle se incrementa o decrementa con las teclas + ó – de la consola RS232.

Page 56: CURSO INTERNET Microcontroladores PIC

El circuito

 

El código fuente

////////////////////////////////////////////////////////////////////////////////// File Name: CCP1_PWM.c// Processor: PIC16F87xA// Compiler: BoostC/C++// Author: Shawn Johnson// Purpose: Módulo CCP1 en modo PWM////////////////////////////////////////////////////////////////////////////////

#include <system.h>#include "usart.h"

#pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _PWRTE_ON & _LVP_OFF & _WRT_HALF

#pragma CLOCK_FREQ 4000000

void main(void){ usart_init(); // 9600 - 8N1 puts("\n\r CCP1 en modo PWM"); puts("\n\r Cambie Duty cycle con +/-"); ccp1con = 0x0C; // CCP1 en modo PWM t2con = 0x04; // Prescaler = 1, Timer2 = ON pr2 = 99; // Periodo PWM = 100us => Freq = 10 kHz ccpr1l = 0; // Duty cycle inicial = 0 = 0% trisc.2 = 0; // pin RC2/CCP1 salida de PWM 1 while(1)

Page 57: CURSO INTERNET Microcontroladores PIC

{ if(kbhit()) { char c = getc(); if(c == '+') { if(ccpr1l <= pr2) ccpr1l++; } else if(c == '-') { if(ccpr1l) ccpr1l--; } } }}

Descripción del código

En el programa se genera la onda PWM con el módulo CCP1 pero bien pudo ser con el CCP2 o también se pudo tener dos PWM al mismo tiempo.

Generación de ondas PWM de 10 bits

En esta sección vamos a extender la resolución de nuestro PWM a 10 bits.

Partamos por el hecho de que la frecuencia (y periodo) de esta señal será la misma que se puede conseguir cuando se trabaja con 8 bits. Lo que varía es la finura del ducy cycle. Con 10 bits el duty cycle podrá recorrer todo el periodo dividiéndolo hasta en 210 = 1024 tramos iguales.

Para que el duty cycle sea de 10 bits el registro CCPR1L se acopla con los bits 4 y 5 del registro CCP1CON. Por su parte, para que el Timer2 pueda desplazarse por cada uno de los 1024 tramos tendrá que juntarse con los dos bits de menor peso del oscilador del sistema Fosc.

El PWM de 10 bits no requiere de ninguna configuración adicional. De hecho los módulos CCPx siempre operan así. Es solo que nosotros hemos estado trabajando con los 8 bits más altos.

Donde:

Fosc = Frecuencia del XTAL.

Prescaler = Prescaler del Timer2 (1, 4 ó 16).

CCPR1L:CCPICON<5:4> = Valor del registro CCPR1L concatenado con los bits 5 y 4 del registro CCP1CON (teóricamente entre 0 y 1023).

Page 58: CURSO INTERNET Microcontroladores PIC

Por último, vamos a interpretar la fórmula del duty cycle expresada en porcentaje. Ésta se obtiene dividiendo la fórmula del duty cycle (en tiempo) entre la fórmula de periodo y multiplicándola por 100%. El resultado simplificado sería:

El denominador nos dice que el periodo se dividirá en 4×(PR2+1) intervalos equitativos. PR2 sigue siendo de 8 bits pero el factor 4 nos dice que la resolución se amplía en incrementos de 4 tramos. Así mismo, el numerador sigue indicando la cantidad de intervalos, de los 4×(PR2+1), que estarán en alto.

Práctica 2 PWM de 10 bits

El PICmicro saca una onda PWM de 10 kHz y duty cycle configurable por el teclado de la consola RS232 con resolución de 0.25%.

El circuito

Se puede usar el circuito de la anterior práctica.

 

El código fuente

////////////////////////////////////////////////////////////////////////////////// File Name: pwm10.c// Processor: PIC16F87xA// Compiler: BoostC/C++// Author: Shawn Johnson// Purpose: Módulo CCP1 en modo PWM con resolución de 10 bits////////////////////////////////////////////////////////////////////////////////

Page 59: CURSO INTERNET Microcontroladores PIC

#include <system.h>#include <ctype.h> // Contiene funciones isdigit,...#include <stdlib.h> // Contiene funciones atoi,...#include "usart.h"

#pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _PWRTE_ON & _LVP_OFF & _WRT_HALF

#pragma CLOCK_FREQ 4000000

void SetDuty1(unsigned int duty);void GetStr(char * buffer, unsigned char len);

void main(void){ char buf[10]; unsigned int n; usart_init(); // 9600 - 8N1 ccp1con = 0x0C; // CCP1 en modo PWM t2con = 0x04; // Prescaler = 1, Timer2 = ON pr2 = 99; // Periodo PWM = 100us => Freq = 10 kHz SetDuty1(0); // Duty cycle inicial = 0 = 0% trisc.2 = 0; // pin RC2/CCP1 salida de PWM 1

puts("\n\r PWM 1 - 10 kHz - 10 bits"); puts("\n\r Ingrese Duty cycle [0..400] \n\r"); while(1) { GetStr(buf, 3); // Leer texto de 3 números n = atoui_dec(buf); // Convertir texto numérico en número SetDuty1(n); }}

//****************************************************************************// Pone Duty cycle del PWM del módulo CCP1. Resolución = 10 bits//****************************************************************************void SetDuty1(unsigned int duty){ ccpr1l = duty>>2; ccp1con.5 = duty.1? 1:0; ccp1con.4 = duty.0? 1:0;}

//****************************************************************************// Lee una cadena de texto de 'len' números// El tamaño de 'buffer' debe ser mayor que 'len'.//****************************************************************************void GetStr(char * buffer, unsigned char len){ char c; unsigned char i=0; while(1) { // Bucle incondicional c = getc(); if(isdigit(c)&&(i<len)) // Si c es ... { buffer[i++] = c; // Guardar en buffer putc(c); // Eco }

Page 60: CURSO INTERNET Microcontroladores PIC

else if((c=='\b')&&(i)) // Si c es RETROCESO y si i>0 { i--; // putc(c); // Eco } else if((c=='\r')&&(i)) // Si c es ENTER y si i>0 { buffer[i] = '\0'; // Poner un 0x00 (fin de cadena) putc(c); // Eco break; // Salir del bucle } }}

Descripción del programa

El código no pone restricciones en el ingreso del duty cycle. Eso lo hice a propósito para examinar cómo responde el módulo PWM a valores de duty cycle fuera del rango teóricamente permitido.

Programación en Ensamblador > Estructura de programa

Introducción

Siempre ha sido tema de debate la eleccion del ensamblador o un compilador de alto nivel como lenguaje de programacion. Cada herramienta tiene sus ventajas e inconvenientes. Siempre habra aplicaciones donde no sea necesaria la eficiencia del ensamblador o la flexibilidad de un compilador, asi como aplicaciones que sí demanden de ambas facilidades. Sea como sea, un buen disenador debe estar preparado para emplear el ensamblador como eventual recurso.

Una razon de gran peso que quiero anadir por la que tarde o temprano se debe aprender el ensamblador es que la mayor parte (casi toda) la informacion proporcionada por Microchip en los datasheets, notas de aplicación o manuales de referencia sobre sus PICmicros se incluyen codigos en ensamblador.

Estructrura del programa en ensamblador

Vamos a analizar el primer programa, el que hace parapadear un LED.;****************************************************************************; FileName: BlinkLed.asm; Processor: PIC16F84A;****************************************************************************

list p = PIC16F84A ; Seleccionar procesador #include <P16F84A.inc> ; incluir archivo P16F84A.inc __config _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF cont1 equ 0x0C ; Ubicar cont1 en dirección 0x0C cont2 equ 0x0D ; Ubicar cont2 en dirección 0x0D

org 0x00 ; Código ejecutable empieza aquíStart ; Iniciar bsf STATUS, RP0 ; RP0 = 1. Cambiar al Banco 1 bcf TRISB, 0 ; Configurar pin RB0 como salida

Page 61: CURSO INTERNET Microcontroladores PIC

bcf STATUS, RP0 ; RP0 = 0. Cambiar al Banco 0MLoop ; Bucle principal bsf PORTB, 0 ; Prender el led call pausa ; Llamar pausa bcf PORTB, 0 ; Apagar el led call pausa ; Llamar pausa goto MLoop ; Saltar a MLoop

;****************************************************************************; Subrutina pausa. Genera 325 milisegundos aprox.pausa movlw d'100' ; Mover 100 a W movwf cont1 ; Mover W a cont1 (cargar cont1) movlw d'255' ; Mover 255 a W movwf cont2 ; Mover W a cont2 (cargar cont2)loop1 decfsz cont1, f ; decrementar cont1, saltear si da 0 goto loop2 ; saltar a loop2 decfsz cont2, f ; decrementar cont2, saltear si da 0loop2 goto loop1 ; saltar a loop1 return ; retornar de subrutina

end ; Fin del código

Visto el código de izquierda a derecha podemos notar que sobresalen cuatro columnas. (Los colores ayudan mucho, aunque no determinan nada.)

La primera columna es la que contiene las etiquetas y también algunas directivas. Las etiquetas sirven para marcar las direcciones de las instrucciones a las que preceden. Pueden ser útiles para algunas instrucciones y en otros casos están de adorno. Por ejemplo, la etiqueta Start vale por la dirección de bsf STATUS, RP0. El nombre de las etiquetas es un identificador. Pueden opcionalmente ir seguidas de dos puntos (:).

En este programa tenemos las etiquetas Start, MLoop, pausa, loop1 y loop2.

En la segunda columna están los mnemónicos de las instrucciones, como bsf, movlw, etc. (en el ejemplo aparecen de color marrón), macros o directivas del ensamblador. Las directivas (cuyos nombres aparecen de color azul) no son instrucciones del PIC ni constituyen código ejecutable. Son ordenes que el ensamblador tendrá en cuenta en el momento de ensamblar el código fuente. Tienen diversas funciones y ayudan bastante, como lo veremos en adelante.

Ahora, lo que puede resultar desalentador es la cantidad de directivas que existen. De la enorme lista disponible solo un grupo de ellas son realmente elementales e iremos conociéndolas de a poco. La lista inicial indispensable está formada por list, include, __config, banksel, equ, org, end, define, cblock, endc, dt.

La tercera columna está constituida básicamente por los operandos de instrucciones, como STATUS, RP0; TRISB; pausa; etc.

En la cuarta columna sobresalen los comentarios. Un comentario es todo lo que sigue en el renglón a un punto y coma (;) y será ignorado por el ensamblador (en el listado es todo lo que se ve de color verde). Digamos que son texto de adorno que solo sirve para documentar el programa. De hecho, los comentarios pueden ponerse en cualquier parte del listado.

Ésa es una forma algo burda de estructurar un programa, pero ayuda muchísimo. Ahora pasaremos a revisarlo de arriba abajo.

Page 62: CURSO INTERNET Microcontroladores PIC

Los identificadores son los nombres que podemos usar para identificar ciertos elementos del código fuente, como registros GPR, etiquetas, macros, etc. Los nombres se forman a criterio del usuario, usando los carecteres alfanuméricos disponibles y los signos _ y ?, respetando las siguientes reglas:

No debe haber dos indentificadores iguales.

No deben empezar con números. Ejemplo, 1n4148.

No deben comenzar con dos rayas bajas seguidas. Ejemplo, __var.

No deben incluir espacios. Ejemplo, contador 1.

No deben ser palabras reservadas, como directivas o mnemónicos. Ejemplo, include, processor, retlw, etc.

A diferencia de los mnemónicos, por defecto el ensamblador distingue entre caracteres mayúsculas y minúsculas.

Set de instrucciones de los PIC de familia Mid-Range

Hasta el momento hemos visto la operación de varias de las instrucciones del PIC. Como habrás notado, son bastante fáciles de usar. Ahora, antes de continuar y para no tener que seguir explicándolas al vuelo, conoceremos el resto de las 35 instrucciones de los PICs Mid-range.

Es un alivio saber que estos PICs tengan tan pocas instrucciones, haciendo todo el honor a su procesador de arquitectura RISC (Reduced Instruction Set Computer). Es probable que en el futuro también estudiemos otros módulos, dedicados a otros microcontroladores, aparte de los PICmicros. La mayoría de ellos, aunque también tienen un diseño RISC, poseen cerca de 100 instrucciones. Así que ponle ganas y termina cuanto antes este capítulo.

Convención de términos

f    Cualquier registro (SFR o GPR) de la RAM del PIC w   Work register o Registro de trabajo

b    Posición de bit

k    Campo literal, dato constante o etiqueta d    Selección de destino; d = 0: el resultado se almacena en W                                     d = 1: el resultado almacenar en el registro F PC    Program Counter o Contador de Programa TOS  Top Of Stack o Cima de la Pila

< >   Posición de bit dentro de un registro

TO   Bit de Time-Out

PD    Bit de Power-down

Label   Nombre de una etiqueta

Notación de números en ensamblador

Hexadecimal:  0x15, H45, h7A

Decimal:         D'41', d'156 ', .25

Page 63: CURSO INTERNET Microcontroladores PIC

Binario:  B'11110010', b'01010000'

Octal:     O'32', o'77'

Ascii:      'A', 'a', 'b'

Expresiones adoptadas

Para fines de documentación vamos a emplear algunos signos o expresiones que resumen el significado de alguna operación, como: → Se utiliza para indicar la transferencia de un dato. Por ejemplo:

0x00 → (TRISB) Significa “cargar el dato 0x00 en el registro TRISB”.

( ) Se utiliza para referenciar el contenido de un registro. Por ejemplo:

(W) → (PORTB) Significa “el contenido del registro W se pasa al registro PORTB”.

= A pesar de la sencillez de estos símbolos, yo prefiero emplear el operador =, propia de los lenguajes de alto nivel. Solo debes acostumbrarte a que la transferencia del dato se dirige de derecha a izquierda y entender que el signo = no implica una ecuación matemática (donde los dos miembros de la expresión son iguales de antemano), solo significa que el valor del segundo miembro es asignado al primero. Por ejemplo.

TRISB = 0x00;            significa TRISB pasará a valer 0x00. PORTB = PORTA;        significa PORTB valdrá igual que PORTA. cnt = PORTB + 0x06;   significa cnt será la suma de PORTB y la constante 0x06. PORTB = PORTB + 1;   significa PORTB es incrementado en 1. PORTA = ~ PORTA;     significa PORTA invierte su valor. Z = 0;                        significa el bit Z será igual a 0. C = 1;                        significa el bit C será igual a 1.Puedes notar que se prescinde de la expresión “el contenido del registro...”, ya que se asume que de eso se trata.

. Aunque en la documentación de Microchip se adoptan los signos < > para indicar la posición de un bit dentro de un registro, aquí también prefiero cambiar a otra notación, punto en este caso. Por ejemplo

PORTB.2 = 0;      significa limpiar el bit 2 del registro PORTB. TRISA.5 = 1;       significa setear el bit 5 del registro TRISA. INTCON.GIE = 0; significa limpiar el bit GIE del registro INTCON.

Resumen de instrucciones de los PIC16F84A y PIC16F87xA

Page 64: CURSO INTERNET Microcontroladores PIC

MnemónicosOperandos Descripción CiclosStatus Afectado

addlw k Sumar literal con W 1 C, DC, Z

addwf f, d Sumar W con F 1 C, DC, Z

andlw k And entre literal y W 1 Z

andwf f, d And entre W y F 1 Z

bcf f, b Limpiar bit en F 1 ---

bsf f, b Setear bit en F 1 ---

btfsc f, b Testear bit en F, saltear si es 0 1 ó 2 ---

btfss f, b Testear bit en F, saltear si es 1 1 ó 2 ---

call k Llamar subrutina 2 ---

clrf f Limpiar F 1 Z

clrw - Limpiar W 1 Z

clrwdt - Limpiar Watchdog 1 TO, PD

comf f, d Complementar F 1 Z

decf f, d Decrementar F 1 Z

decfsz f, d Decrementar F, saltear si da 0 1 ó 2 ---

goto k Saltar a k 2 ---

Incf f, d Incrementar F 1 Z

incfsz f, d Incrementar F, saltear si da 0 1 ó 2 ---

iorlw k OR Inclusiva entre literal y W 1 Z

iorwf f, d OR Inclusiva entre W y F 1 Z

movlw k Mover literal a W 1 ---

movf f, d Mover F 1 Z

movwf f Mover W a F 1 ---

nop - No operación 1 ---

retfie - Retornar de interrupción 2 ---

retlw k Retornar con literal en W 2 ---

return - Retornar de subrutina 2 ---

rlf f, d Rotar a izquierda mediante Carry 1 C

rrf f, d Rotar a derecha mediante Carry 1 C

sleep - Entrar en modo Standby 1 TO, PD

sublw k Restar W de literal 1 C, DC, Z

subwf f, d Restar W de F 1 C, DC, Z

swapf f, d Intercambiar nibbles de F 1 ---

xorlw k OR exclusiva entre literal y W 1 Z

Page 65: CURSO INTERNET Microcontroladores PIC

MnemónicosOperandos Descripción CiclosStatus Afectado

xorwf f, d OR exclusiva entre W y F 1 Z

 

Descripción de instrucciones de los PIC16F84A y PIC16F87xA

ADDLW Add Literal and W

Sintaxis: ADDLW k

Operandos: 0 ≤ k ≤ 255

Operación: (W) + k → (W)

Status Afectado: C, DC, Z

Descripción: El contenido del registro W se suma al literal de ocho bits ‘k’ y el resultado es colocado en el registro W.

Ejemplo 1: ADDWF PORTB, F ; PORTB = PORTB + W Antes de instrucción Después de instrucción PORTB = 0xE8 PORTB = 0x1E W = 0x36 W = 0x36 C = ? C = 1 ; Ocurrió un desbordamiento Z = ? Z = 0 ; El resultado no es cero

Ejemplo 2: ADDWF REG, W ; W = REG + W Antes de instrucción Después de instrucción REG = 0x05 REG = 0x05 W = 0xF2 W = 0xF7 C = ? C = 0 ; No hubo desbordamiento Z = ? Z = 0 ; El resultado no es cero

ADDWF Add W and f

Sintaxis: ADDWF   f, d

Operandos: 0 ≤ k ≤ 255

Operación: (W) + (f)  →  (destino)

Status Afectado: C, DC, Z

Descripción: Sumar el contenido del registro W con el registro ‘f’.Si d = 0, el resultado se almacena en el registro W.Si d = 1, el resultado se almacena en el registro ‘f’.

Ejemplo 1: ADDWF PORTB, F ; PORTB = PORTB + W Antes de instrucción Después de instrucción PORTB = 0xE8 PORTB = 0x1E W = 0x36 W = 0x36 C = ? C = 1 ; Ocurrió un desbordamiento Z = ? Z = 0 ; El resultado no es cero

Ejemplo 2: ADDWF REG, W ; W = REG + W Antes de instrucción Después de instrucción

Page 66: CURSO INTERNET Microcontroladores PIC

REG = 0x05 REG = 0x05 W = 0xF2 W = 0xF7 C = ? C = 0 ; No hubo desbordamiento Z = ? Z = 0 ; El resultado no es cero

ANDLW And Literal with W

Sintaxis: ANDLW    k

Operandos: 0 ≤ k ≤ 255

Operación: (W) AND k  → (W)

Status Afectado: Z

Descripción: Aplica la operación AND entre el literal de 8 bits ‘k’ y el registro W. El resultado es colocado en W.

Ejemplo 1: ANDLW b'00001111' ; W = W AND 00001111 Antes de instrucción Después de instrucción W = 0x34 W = 0x04 Z = ? Z = 0 ; El resultado no es cero

Ejemplo 2: ANDLW b'11110000' ; W = W AND 11110000 Antes de instrucción Después de instrucción W = 0x0D W = 0x00 Z = ? Z = 1 ; El resultado es cero

ANDWF And W with f

Sintaxis: ANDWF  f, d

Operandos: 0 ≤ f ≤ 127

d  Є  [0,1]

Operación: (W) AND  (f)  → (W)

Status Afectado: Z

Descripción: AND entre el registro W y el registro ‘f’.Si  d = 0, el resultado es almacenado en el registro W.Si  d = 1, el resultado es almacenado en el registro ‘f’.

Ejemplo 1: ANDWF STATUS, F ; STATUS = STATUS AND W Antes de instrucción Después de instrucción STATUS = 11111111 STATUS = 01010101 W = 01010101 W = 01010101 Z = ? Z = 0 ; Resultado no cero

Ejemplo 2: ANDWF REG, W ; W = REG AND W Antes de instrucción Después de instrucción REG = 01010101 REG = 01010101 W = 11110000 W = 01010000

Page 67: CURSO INTERNET Microcontroladores PIC

Z = ? Z = 0 ; Resultado no cero

BCF Bit Clear f

Sintaxis: BCF    f, b

Operandos: 0 ≤ f ≤ 127

0 ≤ b ≤ 7

Operación: 0 → (f<b>)

Status Afectado: Ninguno

Descripción: Limpiar (poner a cero) el bit ‘b’ del registro ‘f’.

Ejemplo 1: BCF REG, 6 ; REG.6 = 0 Antes de instrucción Después de instrucción REG = 01101001 REG = 00101001 Ejemplo 2: BCF REG, 1 ; REG.1 = 0 Antes de instrucción Después de instrucción REG = 00001001 REG = 00001001

BSF Bit Set f

Sintaxis: BSF    f, b

Operandos: 0 ≤ f ≤ 127

0 ≤ b ≤ 7

Operación: 1 → (f<b>)

Status Afectado: Ninguno

Descripción: Setear (poner a uno) el bit ‘b’ del registro ‘f’.

Ejemplo 1: BSF PORTA, 5 ; PORTA.5 = 1 Antes de instrucción Después de instrucción REG = 10000011 REG = 10100011

Ejemplo 2: BSF REG, 0 ; REG.0 = 1 Antes de instrucción Después de instrucción REG = 00010000 REG = 00010001

BTFSC Bit Test f, Skip if Clear

Sintaxis: BTFSC    f, b

Operandos: 0 ≤ f ≤ 127

0 ≤ b ≤ 7

Operación: Saltear si  (f<b>) = 0

Status Afectado: Ninguno

Page 68: CURSO INTERNET Microcontroladores PIC

BTFSC Bit Test f, Skip if Clear

Descripción: Si el bit ‘b’ en el registro ‘f’ es ‘1’, entonces se ejecuta la siguiente instrucción.

Si el bit ‘b’ en el registro ‘f’ es ‘0’, entonces la siguiente instrucción es descartada y en su lugar se ejecuta un NOP, haciendo de ésta una

instrucción de 2 ciclos.

Ejemplo 1: Here BTFSC PORTB, 0 ; Saltear siguiente instrucción si RB0 = 0 IsOne GOTO Sub1 ; Saltar a Sub1 si RB0 = 1 IsZero GOTO Sub0 ; Saltar a Sub0 si RB0 = 0 Antes de instrucción Después de instrucción PC = Adress (Here) Si RB0 = 0, PC = Address (IsZero) Si RB0 = 1, PC = Address (IsOne)

BTFSS Bit Test f, Skip if Set

Sintaxis: BSF    f, b

Operandos: 0 ≤ f ≤ 127

0 ≤ b ≤ 7

Operación: Saltear si  (f<b>) = 1

Status Afectado: Ninguno

Descripción: Si el bit ‘b’ en el registro ‘f’ es ‘0’, entonces se ejecuta la siguiente instrucción.

Si el bit ‘b’ es ‘1’, entonces la siguiente instrucción es descartada y en su lugar se ejecuta un NOP, haciendo de ésta una instrucción de 2 ciclos.

Ejemplo 1: MOVLW 0xFF ; W = 0xFF BTFSS PORTB, 0 ; Saltear siguiente instrucción si RB0 = 1 MOVLW 0x20 ; W = 0x20 MOVWF REG ; REG = W Antes de instrucción Después de instrucción REG = ? Si RB0 = 1, REG = 0xFF Si RB0 = 0, REG = 0x20

Page 69: CURSO INTERNET Microcontroladores PIC

CALL Call subroutine

Sintaxis: CALL k

Operandos: 0 ≤ k ≤ 2047

Operación: (PC) + 1 →  TOS (Top of the stack)k → PC<10:0>

(PCLATH<4:3>) → PC<12:11>

Status Afectado:

Ninguno

Descripción: Llamar subrutina. Primero se salva en la Pila la dirección de retorno (PC + 1). Los once bits inmediatos de la dirección se cargan en los bits <10:0> del PC. Los bits superiores

de PC se cargan desde PCLATH. CALL es una instrucción de dos ciclos.

Ejemplo 1: Here CALL There ; Llamar subrutina “There” Antes de instrucción Después de instrucción PC = Address (Here) PC = Address (There) TOS = Address (Here + 1)

CLRF Clear f

Sintaxis: CLRF  f

Operandos: 0 ≤ f ≤ 127

Operación: 0x00 → (f)1 → Z

Status Afectado: Z

Descripción: Se limpia el contenido del registro ‘f’ y se setea el bit Z.

Ejemplo 1: CLRF TRISB, F ; TRISB = 00000000 Antes de instrucción Después de instrucción TRISB = ? TRISB = 00000000 Z = ? Z = 1 ; Resultado es cero

CLRW Clear W

Sintaxis: CLRW

Operandos: Ninguno

Operación: 0x00  → (W)1 → Z

Status Afectado: Z

Descripción: Se limpia el registro W y se setea el bit Z.

Page 70: CURSO INTERNET Microcontroladores PIC

Ejemplo 1: CLRW ; W = 0x00 Antes de instrucción Después de instrucción W = ? W = 00000000

CLRWDT Clear Watchdog Timer

Sintaxis: CLRWDT

Operandos: Ninguno

Operación: 0x00 → WDT0 → WDT prescaler

1 → TO1 → PD

Status Afectado: TO, PD

Descripción: Resetea el temporizador Watchdog (WDT). También se resetea el prescaler del WDT. Los bits de Status TO y PD se setean.

Z = ? Z = 1 ; Result is zero

Ejemplo 1: CLRWDT ; Clear the Watchdog timer. Antes de instrucción Después de instrucción WDT counter = ? WDT counter = 0x00 WDT prescaler = 0 TO = ? TO= 1 PD = ? PD = 1

COMF Complement f

Sintaxis: COMF    f , d

Operandos: 0 ≤ f ≤ 127

d Є [0,1]

Operación: (f) → (destino)

Status Afectado: Z

Descripción: El contenido del registro ‘f’ es complemetado a 1.Si d = 0, el resultado se almacena en el registro W.

Si d = 1, el resultado se queda en el registro ‘f’.

Ejemplo 1: COMF PORTA, F ; PORTA = ~PORTA Antes de instrucción Después de instrucción PORTA = 11110000 PORTA = 00001111 Z = ? Z = 0 ; Resultado no cero

Ejemplo 2: COMF PORTA, W ; W = ~PORTA Antes de instrucción Después de instrucción PORTA = 01010101 PORTA = 10101010 W = ? W = 10101010

Page 71: CURSO INTERNET Microcontroladores PIC

Z = ? Z = 0 ; Resultado no cero

DECF Decrement f

Sintaxis: DECF f , d

Operandos: 0 ≤ f ≤ 127d Є [0,1]

Operación: (f) - 1 → (destino)

Status Afectado: Z

Descripción: Decrementar el registro ‘f’.Si d = 0, el resultado se almacena en el registro W.

Si d = 1, el resultado se queda en el registro ‘f’.

Ejemplo 1: DECF Count, F ; Count = Count - 1 Antes de instrucción Después de instrucción Count = 0x54 Count = 0x53 Z = ? Z = 0 ; Resultado no es cero

Ejemplo 2: DECF Count, W ; W = Count - 1 Antes de instrucción Después de instrucción Count = 0x01 Count = 0x00 Z = ? Z = 1 ; Resultado es cero

DECFSZ Decrement f, Skip if Zero

Sintaxis: DECFSZ    f , d

Operandos: 0 ≤ f ≤ 127d Є [0,1]

Operación: (f) - 1 → (destino)Saltear si el resultado es 0.

Status Afectado:

Ninguno

Descripción: Se decrementa el contenido del registro ‘f’.Si d = 0, el resultado se almacena en el registro W.

Si d = 1, el resultado se queda en el registro ‘f’.Si el resultado no es 0, se ejecuta la siguiente instrucción. Si el resultado es 0,

entonces en su lugar se ejecuta un NOP, haciéndola una instrucción de 2 ciclos.

Ejemplo 1:

Here DECFSZ Count, F ; Count = Count - 1, Saltear si resultado es 0 GOTO Loop ; Saltar a Loop si el resultado no es 0 Continue ... ; El programa salta aquí si el resultado es 0 Antes de instrucción Después de instrucción PC = Address (Here) Si Count = 0, PC = Address(Here + 2) Si Count != 0, PC = Address(Here + 1)

Page 72: CURSO INTERNET Microcontroladores PIC

GOTO Unconditional Branch

Sintaxis: GOTO k

Operandos: 0 ≤ k ≤ 2047

Operación: k → PC<10:0>(PCLATH<4:3>) → PC<12:11>

Status Afectado: Ninguno

Descripción: Goto es un salto incondicional. El valor de los once bits inmediatos de la dirección se cargan en los bits <10:0>. Los bits superiores del PC se cargan

desde PCLATH<4:3>. GOTO es una instrucción de 2 ciclos.

Ejemplo 1: Here GOTO There ; Branch to “There” Antes de instrucción Después de instrucción PC = Address (Here) PC = Address (There)

INCF Increment f

Sintaxis: INCF  f , d

Operandos: 0 ≤ f ≤ 127d Є [0,1]

Operación: (f) + 1 → (destino)

Status Afectado: Z

Descripción: Se incrementa en contenido del registro ‘f’.Si d = 0, el resultado se almacena en el registro W.

Si d = 1, el resultado se queda en el registro ‘f’.

Ejemplo 1: INCF Count, F ; Count = Count + 1 Antes de instrucción Después de instrucción Count = 0x89 Count = 0x8A Z = ? Z = 0 ; Resultado no es cero

INCFSZ Increment f, Skip if Zero

Sintaxis: INCFSZ     f , d

Operandos: 0 ≤ f ≤ 127d Є [0,1]

Operación: (f) + 1 → (destino);Saltear si el resultado es 0.

Status Afectado:

Ninguno

Descripción: Se incrementa el contenido del registro ‘f’. Todos los registros de la RAM son cíclicos, esto es, después de un incremento en 0xFF se producirá un desbordamiento y se

convertirá en 0x00.Si d = 0, el resultado se almacena en el registro W.

Si d = 1, el resultado se queda en el registro ‘f’.Si el resultado no es 0, se ejecuta la siguiente instrucción. Si el resultado es 0, entonces

se ejecuta un NOP, haciéndola una instrucción de 2 ciclos.

Page 73: CURSO INTERNET Microcontroladores PIC

Ejemplo 1: Here INCFSZ Count, F ; Count = Count + 1, Saltear si resultado es 0 GOTO Loop ; Saltar a Loop si resultado no es 0 Continue ... ; El programa salta aquí si el resultado es 0 Antes de instrucción Después de instrucción PC = Address (Here) Si Count = 0, PC = Address(Here + 2) Si Count != 0, PC = Address(Here + 1)

IORLW Inclusive OR Literal with W

Sintaxis: IORLW     k

Operandos: 0 ≤ f ≤ 255

Operación: (W) OR k → (W)

Status Afectado: Z

Descripción: Se aplica un OR entre el contenido del registro W y los ocho bits del literal ‘k’. El resultado queda en el registro W.

Ejemplo 1: IORLW b'00001111' ; W = W OR 00001111 Antes de instrucción Después de instrucción W = 0x34 W = 0x3F Z = ? Z = 0 ; Resultado no es cero

Ejemplo 2: IORLW b'11110000' ; W = W OR 11110000 Antes de instrucción Después de instrucción W = 0x0D W = 0xFD Z = ? Z = 0 ; Resultado no es cero

IORWF Inclusive OR W with f

Sintaxis: IORWF   f, d

Operandos: 0 ≤ f ≤ 255

Operación: (W) OR (f)  → (destino)

Status Afectado: Z

Descripción: OR inclusiva entre el registro W y el registro ‘f’.Si d = 0, el resultado se almacena en el registro W.

Si d = 1, el resultado se queda en el registro ‘f’.

Ejemplo 1: IORWF INTCON, F ; INTCON = W OR INTCON Antes de instrucción Después de instrucción INTCON = 0x00 INTCON = 0x10 W = 0x10 W = 0x10 Z = ? Z = 0 ; Resultado no es cero

Page 74: CURSO INTERNET Microcontroladores PIC

Ejemplo 2: IORWF REG, W ; W = W OR REG Antes de instrucción Después de instrucción REG = 01010101 REG = 01010101 W = 10101010 W = 11111111 Z = ? Z = 0 ; Resultado no es cero

MOVLW Move Literal to W

Sintaxis: MOVLW   k

Operandos: 0 ≤ k ≤ 255

Operación: k → (W)

Status Afectado: Ninguno

Descripción: El literal de ocho bits ‘k’ se carga en el registro W.

Ejemplo 1: MOVLW 0xFF ; W = 0xFF Antes de instrucción Después de instrucción W = ? W = 0xFF

Ejemplo 2: MOVLW 'A' ; W = 'A' Antes de instrucción Después de instrucción W = ? W = 01000001

MOVF Move f

Sintaxis: MOVF    f, d

Operandos: 0 ≤ f ≤ 255d Є [0,1]

Operación: (f) → (destino)

Status Afectado: Z

Descripción: Mover el contenido del registro ’f’ a un destino que depende del estado de d.Si d = 0, el destino es el registro W.

Si d = 1, el destino es el mismo registro ‘f’. d = 1 se usa para testear un registro, dado que afecta el bit de Status Z.

Ejemplo 1: MOVF INTCON, W ; W = INTCON Antes de instrucción Después de instrucción INTCON = 0x11 INTCON = 0x11 W = ? W = 0x11 Z = ? Z = 0 ; Resultado no es cero Ejemplo 2: MOVF Cnt, F ; Cnt = Cnt Antes de instrucción Después de instrucción Cnt = 0x00 Cnt = 0x00 Z = ? Z = 1 ; Resultado es cero

Page 75: CURSO INTERNET Microcontroladores PIC

MOVWF Move W to f

Sintaxis: MOVWF   f

Operandos: 0 ≤ f ≤ 127

Operación: (W) → (f)

Status Afectado: Ninguno

Descripción: Mover el dato desde el registro W al registro ‘f’.

Ejemplo 1: MOVWF REGA ; REGA = W Antes de instrucción Después de instrucción REGA = ? REGA = 0xF0 W = 0xF0 W = 0xF0

NOP No Opetation

Sintaxis: NOP

Operandos: Ninguno

Operación: No Operación

Status Afectado: Ninguno

Descripción: No Operación

Ejemplo 1: NOP ; Solo consume un ciclo

RETFIE Return from interrupt

Sintaxis: RETFIE

Operandos: Ninguno

Operación: TOS → PC1 → GIE

Status Afectado: Ninguno

Descripción: Retorno de interrupción. El valor de la Cima de la Pila se carga en el PC. Se rehabilitan las interrupciones con el seteo del bit GIE del registro INTCON.

Ejemplo 1: RETFIE ; Retornar de interrupción y rehabilitar ; las interrupciones. Después de instrucción PC = TOS ; Restaura el Contador de Programa GIE = 1 ; Rehabilitar global de las interrupciones

RETLW Return with Literal in W

Sintaxis: RETLW     k

Operandos: 0 ≤ k ≤ 255

Operación: k → (W)TOS → PC

Status Afectado: Ninguno

Page 76: CURSO INTERNET Microcontroladores PIC

RETLW Return with Literal in W

Descripción: El registro W se carga con los ocho bits del literal ‘k’. El PC se carga desde la Cima de la Pila (la dirección de retorno). ésta es una instrucción de dos ciclos.

Ejemplo 1: CALL Table ; W contiene el valor de desplazamiento en Table. ... ; W ahora tiene un valor de la tabla : Table ADDWF PCL, F ; W = Desplazamiento RETLW k0 ; Inicio de Table RETLW k1 : RETLW kn ; Final de Table. Antes de instrucción Después de instrucción W = 0x07 W = value of kn

RETURN Return from subroutine

Sintaxis: RETURN

Operandos: Ninguno

Operación: TOS → PC

Status Afectado: Ninguno

Descripción: Retorno de subrutina. El valor de la Cima de la Pila (TOS) se carga en el PC. ésta es una instrucción de dos ciclos.

Ejemplo 1: RETURN ; Retorno de subrutina Después de instrucción PC = TOS ; Restaurar Contador de Programa

RLF Rotate Left f  through Carry

Sintaxis: RLF    f, d

Operandos: 0 ≤ f ≤ 127;     d Є [0,1]

Operación:

Status Afectado: C

Descripción: El contenido del registro ’f’ se rota a la izquierda un bit mediante el flag de Carry.Si d = 0, el resultado se coloca en registro W.

Si d = 1, el resultado se queda en el registro ‘f’.

Ejemplo 1: RLF REG, F ; REG = REG rotado a la izquierda Antes de instrucción Después de instrucción REG = b'00011011' REG = b'00110110' C = 0 C = 0 Ejemplo 2: RLF REG, W ; W = REG rotado a la izquierda

Page 77: CURSO INTERNET Microcontroladores PIC

Antes de instrucción Después de instrucción REG = b'11010000' REG = b'11010000' W = ? W = b'10100001' C = 1 C = 1

RRF Rotate Right f  through Carry

Sintaxis: RRF    f, d

Operandos: 0 ≤ f ≤ 127;     d Є [0,1]

Operación:

Status Afectado: C

Descripción: El contenido del registro ’f’ se rota un bit a la derecha mediante el flag de Carry.

Si d = 0, el resultado se coloca en el registro W.Si d = 1, el resultado se coloca en el registro ‘f’.

Ejemplo 1: RLF REG, F ; REG = REG rotado a la derecha Antes de instrucción Después de instrucción REG = b'00011011' REG = b'00001101' C = 0 C = 1 Ejemplo 2: RLF REG, W ; W = REG rotado a la derecha Antes de instrucción Después de instrucción REG = b'11010000' REG = b'11010000' W = ? W = b'11101000' C = 1 C = 0

SLEEP Enter Sleep mode

Sintaxis: SLEEP

Operandos: Ninguno

Operación: 0x00 → WDT0 → WDT prescaler

1 → TO0 → PD

Status Afectado: TO, PD

Descripción: Poner el procesador en modo SLEEP, con el oscilador detenido. Éste es el modo Standby en que el CPU del PIC se detiene para ahorrar energía. El bit de Status Power-Down PD se limpia. El bit de Status Time Out TO se setea. El Watchdog

Timer y su prescaler se resetean.

Ejemplo 1: SLEEP ; Entrar en modo Standby Antes de instrucción Después de instrucción WDT counter = ? WDT counter = 0x00 WDT prescaler = 0 TO = ? TO= 1 ; Este bit se limpia si PD = ? PD = 0 ; WDT despierta al procesador

Page 78: CURSO INTERNET Microcontroladores PIC

SUBLW Subtruct W from Literal

Sintaxis: SUBLW    k

Operandos: 0 ≤ k ≤ 255

Operación: k - (W) → (W)

Status Afectado: C, DC, Z

Descripción: Restar (con el método de complemento a 2) el contenido del registro W del literal de ocho bits ‘k’. El resultado queda en el registro W.

Ejemplo 1: SUBLW d'124' ; W = 124 - W Antes de instrucción Después de instrucción W = d'100' W = d'24' Z = ? Z = 0 ; Z = 0 y C = 1 indican que C = ? C = 1 ; el resultado es positivo Ejemplo 2: SUBLW d'10' ; W = 10 - W Antes de instrucción Después de instrucción W = d'100' W = -d'90' = d'166' = 10100110 Z = ? Z = 0 ; Z = 0 y C = 0 indican que C = ? C = 0 ; el resultado es negativo.

Ejemplo 3: SUBLW 0x26 ; W = 0x26 - W Antes de instrucción Después de instrucción W = 0x26 W = 0x00 Z = ? Z = 1 ; Z = 1 Resultado es cero. C = ? C = 1 ;

SUBWF Subtruct W from f

Sintaxis: SUBWF   f, d

Operandos: 0 ≤ f ≤ 127d Є [0,1]

Operación: (f) - (W) → (destino)

Status Afectado: C, DC, Z

Descripción: Restar (mediante complemento a 2) el registro W del registro ‘f’.Si d = 0, el resultado se almacena en el registro W.

Si d = 1, el resultado se queda en el registro ‘f’.

Ejemplo 1: SUBWF REG, W ; W = REG - W Antes de instrucción Después de instrucción REG = 9 REG = 9 W = 2 W = 7 Z = ? Z = 0 ; Z = 0 y C = 1 indican que C = ? C = 1 ; el resultado es positivo. Ejemplo 2: SUBWF REG, F ; REG = REG - W Antes de instrucción Después de instrucción REG = 0x00 REG = 0xFF = -d'1' = 11111111 W = 0x01 W = 0x01 Z = ? Z = 0 ; Z = 0 y C = 0 indican que C = ? C = 0 ; el resultado es negativo. Ejemplo 3: SUBWF REG, W ; W = REG - W Antes de instrucción Después de instrucción

Page 79: CURSO INTERNET Microcontroladores PIC

REG = 0x22 REG = 0x00 W = 0x22 W = 0x22 Z = ? Z = 0 ; Z = 1, resultado es cero. C = ? C = 1 ;

SWAPF Swap Nibbles in f

Sintaxis: SWAPF    f, d

Operandos: 0 ≤ f ≤ 127d Є [0,1]

Operación: (f<3:0>) → (destino<7:4>)(f<7:4>) → (destino<3:0>)

Status Afectado: Ninguno

Descripción: Intercambiar los nibbles superior e inferior del registro ‘f’.Si d = 0, el resultado se almacena en el registro W.

Si d = 1, el resultado se queda en el registro ‘f’.

Ejemplo 1: SWAPF REG, W ; W = REG swapped. Antes de instrucción Después de instrucción REG = 0x59 REG = 0x59 W = ? W = 0x95

Ejemplo 2: SWAPF REG, F ; REG = REG swapped. Antes de instrucción Después de instrucción REG = 0x2C REG = 0xC2

XORLW Exclusive OR Literal with W

Sintaxis: XORLW   k

Operandos: 0 ≤ k ≤ 255

Operación: (W) XOR k → (destino)

Status Afectado: Z

Descripción: Aplicar un XOR entre el contenido del registro W y los ocho bits del literal ‘k’. El resultado queda en el registro W.

Ejemplo 1: XORLW b'00001111' ; W = 00001111 XOR W Antes de instrucción Después de instrucción W = 01010101 W = 01011010 Z = ? Z = 0 ; Resultado no es cero. Ejemplo 2: XORLW 0xF0 ; W = 0xF0 XOR W Antes de instrucción Después de instrucción W = 0xF0 W = 0x00 Z = ? Z = 1 ; Resultado es cero.

XORWF Exclusive OR W with f

Sintaxis: XORWF   f, d

Operandos: 0 ≤ f ≤ 127d Є [0,1]

Page 80: CURSO INTERNET Microcontroladores PIC

XORWF Exclusive OR W with f

Operación: (W) XOR (f) → (destino)

Status Afectado: Z

Descripción: OR exclusivo entre el contenido del registro W y el registro ‘f’.Si d = 0, el resultado se almacena en el registro W.

Si d = 1, el resultado se queda en el registro ‘f’.

Ejemplo 1: XORWF PORTB, W ; W = PORTB XOR W Antes de instrucción Después de instrucción PORTB = 00110011 PORTB = 00110011 W = 00000000 W = 00110011 Z = ? Z = 0 ; Resultado no es cero. Ejemplo 2: XORWF REG, F ; REG = REG XOR W Antes de instrucción Después de instrucción REG = 00110011 REG = 11001100 W = 11111111 W = 00110011 Z = ? Z = 0 ; Resultado no es cero.

Directivas del ensamblador

Las directivas no son instrucciones del Microcontroladores, son indicaciones que se le dan al ensamblador para controlar algunos aspectos del ensamblado del código. Todas las directivas se detallan en el manual respectivo de los tantos que se instalan junto con el paquete MPLAB.

Como con los mnemónicos de instrucciones, al ensamblador le da igual si las directivas están en mayúsculas o en minúsculas.

Aquí presentaremos las que suelen ser las más habituales. Ya vimos en acción a muchas de ellas y las restantes las empezaremos a usar en adelante.

Directiva list Directiva processor Directiva include Directivas __config y __fuses Directiva equ Directivas cblock y endc Directiva org Directiva end Directiva banksel Directiva #define Directiva $ Directiva dt Directiva errorlevel Directiva messg Directivas if, ifdef, ifndef, else y endif

La directiva list

Page 81: CURSO INTERNET Microcontroladores PIC

Es una directiva para listar una serie de opciones de ensamblado de diversa índole. Los parámetros listados se separan por comas. Por ejemplo, siguiente directiva

list p = PIC16F84A, r = dec, b = 8, f = INHX8M

tiene cuatro parametros, cuyo significado es:

p: establece el Procesador destino (PICmicro). Esto será equivalente a la directiva processor.

r: establece el sistema de numeración a usar por defecto. Como se vio al inicio, el formato de los números se suele especificar por un prefijo: 0x para hexadecimal, . para decimal, etc. En caso de no especificar nada, el número será considerado en el formato señalado por r. En el ejemplo, es obvio que se indica decimal. El valor por defecto es hex (hexadecimal). Esto es equivalente a la directiva radix.

b: establece la cantidad de espacios en blanco que serán insertados en lugar de cada tabulación del archivo *.lst. Éste es un archivo secundario de los tantos que genera el ensamblador. De cualquier forma, más adelante veremos para que puede servir.

f: establece el Formato del archivo hexadecimal de salida. las opciones disponibles son INHX8M, INHX8S e INHX32. La primera es el valor por defecto.

Además de los citados en este ejemplo hay muchos más parámetros que se pueden incluir con la directiva list. Lo curioso es que ninguno puede ser necesario, es decir, todos se pueden indicar de otra forma, ya sea desde el entorno del ensamblador MPASM, del mismo MPLAB o mediante otra directiva. Mas aun, ni siquiera suele ser necesario mover las configuraciones por defecto.

Es una costumbre poner list con al menos el parametro p = indicando el procesador. Para este propósito sería más práctivo e intuitivo usar la directiva processor, descrita continuación, que tiene el mismo objetivo.

La directiva processor

Es una directiva para establecer el PICmicro para el que se ensamblará el código fuente. Es equivalente a poner la directiva list con el parámetro p. Con esta directiva el ensamblador sabrá qué tipo de instrucciones utilizar, aunque en ese sentido hay muy pocas variaciones entre uno y otro “procesador”.

No obstante, resalto que poner estas directivas solo suele ser necesario cuando se llame al ensamblador desde una línea de comandos, por ejemplo, cuando se ensambla el programa desde Proteus VSM. No hacen falta, por ejemplo, cuando se cuando se contruye el proyecto desde MPLAB IDE.

processor PIC16F84A

La directiva include

Page 82: CURSO INTERNET Microcontroladores PIC

Es la directiva para incluir como parte del programa el archivo que se indica. La inclusión se realiza como si se aplicara un “copiar - pegar” del contenido entero del archivo incluido en el lugar donde aparece la directiva.

Esta directiva debe aparecer en todos los programas de ensamblador al menos para incluir el archivo de dispositivo del PIC usado, como muestra el siguiente ejemplo. Estos archivos se hallan en la carpeta de instalación del ensamblador MPASM, que a su vez se instala con MPLAB IDE, norlmalmente C:\Microchip\MPASM Suite. Solo ponemos la directiva y el ensamblador sabrá dónde buscarlo.

include <P16F84A.inc> ; incluir archivo P16F84A.inc

Include también se usa para incorporar archivos de otros tipos, como librerías de códigos. Es una convención usar los signos < > para referirse a los archivos estándar y los signos “ ” para referirse a los archivos de usuario. Incluso pueden ignorarse dichos signos asi como poner por delante el signo #. Queda claro que no se imponen las restricciones que tiene esta directiva en el lenguaje C.

include "lcd.asm" ; incluir archivo lcd.asm

#include P16F877A.inc ; incluir archivo P16F877A.inc

Las directivas __config y __fuses

__config es más popular que __fuses a pesar de tener el mismo propósito (por lo menos en los PIC16) y de que el nombre de la segunda parecería más ilustrativo.

Son directivas para establecer los Fuses de Configuración. Los fuses también se pueden establecer en el entorno del programa grabador (WinPic800, por ejemplo), pero es recomedable hacerlo mediante esta directiva para que formen parte del archivo *.hex resultante.

Recuerda que el PIC16F84A tiene 4 fuses y los PIC16F87xA tienen 9. Todos los hemos estudiado antes. Los fuses se ponen con un número o a través de máscaras que las representan. Estas máscaras se encuentran en el archivo de dipositivo del PICmicro.

Por ejemplo, en la gran mayoría de las prácticas con el PIC16F84A de este curso vamos a usar la siguiente configuración:

__config _XT_OSC & _WDT_OFF & _PWRTE_ON

que es equivalente a:

__fuses _XT_OSC & _WDT_OFF & _PWRTE_ON

Para los PIC16F87xA especificaremos los siguientes fuses:

__config _XT_OSC & _WDT_OFF & _PWRTE_ON & _LVP_OFF

Los fuses no indicados, como la Protección de Código, quedarán con su valor por defecto. Para mayor información puedes volver al capítulo 3.

La directiva equ

Page 83: CURSO INTERNET Microcontroladores PIC

Cuando se quiere acceder a los registros (SFR o GPR) de la RAM se les debe referenciar por sus direcciones. Como eso sería una labor muy tediosa, el ensamblador permite identificarlos con un alías o nombre escogido por el usuario mediante la directiva equ.Aunque equ permite igualar (equal = igual) un identificador con cualquier constante númerica, su principal aplicación es “darles nombres” a los registros de la RAM. De hecho, todos los registros SFR del PIC ya están identificados así en su correspondiente archivo de dispositivo (revísalos, si quieres). A nosotros equ nos servirá para trabajar con los registros GPR.Con el siguiente ejemplo se “bautizan” con cont1 y cont2 a los registros ubicados en las direcciones 0x0C y 0x0D, respectivamente.

cont1 equ 0x0C ; Ubicar cont1 en dirección 0x0C cont2 equ 0x0D ; Ubicar cont2 en dirección 0x0D

Las directivas cblock y endc

Incluso si usamos la directiva equ para referirnos con más comodidad a los registros GPR, si nuestro programa va a procesar varios datos y variables, seremos propensos a comenter errores con las designaciones.Las directivas cblock y endc siempre deben ir juntas para formar un bloque de variables que ocupan posiciones consecutivas en la RAM del PICmicro, siendo la dirección de la primera variable la indicada después de cblock. Para tener un mejor contexto de su uso analicemos el siguiente boceto de código:

processor PIC16F84A include <P16F84A.inc>

cblock 0x0C ; En el PIC16F84A los registros GPR están cont ; disponibles a partir de la dirección 0x0C var temp endc

org 0x000Start ; ... call subroutine ; ... goto Start

;************************************************************************** cblock ; Aquí no necesitas establecer una bus ; dirección base del0 endcsubroutine ; ... ; ... return end

En el boceto el primer bloque cblock - endc es equivalente a haber puesto las líneas de código:

cont equ 0x0C ; Ubicar count en dirección 0x0Cvar equ 0x0D ; Ubicar var en dirección 0x0Dtemp equ 0x0E ; Ubicar temp en dirección 0x0E

Page 84: CURSO INTERNET Microcontroladores PIC

Más abajo aparece otro bloque cblock - endc con dos variables, bus y del0, que también se pudieron incluir en el primer bloque, pero que se separan, como muchas veces se preferirá, por guardar alguna relación entre ellas y para tratar de ordenar el código. No obstante, a diferencia de los lenguajes como el C, estos registros serán accesibles desde cualquier parte del programa.

Ahora bien, si como dice el comentario, el segundo bloque no necesita una dirección base, ¿qué direcciones les corresponden a esas variables? Como el ensamblador sabe dónde se quedó, a las variables del siguiente bloque les asignará las locaciones subsiguientes. Es decir, el segundo cblock - endc sería equivalente a:

bus equ 0x0F ; Ubicar bus en dirección 0x0Fdel0 equ 0x10 ; Ubicar del0 en dirección 0x10

De hecho, en un programa puedes poner varios bloques más de este tipo, pero sin olvidar que, a menos que sepas lo que haces, solamente el primero debe tener la dirección de la primera variable, inclusive si está vacío.

La directiva org

Su nombre deriva de origen. Es para indicarle al ensamblador a partir de que dirección empezará a mapear el subsiguiente código ejecutable. Como el CPU empieza a ejecutar el código desde la dirección 0x000, al menos la primera instrucción de código debería estar allí.

Sin embargo, poner org 0x00 en programas con código continuo se ha convertido en un hábito a veces hasta innecesario porque el ensamblador, que no es tan tonto, sabe que por defecto debe colocar el código a partir de la dirección 0x000.

org 0x000

Usar org sí es útil cuando se quiere reubicar algunas rutinas de código en determinados segmentos de la memoria de programa.

La directiva end

Es la directiva que pone fin a la lectura del código fuente por parte del ensamblador. Cualquier código ubicado después de esta directiva ya no será tomado en cuenta, lo que implica que solo debería haber una directiva end por programa, incluso si consta de varios archivos. Son sofisticados los programas donde se puede usar varias veces.

La directiva banksel

El nombre de esta directiva es un acrónimo de BANK SELection y, como se prevé, sirve para cambiar de bancos.

Como sabemos, la RAM de los PICmicros de familias Baseline y Midrange se divide en varios bancos por los que tenemos que ir saltando para acceder a sus registros, “jugando” con los bits RP0 y RP1, del registro STATUS, así:

Page 85: CURSO INTERNET Microcontroladores PIC

RP1 RP0 Banco accedido

0 0 Banco 0

0 1 Banco 1

1 0 Banco 2

1 1 Banco 3

En los PIC con dos bancos, como el PIC16F84A, solo se trabaja con el bit RP0.

Dado el tedio que puede acarrear este trabajo, sobre todo si no recordamos a qué banco pertenece un registro, la directiva banksel puede ser de gran ayuda. Banksel se encargará de colocar las instrucciones necesarias para acceder al registro que se le indica como parámetro.

banksel TRISA ; Seleccionar banco del registro TRISA (Banco 1)

La directiva #define

Es otra directiva que se utiliza muy a menudo. Los que programaron alguna vez en C/C++ saben cómo funciona. Para los otros, deben saber que tiene tres partes: el mismo define, un identificador y toda la cadena restante.

#define identificador cadena ;

Lo que hará el ensamblador es sustituir el identificador por toda la cadena restante tal cual es en cada punto del programa donde se encuentre identificador. Por eso se le conoce como directiva de sustitución de texto.

Identificador es una palabra con las mismas reglas impuestas a otros identificadores, como las etiquetas o nombres de registros GPR. En cambio, cadena puede estar formada por cualesquiera otros elementos de código ensamblador.

Un típico ejemplo de define es para establecer los puertos de interface, más o menos así:

#define switch PORTB, 0

Y cuando más adelante escribamos, por ejemplo,

btfsc Switch ; Ver si switch vale 0

lo que en realidad entenderá el ensamblador será

btfsc PORTB, 0 ; Ver si switch vale 0

La directiva $

Page 86: CURSO INTERNET Microcontroladores PIC

Recordemos que las etiquetas en el fondo representan las direcciones de las instrucciones a las que preceden y sirven de referencia para las instrucciones de salto. Así mismo, la directiva $ marca la dirección de la instrucción actual y, por ejemplo, $ - 2 será la dirección de la instrucción que está dos posiciones atrás.

Normalmente es preferible colocar etiquetas y dejar el uso de $ solo para los casos donde la propensión a cometer errores sea mínima, por ejemplo, para las instrucciones de saltos cortos.

A continuación se muestran dos rutinas de delay de 50 ms aprox. Ambas son equivalentes, solo que la segunda emplea la directiva $ en vez de las etiquetas. Se asume que la variable cont ha sido definida previamente.

delay_50ms movlw .33 movwf cont laba addlw .1 btfss STATUS, Z goto labb ; Saltar a labb decfsz cont, F labb goto laba ; Saltar a laba return

delay_50ms movlw .33 movwf cont addlw .1 btfss STATUS, Z goto $ + 2 ; Saltar 2 instrucciones adelante decfsz cont, F goto $ - 4 ; Saltar 4 instrucciones atrás return

La directiva dt

Dt construye una tabla de datos a base de instrucciones retlw. Las tablas son matrices de constantes a cuyos elementos se puede acceder secuencialmente mediante una variable índice.

Dt puede recibir uno o más parámetros separados por comas. Los parámetros de cadenas de texto serán descompuestos en sus letras. Por ejemplo, la siguiente directiva

dt "test"

será entendida por el ensamblador como:

retlw 't' retlw 'e' retlw 's' retlw 't'

La directiva errorlevel

Page 87: CURSO INTERNET Microcontroladores PIC

Después de ensamblar o intentar ensamblar el código el ensamblador generará una serie de mensajes, errores y advertencias. Con la directiva errorlevel podemos indicar cuáles de ellos pueden ser ignorados o reportados. Los errores no se pueden inhibir.

Sus parámetros pueden ser:

0. Indica reportar mensajes, error y advertencias

1. Indica reportar advertencias y errores.

2. Indica reportar errores.

- msgnum. Indica no reportar los mensajes identificados por el número msgnum.

+ msgnum. Indica reportar los mensajes identificados por el número msgnum.

Los valores de msgnum forman una lista casi interminable que la puedes encontrar en el manual del ensamblador MPASM.

Por ejemplo, un clásico mensaje que aparece constantemente incluso cuando el código está escrito correctamente es el 302, que dice “Register in operand not in bank 0. Ensure that bank bits are correct”. Allí nos avisa que estamos accediendo a un registro que no es del banco 0 y que debemos asegurarnos de estar haciendo lo correcto. Si nos cansamos de verlo, podemos escribir la siguiente directiva. errorlevel -302

La directiva messg

Sirve para generar mensajes personalizados definidos por el usuario. El mensaje suele ser condicional, para lo que se requiere de algunas otras directivas como if, ifdef, ifndef, else y endif.

Ejemplo, la siguiente directiva hará surgir el mensaje “Este código está realizado para el PIC16F876A”, si es que se trata de ensamblar para otro PICmicro. (la constante __16F876A está definida en el archivo de dispositivo P16F876A.inc.)

ifndef __16F876A messg "Este codigo esta realizado para el PIC16F876A" endif

Las directivas if, ifdef, ifndef, else y endif

Son directivas para ensamblado condicional. Mediante ellas indicaremos si una o algunas rutinas de código o directivas inclusive serán tomadas en cuenta o no por el ensamblador.

Su estructura se muestra a continuación. El uso del bloque de else es opcional.

if (ifdef o ifndef) condition ; si condition se cumple (o si es una expresión previamente definida) ; Se considerará este código else ; De lo contrario ; Se considerará este código endif

A modo de ejemplo, supongamos que hacemos un programa para el PIC16F84A y que eventualmente querremos cambiar el código para que se pueda ensamblar para el PIC16F877A. Sabemos que los principales cambios a tener en cuenta son el archivo de dispositivo a incluir, la directiva de los fuses,

Page 88: CURSO INTERNET Microcontroladores PIC

el inicio de los registros GPR y la configuración del registro ADCON1 de los PIC16F87xA para que el puerto A sea de E/S digital.

El siguiente boceto de programa considera estos cuatro puntos y se puede ensamblar para uno u utro microcontrolador tan solo cambiando la directiva processor, aunque tampoco eso sería necesario si el programa se construye desde otro IDE como MPLAB, por ejemplo.

processor PIC16F84A ; Seleccionar PIC destino

ifdef __16F877A include <P16F877A.inc> __config _XT_OSC & _WDT_OFF & _PWRTE_ON & _LVP_OFF cblock 0x20 endc else ; Si no es PIC16F877A, asumir que es PIC16F84A include <P16F84A.inc> __config _XT_OSC & _WDT_OFF & _PWRTE_ON cblock 0x0C endc endif cblock ; Algunas variables del programa endc

org 0x000Start ifdef __16F877A ; Si está definido __16F877A banksel ADCON1 movlw 0x06 ; Hacer PORTA digital movwf ADCON1 ; endif ; Resto del cuerpo del programa end

Operaciones comunes en lenguaje Ensamblador

Cambios de Bancos Delays Comparaciones

Cambios de Bancos

Una de las cosas más desagradables en el trabajo con los PICs es estar cambiando de bancos para acceder a los registros de la RAM. Por ejemplo, para leer o escribir en el registro PORTA debemos cambiar al banco 0. Si después quisiéramos acceder al registro OPTION_REG, tendríamos que movernos al banco 1. A continuación trataré de justificar este mecanismo.

Por una razón que acabo de borrar (no era liviana), de los 8 ó 9 bits de dirección de cada registro (SFR o GPR) de los PIC16F solamente los 7 primeros están presentes en el código de las instrucciones. Los 2 bits restantes se extraerán de los bits RP0 y RP1, del registro STATUS y son la razón de la existencia de hasta cuatro bancos. Así, se puede entender, por ejemplo, que cuando RP0 y RP1 valen 0, se accede a los registro del banco 0.

Page 89: CURSO INTERNET Microcontroladores PIC

En los PICs con dos bancos, como el PIC16F84A, basta con modificar el bit RP0 para navegar entre ellos. El bit RP1 debe dejarse en 0 por compatibilidad con otros dipositivos.

Una directiva que nos puede mitigar el fastidio de cambiar de bancos es banksel. Ya fue descrita anteriormente.

Los delays

Un delay es una rutina de demora o retardo que sirve para poner una pausa entre dos puntos del programa. Los Timers permiten realizar temporizaciones con gran presición pero para pausas ordinarias se prefiere poner un delay a base de bucles de conteo anidados.

Los delays no son más que rutinas donde se cuenta con una variable. Por ejemplo, la siguiente subrutina decrementa el registro cont desde 200 hasta 0, y genera un delay de 600 us aproximadamente.

cblock cont endcdelay_600us movlw .200 ; 200 a W movwf cont ; W a contbucle1 decfsz cont, F ; Decrementar cont, saltear si da 0 goto bucle1 ; Saltar a bucle return

El tiempo del retardo se puede ajustar modificando el valor a cargar en el registro cont. Sin embargo, se llegará a un límite que puede ser insuficiente. En esos casos se puede insertar algún código de relleno entre la etiqueta bucle1 y la instrucción decfsz cont, F. Para hacer las cosas con más orden ese código de relleno puede ser otro bucle de conteo (bucle anidado).

En la siguiente subrutina se muestra en otro color el bucle de conteo insertado, el cual cuenta desde 100 hasta 0. Esta subrutina toma en ejecutarse aproximadamente 20 ms. Para ajustar el tiempo del retardo ahora se pueden modificar los conteos de las dos variables cont y cont2. Si el tiempo buscado es mayor que lo que se obtiene así, se puede interpolar o extrapolar otro bucle de conteo hasta conseguir lo deseado.

cblock cont, cont2 endcdelay_20ms movlw .200 ; 200 a W movwf cont ; W a contbucle1 movlw .100 ; 100 a W movwf cont2 ; W a cont2bucle2 decfsz cont2, F ; Decrementar cont2, saltear si da 0 goto bucle2 ; Saltar a bucle2 decfsz cont, F ; Decrementar cont, saltear si da 0 goto bucle1 ; Saltar a bucle return

A quienes ya estamos acostumbrados a trabajar con estas rutinas los ajustes de los delays no son gran molestia, sobre todo si nos apoyamos en herramientas como el simulador del MPLAB o Proteus VSM,

Page 90: CURSO INTERNET Microcontroladores PIC

que estudiaremos luego. A los nuevos en el tema puede resultar de gran ayuda recurrir a herramientas libres que se hallan en Internet. Te recomiendo practicar con el generador de delays dehttp://www.piclist.com/cgi-bin/delay.exe. El algoritmo que emplean esos delays es una variante ingeniosa de los bucles de conteo anidados. Tienen la siguiente forma:

cblock cont, cont2 endcdelay_20ms movlw .16 ; 16 a W movwf cont ; W a cont (contador principal) movlw .100 ; 100 a W movwf cont2 ; W a cont2 (contador secundario)bucles decfsz cont2 goto $ + 2 ; Saltar 2 instrucciones adelante decfsz cont goto $ - 3 ; Saltar 3 instrucciones atrás return

Aunque al principio te parezca algo enredado seguir el flujo del código para saber cuándo termina, con un poco de observación lo lograrás. A mí me fascina la forma cómo están trenzados los dos bucles; por eso uso este tipo de delays en casi todos mis programas. Otra ventaja que tienen es que es relativamente fácil calcular el valor del delay. En el código de arriba depende sobre todo del contador principal. El contador secundario se utiliza para afinar la precisión.

Comparaciones

La filosofía de los procesadores con diseño RISC es reducir en lo posible el juego de instrucciones; aunque en mi opinión a la gente de Microchip se le paso un poquito la mano con estos PICs. Por desgracia solo contamos con el repertorio de 35 instrucciones para construir los programas de todos los proyectos con PICs de esta familia. No hay instrucciones de comparación, no hay instrucciones de multimplicación o división, no hay instruccciones para operar números de más de un byte, no hay instrucciones para trabajar con números de punto flotante, etc.

En el sitio web de Microchip se pueden encontrar varios códigos de ejemplo para realizar esas operaciones, aunque son muy complicados. Para cuando nosotros necesitemos emplearlas ya estaremos trabajando con los compiladores de alto nivel. Por lo pronto conoceremos algunos snippets de comparaciones que nos serán muy útiles en lo que resta del este Módulo.

Las comparaciones en los PIC16 son las operaciones más insufribles que he conocido en toda mi vida de programador. Para comparar dos datos tenemos que restarlos uno de otro y luego comprobar los bits Z (zero) y/o C (carry), del registro STATUS, y actuar según su significado.

Primero debemos tener en cuenta que no existen instrucciones para cargar constantes a registros directamente ni para mover datos de memoria a memoria en un solo ciclo. Hay que hacerlo a través del registro de trabajo W.

Por ejemplo, para mover una constante a un registro se debe hacer así:

movlw 0xF3 ; W = 0xF3 movwf TRISB ; TRISB = W. En conclusión, TRISB = 0xF3

Y para mover el contenido de un registro a otro registro se debe hacer así: movf REG, W ; W = REG

Page 91: CURSO INTERNET Microcontroladores PIC

movwf PORTB ; PORTB = W. En conclusión, PORTB = REG.

¿ registro = 0 ? ¿ registro = registro/constante ? ¿ registro < registro/constante ? ¿ registro ≤ registro/constante ? ¿ registro > registro/constante ?

¿ registro = 0 ?

Para saber si un registro vale 0 hay que aplicarle cualquier instrucción que afecte el flag Z, como mover el registro hacia sí mismo, sumarle 0, etc. Ejemplo:

movf REG, F ; REG = REG btfss STATUS, Z ; ¿Z = 1?, ¿REG = 0 ? goto Notzero ; no goto Zero ; yes

¿ registro = registro/constante ?

El bit C indica si una operación de suma ha producido un resultado mayor que 255 (el máximo valor representado por un número de 8 bits). O sea, C = 1 si el resultado fue mayor que 255 y C = 0 si no fue así.

Por otro lado, si después de una resta el bit C se ha seteado, significa que el resultado ha sido positivo o cero. Si C vale 0, es que la resta ha dado un resultado negativo. Como vemos, el bit C funciona al revés con las restas. Ésta es una peculiaridad exclusiva de los PICs.

Veamos como comparar un registro con una constante:

movlw d'100' ; W = 100 subwf REG, W ; W = REG - W btfss STATUS, Z ; ¿Z = 1?, ¿ REG = 100 ? goto NotEqual ; no,... goto IsEqual ; yes,... ...

En seguida se comparan dos registros:

movf REGA, W ; W = REGA subwf REGB, W ; W = REGB - W btfss STATUS, Z ; ¿Z = 1?, ¿ REGA = REGB ? goto NotEqual ; no, ... goto IsEqual ; yes, ... ...

¿ registro < registro/constante ?

Page 92: CURSO INTERNET Microcontroladores PIC

Ahora empezaremos a testear el bit C.

movlw d'100' ; W = 100 subwf REG, W ; W = REG - W btfss STATUS, C ; ¿ C = 0 ?, ¿ REG < 100 ? goto EsMenor ; yes, ... goto NoMenor ; no, ... ... ; ...

movf REGB, W ; W = REGB subwf REGA, W ; W = REGA - W btfss STATUS, C ; ¿C = 0 ?, ¿ REGA < REGB ? goto EsMenor ; yes, ... goto NoMenor ; no, ... ... ; ...

¿ registro ≤ registro/constante ?

El fundamento de lo que viene es: si un dato no es menor que otro, entonces es mayor o igual que él. Como ya sabemos evaluar el primer caso, los siguientes serán fácilmente deducibles.

movf REGA, W ; W = REGA subwf REGB, W ; W = REGB - W btfsc STATUS, C ; ¿C = 1?, ¿REGA ≤ REGB ? goto EsMenorIgual ; yes, ... goto NoMenorIgual ; no, ... ... ; ...

movf REGA, W ; W = REGA sublw const ; W = const - W btfsc STATUS, C ; ¿C = 1?, ¿ REGA ≤ const ? goto EsMenorIgual ; yes, ... goto NoMenorIgual ; no, ... ... ; ...

¿ registro > registro/constante ? movf REGA, W ; W = REGA subwf REGB, W ; W = REGB - W btfss STATUS, C ; ¿C = 0?, ¿ REGA > REGB ? goto EsMayor ; yes, ... goto NoMayor ; no, ... ... ; ...

movf REGA, W ; W = REGA sublw const ; W = const - W btfss STATUS, C ; ¿C = 0?, ¿ REGA > const ? goto EsMayor ; yes, ... goto NoMayor ; no, ... ... ; ...

Page 93: CURSO INTERNET Microcontroladores PIC

El ensamblador MPASM

Un programa ensamblador se encarga de convertir el código fuente *.asm en código máquina *.hex entendible y ejecutable por el microcontrolador. Ambos son archivos de texto, pero el programa grabador sabe cómo interpretar el archivo hexadecimal. El ensamblador de los PICs se llama MPASM o MPASMWIN y también viene incluido en el paquete MPLAB, aunque se puede

Como muchos programas, este ensamblador se puede llamar vía la línea de comandos y es común hacerlo, por ejemplo, desde MPLAB IDE, Proteus VSM o algún compilador de alto nivel, aunque estos últimos suelen usar sus propios ensambladores.

Si instalas el MPLAB IDE en el directorio por defecto, puedes encontrar el MPASMWIN en la carpeta C:\Microchip\MPASM Suite. Al ejecutarlo veremos su entorno:

El programa MPASM para Windows.

Su uso es bastante sencillo; se puede hacer hasta con dos pasos:

Presionamos el botón Browse y escogemos el archivo *.hex a grabar en PIC.

Podemos dejar las demás opciones con sus valores por defecto y luego presionamos el botón Assemble. Eso es todo.

Observa que muchos de los parámetros a establecer en este entorno también se pueden indicar desde el código fuente mediante directivas, como por ejemplo, el formato por defecto de los números sin prefijo (uso de la directiva radix o parámetro r de la directiva list), el nivel de las advertencias a mostrar (uso de directiva errorlevel), el tipo de archivo hexadecimal de salida (parámetro f de la directiva list), el número de espacios en blanco por tabulación a colocar en el archivo *.lst resultante (parámetro b de la directiva list), el procesador destino (uso de directiva processor o parámetro p de la directiva list).

Al desmarcar casilla case sensitive harás que el ensamblador trate por igual a los identificadores escritos con letras mayúsculas o minúsculas. No lo hagas, es recomendable acostumbrarse a trabajar haciendo estas distinciones.

Si el proceso de ensamblado resulta exitoso, veremos la siguiente clásica ventanita (creo que ya no aparece en las más recientes versiones del MPASMWIN):

Page 94: CURSO INTERNET Microcontroladores PIC

Ensamblado de código exitoso con MPASMWIN.

El compilador BoostC/C++

Voy a empezar con este compilador más por una suerte de descarte de los otros productos:IAR C ya no distribuye compiladores para PICs de las familias Baseline y Midrange. La versión demo de CCS C no nos permite usar nuestro PIC16F84A (usaré CCS C en el siguiente Módulo). Mikro C presenta funciones incorporadas cuyos nombres interfieren con los identificadores del programa principal, no soporta funciones reentrantes y tampoco genera un archivo de depuración-simulación para trabajar con Proteus (por lo menos hasta la versión 8.0.0, que es la veo en este momento). No pude descargar ni el demo Bytecraft porque me pedían una suerte de invitacón, y como me sentí ajeno a la fiesta... FedC tiene un entorno demasiado infantil para mi gusto ytampoco genera archivos de depuración con Proteus (eso para mí es muy importante). Hitech PICC me fascina porque se puede usar el lenguaje C sin tener que preocuparse demasiado por las limitaciones del compilador dado que normalmente lo soporta “todo”. Increíblemente, le encontré algunos errores en la versión 9.60 (la última que revisé) cuando utilizaba el PIC16F84A; en fin, será para otra ocasión. Así me quedé con BoostC; no será el mejor pero su precio lo compensa. Además tiene algunas características que yo considero nos serán útiles para empezar a conocer cómo trabajan los compiladores de alto nivel. De todos modos, no sé si sea el enfoque más adecuado, pero tengo pensado ir cambiando de compilador a lo largo del curso; y he considerado a BoostC como un conveniente punto de partida.

Cuando mencioné el relativo bajo costo de BoostC no quise insinuar que lo tuvieras que comprar. No señor. Este es probablemente el curso más barato que se pueda encontrar. Al igual que mayoría de los otros compiladores, la versión demo de BoostC/C++ permite desarrollar programas que utilicen como máximo 2 k palabras de la memoria de programa en los PICs de la familia Midrange. Como 2 k es el doble de la memoria del PIC16F84A, al menos en ese respecto no tendremos limitaciones.Ahora puedes bajar el compilador BoostC desde su sitio web www.sourceboost.com y a continuación instalarlo como cualquier programa de Windows. No hay ningún detalle a remarcar en este procedimiento.Al ser ejecutado por primera vez, el IDE de SourceBoost presenta un proyecto de ejemplo llamadointerrupt. No voy a hacer una descripción pormenorizada de este entorno, no solo porque es el IDE más sencillo y amigable que conozco, sino porque los archivos de ayuda que trae incluidos son bastante ilustrativos.Aparte de las infaltables barras de menú y de herramientas (cuyas principales funciones quedarán

Page 95: CURSO INTERNET Microcontroladores PIC

evidenciadas en lo sucesivo), se distinguen tres áreas, tres ventanas que, como en los entornos de los mejores programas de Windows, se pueden mover y colocar en las posiciones que mejor convegan:

La ventanita Workspace. Se puede mostrar u ocultar mediante el botón   de la barra de herramientas. Es análoga a la ventanita Project Window del MPLAB IDE (solo que más dócil porque no se anda escondiendo cada vez que maximizamos las otras ventanas;): sirve básicamente para mostrar y administrar los archivos del proyecto; los archivos contenidos pueden ser visualizados en el editor de código haciendo doble click en sus nombres; mediante su menú contentual del botón derecho se pueden añadir otros archivos al proyecto, etc.

Entorno de Desarrollo Integrado (IDE) de SourceBoost.

La ventanita Ouput. Se puede mostrar u ocultar con el botón   de la barra de herramientas. Sus funciones son similares a las ofrecidas por la ventana Output del MPLAB IDE: reporta los resultados de la construcción del proyecto, entre otras cosas.

El editor de código. Se abre automáticamente para mostrar el contenido de algún archivo. Sus capacidades son similares a las de cualquier otro excelente producto: es completamente reconfigurable en cuanto a los colores, tamaños y tipos de fuente del texto, tamaño de las tabulaciones, etc.; tiene capacidades de folding; puede mostrar las líneas de código; puede resaltar los símbolos pares como paréntesis o corchetes; tiene función de autocompletado de palabras definidas al pulsar las teclas “ctrl + spacebar”; permite duplicar las líneas de código con la combinación “ctrl + d”; etc. Muchas de estas características se pueden configurar o habilitar desde la opción de menú Settings > Editor...

Page 96: CURSO INTERNET Microcontroladores PIC

Capacidad de autocompletado de texto (Ctrl + Spacebar).

Ventana de configuración del editor de código.

Ahora trata de mostrar en el editor de código (con doble click sobre sus nombres en la ventanitaWorkspace) los archivos del proyecto interrupt cargado inicialmente. Los archivos con extensión .c (y con extensión .h si los hubiera) son los que contienen los códigos fuente del programa. Los otros (como *.asm, *.lst, *.hex y *.cof) son generados por el compilador. Notarás que estos últimos no se visualizan y la ventanita Output muestra mensajes de “Failed to locate file...” (“No se pudo encontrar el archivo...”). Sucede que este proyecto aún no está construido.

Así que hagámoslo presionando el botón Build Project   de la barra de herramientas o seleccionando el menú Project > Build...

De inmediato verás que dicho botón cambia de icono  . No lo vuelvas a tocar hasta que retome su aspecto original. Cuando lo haya hecho, significa que la construcción del proyecto ha terminado y la ventana Output debería mostrar los resultados del proceso exitoso y el reporte de uso de memoria, como se indica en la figura de abajo.

Page 97: CURSO INTERNET Microcontroladores PIC

Ventana Output mostrando los resultados de una construcción exitosa.

Como la construcción fue exitosa, puedes intentar abrir otra vez los archivos resultantes del proyecto como *.asm o *.hex. Todos estos archivos se generan por defecto en la misma carpeta donde se encuentra el archivo del proyecto; en este caso en carpeta “C:\Archivos de programa\SourceBoost\Samples\C\BoostC”.

Práctica 1 Creación de un proyecto en BoostC

El proyecto que construimos en la presentación de BoostC era uno de los ejemplos que traía incluidos el compilador. En esta práctica vamos a crear un proyecto nuevo desde cero.

El Circuito

Ninguna de las prácticas de este capítulo necesita ser implementada físicamente. Muchas (casi todas) son las mismas que realizamos en el Módulo 1; solo que en versión C. Así no tenemos que preocuparnos ni de armarlos para saber como funcionan en la vida real (porque ya lo hemos visto). Bastará con verlos en un buen simulador como Proteus. Proteus será especialmente útil porque nos permitirá apreciar el flujo de ejecución de un programa en C: sentencia por sentencia, más que línea por línea como en el ensamblador.

Así que empezaremos con la misma práctica con que empezamos MPLAB IDE y Proteus VSM, con el programa que muestra dos LEDs prendidos que se desplazan desde el centro hacia los costados indefinidamente; un secuencial, un LED flasher o como le quieras llamar.

Page 98: CURSO INTERNET Microcontroladores PIC

El circuito.

El código fuente

La explicación de este código se presenta en la subsiguiente sección.//****************************************************************************// FileName: LedFlasher.c // Processor: PIC16F84A// Compiler: BoostC//****************************************************************************

#include <system.h> // Incluir este archivo /* La siguiente directiva establece los Bits de Configuración */#pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _PWRTE_ON

/* La siguiente directiva configura la frecuencia de reloj */#pragma CLOCK_FREQ 4000000

void main(void){ trisb = 0x00; // Configurar PORTB para salida while(1) // Bucle infinito { portb = 0b00000000; // Sacar 0b00000000 a PORTB delay_ms(200); // Pausa de 200ms portb = 0b00011000; // ... delay_ms(200); portb = 0b00100100; delay_ms(200); portb = 0b01000010; delay_ms(200); portb = 0b10000001; delay_ms(200); }}

Page 99: CURSO INTERNET Microcontroladores PIC

Procedimiento

En el menú Project hay disponibles varias formas de crear un nuevo proyecto, incluyendo el clásicoWizard... (asistente). Lamentablemente ese Wizard aún no está muy completo. Así que vamos a tomar el camino que nos da la opción New... Se nos abrirá un cuadro de diálogo para nombrar a nuestro nuevo proyecto. No es necesario escribir la extensión, solo escogemos un nombre prudente y lo guardamos en una carpeta adecuada. (Es siempre recomendable tener cada proyecto en una carpeta diferente.)

Cuadro de diálogo para nombrar el nuevo proyecto.

A continuación se nos presenta la ventanita que pide seleccionar básicamente la toolsuite a usar (¿aún recuerdas lo que es una toolsuite?). El IDE de SourceBoost puede administrar proyectos con los compiladores BoostC, BoostBasic, C2C, entre otros. Los productos estrella son, por supuesto, BoostC y BoostC++ (que para las prácticas de este curso funcionarán igual); así que seleccionamos cualquiera de ellos. En el área superior escogemos with empty source file (con archivo fuente vacío) para que no tengamos que añadirlo después.

Selección de la toolsuite a usar.

Page 100: CURSO INTERNET Microcontroladores PIC

Práctica 2

En ensamblador solíamos redirigir el flujo de un programa utilizando instrucciones de salto como elgoto. Aunque en C también existe una sentenciagoto, que hace casi lo mismo, su uso está sensurado por las buenas prácticas de programación. Si algún programador respetable viese un goto injustificado en tu programa, se reiría de él. Las formas de hacer estas operaciones es mediante las sentencias de control de programa como if (y similares), while, for, etc.

El programa enciende un LED más de los ocho conectados al puerto B cuando se presiona un botón, y apaga otro LED más cuando se pulsa otro botón.

El Circuito

El circuito.

El código fuente

//****************************************************************************// FileName: OnOffLEDs.c// Processor: PIC16F84A// Compiler: BoostC// Purpose: Operadores, sentencia if, bucle while.//****************************************************************************

#include <system.h>

#pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _PWRTE_ON

#pragma CLOCK_FREQ 4000000

Page 101: CURSO INTERNET Microcontroladores PIC

void main(){ char t = 0; // Declarar variable t e inicializarla a 0 trisa.4 = 1; // Pin RA4 entrada trisa.3 = 1; // Pin RA3 entrada trisb = 0x00; // PORTB como salida portb = 0x00; // Limpiar PORTB while(1) // Bucle infinito { if (porta.4==0) // Si RA4 vale 0, ejecutar sig, bloque { t <<= 1; // Desplazar t a la izquierda t |= 0x01; // Setear bit 0 de t portb = t; // Colocar en PORTB delay_ms(40); // Delay antirrebote while(porta.4==0) // Mientras RA4 valga 0, esperar continue; }

if (porta.3==0) // Si RA3 vale 0, ejecutar sig. bloque { t >>= 1; // Desplazar t a la derecha t &= 0x7F; // Limpiar bit 7 de t portb = t; // Colocar en PORTB delay_ms(40); // Delay antirrebote while(porta.3==0) // Mientras RA3 valga 0, esperar continue; } }}

Descripción del programa

El cuerpo de la sentencia while(1) tiene dos sentencias if. Cada sentencia if a su vez tiene varias sentencias más. Así son los programas en C, sentencias conteniendo sentencias y más sentencias.Las sentencias if del programa comparan los bits RA4 y RA3 de PORTA con 0. Valdrán 0 cuando los botones en dichos pines estén pulsados. Claro que sabemos cémo funciona todo eso. Mi punto era este: podemos leer una expresión con el operador == diciendo ‘igual’; por ejemplo:

if (porta.4==0) // Si RA4 vale 0, ejecutar sig, bloque

se leería “si el bit 4 de PORTA es igual a 0, entonces...”. Sin embargo, no debemos confundirlo con el operador =, que transfiere el valor de un dato, variable o una expresión a otra variable. Suele ser un error frecuente en los diseñadores noveles no detectable fácilmente porque el compilador no dará errores. Por ejemplo, esta expresión también es totalmente válida:

if (porta.4 = 0) // Si RA4 igualado a 0 es diferente de 0...

Significa que primero se asigna el valor 0 al bit 4 de PORTA y después se comprueba si ese valor es verdadero. Por supuesto que nunca lo será.

Sigamos con más operadores.

t <<= 1; // Desplazar t a la izquierda t |= 0x01; // Setear bit 0 de t

Page 102: CURSO INTERNET Microcontroladores PIC

Aquí vemos un ejemplo del uso de operadores compuestos. Por si aún no te acostumbras a su forma, puedes desenvolver imaginariamente las sentencias de esta forma:

t = t << 1; // Desplazar t a la izquierda t = t | 0x01; // Setear bit 0 de t

Supongo que ahora está más claro. t << 1 significa desplazar la variable t una posición a la izquierda yt | 0x01 significa aplicar la operacion OR binaria entre la variable t y la constante 0x01. Para más información sobre estos temas puedes releer la sección Los operadores.En realidad, en BoostC también es posible modificar un bit en una variable mediante el operador punto (.) o utilizando una macro como set_bit o clear_bit. Así por ejemplo, t | 0x01 es equivalente a cualquiera de estas formas:

t.0 = 1; // Setear bit 0 de t set_bit(t, 0); // Setear bit 0 de t

set_bit es una macro definida en el archivo boostc.h y si alguna ves lo llegas a examinar, verás que también está implementada con el operador |.En boostc.h también están las macros clear_bit y toggle_bit, que limpian o permutan un bit de una variable cualquiera. Pero como este operador punto no es parte del C estándar y como boostc.h es propio de BoostC, yo prefiero emplear los operadores or binaria (|), and binaria (&) y xor binaria (^) para realizar esas operaciones. Espero que no me maldigas por eso.

Finalmente, asumo que ya sabes para qué ponemos esos delays antirrebotes y por qué tenemos que esperar mientras RA4 valga 0.

while(porta.4==0) // Mientras RA4 valga 0, esperar continue;

El cuerpo de este bucle while se ejecutará mientras el bit 4 de PORTA valga 0 (mientras el botón en cuestión esté pulsado). continue es una sentencia que salta al lugar después de la última sentencia del bloque de while. ¿Qué significa todo esto?, ¿cuál bloque?Significa que mi continue está de adorno ;) ya que el bloque de este while solo tiene una sentencia (el mismo continue). En consecuencia, bien pude haber escrito esa construcción así:

while(porta.4==0); // Mientras RA4 valga 0, esperar

que es su presentación más habitual, o de esta otra forma:

while(porta.4==0) { } // Mientras RA4 valga 0, esperar

Yo acostumbro poner el continue solo para que en la depuración o simulación del código se vea mejor :) ¡Tanto para eso!...

Page 103: CURSO INTERNET Microcontroladores PIC

Práctica 3

En esta práctica seguiremos usando las sentencias selectivas (if – else en este caso) y también veremos la forma de manejar los arrays unidimensionales para trabajar con matrices de datos en operaciones que en ensamblador las resolvíamos mediante las tablas (de búsqueda).

El programa visualiza un contador hexadecimal que avanza de 0 a 15 en modo ascendente si un switch conectado al pin RA2 marca un 1 lógico. El contador avanza en modo descendente si el switch marca 0 lógico.

El Circuito

El circuito

El código fuente

//****************************************************************************// FileName: HexCounter.c// Processor: PIC16F84A// Compiler: BoostC// Purpose: Sentencia if-else, array constante en BoostC.//****************************************************************************

#include <system.h> #pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _PWRTE_ON

#pragma CLOCK_FREQ 4000000

#define swich porta.2 // switch esta conectado a RA2#define Top 12 // Cima de conteo es 12 = 0x0C

rom char * Code7seg = // Array constante almacenado en rom (FLASH){ 0b00111111, // 7-segment code of 0. Format: 0bxgfedcba , x=don't care 0b00000110, // 7-segment code of 1. ... 0b01011011, // 7-segment code of 2 0b01001111, // 7-segment code of 3

Page 104: CURSO INTERNET Microcontroladores PIC

0b01100110, // 7-segment code of 4 0b01101101, // 7-segment code of 5 0b01111101, // 7-segment code of 6 0b00000111, // 7-segment code of 7 0b01111111, // 7-segment code of 8 0b01101111, // 7-segment code of 9 0b01110111, // 7-segment code of A 0b01111100, // 7-segment code of B 0b00111001, // 7-segment code of C 0b01011110, // 7-segment code of D 0b01111001, // 7-segment code of E 0b01110001, // 7-segment code of F};

void main(){ unsigned char Count; // Declara variable Count trisb = 0x00; // Salida para display trisa.2 = 1; // Pin RA2 entrada

if(swich) Count = 0; // Si swich vale 1, iniciar desde 0 (modo asc) else Count = Top; // De lo contrario, iniciar desde Top (modo desc) while(1) // Bucle infinito { portb = Code7seg[Count]; delay_ms(250); delay_ms(250); if (swich) // Si swich vale 1, ejecutar sig. bloque { if (Count < Top) // Si Count < Top Count++; // Incrementar Count else Count = 0; // De lo contrario, reiniciar Count } else // De lo contrario, ejecutar sig. bloque { if (Count) // Si Count > 0 Count--; // Decrementar Count else Count = Top; // De lo contrario, reiniciar Count } }}

Descripción del programa

Hay cuatro temas que voy a tocar sobre este programa. El primero es la directiva #define. Nosotros ya sabemos cómo funciona: sustituye el identificador por el texto subsiguiente. En C existe además la posibilidad de realizar construcciones mucho más complejas, pero la forma típica de usarlas es como ya sabemos.Pasando al siguiente punto: la sentencia if – else ejecuta uno de dos bloques de sentencias, según la condición verdadero-falsa de una expresión. Es muy fácil entender esta condición en una expresión como:

if (Count < Top) // Si Count < Top

Page 105: CURSO INTERNET Microcontroladores PIC

La expresión entre paréntesis será verdadera cuando ‘Count sea menor que Top’. ¡Qué novedad!... Ahora bien, ¿cómo se evalúa esta expresión

if (swich) // Si swich vale 1, ejecutar sig. bloque

o esta otra?

if (Count) // Si Count > 0

¿Con qué valores se comparan swich y count? Bien, en C una expresión no relacional (con operadores de comparación como >, <, ==, etc.) será verdadera si es diferente de cero; o, dicho de otra forma, solo será falsa si vale 0 y en cualquier otro caso será verdadera.Claro que para evitar las dudas estas sentencias bien se pudieron haber escrito empleando los operadores igual (==), diferente (!=) u otros, así:

if (swich != 0) // Si swich es diferente 0,... // ... if (Count > 0) // Si Count > 0,...

Pero a los programadores de C nos da pereza tipear más código de lo necesario. Quizá este estilo te disguste en un inicio pero pronto estarás de acuerdo con nosotros. No lo olvides: una expresión no relacional simple es verdadera si vale diferente de 0 y es falsa cuando vale 0.El tercer tema era el array Code7seg. Esta forma de declarar los Arrays constantes, con la palabra reservada rom y el asterisco, es propia del compilador BoostC; así que no le busquemos mayor lógica porque va a variar en otro compilador.

rom char * Code7seg = // Array constante almacenado en rom (FLASH){ 0b00111111, // 7-segment code of 0. Format: 0bxgfedcba , x=don't care // ... 0b01110001, // 7-segment code of F};

Nota que los elementos deben ir separados por comas; de modo que no es necesario que vaya uno por cada línea. Lo escribí así solo para que se distingan mejor.

Lo que no debería variar en ningún compilador C es el acceso a los elementos del array, mediante corchetes e índices. Así la sentencia

portb = Code7seg[Count];

envía al puerto B el elemento número Count del array Code7seg. En C el primer elemento siempre es el 0.Finalmente, pasemos al cuarto punto: el tipo de dato ideado para trabajar con números enteros en el C estándar es int (entero de 16 bits con signo, suficiente para alojar la gran mayoría de los datos procesados en un programa). Sin embargo, en el mundo de los µCs la RAM no es un recurso que se caracterice por abundar.Es por eso que se muchas veces se suele usar el tipo char, que fue inicialmente concebido para almacenar caracteres (characters) ASCII (de 8 bits), como ‘a’, ‘5’, ‘#’, etc. A este tipo se le han añadido los especificadores signed (con signo) y unsigned (sin signo) para formar los tipos:

signed char establece variables enteras de 8 bits con signo (desde –128 hasta +127). unsigned char establece variables enteras de 8 bits sin signo (desde 0 hasta 255).

Page 106: CURSO INTERNET Microcontroladores PIC

char también se puede usar para almacenar números, pero funcionará ambiguamente, a veces comosigned char y otras como unsigned char, según el compilador entre otras cosas.Si los datos usados en el programa no requieren formato, se podrán usar los tres tipos indistintamente sin que funcione mal y sin que el compilador “se dé cuenta”.Sin embargo, si las variables van a trabajar como números en operaciones aritméticas o relacionales de comparación, será necesario aplicarles el signed o unsigned respectivo.

Descripción del programaEste programa tiene dos funciones: main (infaltable) y Flash, para la que no fue necesario escribir suprototipo de función porque la puse encima de main.Tratemos esta extraña construcción:

for(;;) // Bucle for sin condiciones (infinito) { // Bloque o cuerpo del bucle for // ... }

El bucle for ejecuta un bloque de sentencias según ciertas condiciones que contiene entre los paréntesis. En este programa esas condiciones no existen, lo que para el compilador significa que es un bucle infinito, justamente igual que nuestros anteriores while (1). Se suele usar una u otra forma indistintamente.Ahora veamos los bucles for que sí tienen límites, pero antes quiero que sepas porque uso for y no los bucles while o do-while, que en un inicio pueden ser los más simples. Cuando uno tiene un enunciado que describe alguna forma de conteo, de inmediato debe pensar en el bucle for. Así, cuando yo entendí que para que el LED se desplace de uno a otro lado debe recorrer 8 posiciones, de inmediato imaginé un bucle de la forma for(i=0; i<8; i++).

t = 0b00000001; // Inicializar t for(i=0; i<8; i++) // Bucle que cuenta desde 0 hasta 7 { Flash(t); // Llamar función Flash t <<= 1; // Desplazar t una posición a la izquierda }

Y ahí lo tienes. Lo demás es solo acomodar el código para que el LED se desplace una posición en cada ciclo. La otra sentencia for, para desplazar el LED hacia la derecha, funciona análogamente.En ambos bucles for de main el LED debe parpadear 5 veces en cada ciclo. Así que, para no redundar en código, pensé en una función aparte que hiciera esa tarea.

void Flash(char dato){ unsigned char i; // Declarar variable i for(i=0; i<5; i++) // Bucle que cuenta desde 0 hasta 4 (5 ciclos en total { portb = dato; // Dado a PORTB delay_ms(30); // Pausa portb = 0; // Limpiar PORTB delay_ms(30); // Pausa }}

La función Flash debe mostrar el valor de t en PORTB intermitentemente, 5 veces según el enunciado. Así que pensé automáticamente en otro for, ahora de la forma for(i=0; i<5; i++). (Resulta hasta entretenido codificar así.)

Page 107: CURSO INTERNET Microcontroladores PIC

Ahora bien, como la función Flash no puede acceder a t dado que es variable local de main, ha tenido que implementada para que reciba su valor como parámetro de entrada en dato. De ese modo, al llamar a Flash con la sentencia

Flash(t); // Llamar función Flash

El valor de la variable local t se copia a la variable local dato. Para más información sobre el paso de parámetros ir a Funciones con parámetros (por valor).Habrás notado que en la función Flash hay otra variable i. Ésta no tiene ninguna relación con la i de la función main. Ambas son variables locales independientes una de la otra porque pertenecen a sus respectivas funciones. Para más información al respecto pueder releer la sección Variables locales y variables globales.Debo aclarar que el procedimiento descrito es la forma como diseñe el programa. Es solo uno de los tantos algoritmos que se pueden idear para cumplir con el enunciado planteado al inicio. Por ejemplo, al examinar el código de main podemos ver que bien se pudo haber escrito de esta otra forma, más compacta:

void main(){ unsigned char i; trisb = 0x00; for(;;) { for(i=0; i<8; i++) Flash(0x01<<i) for(i=0; i<8; i++) Flash(0x80>>i) }}

En general, siempre podrás encontrar más de un algoritmo alternativo para cualquier tarea. Una cosa es escribir un código que cumpla con un determinado propósito y otra cosa es hacerlo de una forma más elegante. Hay quienes pueden escribir poesía con sus códigos.

Así como no basta con que una persona nazca con el talento, sino que debe de ejercitarlo para convertirse en poeta, así también la única forma de desarrollar tu “kung fu” es practicar y practicar, y estudiar los buenos códigos de otros programadores.Para terminar, una vez acabado un programa y probado su correcto funcionamiento, viene la etapa de optimización. La palabra optimización, tiene básicamente dos formas: de código, para que el tamaño de memoria utilizada sea el menor posible, y de velocidad de ejecución, para que el código resultante la ejecute el PIC con la mayor velocidad. En general ambos requerimientos se contraponen: es muy raro obtener un programa que se compile en el menor código hex y que al mismo tiempo sea más rápido de ejecutar.Por ejemplo, la alternativa a la función main presentada arriba es más compacta pero genera mayor código y también se ejecuta en mayor tiempo. En este programa, claro está, eso ni se nota ni interesa; tal vez en otros diseños sí.