La Gaceta de Linux ...¡ haciendo a Linux un poco más divertido !

Construyamos un simpático juguete en Linux

Por Pramode C.E

Traducción al español por Javier Cano
el día 24 de Marzo de 2004, para La Gaceta de Linux

Muchos de nosotros vivimos en torno a Linux – pero, si alguien nos pregunta porque nos entra la locura por el, una respuesta muy común seria 'divertido'. Usar Linux es muy divertido – con el valor agregado que, la mayoría de las veces, terminamos aprendiendo mucho. Recientemente, encontré un libro muy interesante que intenta enfatizar el aspecto 'divertido' de Linux – describe varios proyectos pequeños (una rocola, un marco de fotos, etc.) que un usuario Linux moderadamente experimentado puede ser capaz de implementar por si solo. Uno de los proyectos involucra conectarse a un sensor de temperatura y publicar los valores en una pagina web (o incluirlo en la firma de nuestro correo electrónico – y cualquier otra locura que se nos ocurra!). El único problema fue que, en la parte del mundo donde vivo, entrar a una tienda de electrónica y pedir un sensor integrado de temperatura de 1 cable es provocar que le dirijan a uno una mirada fría. Los sensores inteligentes que pueden ser conectados directamente a una PC no son tan disponibles que digamos – tendremos que construir el nuestro – lo que le agregara excitación a la diversión. Con un microcontrolador de bajo costo y de propósito general como el PIC16F628, componentes baratos, siempre disponibles en tiendas de electrónica, y MUCHO código, puedes construir muchos 'juguetes' interesantes y conectarlos a tu maquina Linux – realmente una gran experiencia de aprendizaje para el hacker de hardware que quiere aprender Linux, o para el hacker Linux que quiere aprender un poco de hardware. Este articulo describe como me fue al construir mi propio proyecto de sensor de temperatura – los hackers principiantes de Linux/hardware pueden encontrar algunas de estas ideas de utilidad cuando empiecen a construir sus propios proyectos.

Conseguir un micro PIC, y configurarlo para trabajar con Linux

Este es el primer paso. Los controladores PIC de Microchip son muy comunes y disponibles. Si eres como yo, trabajar con una pistola desoldar por mas de 10 minutos te vuelve loco – así que tendrás que escoger el tipo de PIC apropiado – aquel que puede ser programado con el circuito mas simple posible (conectado al puerto paralelo de la PC), preferiblemente con una fuente de poder de 5V. No busques otro que no sea el PIC16F628. Es un simpático dispositivo que tiene varios periféricos (excepto el ADC – pero entonces, podemos crear nuestro propio conversor analógico a digital con el comparador y las facilidades de modulación de anchura de pulso que nos ofrece el PIC) y soporta un 'Modo de Programación de Bajo Voltaje'. Encontré un pequeño y simpático circuito (el circuito mas simple, y uno que trabaja perfectamente, a diferencia de docenas que he visto en la red) diseñado por Jim Paris para un laboratorio de programación del MIT. Aquí esta el circuito:

[ diagrama ]

Ensamble el circuito en un protoboard en pocos minutos.




Jim Paris ha diseñado un programa (llamado 'jimpic') para quemar el código maquina en la memoria flash del microcontrolador. Esta disponible para descargarlo desde aquí. Yo escribí un sencillo programa en lenguaje ensamblador, lo convertí en código maquina con la ayuda del ensamblador 'gpasm' disponible como parte del Proyecto GNU de utilidades para el PIC y lo queme en el micro ejecutando 'jimpic' con la opción '-b'.

Una rápida introducción a la programación del PIC

Algo bueno del PIC es que, si tienes algo de experiencia en arquitectura general de microprocesadores y programación en lenguaje ensamblador, puedes empezar a ser productivo con el en solo una o dos horas. El conjunto de instrucciones es muy compacto (35 instrucciones) y suficiente para la mayoría de tareas simples de mover y girar bits. El PIC16F628 tiene unos decentes 224 bytes de memoria de datos y 2K de memoria de programa (código). Los periféricos incluyen puertos digitales de E/S de propósito general, tres temporizadores, dos comparadores analógicos, modulo de voltaje referencial integrado, Transmisor Receptor Asíncrono-Síncrono Universal (para comunicaciones seriales), y un modulo de Captura-Comparación-PWM. Las características especiales de CPU incluyen un timer watchdog, circuito detector de sobre voltaje, y un oscilador interno RC (así no necesitamos un cristal externo, si no es de importancia la precisión del tiempo).

La RAM de datos de propósito general empieza en la dirección 0x20 (las ubicaciones debajo de esta area esta ocupada por Registros de Función Especial – básicamente puertos E/S mapeados a memoria, registros de control, etc.). Aquí esta un programa elemental en lenguaje ensamblador, el cual simplemente almacena el valor 0 en el acumulador (el registro 'W', en terminología PIC).

[ Listado 1 ]

(Si descargas el listado elimina la extensión .txt. Solo esta allí para asegurarme que los navegadores lo mostraran apropiadamente.)

Ahora ensamblemos el archivo:

gpasm -a inhx8m a.s

El resultado es un archivo de formato Intel hex, que puede ser pasado a 'jimpic' para el quemado. Cada linea del archivo hex contiene unos cuantos bytes de código maquina, la dirección en la cual el código maquina es almacenado (en la memoria flash del microcontrolador), algún tipo de checksum, ay alguna que otra información. Aquí esta el archivo hex generado al ejecutar 'gpasm' con nuestro programa en lenguaje ensamblador:

:020000000030CE
:02400E00983FD9
:00000001FF

La primera linea del programa le dice al ensamblador que el código maquina es generado para un PIC16F628. La segunda linea incluye un archivo (disponible con la distribución 'gputils') que contiene varias definiciones de símbolos. La tercera linea, una directiva __CONFIG, le dice al ensamblador que características especiales del microcontrolador (digamos, el temporizador Watchdog) deben ser activadas/desactivadas escribiendo un patrón de bits en una 'palabra de configuración' 'mágica' dentro del PIC; _WDT_OFF significa que no queremos habilitar el watchdog, _INTRC_OSC_NOCLKOUT significa que usaremos el oscilador interno para proveer de las señales de tiempo necesarias a la ejecución del programa. Tenemos que referirnos a la hoja de especificaciones del 16F628 para saber mas acerca de esos bits de configuración. La cuarta linea es la única instrucción de lenguaje ensamblador del programa – mueve el valor 'literal' (constante) 0 al registro 'W'. Nótese que cada linea empieza con un tab.

Encendiendo un LED

Aquí esta un programa que enciende un LED conectado al pin RB0 del microcontrolador:

[ Listado 2 ]

PORTB es un puerto de ocho-bits – la dirección de cada pin (esto es, si el pin actúa como una entrada o salida) es controlado por unos bits individuales del registro TRISB – si un bit de TRISB es puesto a 1, el pin correspondiente de PORTB sera una entrada – de otra forma sera una salida. El PIC tiene el concepto de direcciones 'agrupadas', lo que puede ser algo confuso para el principiante. (Es un dolor de cabeza inclusive si eres un desarrollador experto.) Se visualizan 'bancos' de registros de función especial – el registro de STATUS es el mismo a lo largo de todos los bancos mientras que el registro TRISB esta solo disponible en el banco 1. Por defecto nos encontramos en el banco 0. Para acceder a TRISB, debemos conmutar al banco 1. Esto se logra colocando un 1 en el bit RP0 del registro de estado. (Cuando leas manuales de microcontroladores, notaras que no solo a los registros de control se le dan nombres especiales, inclusive los bits individuales son nombrados. Los archivos de cabecera (definición) disponibles con el kit de desarrollo del microcontrolador enlazan estos nombres simbólicos a los números dados en el manual, haciendo la vida del programador en ensamblador un poco mas fácil.) La instrucción 'bsf' (setear bit f - 'f' representa el hecho de que el numero que viene como operando de la instrucción representa una dirección de memoria o un registro de función especial y no un 'literal') toma dos operandos – el primero es la dirección de la ubicación en RAM o de un registro de función especial, y el segundo un numero bit. La instrucción 'movwf' copia el contenido del registro 'W' a la ubicación de memoria cuya dirección es el operando de la instrucción.

Construyendo un circuito que funciona

Después de ensamblar y quemar el programa de arriba, estamos listos para verlo en acción. El circuito puede ser construido en un instante - coloca +5V en el pin VDD del PIC (pin 14), conecta Vss (pin 5) a la tierra del circuito, conecta MCLR (pin 4) a +5V mediante una resistencia de 2K, conecta el LED entre RB0 Gnd (tierra) con una resistencia limitadora de corriente de 1K en serie – y eso es todo. Debemos ver un LED encendido tan pronto como apliquemos voltaje. El siguiente intento sera hacer parpadear el LED – para eso tenemos que leer un poco mas sobre el conjunto de instrucciones del PIC – el manual nos sera de mucha ayuda.

Consejos de depuración de errores

Aquí hay algunas cosas que he encontrado útiles mientras depuro un proyecto:

El proyecto de conexión al sensor de temperatura

El LM35 es un sensor de temperatura calibrado comúnmente disponible que convierte la temperatura (en grados Celsius) a voltaje – cada incremento en grados de la temperatura resulta un incremento de 10mV en el voltaje de salida. Es un dispositivo de 3 pines - Vcc, Gnd, y el voltaje de salida. Se puede obtener la hoja de especificaciones de aquí. Digamos que la temperatura actual es de 23°C; el voltaje de salida es de 230 milivoltios.

La pregunta es, ¿como convertimos ese voltaje a un valor digital? La manera mas fácil puede ser usando un conversor analógico a digital, y conectarlo al puerto paralelo. Otra solución seria utilizando un PIC con ADC integrado (digamos el 12F675). La tercera seria utilizar algunos periféricos disponibles del 16F628, escribir algo de código, y construir por nuestra cuenta un ADC. Como ya he explorado las primeras dos opciones en el pasado, pensé intentar la tercera.

Dos periféricos característicos del PIC son de nuestro interés aquí – uno es el modulo PWM integrado (Modulación por Anchura de Pulso), el cual es capaz de generar en hardware, un flujo constante de pulsos digitales on-off cuyo ciclo puede variar simplemente almacenando ciertos números en registros específicos de función especial. Una vez que el modulo PWM es iniciado para generar un tren de pulsos de un ciclo especifico, se mantendrá así sin intervención alguna del software – nuestro programa puede hacer otras cosas.

El PIC también esta equipado con dos comparadores analógicos, que pueden ser configurados de varias formas. Digamos que usamos solo uno de los comparadores. Dos pines PORTA pueden ser programados para aceptar niveles de voltaje y transmitirlos a los pines Vin+ y Vin- del comparador. La salida del comparador es alta si el valor de Vin+ es mayor que Vin-, y bajo si es lo contrario. La salida puede ser entregada en otro pin PORTA, o simplemente leida de algún bit en particular del Registro de Control del Comparador, CMCON.

Filtrando pulsos PWM




La figura muestra un pulso PWM pulse (off OV, on +5V) de un periodo T que es alimentado por un circuito RC (R*C >> T). Si los periodos on-off son iguales, la salida vista en el condensador sera un nivel DC constante de 2.5V. Libros de texto de ingeniería eléctrica nos darán una razon de porque esto es así – o, si no estas muy seguro de la matemática involucrada (así como yo), juega con algunos valores de R y C hasta que obtengas el valor deseado. Ahora que sucede si alimentamos un pulso PWM cuyo tiempo en on es menor a T/2? Veremos que la salida es otra vez un nivel DC, pero la magnitud ha bajado proporcionalmente. ¿Que pasa si incrementamos el tiempo en on? De nuevo, la salida es un nivel DC, solo que la magnitud se ha incrementado proporcionalmente. Ahora tenemos una forma interesante de implementar un DAC, un conversor de digital a analógico. Digamos que queremos generar un voltaje de 0.449V. Que tal si programamos al PIC para que genere un tren de pulsos PWM de un periodo de 256 microsegundos y el tiempo en on de 128 microsegundos. El voltaje de salida seria de unos 5V*(128/256.0) = 2.5V. Ahora, que pasaría si el tiempo en on fuera de 23 microsegundos? El voltaje de salida es 5V*(23.0/256) = 0.449V. (Uso Python para hacer estos cálculos de una manera rápida y sencilla. Es uno de mis usos favoritos para este gran lenguaje.) El tiempo en on puede ser alterado fácilmente al escribir algunos números en dos registros, CCPR1L y CCP1CON. Una forma puramente digital de generar un voltaje analógico!

Del DAC al ADC

¿Que tiene que ver todo esto con convertir la salida analógica del sensor LM35 a un valor numérico? Bueno, un DAC, junto a un comparador, constituyen un ADC. ¿Como? Digamos que las temperaturas máxima y mínima en tu lugar de residencia nunca baja/sube de 45°C y 20°C. Así que la salida del sensor siempre estaría entre .45V y .2V (recuerda, 10mV por grado de cambio en la temperatura). Empezamos generando una señal PWM de un periodo de 256 microsegundos. La salida del filtro RC es alimentada a Vin+ del comparador, y la salida del sensor es llevada a Vin-. Digamos que la salida del sensor es de .3V. Si el periodo en on del PWM es de 23 microsegundos, el nivel DC seria de 5*(23.0/256) = 0.449V. Así que, Vin+ es mayor que Vin-, y la salida del comparador (tal como se obtiene de un bit del registro CMCON) es alta. Ahora, empezamos a bajar el tiempo en on. En cierto punto, Vin- subirá por encima de Vin+, y la salida del comparador cae a cero. La magnitud del tiempo en on en ese punto es la real representación del valor analogico de la salida del sensor. Comunicamos este numero a un programa en ejecución en nuestra maquina Linux a traves de un puerto serial. Puedes descargar el programa en lenguaje ensamblador del PIC que hace todo este truco:

[ Listado 3 ]

En lugar de realizar una búsqueda 'lineal' desde el limite superior hasta el inferior, podemos generar un voltaje que se ubique en el medio del rango y compararlo con la salida del sensor. Si el comparador dice que la salida del sensor es mayor, podemos repetir el mismo procedimiento con la mitad superior. Es la clásica 'búsqueda binaria' aplicada para resolver un problema de hardware! Horowitz y Hill, en su libro El Arte de la Electrónica, muestra trazos en osciloscopio de esta búsqueda binaria en acción! Los programadores deberían mostrar siempre algo de escepticismo frente a código que dice hacer búsqueda binaria – el algoritmos se ve demasiado simple – pero de hecho no es tan sencillo de implementar apropiadamente.

De vuelta a Linux

El PIC envía la información de temperatura a traves del pin (RB2) en forma serial – este pin esta conectado directamente al pin RxD del puerto serial de la PC. Lo que queda es escribir un programa que lea estos datos y los procese de alguna forma. Aunque el estandardizó de comunicaciones seriales RS-232C define un voltaje 'on' entre -3 y -12V y un voltaje 'off' debe ser entre +3 y +12, he sido capaz de obtener resultados satisfactorios usando las salidas de 0 y 5V lógicos del puerto del PIC – si no trabaja así para ti, tendrás que colocar un dispositivo como el MAX232 entre el puerto del PIC y el pin RxD del puerto serial de la PC.

Conectándose al puerto serial

Veamos la forma mas simple de conectar un circuito externo al puerto serial. (No enviaremos datos por el puerto serial de la PC – eso complicaría aun mas el circuito.) El pin numero 2 de un conector de 9-pines del puerto serial es el pin de recepción (RxD), el numero 3 es el pin de transmisión (TxD), y el numero 5, tierra (GND). Digamos que el PIC envía datos a traves del pin RB2 a 9600 bits por segundo, en formato 8N1 (8 bits de datos, no paridad, 1 bit de parada). El UART que controla el puerto serial de la PC debe ser programado con esos mismos parámetros. Esto se puede lograr escribiendo los bits mágicos en ciertos registros de control. Una vez realizado, nuestro programa puede mantenerse a la espera de un bit en el registro de estado del UART para saber si un nuevo dato ha arribado. Aquí esta el listado del código:

[ Listado 4 ]

El programa tiene dos desventajas. Una es el uso de llamadas E/S de bajo nivel, las cuales, si queremos que trabajen bien, deben ser precedidas por una llamada iopl(). Solo el superuser puede invocar iopl() con éxito – así que nuestro programa deberá ejecutarse con privilegio de root. La otra es que desperdiciamos tiempo de CPU cuando mantenemos un bucle esperando la llegada de datos; es otro gran problema. Ambos son resueltos al no interactuar directamente con el hardware – podemos hacer uso de llamadas al sistema para conversar con el controlador del puerto serial que existe en el kernel Linux – que se encargara de todo el trabajo de bajo nivel necesario para manejar el bloqueo y las interrupciones de E/S.

E/S Seriales en Python

El modulo 'termios' de Python puede ser usado para comunicaciones seriales de alto nivel. Isaac Barona Martinez a escrito un wrapper sobre 'termios'. Se llama uspp y esta disponible para su descarga desde aquí. Al usar este modulo, la lectura del puerto serial es algo muy sencillo:

[ Listado 5 ]

from uspp import *

# COM1 is initialized at 9600 baud. The
# default data format is 8N1

s = SerialPort("/dev/ttyS0", None, 9600)
s.flush() # discard unread bytes

print ord(s.read()) # s.read() returns a one-character
                    # string. We convert it into its ascii
                    # value

Una vez que hemos llegado tan lejos, podemos dejar volar nuestra imaginación!

Agradecimientos

Gracias a Christopher Negus y Chuck Wolber por un libro tan interesante!

Gracias a Jim Paris, Ariel Rodriguez y Sheldon Chan por tan excelente hardware y software del 'jimpic'. Como mencione anteriormente en este articulo, encontré que esta es la mejor manera de empezar a programar con PIC bajo Linux. Gracias a Isaac Barona Martinez por uspp, el cual simplifica mucho la programación serial.

Conclusión

Existen dos excelentes documentos que describen la programación serial bajo Linux. Uno es COMO de la Programación Serial. El otro es Guia de Programación Serial para sistemas operativos POSIX. La pagina Web de Microchip contiene muchas notas de aplicación, lecturas que pueden darnos muchas ideas para nuestra siguiente aventura con hardware en Linux – solo no olvides compartir la diversión con los lectores de La Gaceta de Linux! Me pueden contactar en mi pagina Web en pramode.net.

[BIO]Soy un instructor que trabaja para IC Software en Kerala, India. Estoy muy contento de ser un químico orgánico, pero lo segundo que hago lo mejor posible es, jugar con Linux y enseñar programación!

Copyright © 2004, Pramode C.E. Licencia de copia http://linuxgazette.net/copying.html

Publicado en el numero 99 de Linux Gazette, Febrero 2004