Archivo por meses: octubre 2011

Microchip va a sacar microcontroladores PIC de 32 bit con encapsulado DIP

El hecho de que Microchip saque al mercado PICs de 32 bit con encapsulado DIP va a revolucionar el mundo de los aficionados a la electrónica. Un simple chip con 28 pines tan potente como el primer 386 de intel (salvando las arquitecturas Harvard y von Neumann) que podemos poner en nuestras protoboards. Puede correr hasta 80 Mhz., 512KB de Flash (donde se almacena el código), 128KB. de SRAM (donde se almacenan los datos) y la posibilidad de conectar con periféricos mediante DMA.

Se pueden pedir samples, pero pueden tardar 42 días en enviarlos.

Leer múltiples sensores de infrarrojos con un sólo pin analógico / Read several infrared sensors with an unique analogic pin

Cuando queremos crear un robot que distinga el blanco del negro de una superficie tenemos que leer la posición en la que se encuentra con varios sensores infrarrojos.

To make a robot that distinguishes a black area between a white one, we need to know the position of the robot by reading the information of several infrared sensors.

Muchas veces los microcontroladores que usamos para estos robots tienen un número muy ajustado de pines de entrada y salida, y si tenemos que usar uno de estos por cada sensor infrarrojo que utilicemos vamos a tener problemas para añadirle funcionalidades a nuestro robot: Comunicaciones serie, acelerómetros, giroscopios, i2c, sensores de distancia, bumpers, botones, motores, leds, etc.

Many times the microcontrollers used for these robots have a very limited number of in/out pins, so if we have to use one of those for each infrared sensor, we will find problems to add functionalities to our robot as Serial Communications, accelerometers, gyroscopes, i2c, distance sensors, bumpers, buttons, motors, LEDs, etc..

En los robots rastreadores se usan dos sensores infrarrojos como mínimo, en los de sumo se usan 4, en los velocistas suelen ser 6 sensores o más. Todo esto provoca que tengamos que «desaprovechar» pines de nuestro micro para leer los sensores. Sin embargo hay una forma de leer varios sensores de infrarrojos usando sólo un pin analógico del microcontrolador.

Tracker robots at least use two infrared sensors; sumo robot 4 and line follower robot tend to have 6 or more sensors. All this causes the «waste» of the pins of our micro to read sensors. However, there is a way of reading several infrared sensors using only one analog pin microcontroller.

La idea proviene de este artículo, donde se explica cómo se puede leer un teclado matricial de 4 filas x 3 columnas con un sólo pin analógico de un microcontrolador PIC.  El objetivo es usar varias resistencias para que, dependiendo de la tecla que se pulse, el pin del micro reciba una tensión distinta y poder discernir cuál es la que se ha pulsado. Aquí tendremos un inversor Schmitt trigger en cuyas salidas pondremos resistencias en serie de distintos valores unidas a un punto en común. Desde ese punto se medirá el valor de la tensión, que será distinto dependiendo del sensor activo, pudiendo conocer así la posición del robot.

The idea comes from this article, which explains how to read a keypad matrix of 4 rows x 3 columns with only one analog pin of the PIC microcontroller. The objective is to use several resistors for, depending on which key is pressed, the micro pin receives a different voltage discerning this way which key has been pressed. At this point, we will have a Schmitt trigger inverter whose output have resistors connected in series of different values attached to a common point. From this point the voltage value is measured, which will be different depending on the active sensor, being able to know the position of the robot.

Primera ventaja: Tener varios sensores CNY70 o un array QTR-8A ya no es un problema porque podemos leer todos los valores  con un sólo pin de nuestro microcontrolador y dejar el resto para otras tareas.

First advantage: Having multiple CNY70 sensors or a QTR-8A array is no longer a problem because we can read the values with a single pin of our microcontroller and leave the rest for other tasks.

Segunda ventaja: Por cada sensor que se leía con un pin analógico se provocaba una pausa, ya que la lectura de un ADC tarda un tiempo en hacerse, multiplicado por el número de sensores. Con esta solución sólo se hace una lectura.

Second advantage: Each sensor read with an analog pin causes a pause, since the reading of an ADC takes a while to execute, and this pause must be multiplied by the number of sensors. Using this solution takes only one reading.

Tercera ventaja: Como vamos a usar un inversor schmitt trigger y este sólo nos da una señal alta (5 v.) o baja (0 v.) en sus salidas, con las resistencias siempre vamos a obtener los mismos resultados de tensión aunque cambiemos de entorno (pistas de competición o caseras con distinta iluminación), por tanto no hay que calibrar.

Third advantage: As it is use a Schmitt trigger inverter which only gives a high level (5 V) or low one (0 V) in their outputs, the resistors are always going to get the same voltage if you change the environment (race tracks with different lighting or home), so there is no need to calibrate.

Cuarta ventaja: Con las resistencias correctas sólo es necesario tener un ADC de 8 bits (0-255) para medir el voltaje (en tramos de 0,02 V. aproximadamente) con una referencia de 5 V.

Fourth advantage: With the proper resistors it is only necessary an ADC of 8 bits (0-255) to measure the voltage (0.02 V steps approximately) with a 5 V reference.

Voy a poner como ejemplo 8 sensores infrarrojos que leen una hoja que tiene fondo blanco (devuelven valor cercano a 0) y la línea de color negro (devuelven un voltaje mayor). Como inversor schmitt trigger podemos usar un 40106 o un 74HCT14 que tienen 6 entradas/salidas. Como se necesitan 2 entradas más para alcanzar las 8 hay que poner otro chip inversor (recomiendo distribuirlos en 4 + 4 en vez de 6 + 2). También necesitaremos 8 diodos y 9 resistencias.

Let me give an example of 8 infrared sensors that distinguish a white background (return value close to 0) and the black line on it (that return a higher voltage). As the Schmitt trigger inverter it can be used a 40106 or 74HCT14 which has 6 inputs / outputs. Since it takes 2 more entries to reach the 8 sensor, another chip inverter is necessary (I recommend distribute 4 + 4 instead of 6 + 2). We also need 8 diodes and 9 resistors.


La salida de cada CNY70 o de cada elemento del array QTR-8A va dirigido a una de las entradas de uno de los inversores.

The output of each CNY70 or each element of the QTR-8A array is routed to one input of one of the inverters.

La salida correspondiente de ese inversor va a un diodo enfrentado. Esto es necesario ya que al juntar al final todas las salidas evitamos que si una salida esta a 5 v. y otra a 0 v. se derive la corriente entre ellas.

The corresponding output of each inverter is routed to a faced diode. This is necessary since it prevents the pass of current among outputs in different states (one output in 5V and another at 0V).

Después del diodo viene la resistencia, que dependiendo del valor que tenga hará que la tensión caiga más o menos. El valor de la resistencia debe ser único con respecto al de las otras para que la caida de tensión sea diferente.

After the diode, it is placed the resistor, which depending on its value, the voltage will decrease more or less. Each resistor value must be unique in the set so the final voltage was different.

Finalmente se unen todas las salidas en otra resistencia para crear lo que se denomina un divisor de tensión. En ese punto se debe poner la línea que une al pin analógico del microcontrolador para que este pueda medir el voltaje total y diferenciar qué sensor o sensores están activos. Esta resistencia final que une al resto va a alimentación (Vcc). Esta configuración esta diseñada para poder leer el fondo blanco con una línea negra siempre y cuando los sensores nos den un valor cercano a 0 para cuando leen el fondo blanco y un valor mucho mayor para cuando leen la línea negra. Si se necesita cambiar este comportamiento, se puede conectar la resistencia final a masa e invertir los diodos.

Finally, all outputs are joined together in another resistor to create what is called a voltage divider. In that point you may put the line connected to the microcontroller’s analog pin so the total voltage can be measured and distinguish which sensor or sensors are active. This final resistor that joins the other ones must be connected to Vcc. This configuration is designed to read a black line on the white background as long as the sensors give us a value close to 0 when reading the white background and a much greater value when reading the black line. If you need to change this behavior, you can connect the ending resistor to ground and reverse the diodes.

Ahora que ya recibimos distintas tensiones en el pin analógico de nuestro microcontrolador dependiendo de los sensores que estén activos o no, debemos plantearnos cuántas medidas posibles podemos tener. Como he puesto un ejemplo de un velocista podemos tener los siguientes casos:

  • Todos los sensores leen el fondo blanco.
  • Un sensor lee la línea negra y el resto el fondo blanco.
  • Dos sensores leen la línea negra y el resto el fondo blanco.

Now that we got different voltages in the analog pin of our microcontroller depending on the sensors that are active or not, we must consider how many possible measures can we have. As continuing with the example of the line follower, we have the following cases:

  • All sensors read white background.
  • One sensor reads the black line and the rest, white background.
  • Two sensors read the black line and the rest, white background.

Así pues según la combinatoria, debemos multiplicar el número de sensores por 2. En total tenemos 16 medidas posibles (y diferentes) para todos los estados que pueden tener nuestros sensores. Pongo un esquema con los distintos estados, el voltaje resultante según una simulación y su valor de ADC de 8 bits:

Using Combinatory, we must multiply the number of sensors by 2. In total there are 16 possible (and different) measures for all states which can have in our sensors. I put a scheme with the states, the resulting voltage according to a simulation and its value in 8-bit ADC:

Aquí dejo un vídeo de una simulación en proteus sobre la activación de varios sensores (verlo en HD y a pantalla completa):

Here I show a video of a simulation in proteus on the activation of multiple sensors (see this in HD and full screen):

Para uno de sumo ya no valdría el cálculo anterior ya que habría 7 combinaciones posibles con sus 4 sensores y el fondo es negro con una línea blanca:

For a sumo robot the previous situation is no longer valid as it would be 7 combinations with 4 sensors and the background is black with a white line:

Ahora sólo quedaría medir una primera vez los distintos valores de los sensores y luego programar en nuestro microcontrolador una tabla con esos valores que nos servirá para siempre. Por supuesto como los valores de las resistencias tienen un margen de error y la caída de tensión de los diodos no suele ser siempre el mismo, sólo podremos hablar de valores orientativos y únicamente podemos sacar los valores correctos midiéndolos directamente con un polímetro o que el microcontrolador nos lo diga a través del puerto serie. Yo he probado con valores consecutivos de resistencias comerciales y me ha funcionado bien.

Last action to take is to measure the different sensor values and then program a table in our microcontroller with those values that will be correct for us forever. Of course, the values of the resistors have a margin of error and the voltage drop across the diodes is not usually the same: we are talking only about approximate values and we can only get the correct values by measuring directly with a multimeter or with the microcontroller and sending it trough the serial port. I’ve tried commercial consecutive values of resistors and it has worked well.

Finalmente comentar que si nuestro micro no tiene pin analógico pero si tres pines digitales libres podemos usar un ADC0831.

Finally, I would like to remark that if our micro does not have an analog pin but three digital pins, we can use an ADC0831.

Gracias a Maiki por la traducción / Thanks to Maiki for translation

Descansa en paz Dennis MacAlistair Ritchie

Todo el mundo ha hablado de la reciente muerte de Steve Jobs. Sin embargo también recientemente ha fallecido una persona que ha contribuido enormemente al desarrollo de la informática: Dennis Ritchie. Este hombre fue el creador junto a Ken Thompson del sistema operativo Unix (en el cual está basado GNU/Linux de Richard Stallman y Linus Torvalds) pero su mayor aportación fue crear el lenguaje de programación C, quizá el más usado de la historia y del que derivan otros tantos como objective-c, java y c#. Hasta siempre Dennis.

(Fuente: chw.net)

Mi charla de telemetría

Ya han publicado el vídeo de la charla de telemetría que di en la OSHWCON 2011.

Toda la documentación de mi charla (presentación, código fuente, esquemáticos, etc.) lo podeis descargar aquí.

Agradecer a los organizadores su tiempo, esfuerzo y ganas por sacar adelante algo tan novedoso y pionero. También dignos de mención son los ponentes que de forma altruista hemos hecho realidad este fantástico evento. Por supuesto no nos olvidemos de los patrocinadores que han permitido que este evento tuviese un nivel alto y de calidad.

A todos, nos vemos en la OSHWCON 2012.

Crear un demonio en el linux embebido en placas

Ahora que están de moda las placas que contienen un linux embebido como las beagleboard, las raspberry pilas foneras, he creido interesante escribir un artículo en el cual se explica cómo ejecutar una tarea por tiempo indefinido desde que arranca la placa  y sin necesidad de acceder por shell a la misma.

Presupongo que tienes el compilador cruzado que genera ejecutables para la plataforma de la placa y que tienes acceso a ella mediante shell con el usuario root.

Nuestro objetivo es sencillo, crear lo que se denomina en entornos linux y unix un demonio (en windows es un servicio) lo más sencillo posible. Un demonio no es nada más que una aplicación que se ejecuta en segundo plano y no muestra directamente datos al usuario ni este puede interactuar con ella.

Como queremos que el ejemplo sea bastante sencillo nuestro demonio simplemente va a escribir en un fichero una cadena cada cierto tiempo. Vosotros podreis modificarlo para que haga lo que querais (leer y escribir datos en un puerto serie, analizar imágenes de una webcam, manejar GPIO, crear un servicio para internet, etc).

Scripts de demonios:

Normalmente cuando se arranca un sistema linux, después de cargar el kernel se ejecuta el proceso init, que es el proceso padre del que dependerán el resto de procesos que se ejecuten en el sistema. Este proceso lee el fichero /etc/inittab para saber entre otras cosas en qué nivel de arranque (runlevel de 1 a 5) debe iniciar el sistema.

Dependiendo de ese nivel de arranque se ejecutarán unos scripts ubicados en la carpeta correspondiente. Así por ejemplo si el nivel es 3, los scripts de la carpeta /etc/rc3.d que empiecen por S (Start) se ejecutarían al arrancar. Estos scripts tienen un número que indica en qué orden se ejecutan (se puede repetir el número).

Pero… un momento… ¡¡¡ Si estos ficheros son en realidad son enlaces simbólicos !!!.

Efectivamente, en realidad son accesos directos que apuntan al directorio /etc/init.d donde realmente están los scripts para los demonios. El proceso init lee de la carpeta /etc/rc3.d los enlaces que empiezan por S y ejecuta el script al que apunta con el parámetro start. Igualmente cuando se apaga o se reinicia el sistema el proceso init lee de la carpeta /etc/rc0.d o /etc/rc6.d  respectivamente los enlaces que empiezan por K y ejecuta el script al que apunta con el parámetro stop.

Los scripts que se encuentran en la carpeta /etc/init.d son en realidad scripts shell que dependiendo del parámetro que se le pase (start, stop, reload, etc) ejecuta el comando necesario para lo que se requiere. Ni que decir tiene que igualmente nosotros podemos ejecutar por nuestra cuenta el script con los parámetros mencionados para parar o arrancar el demonio desde una consola.

Por tanto vamos a crear un sencillo script que arranque o pare nuestro demonio. Lo crearemos dentro del directorio /etc/init.d y lo llamaremos nohacenada con el siguiente contenido:

Este ejemplo muestra un sencillo script donde se espera como parámetro una cadena start o stop. Si es start simplemente arranca la aplicación. Si es stop comprueba si existe el fichero /var/run/nohacenada.pid para saber si la aplicación está corriendo, después lee su contenido, que es el identificador del proceso, para posteriormente mandarle una señal kill y que este pueda cerrarse por si sóla limpiamente. Si no es ninguno de los dos parámetros anteriores es que el usuario intentó ejecutar el script por su cuenta sin poner start o stop como parámetro.

El script debe tener permisos 755  y pertenecer a root por lo que debemos dárselo de esta forma desde una consola shell con el usuario root:

Además hay que crear los enlaces simbólicos en el directorio correspondiente para que init sepa que tiene que arrancarlo (niveles 2, 3, 4 y 5) y pararlo (niveles 0, 1 y 6):

o si te lo permite el linux que tienes instalado, simplemente:

Con estos pasos ya hemos terminado nuestro script para que el proceso init pueda arrancar o parar nuestro demonio.

El demonio:

Para crear nuestro demonio usaremos el lenguaje C, que es el lenguaje estandar de linux. Nuestra aplicación se convertirá en demonio para quedar residente en el sistema permanentemente hasta que se termine mediante kill.

Programaremos nuestra aplicación para que informe de los errores en el log, genere un fichero pid, cree un hilo de ejecución que se convierta en demonio y escriba una cadena cada segundo mientras espera a que se termine la aplicación mediante una señal.

Dado que la aplicación no muestra datos al usuario este no sabe que está pasando por dentro, por eso habrá que informarle a través de los log. De esto se encargan las funciones openlog y syslog. Toda la información podrá ser consultada en el fichero /var/log/syslog.

Muchos demonios generan en el directorio /var/run un fichero con el nombre de la aplicación y extensión pid. Dentro guardan el PID o identificador de proceso en formato numérico. Con esto se obtienen dos ventajas: por un lado la misma aplicación sabe si ya hay una copia de ella misma ejecutandose para no duplicar procesos; por otro lado como guarda el pid dentro del fichero cualquier proceso puede leerlo para poder comunicarse con la aplicación (por ejemplo el comando kill que explicaré más adelante).

Para crear un demonio la aplicación principal crea un hilo de ejecución con fork y la aplicación principal se saldrá. Esto provoca que el hilo de ejecución se quede huerfano. Después se ejecuta umask para no heredar los permisos de los ficheros del proceso padre. A continuación se ejecuta setsid para que el proceso huerfano tenga su propio SID y sea un proceso independiente para el sistema operativo.  Por otro lado cambiaremos de directorio de ejecución para apuntar a la raiz con un chdir ya que es el único directorio seguro que existe en linux.  Finalmente cerraremos con un close la entrada estandar, la salida estandar y la salida de errores ya que no las necesitamos.

Con la función signal haremos que cuando el usuario (o init) nos envíe un comando kill (sin el -9) salgamos de la aplicación limpiamente. Esto es debido a que cuando se ejecuta kill <pid> lo que se está haciendo realmente es enviar una señal SIGTERM a la aplicación. La aplicación recupera la señal y ejecuta la función asociada mediante la función signal. En el ejemplo de más abajo veremos que se asocia a la función adios que simplemente cambia una variable para que se salga del bucle principal. Mientra se espera a recibir la señal, cada segundo se está escribiendo en el fichero /tmp/nohacenada.txt una cadena.

Al salir del bucle se escribirá en el fichero anterior otra cadena y cerramos ese fichero. Igualmente cerraremos el log y se borrará el fichero pid para que se pueda volver a ejecutar la aplicación nuevamente (en un arranque del sistema o nosotros mismos).

Dejo el código fuente de la aplicación llamado nohacenada.c para que os hagais una idea y poder hacer vuestros demonios basados en este:

Para compilarlo depende del toolchain para cada plataforma, pero sería algo parecido a esto:

Como seguramente hayais instalado un compilador cruzado en vuestro ordenador de sobremesa, habrá que subir el fichero ejecutable a la placa. Yo recomiendo que useis scp en linux o winscp en windows si la placa tiene acceso a la red ethernet o wifi ya que hace uso del demonio sshd (el que se usa para las sesiones de consola remotas por ssh).

Una vez subido el fichero a la placa debemos darle permisos de ejecución, asignarle como propietario al usuario root y moverlo a la ruta /usr/sbin a través de la consola shell con el usuario root de la siguiente manera:

Ahora podeis probar si funciona realmente simplemente ejecutando:

Podeis comprobar en la carpeta /tmp si hay un fichero llamado nohacenada.txt y consultarlo, también podeis mirar en la carpeta /var/run si existe un fichero llamado nohacenada.pid y visualizarlo. Si no veis nada podeis mirar el fichero /var/log/syslog para ver si hubiese algún error de la aplicación nohacenada.

Y para pararlo:

Con esto espero que le saqueis bastante provecho a vuestras placas con linux embebido ya que así conseguis que nada más encenderla se ejecute el programa sin tener que hacer vosotros nada por vuestra cuenta. Quizá en el futuro explique cómo programar módulos para el kernel y extender la funcionalidad de vuestra placa aún más lejos (drivers para hardware, sistemas de ficheros, llamadas al sistema, etc).

Calcular la resistencia para un transistor accionado por un microcontrolador

Muchas veces he querido usar un transistor NPN para actuar como interruptor y poder des/activar otras partes del circuito que con las patas de un microcontrolador no se puede hacer directamente (un relé, una bombilla de 12 voltios, otro circuito, etc).

Un transistor puede ser activado (saturación) o desactivado (corte) desde un microcontrolador, pero es necesario poner una resistencia entre la pata del micro y la base del transistor. En este artículo explicaré como se puede calcular de una forma sencilla.

Dependiendo de la carga que queramos manejar debemos seleccionar un transistor NPN u otro. No es lo mismo usar un BC107 que permite tensiones de hasta 45 V. y corrientes de hasta 100 mA. que un 2N3055 que permite tensiones de hasta 60 V. y corrientes de hasta 15 A. Aquí podemos ver unos cuantos para ver cuál se adapta mejor a nuestras necesidades. Por eso debemos saber qué corriente pasa por el punto donde queremos poner el transistor para que actúe como interruptor.

Una vez que hemos seleccionado el transistor , debemos calcular qué resistencia debemos poner entre la patilla del microcontrolador que elijamos y la patilla base del transistor. Para eso primero debemos saber qué hFe (ganancia de corriente) mínima tiene nuestro transistor y nada mejor que consultar el datasheet para saber ese dato.

Después con la siguiente fórmula ya podemos calcular qué resistencia necesitamos:

  • Voltaje: Es la tensión que proporciona la pata del microcontrolador, normalmente 5 o 3,3 V. Se resta 0,7 V. porque es la caída de tensión típica entre la base y el emisor de un transistor, aunque lo puedes mirar en el datasheet del transistor como Vbe.
  • Corriente: Es la corriente que consume el circuito que queremos encender o apagar.
  • hFe: Es la ganancia de corriente (current gain) que tiene el transistor (si hay varios valores elegir el más pequeño).

El resultado es el valor en ohmnios de la resistencia que necesitamos poner.

Así por ejemplo vamos a calcular la resistencia que usaremos para manejar un circuito que consume 500 mA. funcionando a 12 V. y gestionado por un microcontrolador PIC cuya patilla da una tensión de 5 voltios.  Lo primero es buscar un transistor que se adapte a nuestras necesidades, mirando la lista anterior el 2N3053 nos viene bien ya que permite tensiones de hasta 40V. y corrientes de hasta 700 mA. Podemos ver que su hFe es de 50, por tanto la fórmula aplicada sería:

Una resistencia de 430 ohm. no es una resistencia común, por lo que buscaremos el valor más aproximado de las resistencias comerciales, que en este caso podríamos elegir entre una de 390 ohm. o una de 470 ohm.