Mostrando entradas con la etiqueta microcontrolador. Mostrar todas las entradas
Mostrando entradas con la etiqueta microcontrolador. Mostrar todas las entradas

sábado, 28 de septiembre de 2013

Taller de Introducción a Arduino en Altea

Dentro de dos semanas, entre el 9 y el 13 de Octubre de 2013, tendrá lugar la primera edición de Altea Energy Lan Party. Esta será la primer Party LAN donde podremos reunirnos todos los aficionados a la informática, la electrónica y los videojuegos de la provincia de Alicante y por supuesto todo aquel que viva más lejos pero dese pasar unos días entre amigos. La Altea Energy LAN Party ofrece una oportunidad única para conocernos, aprender unos de otros y pasarlo bien.

Altea Energy Lan Party

Dentro de este evento, GoShield impartirá una charla/taller introducción a Arduino. La presencia en dicha charla es gratuita para todos los asistentes al evento, y tras la charla de introducción se realizará un taller donde se podrán hacer una serie de prácticas que perseguirán enseñar a utilizar los conceptos más básicos de Arduino, el uso de salidas digitales moduladas en PWM, el uso de las entradas analógicas y como conectar sensores analógicas a estas  y el uso de pantallas LCD paralelas basadas en caracteres. Todo esto tendrá lugar la tarde del Viernes 11 de Octubre entre las 17:30 y las 21:00. Aquellos que dispongan del material podrán llevárselo de casa y seguir el taller libremente, y para aquellos interesados que no dispongan del material podrá adquirir el kit para la realización del taller allí mismo. El máximo de kits disponibles es de 10 y es posible realizar la reserva pagando 10 euros a través de nuestra web, para aquellos que estén interesados y no quieran quedarse sin plaza, por supuesto para participar en el taller hay que estar inscrito al evento el día de su realización.
Espero que sea de vuestro interés y veros allí a todos.

martes, 28 de mayo de 2013

Programando Baby Orangutan con AVR Studio 5.1

Al diseñar nuestro robot, normalmente necesitamos un driver para controlar al menos un par de motores y un microcontrolador para controlar la lógica que gobierna el robot. Si utilizamos un Arduino y un driver externo esto nos puede costar entre 35 y 80 euros según los elementos utilizados. La placa que os presento hoy es una placa compacta que integra un Atmega 328P, el mismo microcontrolador que utiliza Arduino UNO, y un driver de dos canales de 3A de pico por canal, con lo que podemos controlar un par de motores de una potencia relativamente alta.

Este controlador tiene múltiples ventajas, es barato, compacto, ligero, integra un microcontrolador AVR junto a un driver de 3A de pico por canal e incluye un potenciometro para poder realizar ajustes online en nuestro robot sin necesidad de añadir nada nuevo a la placa electrónica de nuestro robot. Sin embargo, a la hora de comprar este controlador hay que tener en cuenta una serie de detalles. En primer lugar esta placa no incorpora un bootloader preinstalado, el bootloader es un código residente en el micro que permite cargar un programa través del puerto serie como ocurre en el caso de Arduino. Al no tener este código residente, no es posible enviarle un programa a través del puerto serie y es necesario utilizar un programador externo como nuestro USBtinyISP para poder cargar los programas. Con un programador externo también es posible cargar el bootloader de Arduino y a partir de ese momento si es posible programar a través del puerto serie como con cualquier otro Arduino. Otra opción, es programar directamente a través del puerto de programación con el mismo IDE de Arduino, o con IDEs avanzados como el que vamos a utilizar hoy que es AVR Studio.

Hoy me voy a centrar en contaros como programar esta placa con AVR Studio. AVR Studio es un entorno de programación de Atmel basado en Visual Studio, por lo que aquellos que tengan experiencia con programación en .Net se sentirán muy cómodos utilizando este entorno. Una de las ventajas de programar con un entorno como este, es la posibilidad que ofrece el entorno de simular el micro y ejecutar el programa en modo el debug lo que permite realizar trazas de una forma muy cómoda  De esta manera es posible ver el valor que irían adquiriendo los registros en tiempo de ejecución, deteniendo el programa y pudiendo incluso ejecutarlo paso a paso, lo que nos permite depurar errores de una forma mucho mas eficiente.

El primer paso es instalar el entorno Atmel Studio o AVR Studio dependiendo de la versión que instalemos. Es importante instalar la versión 4.0, 5.1 o bien la 6.0 ya que son las versiones compatibles con el paquete de librerías de pololu, AVR development bundle, que incluye librerías varias para la programación de microcontroladores AVR.

A continuación hay que instalar el driver de tu programador para AVR, si utilizas Windows 8 tendrás que seguir los pasos descritos en esta entrada que explica como instalar los drivers de Arduino DUE en Windows 8 pero el mismo procedimiento puede utilizarse con muchos otros dispositivos como por ejemplo es este caso. 

Una vez instalados los drivers del programador tenemos que configurar nuestro USBtinyISP, para ello lo primero es instalar la herramienta WinAVR que incorpora diferentes herramientas para la programación de dipositivos ATmega, en concreto la que nos interesa a nosotros es AVRdude. Posteriormente hay que configurarlo en el entrono de AVR Studio, para ello os dejo un vídeo en el que explican como configurarlo ya que es complicado de explicar y viéndolo se hace mucho más sencillo.


Tras instalar WinAVR, se instalan en la carpeta C:\WinAVR-20100110 multitud de herramientas. En esta carpeta se encuentra la carpeta bin donde están todos los ejecutables y ahí podemos encontrar AVRdude que es el programa que tenemos que configurar en el entorno como programador. En el entorno de AVR Studio hay que utilzar la opción Tools --> External Tools que permite añadir un programador como herramienta externa. Al utilizar esta opción, aparecerá un formulario done hay que configurar en primer lugar el nombre de nuestra herramienta, por ejemplo USBTiny. El segundo argumento se refiere al ejecutable de nuestra herramienta que será avrdude, por lo que hay que poner la ruta hasta el ejecutable que por defecto será C:\WinAVR-20100110\bin\avrdude.exe. Los siguientes argumentos dependerán de la solución que hayamos creado. Cuando creamos un nuevo proyecto hay que elegir la librería de Pololu y dentro de la librería elegir BabyOrangutan 328P, lo que creará una solución para este dispositivo. Como se puede ver en el ejemplo, hay que seleccionar el nombre del proyecto, el nombre de la solución y el directorio donde estará la solución.


Una vez creada la solución, podemos consultar estos parámetros a la derecha en el explorador de soluciones como se ve en la imagen siguiente. Al generar el proyecto, según si hemos elegido Release o Debug, se generará una carpeta dentro del directorio de la solución con ese nombres y dentro de dicho directorio, estará el archivo nombreProyecto.hex que es el archivo binario generado que hay que cargar al controlador Baby Orangutan.


Al crear el proyecto por defecto, se creará con un archivo con el código del ejemplo blink que enciende y apaga un Led. A partir de aquí, hay que rellenar el resto de parámetros en la configuración de la herramienta externa de programación. Hemos añadido el nombre y el ejecutable que realizará las tareas de grabación en el Baby Orangutan, pero ahora debemos rellenar los argumentos donde según el vídeo hay que utilizar la linea -c usbtiny -p m328p -U flash:w:$(ItemFileName) pero lo que hay que hacer es ver el nombre con el que se generea el archivo con extensión .hex y utilizar este nombre. Para ello, hay que generar la solución con la opción Build->Build Solution y luego navegar hasta la carpeta de la solución. Si hemos compilado en Release habrá que mirar en la carpeta con este nombre y si hemos compilado en Debug habrá que mirar en la carpeta con este otro nombre. Allí encontraremos un archivo generado con la extensión .hex y ese es el que hay que utilizar en la linea de comando anterior. Por defecto este nombre será el mismo del del proyecto por lo que si nuestro proyecto se llama nombreProyecto se deberá usar la sentencia  -c usbtiny -p m328p -F -U flash:w:nombreProyecto.hex. Puede verse que en la linea anterior se ha añadido el parámetro -F que soluciona algunos problemas que pueden aparecer al intentar cargar código al microcontrolador utilizando avrdude.


Es importante tener en cuenta que el Baby Orangutan utiliza los pines PB4 y PB5 para la programación por lo que si utilizamos estos pines en nuestros proyectos podemos encontrar problemas a la hora de programarlo. En concreto, no debería haber problema a no se que se conecte en dichos pines un condensador que impediría programar el microcontrolador sin quitarlo del zócalo. Otra cosa a tener en cuenta a la hora de programarlo es la posición del conector, en la placa del Baby Orangutan puede verse marcado con una flecha el pin 1 del conector ISP. El pin 2 es el que se encuentra encima de este y corresponde con VCC y por lo tanto el lado con una franja roja del conector del programador debe conectarse en ese lado.


Por último, en el cuarto parámetro hay que indicar el directorio donde se encuentra este archivo ejecutable, indicando la carpeta Release o Debug según corresponda. Con esto, aparecerá un nuevo ítem en el menú Tools con el nombre de nuestra herramienta. Si conectamos el programador USBTiny al PC y le conectamos nuestro Baby Orangutan, al pulsar el botón Tools -> USBTiny compilará el código de ejemplo y lo cargará en nuestro Baby Orangutan. Después de esto podremos ver como el led se enciende y se apaga intermitentemente, a partir de aquí ya podemos comenzar a crear nuestro propio código, basándonos en las librerías de pololu y con la ayuda de InteliSense que nos sugerirá código a medida que vamos programando.



Espero que os sea de ayuda, y si necesitáis aclarar alguna cosa no dudéis en poner un comentario e intentaremos ayudaros en todo lo posible.




jueves, 16 de mayo de 2013

¿Conoces GBoard?: GSM/GPRS + ARDUINO todo en uno


En muchas ocasiones tenemos en mente realizar un proyecto en el que queremos monitorizar
algunos sensores y enviar la información a través un módulo GSM/GPRS, bluetooth, XBEE o sencillamente almacenarla en una tarjeta SD a modo de datalogger. Si lo hacemos con Arduino
necesitaremos como mínimo una placa base Duemilanove/UNO/MEGA/Due más el shield de comunicaciones GSM/Bluetooth/XBEE, si además queremos conectar sensores necesitaremos añadir otro Shield más. Si además queremos almacenar la información capturada por estos sensores
en una tarjeta SD necesitaremos añadir un nuevo Shield adicional.

El resultado será una torre de shields que probablemente funcione, pero cuya estética y control se complicaría al tener que trabajar con las diferentes señales de control empleadas por cada una de estas placas. Además sería necesario realizar un estudio previo para comprobar la compatibilidad entre las diferentes placa, ya que si dos o mas de ellas utilizan el mismo pin no podríamos usarlas al mismo tiempo de forma correcta. 

Para estos casos tenemos una solución económica y sencilla de utilizar, se trata de la placa Gboard, un sistema que integra un ATMEGA328P con bootloader de Arduino, un módulo GSM/GPRS SIM900, zócalo para tarjeta MicroSD, XBEE/Bluetooth/nRF24L01 y pines de conexión para sensores o actuadores, y todo esto en una placa de tan solo 89 x 61mm. La programación del microcontrolador ser realiza a través de un convertidor USB/RS232 y se programa igual que se programa un Arduino. Está preparada para realizar la interacción con el módulo GSM/GPRS a través del puerto serie hardware o bien utilizando otros pines y la librería para Software serial pudiendo tener así disponible el puerto serie hardware para enviar datos de DEBUG a nuestro PC.

Es posible realizar la gestión del módulo SIM900 utilizando comandos AT, para conocer la lista de comandos AT disponibles hay que basarse en la lista detallada en la documentación del módulo SIM900. También puedes programarla directamente con la librerías para entorno Arduino, en este enlace puedes decargar la librería para GBoard adaptada por GoShield a las versiones del IDE 1.0 o superior de Arduino.

Si estas pensando realizar un proyecto que utilice GSM/GPRS la Gboard es una buena opción a tener en cuenta, pero si además tu proyecto ha de integrar los diferentes periféricos que hemos comentado, entonces es la opción idónea.

Con esta misma filosofía existen otras placas que integran un ATMEGA328P +  Dispositivo/Actuador/Módulo. Entre las más interesantes te presentamos las siguientes:


Puedes encontrar todos estos artículos y la información adicional están disponibles en nuestra tienda online.

sábado, 4 de mayo de 2013

¿Quieres aprender a diseñar tus propios robots?

Aquellos que estamos empezando en el mundo de los concursos de robótica, solemos tener el problema de afrontar los problemas de la construcción del robot desde cero. Al no tener experiencia es común cometer errores tontos que cuando llegamos a pista nos damos cuenta que nos van a impedir hacer nada. En mi caso, el primero robot con el que me presenté a un concurso tenía el principal problema de controlar mal los motores y cuando me di cuenta de ello ya era demasiado tarde.

Hoy quiero dejaros la idea, de que si queréis comenzar a construir vuestro robot, lo mejor es que comencéis cuanto antes y que no os rindáis  Si vais a una competición seguramente descubriréis mil fallos de vuestro robot que lo hacen totalmente inservible al lado de la mayoría de rivales, pero esto no tiene que echaros atrás, lo importante es descubrir estos defectos y corregirlos para mejorar.

Otra cosa importante es no estar solo, buscad a alguien con vuestra misma motivación, leed foros, blogs, leed a gente que hable de estas cosas, de como construirlas y como mejorarlas  No dudéis en preguntar en foros o blogs, seguro que están encantados de ayudaros, yo me ofrezco humildemente a responder todas aquellas dudas que sea capaz. Y sobre todo, aprender de los mejores, es decir de aquellos que ya tienen experiencia y saben de lo que hablan, aquellos que ya se han llevado mil palos porque así os evitareis dároslos vosotros también.

Hoy os traigo un vídeo, de los que creo que han sido los mejores durante mucho tiempo en carreras de robots velocistas. Es un vídeo muy interesante sobre la ponencia que dan Daniel Alvarez y Alberto Calvo en las jornadas de la robótica en Valladolid. Daniel y Alberto han sido campeones de velocistas los últimos años en casi todas las pruebas en las que se han presentado en España. Yo he tenido la suerte de competir con ellos en una edición de campus party y verlos en directo, aunque no se si se puede llamar competir a lo que hice, ya que mi robot tenía un error garrafal de diseño, que fue no utilizar el freno eléctrico en los motores, algo que os contaré el día que consiga un poco de tiempo para hacer una entrada sobre el control de motores. El caso es que podéis aprender mucho de la experiencia de Daniel y Alberto y seguro que os despierta alguna idea. No pretendo que os deprimáis  porque cuando veáis el nivel de estos caballeros os vais a asustar, pero es lo que hay. Hay que avanzar poco a poco, se pueden hacer robots mas sencillos e igualmente competitivos, pero no esta mal saber lo que se esta haciendo y tomar ideas, para no dar palos de ciego.



Como me dijo una vez un profesor, hay que aprender de los que saben mas que tu y si es posible copiar lo que hicieron para poder entenderlo realmente, comprender porque lo hicieron así y una vez conseguido eso, descubrir lo que puedes aportar tu y mejorarlo.

Un saludo a todos y por si me leen algún día, aprovecho para mandar un saludo a Daniel y a Alberto y dales mi enhorabuena por todo su trabajo, y también agradecerles que nos ilustren a todos con charlas como esta, es una verdadera gozada poder escucharles contar su experiencia.

lunes, 8 de abril de 2013

Estamos en Alcabot 2013

Si seguís nuestro blog, os habréis dado cuenta de que hace unos días que no publicamos. Si pensáis que ha sido porque estábamos de vacaciones, estabais equivocados. Mañana Lunes 8 de Agosto y pasado Martes 9 de Agosto de 2013, se celebran las competiciones de robótica de la semana de la robótica en La Universidad Alcalá de Henares. Durante las últimas semanas hemos estado preparando un equipo de robots para dicha competición. Hemos desarrollado cuatro robots en tan sólo unos días por lo que no esperamos conseguir grandes cosas, pero la idea es participar, aprender, disfrutar de la experiencia y tener un punto de partida para ir mejorando de cara al año que viene.

Si queréis seguir las pruebas mañana y pasado aquí os dejo un enlace a los horarios de las pruebas y aquí os dejo otro enlace a la publicación en streaming de las mismas.

A continuación os presento el equipo de robots que hemos preparado. En la izquierda del todo, tenemos el robot javotron desarrollado por Jaiver Perez que realizará la prueba de rastreadores el Lunes. El siguiente robot, un poco más atrás, es el robot FatBot-mini, este robot se presentará a la prueba de mini sumo que se celebrará el Martes. Y a Continuación podemos ver los robots G1-v1 y G1-v2, que se presentarán a la prueba de velocistas del Martes.


La prueba de rastreadores básicamente consiste en resolver un laberinto formado por lineas negras en el suelo. Antes de las intersecciones se encontrarán lineas a un lado o a otro, que indica que camino debe tomarse en la próxima intersección. Si por ejemplo la marca se encuentra al lado izquierdo de la linea central, entonces en la próxima intersección se deberá tomar el camino izquierdo, mientras que si se encuentra al derecho habrá de tomarse el camino derecho. En algunas competiciones incluso, se tiene en cuenta la posibilidad de encontrar dos marcas, en cuyo caso habría que elegir el camino central, en una intersección con tres caminos posibles. Podéis ver la normativa para la prueba de rastreadores aquí.

Para esta prueba se utilizará el robot Javotron, que utiliza el siguiente hardware:



La reglas de la prueba de mini sumo, es bastante sencilla. Consiste en sacar de la pista al rival, antes de que sea el quien eche a tu robot. Para esta prueba hemos basado nuestro robot en un kit de mini sumo, el cual hay que decir que ha dado unos resultados excelentes, incluso utilizando baterías AA convencionales, sin necesidad de utilizar baterías Lipo.

A continuación podéis verlo en pleno funcionamiento:




Por último, una de las pruebas de mayor dificultad es la prueba de velocistas. Esta es la prueba en la que los diferentes equipos demuestran su capacidad técnica al máximo nivel. En esta prueba, existen dos calles marcadas con una linea de color negro. Un robot se pone en una de las lineas y el otro robot se pone en otra, pero con una distancia entre ellos de aproximadamente la mitad del circuido. De este modo cada robot comienza el circuito desde un punto y han de conseguir pillar uno al otro. El primero robot que consiga alcanzar al contrincante gana la carrera. Podéis ver aquí las reglas de la prueba de velocistas.

Nuestra intención es competir en esta prueba con la plataforma G1. Esta plataforma es el nuevo desarrollo que tenemos en marcha, se encuentra en fase beta y queremos medirlo para evaluar su rendimiento y posibles mejoras de cara a realizar la versión final. Esta plataforma, es un robot especialmente pensado para competir en pruebas de velocistas o rasteradores, está pensado para ser utilizado con placas de desarrollo Arduino. Para ello tiene un zócalo donde podemos insertar una placa Arduino y programarlo como si se tratase de un Shield. En nuestro caso estamos trabajando con un Arduino DUE y el resultado esta siendo muy satisfactorio.


El hardware empleado en este robot es:

Aquí podéis verlo en funcionamiento:




Este Robot es otra versión del G1, con la que pretendíamos competir con motores diferentes y diferentes algoritmos para poder evaluar una frente a otra, pero finalmente no es seguro que termine compitiendo en esta ocasión. Esta opción tiene una velocidad punta mayor, y encoders en las ruedas. Esto permite con tiempo realizar un algoritmo mucho mejor que el desarrollado en el caso anterior, pudiendo controlar la velocidad real de las ruedas mientras que en el caso anterior la velocidad de las ruedas se presupone a partir de la frecuencia de la señal PWM generada.


Por último os dejo otra foto de la escudería al completo, esperemos que haya suerte y os mantendremos informados.




jueves, 7 de febrero de 2013

III Concurso de Robótica en la Universidad de Alicante

Para aquellos a quienes interese la robótica, os informo que el día 20 de Febrero, tendrá lugar la 3ª edición del concurso de robótica de la universidad de Alicante, englobado en el mes cultural de la Escuela Politécnica Superior. Cómo los años anteriores, consistirá fundamentalmente en dos pruebas; una primera prueba de robots rastreadores, y una segunda prueba de una especialidad ideada en la universidad denominada Balloon Fight.

Prueba Rastreadores: Esta prueba, consiste en conseguir resolver un laberinto antes que el rival. En esta prueba, existe una serie de caminos trazados en cinta aislante negra sobre fondo blanco. Aproximadamente 5 cm antes de las intersecciones  se encuentran unas lineas a los lados del camino que indican el camino que se ha de tomar en el siguiente cruce. Una sola linea al lado derecho o al izquierdo indica que se ha de tomar el camino derecho o izquierdo respectivamente. Si, por el contrario se encuentran dos lineas (una a cada lado) habrá que tomar el camino central en la próxima intersección.

A continuación os dejo un vídeo del concurso del primer año:



Prueba Blloon fight: La segunda prueba, consiste en una pelea de sumo, en la que los competidores llevan atado a su espalda un globo, teniendo que intentar explotar los globos de sus oponentes o bien tirarlos del ring. Cada uno de estos logros tiene asociada una puntuación, por lo que cuantas más veces consiga un robot tirar a sus contrincantes del ring o bien explotar un globo a su adversario, mejor calificación obtendrá en la prueba. Además los robots, llevaran un LED emisor de alta luminosidad, para facilitar su localización al resto de robots mediante sensores de bajo coste como LDRs (Resistencias dependientes de la luz).

Finalmente se ponderan ambas pruebas obteniendo así la clasificación definitiva. Espero que os animéis a participar, ya que es muy divertido y a quien no le de tiempo a preparar un robot pues que venga y así coja ideas para poder participar el año que viene. Por supuesto si alguien está interesado, puede contactar con nosotros y le asesoraremos y ayudaremos en todo lo que podamos para que llegue a tiempo para presentar un robot este año. 

Aquí os dejo un enlace con las normas de la competición de este año y a continuación un vídeo promocional con tomas de la competición del año pasado:



domingo, 13 de enero de 2013

Arduino Shield List: Lista de placas para Arduino

Arduino se ha convertido en una de las plataformas más populares para el desarrollo de electrónica en el hogar a nivel aficionado. Muchas universidades han incluido esta placa de hardware y software libre en sus clases prácticas, por la facilidad de programación que ofrece su entorno, donde es posible programar directamente en C ó C++ y cargar los programas a través del USB.

Pero esto no es todo, hay infinidad de posibilidades para la creación de nuevas ideas a partir de una placa Arduino. Una de las formas más fáciles de añadir nuevas funcionalidades a la placa Arduino es a través de las Shields de Arduino. Pero, ¿que es un shield?. Pues un shield no es más que una placa electrónica que puede ser conectada en la parte superior de Arduino y que normalmente permite a su vez conectar más placas encima de ella y que incorpora una determinada funcionalidad.

Jonathan Oxer ha creado y mantiene desde hace tiempo Arduino Shield List una interesante página sobre este tema. Su cometido, creo entender, que consiste en recopilar toda la información de utilización de los pines originales de Arduino de cada placa, a modo de poder determinar fácilmente que shields son compatibles con que otros.

Diferentes Arduino Shields Apiladas


Entre otras muchas cosas, muestro a continuación algunas de las funcionalidades más populares de los Shields de Arduino que pueden encontrarse por ahí:


  • Módulo de Relés: Un relé permite controlar con una salida de Arduino, la activación de dispositivos que tengan altos consumos de corriente. Cada salida de Arduino no puede emitir más de 20mA por lo que ciertos elementos como por ejemplo motores u otros elementos actuados con bobinas, no pueden ser activados directamente desde una salda de Arduino. En estos casos es util utilizar un modulo de Relés para poder activar dichos elementos. A continuación podéis ver un vídeo donde se utiliza un Módulo de relés para encender una bombilla, aquí tened cuidado ya que hay relés de características diferentes, por lo que esto no se debe hacer con cualquier tipo de relé, comprobad antes que el relé es capaz de conducir la intensidad correspondiente.

  • Módulo Ethernet: Con estos módulos es posible conectar Arduino a nuestra red local de cada. De manera que podemos hacer que acceda a cualquier información o bien que actúe como un pequeño servidor Web o de directorios, aunque su uso más útil es poder conectar a Arduino un dispositivo actuador o sensor, y acceder a su control o monitorización a través de la red local de casa. En este otro vídeo se muestra como controlar un módulo de relés a través de un PC utilizando para ello un módulo Ethernet para publicar el servicio.

  • Expansores de I/O: En muchas ocasiones, nos encontramos con determinados tipos de aplicación, donde podemos encontrar que Arduino no tiene suficientes entradas o salidas para controlar todos los elementos necesarios. En estos casos, se puede recurrir a Shields específicos para aumentar la cantidad de entradas salidas de nuestro Arduino. Generalmente estos Shields utilizan un bus de comunicaciones I2C o SPI para controlar desde el Arduino las nuevas I/O por lo que hay que fijarse en que bus utiliza el shield en concreto ya que según cual sea dejará sin poder utilizar unas determinadas entradas de Arduino. En el vídeo incluido a continuación, se muestra como con uno de estos expansores de entradas, es posible utilizar hasta 8 entradas como entradas de interrupción. Esto se consigue ya que cada puerto del expansor (8 entradas/salidas) tiene asociada una patilla de generación de interrupción (de manera que si hay un cambio en cualquier entrada del puerto se genera una señal de interrupción). Por lo tanto, es tan sencillo, como conectar esta salida de interrupción a una entrada de interrupción de Arduino y cuando se produzca una señal leer el puerto completo para detectar cual ha sido la que cambió. Trabajar de esta forma, con interrupciones  evita tener que chequear el puerto en cada ciclo de programa.


martes, 20 de marzo de 2012

Programando PIC con C++: Switch VS if {...} else if {..}

Cuando se programa microcontroladores en C++. no hay que perder de vista la arquitectura con la que se está trabajando. El código que se escriba en C++ condicionará el código ensamblador que generará el compilador empleado. Un claro ejemplo de esto es el caso de la estructura switch frente a una estructura if else if. Mucha gente pensará que los siguientes códigos en C++ son equivalentes:

void main(void)
{
 int a=0;
 while(1){
  a++;
  if(a==0){
   a=1;
  }else if(a==1){
   a=2;
  }else if(a==2){
   a=3;
  }else if (a==3){
   a=4;
  }else{
   a=0;
  }
 }
}







void main(void)
{
 int a=0;
 while(1){
  a++;
  switch(a){
   case 0:
    a=1;
   break;
   case 1:
    a=2;
   break;
   case 2:
    a=3;
   break;
   case 3:
    a=4;
   break;
   default:   
    a=0;
   break;
  }
 }
}

No obstante el código que realmente genera el compilador no es el mismo. Por lo general el código que se genera para un switch es, en termino medio, más eficiente que en el caso de los if else. Cuando se trabaja con sistemas de tiempo real que deben interaccionar con el entorno, hay que tener en cuenta que se deben realizar ciclos con las siguientes fases :
  1. Lectura de sensores
  2. Ejecución del código y toma de decisiones
  3. Actuación (transmisión de las decisiones a los actuadores)
Este código debería ejecutarse con unos tiempos de ciclo lo mas constantes que sea posible, es decir, que la en el tiempo de ejecución de diferentes ciclos no haya grandes diferencias. Si se utilizan las estructuras if else, intuitivamente se puede sospechar que no será la misma cantidad de comprobaciones las que se harán para ejecutar el primer if que si se ejecuta el último. Esto se debe a que para que se ejecute el último caso primero de deben haber descartado todos los anteriores. El problema es que se está haciendo ineficiente la ejecución de acciones para los últimos casos de la estructura, y además sin que esto aporte ninguna ventaja. Este tipo de códigos se pueden construir mediante estructuras switch como se muestra en el ejemplo y esta creará un código bastante más eficiente y con unos costes temporales menos extremos, los mejores y los peores casos tendrán costes temporales similares.

Para ilustrar los ejemplos veamos el código ensamblador que se genera en cada uno de ellos para el PIC16F876A con el compilador SDCC. Para entender el código, se recomienda leer la entrada anterior, pero en todo caso al menos se habrá de tener en cuenta las siguientes indicaciones:

  • el registro r0x1000 se refiere a la parte baja del valor de a y r0x1001 a la parte alta de la misma variable.
  • La variable a es una variable entera de 16 bits, 8 por registro.
  • Cuando se habla de L(a) y H(a) en los comentarios se refiere a la parte baja y alta de la variable a respectivamente.
  • La instrucción BTFSC <reg>,<num> se salta la instrucción contigua cuando el bit <num> del registro <reg> está a 0 (clear)
  • La instrucción BTFSS <reg>,<num> se salta la instrucción contigua cuando el bit <num> del registro <reg> está a 1 (set) 
  • W es el registro acumulador de la ALU
Código 1: estructura if else if

_main ;Function start
; 2 exit points
; .line 3; ------ int a=0;
 BANKSEL r0x1000 
 CLRF r0x1000 ;se borra la parte baja de a
 CLRF r0x1001 ;se borra la parte alta de a
_00118_DS_
; .line 5; ------ a++;
 BANKSEL r0x1000
 INCF r0x1000,F ;incremento de a
 BTFSC STATUS,2 ;si el resultado es cero
   ;se ejecutará la siguiente linea que 
 INCF r0x1001,F  ;incrementa la parte alta
; .line 6; ------ if(a==0){
 MOVF r0x1000,W ;se pone H(a) de a en W
 IORWF r0x1001,W ; OR entre W y la L(a)
 BTFSS STATUS,2 ;si el resultado no es cero
 GOTO _00115_DS_ ;se salta a esta etiqueta
; .line 9; ------ a=1;
 MOVLW 0x01
 MOVWF r0x1000
 CLRF r0x1001
 GOTO _00118_DS_
_00115_DS_
; .line 10; ---- }else if(a==1){
 BANKSEL r0x1000
 MOVF r0x1000,W
 XORLW 0x01      ;XOR entre L(a) y 0x01
 BTFSS STATUS,2  ;si el reslutado no es 0
 GOTO _00112_DS_ ;se salta a la etiqueta
 MOVF r0x1001,W  ;de lo contrario se
 XORLW 0x00 ;se comprueba la parte alta 
 BTFSS STATUS,2  ;si H(a) no es cero
 GOTO _00112_DS_ ;se salta a la etiqueta
; .line 11; ---- a=2;
 MOVLW 0x02
 MOVWF r0x1000
 CLRF r0x1001
 GOTO _00118_DS_
_00112_DS_

; .line 12; ---- }else if(a==2){
 BANKSEL r0x1000
 MOVF r0x1000,W
 XORLW 0x02
 BTFSS STATUS,2
 GOTO _00109_DS_
 MOVF r0x1001,W
 XORLW 0x00
 BTFSS STATUS,2
 GOTO _00109_DS_
; .line 13; ---- a=3;
 MOVLW 0x03
 MOVWF r0x1000
 CLRF r0x1001
 GOTO _00118_DS_
_00109_DS_
; .line 14; ---- }else if(a==3){
 BANKSEL r0x1000
 MOVF r0x1000,W
 XORLW 0x03
 BTFSS STATUS,2
 GOTO _00106_DS_
 MOVF r0x1001,W
 XORLW 0x00
 BTFSS STATUS,2
 GOTO _00106_DS_
; .line 15; ---- a=4;
 MOVLW 0x04
 MOVWF r0x1000
 CLRF r0x1001
 GOTO _00118_DS_
_00106_DS_
; .line 17; ---- a=0;
 BANKSEL r0x1000
 CLRF r0x1000
 CLRF r0x1001
 GOTO _00118_DS_
 RETURN 


Cómo se puede observar en el código anterior, hasta que se ejecuta el caso por defecto, se han tenido que realizar unos 4 saltos condicionales. Teniendo en cuenta el coste de ciclos de cada una de las operaciones se tiene un mejor caso (a=0) de 11 ciclos hasta que se llega a ejecutar el código de dicha opción. El conteo de los ciclos se incluye a continuación de forma ilustrativa. Nótese que en el caso de las instrucciones de salto condicional BTFSC y BTFSS valen 2 ciclos ya que el mejor caso se considera que no se cumplen, también derivado de este hecho la operación contigua a estas tiene un coste 0 ya que en su lugar se ha ejecutado una operación nop es decir un ciclo vacío.

 (1) BANKSEL r0x1000 
 (1) CLRF r0x1000 ;se borra la parte baja de a
 (1) CLRF r0x1001 ;se borra la parte alta de a
_00118_DS_
; .line 5; ------ a++;
 (1) BANKSEL r0x1000
 (1) INCF r0x1000,F ;incremento de a
 (2) BTFSC STATUS,2 ;si el resultado es cero
   ;se ejecutará la siguiente linea que 
 (0) INCF r0x1001,F  ;incrementa la parte alta
; .line 6; ------ if(a==0){
 (1) MOVF r0x1000,W ;se pone H(a) de a en W
 (1) IORWF r0x1001,W ; OR entre W y la L(a)
 (2) BTFSS STATUS,2 ;si el resultado no es cero
 (0) GOTO _00115_DS_ ;se salta a esta etiqueta

Si se considera el peor caso, es decir, en el que se debe ejecutar el caso por defecto pasando por el camino más largo, se tiene un total de 42 ciclos ya que cada comparación (excepto la de a==0) tiene un coste de 10 ciclos de ejecución en su peor caso y la de a==0 tarda un ciclo más en el caso en que se ejecute el GOTO que tiene un coste de 2 ciclos, aunque el BTFSS pase a costar 1 ciclo.

Codigo 2 : Estructura switch

_main ;Function start
; 2 exit points
; .line ---- int a=0;
 BANKSEL r0x1000
 CLRF r0x1000
 CLRF r0x1001
_00112_DS_
; .line 7; "ejemplo1-2.c" a++;
 BANKSEL r0x1000
 INCF r0x1000,F
 BTFSC STATUS,2
 INCF r0x1001,F
;---------------------------
;Hasta aquí es igual que antes
;---------------------------

A partir de aquí se muestra a la derecha el caso default y a la izquierda la continuación del código que ejecutaría el caso general.

;signed compare: 
;left < lit(0x0=0), size=2, mask=ffff
; .line 8; "ejemplo1-2.c" switch(a){
 BSF STATUS,0    ;se borra el flag C
 BTFSS r0x1001,7 ;se mira signo de a
        ;si el signo de a es negativo
 BCF STATUS,0    ;se activa el flag C
 BTFSC STATUS,0  ;si el flag C está activo
 GOTO _00109_DS_ ;se manda al caso default
;genSkipc:3083: created from rifx:0x286044
;swapping arguments (AOP_TYPEs 1/2)
;signed compare:
; left >= lit(0x4=4), size=2, mask=ffff
 MOVF r0x1001,W  ;Se carga H(a) en W
 ADDLW 0x80  ;se le suma dos veces 0x80
 ADDLW 0x80  ;con esto se elimina el signo
 BTFSS STATUS,2 ;si el resultado no es cero
 GOTO _00119_DS_ ;se pasa al caso default
 MOVLW 0x04      ; se carga un 4 en W
 SUBWF r0x1000,W ;se resta L(a)
_00119_DS_
 BTFSC STATUS,0  ;si el flag C está activo
 GOTO _00109_DS_ ;se va al default
;Hasta aquí sólo se ha analizado el default
; y se puede comprobar un mejor caso de 
;13 ciclos (salir por el primero GOTO)
; y un peor caso de 22 ciclos
; saliendo por el último

;genSkipc:3083: created from rifx:0x286044
 MOVLW HIGH(_00120_DS_);se carga la parte H
 MOVWF PCLATH ;de la direc. 120 al PCLATCH
    ;esto establece la parte alta del valor
    ;del contador de programa (PC)
 MOVLW _00120_DS_ ;mueve la parte baja de 
 BANKSEL r0x1000  ;la misma dirección a W 
 ADDWF r0x1000,W  ;y se le suma a.
 BTFSC STATUS,0  ;Si hay accarreo
 INCF PCLATH,F  ;se incrementa el PCLATCH
 BANKSEL PCL   ;Con esto se ha establecido
 MOVWF PCL ;el nuevo valor para el contador 
    ; de programa. Este ahora estará
    ; apuntando a uno de los GOTO 
    ; siguientes. Cada GOTO representa
un case del switch.
_00120_DS_
 GOTO _00105_DS_
 GOTO _00106_DS_
 GOTO _00107_DS_
 GOTO _00108_DS_
    ; este código consume 11 ciclos incluyendo
    ;el último GOTO




Como se puede observar en el caso del switch, el peor caso ya no es el default sino cualquiera de los demás casos. Además todos tardarán la misma cantidad de ciclos en llegar al código que deben ejecutar que en este caso es de 7 (inicialización de a e incremento) 5+9 (comprobación del default) + 11 (caso general) = 32 ciclos. Nótese que esa cantidad de ciclos representa aproximadamente tres cuartas partes del peor caso del ejemplo inicial con la estructura if else, además este coste es constante para cualquiera de los diferentes casos del switch. Existan la cantidad de casos que existan este coste permanecerá constante siempre y cuando estos casos tengan valores consecutivos, en caso contrario se iría añadiendo complejidad a la parte que evalúa el default. En un caso general en el que se implementa una maquina de estados, esta solución es la solución idónea para programar dicho sistema ya que evitará problemas y proporcionará tiempos equivalentes para alcanzar los diferentes casos y proporcionar una respuesta adecuada, por lo que el funcionamiento global mejorará considerablemente. Además de esto, con maquinas de estados complejas, la ganancia al emplear una estructura switch frente al uso de una estructura if else crecerá linealmente.

Por último el resto del código para este caso, donde están las etiquetas de cada uno de los case del switch:

_00105_DS_
; .line 10; "ejemplo1-2.c" a=1;
 MOVLW 0x01
 BANKSEL r0x1000
 MOVWF r0x1000
 CLRF r0x1001
; .line 11; "ejemplo1-2.c" break;
 GOTO _00112_DS_
_00106_DS_
; .line 13; "ejemplo1-2.c" a=2;
 MOVLW 0x02
 BANKSEL r0x1000
 MOVWF r0x1000
 CLRF r0x1001
; .line 14; "ejemplo1-2.c" break;
 GOTO _00112_DS_
_00107_DS_
; .line 16; "ejemplo1-2.c" a=3;
 MOVLW 0x03
 BANKSEL r0x1000
 MOVWF r0x1000
 CLRF r0x1001
; .line 17; "ejemplo1-2.c" break;
 GOTO _00112_DS_
_00108_DS_
; .line 19; "ejemplo1-2.c" a=4;
 MOVLW 0x04
 BANKSEL r0x1000
 MOVWF r0x1000
 CLRF r0x1001
; .line 20; "ejemplo1-2.c" break;
 GOTO _00112_DS_
_00109_DS_
; .line 22; "ejemplo1-2.c" a=0;
 BANKSEL r0x1000
 CLRF r0x1000
 CLRF r0x1001
; .line 24; "ejemplo1-2.c" }
 GOTO _00112_DS_
 RETURN 

Programando PIC con C++: ¿Porque programar en C++?

Tradicionalmente, cuando se enseña programación de microcontroladores, se emplea como lenguaje de programación el ensamblador del microcontrolador seleccionado. Esto tiene particular interés, desde el punto de vista didáctico, ya que al utilizar las funcionalidades del microcontrolador en ensamblador se está obligado a entender perfectamente el funcionamiento del propio microcontrolador. Se podría decir que la cercanía del lenguaje a la arquitectura de la maquina fuerza a su comprensión para poder programarlo. Sin embargo, como es evidente para cualquier persona que haya programado en lenguajes de alto nivel, la programación en lenguajes de bajo nivel no es eficiente en cuanto a la generación de código. Algunas de las tareas más sencillas como la programación de una estructura for o un simple if pueden llegar a variar mucho de un microcontrolador a otro en función de su arquitectura, por lo que hasta para este tipo de funcionalidades tan elementales habría que estudiar el repertorio de instrucciones, con el riesgo de no crear el código más óptimo.

Los microcontroladores más típicos (arquitecturas de 8 a 16 bits) suelen ser maquinas con arquitectura RISC, es decir, computadoras con un reducido conjunto de instrucciones. El motivo de esto es que se persigue construir máquinas lo más sencillas que sea posible. Las arquitecturas RISC permiten crear máquinas con un pequeño conjunto de instrucciones atómicas que permiten crear cualquier programa. La sencillez de estas instrucciones, a su vez, las hace muy rápidas, requiriendo sólo de uno o dos ciclos para ser ejecutadas. Sin embargo, esto tiene ciertas implicaciones dependiendo del criterio con que el fabricante haya diseñado/seleccionado dicho repertorio de instrucciones. Según las instrucciones incorporadas y su funcionamiento, la creación de estructuras sencillas puede variar mucho y por tanto se ha de invertir un tiempo en dominar la arquitectura en cuestión antes de comenzar a programar. Si a esto se le añade los problemas comunes inherentes a la programación de microcontroladores como conocer el patillaje del microcontrolador, realizar la correcta configuración de los puertos y de los distintos periféricos, funcionamiento de los registros especiales, etc., cambiar de fabricante o de microcontrolador se convierte en una ardua tarea.

No obstante, el repertorio de instrucciones es muy limitado, para abordar un ejemplo se ha elegido para el caso, el repertorio de instrucciones de la familia PIC16F87X. Este repertorio de instrucciones consta de aproximadamente 35 instrucciones. Además de estas existe instrucciones como nop que realiza un ciclo sin operación y algunas otras con fines muy concretos, y que no nos interesan para el tema que abordamos. En las siguientes tablas se muestran las instrucciones más importantes. En ellas se puede ver sucesivamente 18 operaciones orientadas a byte, 4 orientadas a bit y 13 operaciones con literales e instrucciones de control.


Mnemonic Operands Description Cycles Status Affected
ADDWF f, d Add W and f 1 C,DC,Z
ANDWF f, d AND W with f 1 Z
CLRF f Clear f 1 Z
CLRW - Clear W 1 Z
COMF f, d Complement f 1 Z
DECF f, d Decrement f 1 Z
DECFSZ f, d Decrement f, Skip if 0 1(2) -
INCF f, d Increment f 1 Z
INCFSZ f, d Increment f, Skip if 0 1(2) -
IORWF f, d Inclusive OR W with f 1 Z
MOVF f, d Move f 1 Z
MOVWF f Move W to f 1 -
NOP - No Operation 1 -
RLF f, d Rotate Left f through Carry 1 C
RRF f, d Rotate Right f through Carry 1 C
SUBWF f, d Subtract W from f 1 C,DC,Z
SWAPF f, d Swap nibbles in f 1 -
XORWF f, d Exclusive OR W with f 1 Z


Mnemonic Operands Description Cycles Status Affected
BCF f, b Bit Clear f 1 -
BSF f, b Bit Set f 1 -
BTFSC f, b Bit Test f, Skip if Clear 1 (2) -
BTFSS f, b Bit Test f, Skip if Set 1 (2) -


Mnemonic Operands Description Cycles Status Affected
ADDLW k Add Literal and W 1 C,DC,Z
ANDLW k AND Literal with W 1 Z
CALL k Call Subroutine 2 -
CLRWDT - Clear Watchdog Timer 1 TO,PD
GOTO k Go to Address 2 -
IORLW k Inclusive OR Literal with W 1 Z
MOVLW k Move Literal to W 1 -
RETFIE - Return from Interrupt 2 -
RETLW k Return with Literal in W  2 -
RETURN - Return from Subroutine 2 -
SLEEP - Go into Standby mode 1 TO,PD
SUBLW k Subtract W from Literal 1 C,DC,Z
XORLW k Exclusive OR Literal with W 1 Z


Para más detalles acerca de dichas instrucciones se puede recurrir a la sección 15 del datasheet de los PIC de la familia 16F78X. Por poner un ejemplo, el código requerido para la programación de un if debería ser como el siguiente:

Código C++:

        .....
        if(a==0){
            f();
        }else{
           ....

Código Generado con compilador SDCC:

Ciclos   Instrucción
  (1)     BANKSEL    _a  ;Se selecciona el banco de memoria donde está la variable a
  (1)     MOVF    _a,W    ;Se mueve a al acumulador
  (1)     IORWF    (_a + 1),W  ;Se realiza una OR lógica entre (a+1) parte alta H(a) de a 
                                        ; y el acumulador parte baja de a L(a)
  (1,2)  BTFSS    STATUS,2    ;Se comprueba el estado del bit de Zero (si es 1 se salta la siguiente
                                               ; instrucción) si el bit es set (1 ciclo sino 2 ciclos)
  (2)     GOTO    _00110_DS_  ;Si la OR lógica entre H(a) y L(a) no es cero se salta al else del if
  (2)     CALL    _f         ; De lo contrario significa que a vale 0 y por lo tanto se ejecuta el interior del if


Como se puede comprobar en el código anterior, el funcionamiento de la comparación de la variable a con cero, se realiza de una forma muy dependiente de la maquina y que porbablemente se haya elegido por rendimiento frente a otras opciones.  En el mejor caso este código tarda 6 ciclos y en el peor caso el código tarda 7 ciclos. Sin embargo al realizar una comparación con uno se puede comprobar que el código generado no es el mismo:

Código C++:
        .....
        if(a==1){
            f();
        }else{
           ....

Código Generado con compilador SDCC:

 Ciclos   Instrucción
  (1)     BANKSEL    _a  ;Se selecciona el banco de memoria donde está la variable a
  (1)     MOVF    _a,W    ;Se mueve a al acumulador la parte baja de a
  (1)     XORLW    0x01  ;Se realiza una XOR entre el acumulador y el valor 1 de manera que si difiere en 
                                       ;algún bit el resultado será disinto de 0
  (1,2)  BTFSS    STATUS,2    ;Se comprueba el flag de cero Z 
                                                ;(si está activo se salta la siguiente instrucción)
  (2)     GOTO    _00112_DS_   ;Si es distinto de cero quiere decir que no vale 
                                                  ; uno y portanto sale del if con esta instrucción GOTO

           ;A continuación se realiza la misma opreación para la parte alta de a

  (1)     MOVF    (_a+1),W       ;Se mueve la parte alta de a al acumulador
  (1)     XORLW    0x00            ;Se realia una XOR entre el acumulador y cero
  (1,2)  BTFSS    STATUS,2      ;Se comprueba el estado del flag cero Z 
                                                  ;Si está activo se salta la siguiente  instrucción y ejecutaría el código del if
  (2)    GOTO    _00112_DS_  ;Si el flag de cero no está activo significa que la parte de a no vale cero
  (2)     CALL    _f         ; Este sería el código interno del if

Como se puede ver este último código se puede generalizar y se podría emplear para realizar la comparación también con cero simplemente sustituyendo el valor de la segunda instrucción por 0x00 al igual que se hace con la parte alta de la variable a. Sin embargo, el primer código que generó el compilador es más óptimo ya que este último tiene un mejor caso de 6 ciclos (correspondería al caso en que la parte baja de a no vale 1) y un peor caso de 11 ciclos (se ejecutarían las instrucciones 1,2,3,4x2,6,7,8x2 y 10). Al programar directamente en ensamblador, este tipo de optimizaciones corren por cuenta del programador y puede que se le ocurra realizar las tareas de esta forma pero también corre el riesgo de que no sea así. Además, por lo general estas optimizaciones dependen enormemente del microcontrolador que se está empleando por lo que requeriría de un profundo estudio para encontrar las técnicas más eficientes y una gran disciplina para ser metódico y hacer las cosas siempre de la misma forma, y no usar diferentes métodos según se le vayan ocurriendo.

En conclusión, al programar en C++ un programador tiene la ventaja de abstraerse de este tipo de detalles dejándolos para el compilador. En C++ las estructuras if, for o while siempre son de la misma forma y por lo tanto el programador no necesita preocuparse por estos detalles. Además, como se ha demostrado en muchos casos el compilador va a realizar códigos muy eficientes de manera automática. 

No obstante, cabe destacar que no es oro todo lo que reluce. Cuando se programa un microcontrolador en C++ hay que tener en cuenta ciertos detalles, que pueden pasar desapercibidos por un programador experto que desconozca la arquitectura sobre la que se está trabajando. La mayoría de estos detalles, se refieren a la forma de trabajar de un compilador. Es muy importante que el programador tenga conocimientos de bajo nivel sobre compiladores para que tenga en cuenta estos detalles, sin perder de vista que no todos los compiladores tienen porque generar el mismo código, pero que sí es frecuente que sigan unas ciertas pautas comunes a todos ellos. A groso modo, se puede adelantar que por regla general un switch es más eficiente que una serie de estructuras if else, que un if else if es mejor que varios if independientes consecutivos cuando los casos son excluyentes, que las llamadas a funciones consumen pila del microcontrolador y que en el caso del 16F876X esta pila está limitada a 8 niveles. En futuras entradas se comentarán estos y otros detalles acerca de la programación de este microcontrolador en C++ intentando que la mayoría de ellos se pueden extrapolar a otros casos.