domingo, 26 de agosto de 2012

Mostrando canción en LCD con Arduino (I)

En la última imagen del post anterior se podía ver cómo la canción que se reproducía actualmente en la radio online se mostraba en una pantalla LCD. En este post explicaré cómo lo estoy haciendo y aprovecharé para introducir la comunicación en serie entre el RPi y el Arduino.

No me voy a extender mucho describiendo el Arduino, ya que hay muchísima información disponible en la red. Básicamente es una plataforma basada en un microcontrolador AVR cuyo diseño es completamente libre así como su IDE y SDK. Se utiliza mucho en multitud de proyectos relacionados con la electrónica e incluso con la robótica, por ejemplo para controlar impresoras 3D, resolver cubos de Rubik o realizar mediciones mediante diversos sensores. Su consumo es muy reducido y puede funcionar incluso con una pila de 9V.

Debido a la gran cantidad de librerías que existen para Arduino, es relativamente sencillo controlar muchos dispositivos como pantallas LCD, matrices de LEDs, sensores de todo tipo, motores, etc. Además, es posible extenderlo con otros circuitos denominados shields, que le dotan de más posibilidades. Existen shields que incluyen conexión de red, conexión Bluetooth, lector de tarjetas SD, incluso conexión GSM.

En mi caso, para la prueba he usado un Arduino Duelillamove (el de toda la vida) con un shield LCD Keypad, que incluye un pequeño display LCD de 16 caracteres y 2 líneas y 4 botones programables.

IMG_0405

Ambos dispositivos los compré en eBay, que suelen salir más baratos que en tiendas de electrónica online. Para conectarlos basta con encajar el shield en la parte superior del Arduino, como muestra la imagen:

IMG_0411

En realidad, el shield lo único que hace es conectar de forma sencilla y sin soldaduras la pantalla y los botones con el Arduino, lo que es bastante más cómodo para las pruebas que conectar todo a mano, ya que queda más compacto. Seguramente más adelante usaré directamente una pantalla y unos botones o un receptor de IR para controlar la radio con un mando a distancia. Las pantallas de este tipo se pueden encontrar muy baratas por eBay. Yo tengo una pequeña colección Risa.

IMG_0406

Aquí podéis ver una pantalla de 20x4 caracteres en la parte de abajo a la derecha, y varias de 16x2 de diferentes colores. Seguramente acabe utilizando la de 20x4, que permite mostrar más información al usuario de la radio.

También existen otro tipo de pantallas que pueden ser más apropiadas para otros proyectos. Por un lado están las matrices de LEDs, que son más complicadas de programar, ya que las librerías no están tan depuradas y se trabaja a muy bajo nivel. En mi caso utilicé este tipo de pantalla para un proyecto ya acabado de reloj despertador con Arduino.

IMG_0407

Como se puede ver en la imagen, la pantalla es simplemente una matriz de LEDs que pueden estar o no iluminados. También existen matrices de LEDs RGB que permiten elegir el color de cada LED, aunque son bastante más caras.

Otro tipo de pantallas son las de segmentos, parecidas a las de las calculadoras.

IMG_0408

La imagen de arriba es simplemente un termómetro usando un Arduino y un sensor de temperatura LM35 (a la derecha del display).

Existen aún más tipos de pantalla. Las hay incluso gráficas, como la de muchas calculadoras avanzadas. Sin embargo, para la radio, las pantallas de caracteres me parecen mas adecuadas y me permiten aprovechar material ya comprado.

Para empezar a trabajar con el Arduino, simplemente hay que descargarse el IDE desde la página oficial, descomprimirlo en donde deseemos y ejecutarlo. Ahora podemos conectar al PC el Arduino y se instalará automáticamente. Por último podemos cargar un programa de prueba desde Archivo –> Ejemplos. Yo he elegido Blink:

image

Con el Arduino conectado basta con pulsar en cargar (el icono con la flecha hacia la derecha de la parte superior de la interfaz) y el IDE se encarga de programar el Arduino de reiniciarlo para ejecutar el programa.

Una vez probado el funcionamiento, he realizado un pequeño programa para permitir que el Arduino muestre el artista y la canción que se está reproduciendo en el display del shield. Pongo el código y lo comento a continuación:

  1: #include <LiquidCrystal.h>   
  2: #include <LCDKeypad.h>   
  3:     
  4: LCDKeypad lcd;   
  5: String serialIn;   
  6: String serialOut;   
  7: boolean serialComplete = false;   
  8:     
  9: void setup(){  
 10:   Serial.begin(9600);  
 11:     
 12:   lcd.begin(16,2);  
 13:   lcd.clear();  
 14:   lcd.print("Arduino Radio");  
 15:   lcd.setCursor(0,1);  
 16:   lcd.print("V 0.0");  
 17:   serialIn.reserve(200);  
 18:     
 19:   Serial.println("INITOK");   
 20: }  
 21:    
 22: void loop(){  
 23:   if(serialComplete){  
 24:      Serial.println(serialIn);  
 25:      if (serialIn.startsWith("UP")){  
 26:        lcd.setCursor(0,0);  
 27:        lcd.print("                ");  
 28:        lcd.setCursor(0,0);  
 29:        lcd.print(serialIn.substring(3));  
 30:          
 31:        Serial.println("OK");  
 32:      }  
 33:        
 34:      else if (serialIn.startsWith("DW")){;  
 35:        lcd.setCursor(0,1);  
 36:        lcd.print("                ");  
 37:        lcd.setCursor(0,1);  
 38:        lcd.print(serialIn.substring(3));  
 39:          
 40:        Serial.println("OK");  
 41:      }  
 42:        
 43:      else{  
 44:        Serial.println("KO");  
 45:      }  
 46:    
 47:      serialIn = "";  
 48:      serialComplete = false;  
 49:   }  
 50:   Serial.println("Loop");  
 51:   delay(1000);  
 52: }  
 53:    
 54:    
 55: // Reads the serial input and stores in serialIn  
 56: void serialEvent() {  
 57:   while (Serial.available()) {  
 58:     // get the new byte:  
 59:     char inChar = (char)Serial.read();   
 60:     // add it to the inputString:  
 61:     if(inChar != '\n'){  
 62:       serialIn += inChar;  
 63:     }  
 64:     // if the incoming character is a newline, set a flag  
 65:     // so the main loop can do something about it:  
 66:     if (inChar == '\n') {  
 67:       serialComplete = true;  
 68:     }  
 69:   }  
 70: }



Las dos primeras líneas cargan las librerías necesarias para controlar la pantalla LCD y el Shield LCDKeypad. Esta versión del LCDKeypad hereda de LiquidCrystal, así que es posible utilizar todas las funciones de LiquidCristal desde la librería LCDKeypad). En principio LiquidCrystal.h no es necesario incluirlo, aunque habrá que hacerlo cuando cambiemos el shield por una pantalla independiente.


Las líneas 4 a 7 declaran las variables globales que vamos a utilizar, en concreto un objeto LCDKeypad que representa nuestro shield, dos cadenas para poder recibir y enviar texto a través del puerto serie y un booleano que nos indique si la transmisión de datos ha terminado o no.


La función setup (líneas 9 a 20) se ejecuta una sola vez en cuanto se enciende el Arduino, y se suele usar para inicializar el sistema. En mi caso, inicio la conexión serie a 9600 baudios (línea 10), inicializo el display (línea 12) indicando que el display es de 16 caracteres y dos líneas.


En la línea 13 borro cualquier carácter que pudiera haber en la pantalla y a continuación escribo Arduino Radio (por defecto el cursor está en la posición 0,0 después de un clear), me desplazo a la columna 1 y escribo la versión.


En la línea 17 reservo 200bytes para la cadena de entrada y envío un INITOK por el puerto serie para que el dispositivo receptor (en este caso el RPi) sepa que el Arduino ya se ha inicializado.


Una vez ejecutada la función setup, Arduino ejecuta de forma periódica la función loop (líneas 22 a 52). En ella primero comprobamos que se haya recibido un envío por puerto serie (de lo que se encarga la función serialEvent que se puede ver más abajo). En ese caso, mira los dos primeros caracteres:


Si los caracteres son “UP” escribe el resto de la cadena en la línea superior de la pantalla y envía un “OK”.


Si los caracteres son “DW” escribe el resto de la cadena en la línea inferior de la pantalla y envía un “OK”.


Si los caracteres no son ni “UP” ni “DW”, no hace nada y envía “KO” por el puerto serie, para indicar que no se ha procesado el mensaje.


Por último, borra la cadena de entrada para poder utilizarla de nuevo, y pone la variable serialComplete a false para prepararse para el siguiente envío del RPi. La última línea de la función es un delay de 1s para que no esté ejecutando continuamente el bucle, sino que espere un segundo entre ejecuciones.


La función serialEvent (líneas 56 a 70) se activa cuando Arduino detecta datos entrando por el puerto serie. En este caso lo que hacemos es almacenar los datos en la cadena serialIn y activar la variable serialComplete una vez que hayamos terminado la cadena (en nuestro caso, al recibir un carácter de salto de línea).


La idea de este programa de ejemplo, es que podamos parsear el artista y la canción (o lo que queramos) desde el RPi, y lo vayamos enviando al Arduino por el puerto serie, actuando el Arduino como un simple controlador de la pantalla, que procese las órdenes que le llegan y muestre la información en el display. Más adelante podremos introducir otras órdenes más complejas y dejar que el Arduino se encargue de actualizar el display. Por ejemplo podríamos utilizar un comando desde el RPi para obtener la cobertura Wifi, y enviar un comando al Arduino como:


WF 78%


Y que éste de encargase de actualizar sólo la zona de la pantalla donde se muestra la cobertura Wifi, evitando actualizar toda la pantalla.


Si ejecutamos este programa en el IDE de Arduino, podemos activar el monitor serie y ver cómo efectivamente, se recibe el INITOK, el Loop en cada bucle y como procesa las órdenes (que le podemos escribir directamente en el monitor):


image


En el siguiente post veremos cómo reproducir emisoras con el MPD y MPC, cómo extraer los datos de la canción y cómo enviarlos a RPi utilizando Python.


Aprovecho para comentar que lo más seguro es que los códigos que vaya colgando no sean lo más correcto en cuanto a programación, tolerancia a fallos y demás. Conforme vaya avanzando en el proyecto iré puliendo los códigos, pero se agradece cualquier comentario y/o crítica constructiva que pueda servir para mejorar.

No hay comentarios:

Publicar un comentario