Empezando con PICs
Es un articulo del blog de NetAndTech que conseguí en Internet, muy bueno, lo copio en mi blog con el mismo titulo, haciendo el respectivo trackback al post original
el post: http://netandtech.wordpress.com/hardware/empezando-con-pics
Conseguí ese post porque ando buscando información sobre ese mundo entre el hardware y el software, lo vi como un buen comienzo para mi, espero que le sirva a otros
a continuación el post:
Empezando con Microcontroladores
Antes de nada, quisiera explicar el motivo por el que escribo esta “documentación”. Seguro que hay muchos escritos sobre microcontroladores en la Web. ¿Por qué otro más? Bueno, este no quiere ser otro más. No pretendo crear un curso de microcontroladores, puesto que un curso debe abarcar una gran cantidad de datos generales, que yo no abarcaré. No. Más bien, lo que pretendo es escribir una serie de “recetas” que me ayuden (a mi y a cualquiera que las necesite) cuando quiera recordar algo determinado: ICSP, conversión A/D, buses I2C, SPI, USART, etc. Así pues, estos documentos mayormente pretender subsanar la poca capacidad de almacenamiento de datos que tengo
Como también pretendo que puedan ser útiles para mucha gente (por que sino escribirlos aquí), pues intentaré empezar por cosas sencillas y básicas, y hacerlo todo lo más comprensible posible. Una de las cosas que no haré será dar explicaciones extensas sobre temas relacionados. En su lugar, intentaré dejar recursos suficientes para los autodidactas que pretendan saber más.
En cuanto al “background” que debería tener todo aquel que quiera comprender esto, no soy muy exigente. Lo más importante es que le guste aprender y no se canse pronto: las cosas nunca salen a la primera. Eso es imprescindible. El que sepa algo de sistemas informáticos, programación y electrónica no viene nada mal, pero no es vital.
Ah, un pequeño detalle más: ¿te puedo tutear? Excelente.
Empecemos
La pregunta del millón: ¿que es un microcontrolador? Pues básicamente un microcontrolador es un dispositivo electrónico de pequeño tamaño capaz de realizar operaciones e interactuar con el entorno exterior para llevar a cabo una tarea. Generalmente son circuitos integrados (IC, Integrated Circuit) programables, es decir, el usuario puede decidir que labor va a desempeñar, codificando en algún lenguaje los pasos que debe dar.
Para entendernos, podemos hacer una analogía con un PC. En un PC, a groso modo, tenemos diferentes dispositivos que desempeñan diversas labores. Contamos con una Unidad Central de Proceso (CPU, Central Proccess Unit) que se encarga de los cálculos, una unidad de almacenamiento para nuestros programas y/o datos personales y dispositivos periféricos para la interactuación humana con el PC (HID, Human Interface Devices). En un microcontrolador podemos encontrar las mismas funcionalidades: contamos con una UCP para ejecutar nuestros programas, un espacio donde almacenarlos así como nuestros datos, y una interfaz de comunicación con el exterior.
Si quieres una definición más exacta y más extensa, así como detalles sobre la arquitectura de un microcontrolador PIC, puedes irte al “datasheet” de cualquier PIC de microchip, disponibles en su página web: www.microchip.com o a la entrada sobre PIC’s en la Wikipedia.
Existen muchos fabricantes de microcontroladores, así como diversas arquitecturas e implementaciones. En general hablaré de una familia muy conocida y para la cual existen muchas herramientas: los PIC de microchip. Esto no quiere decir que deje de lado a los AVR de Atmel o a los preciosos ARM. ¡Ni que decir tiene! Hablaremos de ellos en otro momento.
Me gustan los PIC’s por diversas razones. En primer lugar, porque existen muchas herramientas para trabajar con ellos. En segundo lugar, porque existe una extensa documentación al respecto, sobre todo los datasheets que ofrece el fabricante y los AN’s (Application Notes) que son muy interesantes. También por que existen herramientas tanto hardware como software libres para programarlos, depurarlos, emularlos, etc. Otra cosa que me llama la atención es su reducido precio. Y alguna otra razón personal que no recuerdo.
Algunas notas sobre los PIC’s
Los PIC’s componen una familia extensa de microcontroladores, cada uno con sus peculiaridades que serán comentadas cuando hablemos de ellos. Sin embargo, podemos citar características comunes a todos ellos. Por ejemplo, los PIC’s están diseñados siguiendo la arquitectura Harvard, en donde la memoria de datos está separada de la de programa. También son RISC (Reduced Instruction Set Computer), es decir, cuentan con un número reducido de instrucciones, en concreto con unas 35 (depende del microcontrolador). Suelen tener una memoria Flash para programas y una EEPROM para datos.
Entorno de trabajo
Entremos en lo interesante. Para empezar vamos a diseñar un simple “proof of concept”, es decir, haremos un pequeño programa que simplemente configurará el PIC para que encienda y apague un LED a la frecuencia de 1Hz (aprox.), lo compilaremos y lo grabaremos en el PIC elegido. Después montaremos una placa de prototipos con el micro y todo lo necesario para que funcione. Básicamente, estos son los ingredientes necesarios:
- PICmicro: El microcontrolador que vamos a emplear. En este caso vamos a usar uno de gama media, el PIC16F84A (si no tienes este, para un ejemplo tan sencillo como este seguro que te vale cualquiera, pero has de tener en cuenta las diferencias entre ambos en todo momento). Es un micro sencillo, de 18 pines, con 68 bytes de RAM, 64 bytes de EEPROM (para datos) y 1KiB (Kilo-Information-Byte = 1024 bytes) para programas.
- Programador: Necesitamos el hardware necesario para escribir el programa que hagamos en el PIC. Microchip ha diseñado diferentes programadores, que puedes conseguir de cualquier distribuidor o desde su Web, a un precio moderado. Desde luego, esa suele ser la mejor opción, pero hay más. Puedes por ejemplo, tomar el datasheet de uno de los modelos de Microchip, en el que te vienen los esquemas e incluso el PCB, para hacerlo tu mismo. O puedes tomar algún programador libre de los que circulan por la red e implementarlo. Simplemente busca por Pic programmer. El que yo usaré será el PICSTART PLUS de Microchip, pero el PicKit 2 funciona bastante bien y no es tan caro. Busca información si tienes dudas.
- ProtoBoard: Necesitamos un sitio donde ensamblar los componentes. Una placa de prototipos sencilla nos vendrá de perlas, junto con el set de jumpers adecuado (puedes usar un trozo de cable UTP de pares trenzados). No cuesta mucho en las tiendas de electrónica. Si no tienes una, va a ser difícil hacer las pruebas, porque tendrás que ingeniártelas para conectar los componentes entre sí (soldándolos en una placa perforada por ejemplo).
- Componentes: Este ejemplo es muy sencillo, por lo que el número de componentes es muy reducido. Necesitamos:
- 1 Cristal de cuarzo de 4 MHz
- 2 Condensadores de entre 15 y 33 pF (yo los uso de 22 pF)
- 1 Resistencia de 1K (1KOhm) 0.25W
- 1 LED
- Herramientas: Básicamente una fuente de alimentación estable de entre 2 y 5V de poca potencia (los PIC’s consumen muy poco): puedes usar 3 pilas de 1.5V, una fuente de alimentación estabilizada regulable, etc. Además te sería útil un polímetro, unos alicates y unas pinzas.
- Software: GNU/Linux. A ser posible Debian. Por mi parte, prefiero hacer las cosas con herramientas libres. Existen muchas utilidades libres disponibles. Si no tienes Debian pero si otro GNU/Linux, puedes buscar los binarios empaquetados para tu distribución o las fuentes para compilarlas tu mismo. Si usas Debian, todas las herramientas están disponibles en los repositorios oficiales. Si no tienes GNU/Linux, lo siento por ti :-(. Tienes IDE’s de desarrollo disponibles, como el MPLAB de Microchip para Windows, o el IcProg, e incluso las gputils están portadas para Windows y Mac OS X, pero yo no te puedo dar soporte para ninguna porque yo no uso Windows :-). Las herramientas son:
Cada una se explicará en su momento. Algo que quiero reseñar es que todas estas herramientas se pueden englobar bajo GNUPIC, en donde puedes encontrar muchos proyectos libres para trabajar con PICS, desde programadores (hardware y software), simuladores… hasta librerías e IDE’s.
Si visitas la página de GNUPIC verás que decantarse por un entorno de trabajo libre es una buena opción. Recuerda que siempre puedes instalarte GNU/Linux, pero de eso, hablaremos otro día :-).
Antes de programar
No podemos ponernos a programar el PIC sin antes saber que estamos haciendo. Nuestro objetivo es dotar al microcontrolador del conjunto de instrucciones que queremos que siga. Todas esas instrucciones pertenecen al juego de palabras que el microcontrolador entiende. El PIC es electrónico y solo entiende datos en binario. Pero decirle los pasos que debe seguir en binario sería una labor hercúlea, así que usamos un lenguaje mnemotécnico más sencillo, que consta de unas 35 instrucciones. Estas instrucciones son atómicas, realizan labores individuales bien diferenciadas. Las iremos conociendo poco a poco.
Por otro lado, debemos saber que un PIC ejecuta las instrucciones de una forma secuencial, es decir, una detrás de la otra (aunque gracias al pipeline, tenemos cierto solapamiento, pero eso de momento no nos incumbe). Eso no quiere decir que si escribimos 10 instrucciones, la número 3 se ejecutará antes que la 5. ¿Como? Es sencillo si tienes en cuenta que contamos con instrucciones que sirven para dar saltos. Así pues, podemos saber el flujo de ejecución del programa de una forma relativamente sencilla.
Otra cosa importante a saber es que podemos referenciar posiciones de memoria específicas, cosa muy útil a la hora de acceder a los “periféricos” del PIC, porque suelen ser accesibles como si fuesen posiciones de memoria. Un ejemplo claro de esto son los puertos del PIC. En un PIC, la manera más usual de comunicarse con el mundo exterior es por medio de los PUERTOS. Estos no son sino registros especiales que están mapeados con ciertos pines del integrado. Es decir, que podemos acceder a una posición de memoria (un registro realmente) en el que podemos leer el nivel de las señales que entran en un conjunto de pines del circuito. Por ejemplo, podemos tener un puerto llamado PORTA, de 1 byte, es decir 8 bits. Cada uno de estos bits está mapeado con una patita del CI. Por ello, si todas las patitas tienen un nivel lógico bajo (es decir, un 0), cuando leamos el registro PORTA, leeremos ‘00000000′. En cambio, si todas tuviesen un nivel lógico alto (es decir, un 1), leeríamos ‘11111111′, etc.
En este caso, cuando leemos el PORTA, estamos leyendo un registro, es decir, una celda de memoria que contiene un valor. Existen múltiples registros en un PIC, algunos de propósito específico, como el PORTA, y otros de propósito general, que podemos usar para guardar lo que queramos. Existe un registro especial, llamado Working Register, o simplemente W, que cumple un cometido específico. Podemos decir que nos sirve de comodín para muchas instrucciones, y donde se guardan los resultados de muchas operaciones. Lo veremos con más profundidad un poco más adelante.
Por último, recomiendo encarecidamente que te leas el datasheet del PIC que vayas a usar, pues tiene mucha información muy bien explicada de todo el integrado. Ahí es donde vas a aprender muchas cosas interesantes que aquí no voy a explicar. Particularmente, suele contener el juego completo de instrucciones, los bancos de registros, un diagrama de su ALU para ver el flujo de datos, así como características específicas de cada PIC. Para este ejemplo, nos será util tener el Pinout del PIC16f84A:
Primera aproximación
Todo esto se puede entender fácilmente con un ejemplo. Vamos a escribir unas cuantas instrucciones y ver que es lo que hacen. Verás como son muy intuitivas y sencillas de recordar.
movlw 240 ; Mueve el literal al registro W,
; es decir, pone en W el valor 240.
clrf 0x10 ; Pone a 0 el registro 0x10
movwf 0x10 ; Pone el valor de W en el registro 0x10
addwf 0x10,1 ; Suma el contenido de W con el del registro
; 0x10 y lo deja en el mismo registro 0x10
Se puede observar que las instrucciones hacen cosas bien definidas. Simplemente manipulan datos o registros, o el flujo de ejecución del programa, pero siempre de una manera controlable. Algo que todavía no he comentado es la existencia de un registro especial, llamado STATUS, que almacena el estado del PIC. Cada uno de sus bits es una bandera sobre un hecho determinado. Por ejemplo, sabemos que si sumamos dos valores de 8 bits el resultado puede ser mayor de 8 bits. Si esto ocurre, se produce un overflow. En ese caso, se pone a 1 una bandera llamada C (de Carry, Acarreo). Veremos todas las banderas cuando las usemos.
Observemos más de cerca el PIC que vamos a usar. Es un integrado de 18 pines, como ya sabemos. Dos de ellos están destinados a la alimentación, Vdd y Vss. Otros dos los podemos usar para la señal de reloj, que es una señal que marca el ritmo de trabajo del PIC. Estos son OSC1 y OSC2. El MCLR es el pin de RESET, que nos sirve para reiniciar el microcontrolador. Luego tenemos los pines de dos PUERTOS: A, de 5 bits (RA0-RA4) y B, de 8 bits (RB0-RB7). Veamos que podemos hacer con ellos :-).
Codigo del ejemplo
Bueno, nos vamos a dejar de teoría y vamos a escribir el programa final. Intentaré explicarlo detenidamente, resaltando aquellas cosas que no hemos visto todavía. El código lo puedes escribir con tu editor de textos preferido, siempre y cuando lo guardes como texto plano no formateado. Yo te recomiendo Emacs (no solo para esto, sino para todo :-)). Todo lo que se escribe despues de un “punto y coma” (;), es un comentario y el compilador lo ignorará.
;;; Ejemplo de programación PIC ;;; Oscar Aceña (C) 2007 ;;; Cambia el estado de RA0 con una ;;; frecuencia aproximada de 1 Hz. list p=pic16f84 ; Le indica al compilador ; que micro usar. include <p16f84.inc> ; Añade las constantes a usar. ;; Directiva de comfiguración de micro __CONFIG _CP_OFF & _WDT_OFF & _XT_OSC org 0 ; Dirección de memoria 0 goto main ; Salto a la etiqueta main. org 4 ; Dirección de memoria 4 retfie ; Retorna si re produce una excep. TIME1 equ d'255' ; Constantes TIME2 equ d'227' TIME3 equ d'6' REG1 equ 0x10 REG2 equ 0x11 REG3 equ 0x12 main: bsf STATUS,RP0 ; Banco 1 bcf TRISA,0 ; RA0 como salida bcf STATUS,RP0 ; Banco 0 up: bsf PORTA,0 ; RA0 a 1 movlw TIME3 ; movemos el valor de TIME3 movwf REG3 ; en el registro REG3 _up1: movlw TIME2 ; movemos el valor de TIME2 movwf REG2 ; en el registro REG2 _up2: movlw TIME1 ; movemos el valor de TIME1 movwf REG1 ; en el registro REG1 decfsz REG1,F ; Decrementamos REG1 y volvemos aqui goto $-1 ; si el resultado no es cero. decfsz REG2,F ; Decrementamos REG2 y volvemos aqui goto _up2 ; si el resultado no es cero. decfsz REG3,F ; Decrementamos REG3 y volvemos aqui goto _up1 ; si el resultado no es cero. down: bcf PORTA,0 ; Ponemos RA0 a 0 movlw TIME3 ; movemos el valor de TIME3 movwf REG3 ; en el registro REG3 _down1: movlw TIME2 ; movemos el valor de TIME2 movwf REG2 ; en el registro REG2 _down2: movlw TIME1 ; movemos el valor de TIME1 movwf REG1 ; en el registro REG1 decfsz REG1,F ; Decrementamos REG1 y volvemos aqui goto $-1 ; si el resultado no es cero. decfsz REG2,F ; Decrementamos REG2 y volvemos aqui goto _down2 ; si el resultado no es cero. decfsz REG3,F ; Decrementamos REG3 y volvemos aqui goto _down1 ; si el resultado no es cero. goto up ; Volvemos a 'up' end ; Finaliza el codigo
Guárdalo con la extensión .asm, por ejemplo ‘test.asm’.
No te preocupes por el hecho de que sea mucho código y de que no entiendas muchas cosas. Vamos poco a poco. En primer lugar, ignora si quieres todos los comentarios, solo sirven para aclarar un poco el código. Quizá sea un poco más limpio sin ellos.
Lo que debemos distinguir en toda esa lista de instrucciones son dos grandes grupos: las propias del microcontrolador y las que son para el compilador. El compilador es un software que básicamente traduce las instrucciones en ASM (es decir, lo que nosotros escribimos) a código máquina (es decir, lo que el PIC entiende). Para facilitarnos la tarea, el compilador acepta ciertas órdenes. Por ejemplo, la primera de todas, “list p=pic16f84″, le indica al compilador que queremos que compile el código para un pic 16f84.
La seguna orden también es para el compilador: “include <p16f84.inc>”. Indica que se debe cargar un archivo llamado ‘p16f84.inc’, que se encuentra en la ruta predefinida del compilador. Este archivo contiene básicamente un conjunto de constantes para nuestro uso. Por ejemplo, cuando hacemos referencia a PORTA, lo que hacemos es usar una de esas constantes predefinidas. Así no tenemos que poner el valor númerico, 0×5. Si buscas ese fichero y lo abres, verás que contiene más instrucciones, del tipo “NAME EQU VALOR“. Eso nos hace ver que podemos dividir el código de nuestros programas en diferentes archivos, o que podemos tener una biblioteca de funciones que podemos usar en muchos casos, pudiendo reutilizar el código.
La tercera indica al programador como debe configurar el micro cuando se grabe el programa. Es una directiva de configuración. En este caso, le indica que no debe activar la protección de código (una opción de seguridad que impide que cualquiera pueda leer el contenido de un microcontrolador), _CP_OFF; también que debe desactivar un periférico interno de protección llamado WatchDog Timer, _WDT_OFF; y también le indica que como fuente de reloj vamos a usar un oscilador de cuarzo de tipo XT, __XT_OSC. Existen más opciones que veremos cuando sea necesario.
La siguiente directiva, “org 0″, le indica al programador que la próxima instrucción debe escribirla en la posición de memoria número 0. La instrucción que escribirá será “goto main”. La instrucción “goto” hace lo que debe hacer: un salto, es decir, la próxima instrucción que ejecutará será la que está marcada por la etiqueta ‘main’. Una etiqueta es un nombre que se le pone a una dirección de memoria, por ejemplo main. En PIC asm, podemos poner etiquetas donde queramos, siempre y cuando vayan después de un retorno de carro. Simplemente escribes el nombre y pones dos puntos, “main:”.
La siguiente instrucción nueva es “retfie”, que se escribirá en la posición 4 y no por capricho. En el pic, existe la posibilidad de que algún agente “externo” a la ejecución del programa tenga prioridad y se le atienda a él, utilizando un mecanismo llamado “interrupción”. Cuando se produce una interrupción, el 16f84 deja la instrucción que iba a ejecutar y se dirije a la posición 4, a ejecutar lo que allí haya hasta que se encuentre con la instrucción “retfie”, que le indica que debe volver a donde estaba. Contaremos más profundamente este mecanismo en otra entrega, por ahora nos vale entender que si se produce alguna interrupción, simplemente retorna sin hacer nada y sigue su curso el programa, por eso el “retfie”.
Las siguientes seis instrucciones son para el compilador. Simplemente se definen 6 constantes, usando el mecanismo antes mencionado: “NOMBRE EQU VALOR“. En adelante, cuando el compilador se encuentre con el NOMBRE lo sustituirá por su VALOR.
Lo siguiente, “main:”, es una etiqueta :-).
La próxima instrucción merece una pequeña explicación, pero breve. En el pic 16f84 existen, como sabes, diferentes registros. Lo que no sabes es que están distribuidos en diferentes conjuntos lógicos, llamados bancos, de igual tamaño. En el 16f84 hay 2 bancos. Por defecto, cuando hacemos referencia a un registro, como PORTA o 0×5, el micro nos devolverá el registro en el banco 0, es decir el 0×5 del banco 0. Si queremos que use otro banco, se lo debemos especificar. Esto lo hacemos poniendo a uno un bit en el registro de estado del sistema: RP0 en STATUS. Para ponerlo a uno, usamos la instrucción que pone a 1 un bit determinado: “bsf REG,BIT”, de Bit Set File (que no te confunda lo de File, hace referencia a un registro).
Lo siguiente, “bcf TRISA,0″ hace lo contrario, pone a 0 un bit de un registro. En este caso, el registro es TRISA, que es el registro de configuración del puerto A. Como los puertos en el PIC pueden servir de entrada/salida, debemos especificar si serán de entrada o de salida. Por defecto, están puestos como entrada (es decir, que si lees el registro TRISA leeras un 1 por cada patita). Como regla mnemotécnica, podemos asimilar que un 1 implica Input mientras que un 0 indica Output. Así que ponemos como salida (0) el pin 0 del puerto A.
Volvemos a indicar que queremos usar el banco 0: “bcf STATUS,RP0″.
Bien, hasta aquí todo era de configuración. Ahora empezamos a hacer lo que de verdad queríamos hacer. ¿Como podemos conseguir que ese pin de salida cambie cada segundo (aprox.)? Bueno, pues hay diversas maneras. La mejor de todas implica que explique conceptos sobre temporizadores e interrupciones así como unas cuantas instrucciones más. La más sencilla de ver, pero sin duda la peor es la que vamos a usar. :-). Así solo tendremos que utilizar 3 instrucciones nuevas más.
El método es sencillo. Como usamos un cristal de 4MHz, podríamos deducir que cada instrucción se ejecuta en un tiempo de 1/4000000 s, o lo que es lo mismo, 250 ns (nanosegundos). Pero debido a ciertas mejoras para conseguir algo de procesamiento paralelo (más bien semi-solapado), tenemos que cada pulso de reloj, internamente, se divide entre 4. Por ello, realmente, el periodo de instrucción es de 1us (1 microsegundo). Para conseguir que cada segundo cambie un pin del IC, tenemos que contar 1.000.000 de instrucciones, y entonces cambiar. ¿Como? Pues lo que podríamos hacer sería almacenar en un contador una cantidad, e ir restandole 1 hasta que se quede en 0. Bien, pero ¿que cantidad?. Debemos tener en cuenta que en el bucle principal, vamos a ejecutar 3 instrucciones de media: 1 para disminuir el contador, 2 para hacer el salto a la instrucción que disminuye (las instrucciones de salto suelen requerir dos ciclos). Por ello, necesitaríamos guardar 300.000 aprox. Pero eso, en binario ocupa más de 8 bits, que es el máximo que puede guardar un registro. Lo tenemos que dividir en etapas, 3 en este caso. Cada una almacena un valor y lo decrementa. Cuando una etapa termina, se decrementa el valor de otra y se inicia la primera de nuevo. Es un decremento en cascada.
Haciendo los cáluclos empíricamente, obtegno 255, 227 y 6 ya que 255*227*6*3 = 1041930, que es 1 segundo aproximado (con mucho error realmente, casi 42 ms, pero para el ejemplo nos basta. Si quieres refinar, cambia los números).
Así que guardamos en tres registros (REG1, REG2, REG3) los valores 255, 227 y 6. Decrementamos consecutivamente REG1. Cuando llegue a cero, decrementamos REG2 en 1 y volvemos a poner 255 en REG1 y a decrementarlo. Cuando REG2 llegue a 0, decrementamos en 1 a REG3 y volvemos a iterar sobre REG1 y REG2. Cuando REG3 sea 0, ya podemos cambiar el estado del pin 0 del PORTA.
Creamos dos bucles idénticos (aunque bien se podría reutilizar el mismo bucle), uno para encender el LED y otro para apagarlo, de forma que se ejecuta indefinidamente.
Las 3 instrucciones que faltan por explicar son:
“movlw VAL”, que coloca en W el valor VAL (MOVe Literal to W)
“movwf REG”, que mueve el valor de W al registro REG (MOVe W to File)
“decfsz REG,POS” que decrementa el registro REG en uno, colocandolo en W o en F, dependiendo de POS, y si el resultado es 0, salta la siguiente instrucción (DECrement File and Skip if Zero).
La última directiva, “end”, solo le indica al compilador que el código ASM termina ahí.
Compilando y programando
Bueno, espero que no hayas tenido muchos problemas hasta aquí. No es fácil la primera aproximación, pero seguro que te engancha :-).
El siguiente paso es compilar el código. Algo muy sencillo gracias a los compiladores. Si tuviéramos que hacerlo a mano…
El compilador que usaremos es “gpasm”, para GNU/Linux. Viene dentro de las gputils (y además está empaquetado para Debian, por lo que instalarlo es sencillísimo). Para compilar nuestro ejemplo, sólo tenemos que escribir:
$ gpasm test.asm
Si todo ha salido bien, obtendrás tres archivos más: test.hex, test.cod y test.lst. Quizá obtengas un mensaje como:
test.asm:28:Message [302] Register in operand not in bank 0. Ensure bank bits are correct.
No te preocupes, esta vez no es un error. Simplemente nos indica que estamos haciendo una operación con un registro que está en el banco 1. Es bueno saberlo, porque nos puede ahorrar más de un problema.
En cuanto a los ficheros que ha creado el compilador, ‘test.cod’ es un fichero codificado que nos servirá más tarde para simular la ejecución del programa. El ‘test.hex’ es una versión compilada, en hexadecimal, del programa. Será la que cargaremos en el PIC. Por último, test.lst, que prácticamente es un mapa de memoria e información sobre la compilación.
Para asegurarnos de que nuestro programa funciona como debiera, sería muy útil contar con algún mecanismo para simularlo directamente en nuestro PC. En este caso contamos con uno: gpsim. Gpsim posee una interfaz gráfica, pero en la versión que había cuando escribí esto, surgen algunos problemas. La depuración desde consola esta bastante lograda y permite usar funciones que no te permite la Gui. Para probar nuestro programa simplemente tecleamos:
$ gpsim -s test.cod
Se nos abrirán varias ventanas. Una de ellas controla la ejecución del programa. En otra podemos ver un mapa de los registros. También podemos ver el codigo fuente, y el contador de programa, que es un puntero a la instrucción en ejecución en ese momento. Otra cosa muy útil es el pinout, es decir, podemos ver el estado de los pines I/O del integrado: si están como entrada o salida y el nivel.
![]() |
![]() |
![]() |
![]() |
El interfaz es muy intuitivo. Podemos ejecutar el programa como si estuviera en un micro real, o ir paso a paso. También podemos especificar la frecuencia del reloj, o establecer puntos de ruptura donde se parará la ejecución del programa. En fin, puedes hacer pruebas para comprobar que todo funciona.
Una vez que estás convencido de que todo funciona correctamente, es hora de cargar el programa en el PIC. En primer lugar debes tener conectado el programador al PC. No importa si es usb o serie. Conectalo al pc e intenta verificar que el software te lo reconoce. Por ejemplo, si usas el PICSTART PLUS, puedes ejecutar esto:
$ picp /dev/ttyS0 -v
Si el programador está conectado al ttyS0, te dirá versión del firmware. Si te dice que no está conectado, aunque realmente lo está, puede ser que sea un ttyS diferente. Si no dice nada, es que está conectado, pero no reconoce el firmware que tiene (a mi me pasa si uso otro que no sea el PICSTART PLUS).
Si has comprobado que el programador está bien conectado, inserta el PIC y carga el programa. En el caso del picp, lo hacemos así (si usas otro, como el picprog, la página del manual te puede ayudar sobre las opciones disponibles, ‘man picprog’)
$ picp /dev/ttyS0 16f84 -wp test.hex
Esto graba (la opcion -w) en la memoria de programa (la opcion ‘p’) el fichero hexadecimal test.hex, para un pic 16f84, usando un programador conectado al ttyS0.
No tardará mucho. Una vez que lo hayas programado, puedes desconectar el programador y sacar el micro.
Pruebas finales
Ahora, lo que nos queda es probarlo en la placa de pruebas. El esquema del circuito que tenemos que hacer es muy sencillo. Lo primero es conectar el cristal a las patitas OSC1 y OSC2. A estas mismas patitas tenemos que conectar los dos condensadores de 22 pF uniéndolos a GND. Conectamos Vss a GND y Vdd a una fuente de +5V. Además también tenemos que conectar a +5V el MCLR, con una resistencia de 1K. Por último, conectamos un diodo LED a la patita RA0 y a GND con una resistencia de 1K.
Listo. Si le metemos corriente, el LED debería parpadear a la frecuencia de 1Hz (aprox.).
![]() |
|
![]() |
![]() |
Conclusión
Con las herramientas actuales, programar microcontroladores PIC es muy sencillo, como has visto. El programa de ejemplo no esta optimizado, ya que es posible hacer esto mismo de forma más precisa y con menos código, pero que implica conocer otros dispositivos del PIC que dejaré para más tarde.Podíamos haber hecho un ejemplo más sencillo, como encender simplemente un LED, pero eso es algo demasiado fácil como para que merezca la pena
.
Espero que hayas disfrutado y comprendido todo. Si tienes dudas, primero busca documentación y después pregunta.
¡Ahh! Quizá te interese la siguiente parte: un segundo con el PIC donde se pretenden hacer las cosas un poco mejor… ![]()




























