Algunos consejos para usar TFT´s

No pretendo crear una guía, solo quiero compartir lo que he aprendido al urgar entre las muchas lineas de código que suben los compañeros al foro. A sugerencia de surbyte, creo este hilo con la idea de que entre todos le saquemos todo el provecho posible a las pantallas TFT.

Advierto que habrá aspectos que bien se podrían resolver con lineas de código mejor optimizadas o depuradas, debo decir que soy un fan de la electrónica y no me considero un erudito, asi que toda crítica constructiva, será bien aprovechada.

Las librerías que he usado por orden de importancia son FTDI (FT800 de FTDI), ILI9341_due (me inclino por la versión 094 ), ILI9341 (Adafruit), TFTLCD (Adafruit), UTFT. Me gustaría manejar la librería ILI9341_t3 (teensy) o la desarollada para el gameduino2, pero ya veremos. Las que me parecen mas complicadas son: TFTLCD y ILI9341_due

Presentación de valores numéricos

Una de las primeras cosas que queremos ver en nuestra flamante pantalla TFT, es el valor de algun sensor de temperatura o de un acelerómetro, un voltaje, las RPM´s de algun motor, el ángulo de un servo, los datos de un GPS, etc, etc; casi siempre se vuelve un dolor de cabeza cuando vemos que lo que mandamos a la pantalla o se sobreescribe, presenta residuos de caracteres o bien en el mejor de los casos tiene un efecto parpadeante, y nos deja a medias con el gusto inicial.

El mejor camino es convertir el valor numérico en una cadena de caracteres; casi todas las librerías tienen muy bien optimizada esta parte.

El primer paso es definir una variable tipo char, con una sola basta para presentar todos los valores en un proyecto.

char TX[50];

Dentro del loop en el que se presentarán los datos en pantalla, convertimos el valor numérico en una cadena de caracteres mediante la instrucción sprint. Esta conversión funciona con valores enteros, aunque bien podría funcionar con numeros float, he visto que se obtiene un "?" como resultado. Dado que el resultado es una cadena, podemos dar el formato que deseemos, dependiendo del tipo de fuente, podemos incluso insertar símbolos o letras, Acá algunos ejemplos

Número con tres decimales "000"

sprintf(TX,"%03d", Valorslider);

Número con dos decimales, espacio y letras:

sprintf(TX,"%03d C", Valorslider);

Número con compuesto por varios datos:

sprintf(TX,"%02d:%02d:%02d", hh, mm, ss);

La ventaja de complementar con un cero las posiciones a la izquierda del dato es que los números no se encimarán o dejarán pixeles remanentes.

Bien pueden usarse expresiones como estas: %2d, en las que no se dibujan ceros en las posiciones libres a la izquierda, habrá que probar cual de las dos opciones da el mejor resultado, ya que algunas librerias centran por default los caracteres y dejan pixeles de los caracteres previos. Las librerias derivadas de la adafruit_ILI9341 responden mejor con el formato %02d, el %2d deja residuos.

Otro problema que es culpable de pixeles remanentes, tiene que ver con el diseño de la propia fuente, en teoría todos los caracteres deben tener dimensiones idénticas, es decir altura y ancho común, esto da como resultado que los caracteres se sobreescriban sin dejar residuos, cuando alguno de ellos no coincide en medidas, tiende a dejar residuos. La solución es crear una fuente personalizada o bien que la propia libreria tenga la posibilidad de insertar espacios adicionales entre caracteres.

Con la libreria TFTLCD ambos formatos funcionan sin problemas. Ejemplo:

     int T = random(90,110);
     sprintf(TX,"%3d C", T);
     tft.setCursor(137, 50); 
     tft.setTextColor(YELLOW, BLACK);  tft.setTextSize(3);
     tft.println(TX);   
   
   
     int TDInt = random(95,115); //simula los datos del sensor
     int fracc = random (0,99);    //simula los datos del sensor
     sprintf(TX,"%3d.%02d C", TDInt, fracc);
     tft.setCursor(85, 100); 
     tft.setTextColor(YELLOW, BLACK);  tft.setTextSize(3);
     tft.println(TX);

Code in action

Ejemplo con la librería ILI9341_due (v 094)

t3.defineArea(0, 0, 319, 239);
t3.selectFont(Arial14);  
t3.setFontLetterSpacing(2);

   unsigned long currentMillis1 = millis();        
   if(currentMillis1 - previousMillis1 > 2000)
    {
       previousMillis1 = currentMillis1;  
       lecturaV = random(0,1023);  //simula los datos del sensor
       
       Volumen = map(lecturaV,0,1023,0,100);
       sprintf(TX,"Lectura = %04d  (%03d ml)", lecturaV, Volumen);
       t3.setFontColor(WHITE, ILI9341_BLACK);
       t3.drawString(TX,80,50); 
    } //usa millis en lugar de delay

Las librerias UTFT y FTDI, cuentan con instrucciones que directamente pueden manejar valores numéricos e incluso permiten aplicarles un formato, su uso es bastante simple

Sigue: creación de menus aprovechando la pantalla táctil

2 Likes

Creo que este post (y los prometidos siguientes) es muy interesante y deberías publicarlo en el hilo de documentación.

Me has convencido, cuando finalice uno que me esta llevando de cabeza, voy a probar con un tft. Siguiendo este hilo. Parece ser sencillo y con el camino abierto.

Gracias por el aporte.

Esperemos que ayude a mas de uno a mejorar sus proyectos, vamos con el siguiente punto.

Creación de menús con la pantalla táctil

La mayoría de TFT´s disponibles tienen pantallas táctiles resistivas. Debo aclarar que existen dos tipos de cableado: uno de ellos fue diseñado para funcionar en el arduino UNO y emplea cuatro hilos generalmente dos pines analógicos y dos pines digitales, resulta algo confuso ponerlo a punto ya que hay que asignar manualmente y por prueba y error el valor de la resistencia de referencia de la pantalla táctil. Usan chips tanto XPT2046 como STMPE610, su funcionamiento es complejo y aun hoy no he podido llegar a conocerlos bien.

La otra variante en la que se conecta el XPT2046, emplea 5 lineas: TCLK, TCS, TDIN, TDOUT, IRQ. A pesar de que el nombre de cada pin podría señalar a la pantalla táctil como un dispositivo SPI, esto no es así, gracias a la librería Utouch diseñada por Henning Karlsen, la pantalla puede ser controlada por completo con pines digitales. En el Due o MEGA se puede usar cualquiera de ellos. No es necesario el empleo de conversores lógicos 5-3.3 V, ya que la pantalla se comporta igual tanto en arduinos como el UNO o MEGA, e incluso el Due.

No he podido conseguir TFT con pantallas táctiles capacitivas, aun tengo mucho por aprender de ellas.
Me centraré en pantallas con chip XPT2046 y 5 hilos. Asumiré que ya tenemos la tripleta de calibración que podemos conseguir del ejemplo Utouch_Calibration.

Para usar la pantalla táctil dentro de un sketch, las lineas de código básicas son

Inicio del encabezado

#include <UTouch.h>   // touch lib   XPT2046

Antes de la definición de variables generales

//touch panel (TCLK, TCS, TDIN, TDOUT, IRQ)
UTouch  myTouch(6,5,4,3,2);

Estas variables generales posibilitarán el acceso a las coordenadas de la pantalla táctil

int x, y;

En el setup(), hay que incluir estas lineas:

   myTouch.InitTouch();
    myTouch.setPrecision(PREC_HI);

Hay 4 modos para esta linea: LOW, MEDIUM, HI y EXTREME, la que mejor se comporta es la HI.

La mejor forma de usar la pantalla táctil es dividirla en segmentos rectangulares, dentro de bucles de espera que responden al cambio de alguna coordenada xy de la pantalla táctil. De esta forma podemos usar toda la pantalla o solo segmentos de ella.

Sugiero diseñar cada menú como una función independiente, de esta forma podemos usar la pantalla táctil completa en cada menu, sin que se superpongan secciones táctiles remanentes.

void Menubase()
{
    //Instrucciones que solo se usan una vez al activar el menu: fondos de pantalla, valores iniciales de una variable, imagenes BMP, texto inicial, encabezados, distribución de botones. 
    
    while (true)
      {

//Instrucciones que llaman secciones de programa que cambian con el tiempo: la hora de un reloj, la lectura de algún sensor, acción con algún led, por ejemplo


        if (myTouch.dataAvailable())
           {

//Instrucciones que dependen de la presión de algún segmento de la pantalla táctil
              myTouch.read();
              x=myTouch.getX();
              y=myTouch.getY();        


//Segmentos de pantalla táctil para accesar a nuevos menús o bien manipular algún deslizador o icono

// MenuX              
        if ((y>=y11) && (y<=y12)) 
           {      
          if ((x>=x11) && (x<=x12)) 
             {        
                Redbox24SPI(x11,y11,x12,y12);                
                MenuX();
             }
           }    
//End Menu X

           }

      }
}

Esta función podemos usarla para crear el menu principal y también permite crear todos los menus que necesitemos en el proyecto, usando cualquier parte de la pantalla

Sugiero usar segmentos acotados con valores específicos, con la idea de no cargar de variables cada sketch, en el ejemplo uso variables para cada segmento táctil debido a que me resultó muy cómodo para diseñar menus rápidos.

El dibujo de botones lo podemos lograr usando funciones generales como esta:

void button24SPI(int x1, int y1, int x2, int y2, uint16_t color)
{
  tft.fillRoundRect(x1,y1,(x2-x1),(y2-y1),3,color);  
  tft.drawRoundRect(x1,y1,(x2-x1),(y2-y1),3,WHITE);  
}

Para resaltar los botones que pulsamos, recomiendo usar una función indicadora como esta:

void Redbox24SPI(int x1, int y1, int x2, int y2)
{
  tft.drawRoundRect(x1,y1,(x2-x1),(y2-y1),3,RED);  
  
  while (myTouch.dataAvailable())
  myTouch.read();
  tft.drawRoundRect(x1,y1,(x2-x1),(y2-y1),3,RED);  
}

Así podremos "tener la sensación de tocar" el botón cuando lo pulsamos

Este es el sketch completo MEGA menu

Funciona con la librería ILI9341_due versión 094, tanto en Due como en MEGA, incluso funciona en el arduino UNO. Las pantallas en las que funciona directamente son estas: ILI9341 2.4" o ILI9341 2.8".

Con algunos ajustes también puede funcionar en pantallas que funcionan con la librería UTFT, como las basadas en el chip SSD1986 o bien ILI9325D/C, ya que casi todas tiene el chip XPT2046 con 5 hilos de control

Funcionamiento de algunos ejemplos:
Calibración de la pantalla táctil
Botón táctil de encendido/apagado de la PC
Menu 1
Menu 2

En la siguiente: diseño de barras deslizantes que funcionan con la pantalla táctil

Haré una pausa en el diseño de indicadores. La primer TFT que llegó a mis manos fué una pantalla de 2.4" de mcufriend. Nunca pude hacer que la pantalla táctil diera signos de vida.

Me topé con este par de trabajos, en los que un fan de estas pantallas ha trabajo para conseguir que de una vez funcionen tal como nos prometen los vendedores.

TFT en UNO

TFT en MEGA

Modificó con éxito algunas secciones de la librería Adafruit TFTLCD con la idea de poder usar la pantalla, su lector SD y la libreria TouchScreen para activar pantalla táctil que a tantos nos ha costado despertar. También hizo algunos cambios en la libreria SD y me parece que las imagenes BMP se pueden leer de forma estable, solo hay que cuidar que el formato de cada BMP sea de 24 bits.

No ahondaré en la puesta a punto, ambas ligas tienen todo lo necesario para activar el shield. Me parece un logro bastante destacable el hecho de que se puede usar la pantalla conectándola directamente en el MEGA sin modificar nada.

Tomando como base los ejemplos, conseguí aproximar los parámetros para que la calibración de la pantalla táctil se adapte a la rotación 3 del TFT (por default las librerias usan la Rotación 1). Modifiqué los parámetros de ajuste para que la pantalla táctil inicie desde los iconos prediseñados, con la idea de poder usarlos en cualquier parte de un skecth.

La estructura de control que posibilita integrar la función táctil en la libreria Touchscreen, también se puede usar en la libreria Adafruit_STMPE610 que usan algunas pantallas ILI9341 o HX8357

En este caso, la estructura de cada menú tiene las siguientes partes

Instrucciones que solo se cargan una vez al llamar el menu

void MenuBlanco()
{
    bmpDraw(imagesOnSDCard1[imagenSD1],0,0);  //o puede ser un tft.fillScreen(0);
    tft.setTextSize(0);              
    
//botones prediseñados    
    button24(ix11, iy11, ix12, iy12, GREEN); //icono casa    
    button24(ix21, iy21, ix22, iy22, GREEN); //icono libro
    button24(ix31, iy31, ix32, iy32, GREEN); //icono correo
    button24(ix41, iy41, ix42, iy42, GREEN); //icono cámara    
    button24(ix51, iy51, ix52, iy52, GREEN); //icono monitor
//botones prediseñados    
    tft.setTextSize(2);
    button24(x21, y21, x22, y22, BLUE);   //Botones diseñados
    tft.setCursor(x21+TextoX,y21+TextoY);  tft.setTextColor(WHITE,BLUE);  tft.println("M P");//Botones diseñados

Instrucciones que permiten actualizar la lectura de un sensor, un reloj, o monitorear continuamente las entradas táctiles

do
     {
        //lecturas que cambian con el tiempo, monitoreo de pantalla táctil
     }
while(1);

Las lineas anteriores, posibilitan que la parte void loop(), permanezca sin usar, llamando los ciclos de todo el sketch desde el void setup()

Dentro de ellas, se puede colocar la función que se encarga de monitorear las coordenadas de la pantalla táctil y las coordenadas entre las que deseamos que un elemento grafico tenga funciones táctiles.

void lecturaPanelTactil()
{
    TSPoint p = ts.getPoint(); 
    pinMode(XM, OUTPUT); 
    pinMode(YP, OUTPUT); 
//Rotacion 3
    X = map(p.y, TS_MINX, TS_MAXX, tft.width(), 0);
    Y = map(p.x, TS_MAXY, TS_MINY, tft.height(), 0);
//Rotacion 3
    Z = p.z;
}

Por ejemplo, para el diseño de botones, recomiendo usar una función que sea la encargada de dibujarlos, con esto ahorramos espacio de programación. Por ejemplo

//Funcion para dibujar botones
void button24(int x1, int y1, int x2, int y2, uint16_t color)
{
  tft.fillRoundRect(x1,y1,x2,y2,3,color);  //relleno del botón
  tft.drawRoundRect(x1,y1,x2,y2,3,WHITE); //Borde del botón 
}

Solo falta definir los segmentos de pantalla táctil que corresponderán a los botones o elementos gráficos que haran alguna acción o llamarán a un nuevo menu. Este es un ejemplo:

//boton azul   --- Retorno a menu principal
      if((X > x21+deltaTactil && X < x21+x22+deltaTactil) && (Y > y21 && Y < y21+y22) && (Z > MINPRESSURE && Z < MAXPRESSURE)) 
        {  
          Serial.print("x= ");
          Serial.print(X);    
          Serial.print("   y= ");            
          Serial.print(Y);  
          Serial.println("   ");
          tft.fillRoundRect(x21, y21, x22, y22,3, RED);
          tft.setCursor(x21+TextoX,y21+TextoY);  tft.setTextColor(WHITE,RED);  tft.println("M P");//Botones diseñados          
          delay(350);
          button24(x21, y21, x22, y22, BLUE); 
          tft.setCursor(x21+TextoX,y21+TextoY);  tft.setTextColor(WHITE,BLUE);  tft.println("M P");//Botones diseñados
          MenuP();
        }   
//boton azul   --- Retorno a menu principal

Ejemplo de menus y carga de imagenes en funcionamiento

Sketch e imagenes

El trabajo me mantiene bastante ocupado, no obstante en los ratos libres he estado aplicado con otra pantalla: un gameduino 2. Recientemente el creador de este proyecto de pantalla, ha liberado la libreria oficial para el arduino Due.

Aunque fué diseñado como un shield para el arduino UNO, el creador del gameduino2 añadío a la librería, la posibilidad de redirigir las señales del cabezal SPI a los pines 11,12 y 13 del arduino Due, por lo que sin ningun problema el shield puede instalarse sobre el arduino Due, tal como se conecta al arduino UNO.

El ángulo de visión de la pantalla que tiene el gameduino es un 60% más estrecho que el ángulo de visión del FT843, no obstante, la velocidad de ambas pantallas para el manejo de gráficos es asombrosa, nada menos que 60 Hz de tasa de refresco. Nada mal, considerando la modesta velocidad de los micros como el UNO o el MEGA.

En la siguiente intervención les compartiré algunos ejemplos de lo que se puede hacer con esta pantallita.

Muy buenas TFTLCDCyg, lo primero agradecerte este tema tan interesante que la verdad me ha venido de perlas, y por otra parte te quería preguntar una cosita.

Para el proyecto tengo un DUE, el shield y una pantalla TFT de 5" para la presentación por pantalla utilizo pantallas completas para ver la representación gráfica, mi duda es que no se si se puede que en una parte de la pantalla osea encima dibuje un circulo y luego pueda borrarlo sin que desaparezca la parte de atrás, osea la pantalla que ya estaba puesta.

A ver si puedes darme un poco de luz en este tema, y cuando puedas completar todo lo que dices que estoy seguro que sera cuando menos igual de interesante como hasta ahora.

Saludos.

Directamente un TFT en arduino no es capaz de conseguir un efecto gráfico como el que describes, pensando en que todo lo consigas en una sola presentación o un solo paso.

El mecanismo que te sugiero, funciona muy bien a bajas velocidades, es decir que mantengas una presentación cada determinado tiempo. Si deseas algo en tiempo real o alta frecuencia, como digamos algo parecido al video del analizador de espectro en el gameduino 2, en definitiva el equipo que tienes no te va a servir.

Este es el video al que me refiero con el gameduino 2 y el analizador de espectro

El truco que podrías usar consiste en diseñar dos o tres o las "presentaciones" que necesites con la misma imagen de fondo y mediante un botón táctil, ubicado en alguna de las esquinas o bien que que ese botón táctil ocupe toda la pantalla, podrías ir pasando de presentación en presentación. Cada presentación puede tener botones, o imágenes superpuestas, en el orden que quieras.

El efecto negativo que podrías ver al pasar de una presentación a otra, es el relativo a la velocidad con la que la imagen de fondo se dibuja en la pantalla.

El primer paso es que consigas cargar las imagenes desde el lector SD que debe tener tu pantalla. Para la libreria UTFT lo mejor es que uses la libreria que describen en este post:

http://forum.arduino.cc/index.php?topic=273573.0

Te recomiendo leerlo todo ya que hay varias actualizaciones de la libreria, y lo mejor de todo es que puedes aprender a usarla adecuadamente. Hay que convertir las imagenes a formato RAW, en el post está lo que necesitas saber.

Este es un ejemplo de lo que puedes conseguir, es una pantalla de 2.4" funcionando con la libreria que te sugiero, para UTFT y Sdfat.

Debes calibrar el panel táctil de tu pantalla con la libreria Utouch que viene dentro de UTFT.

Luego debes familiarizarte con el manejo de menus y submenus mediante el uso de la pantalla táctil, esto te ayudará a intercambiar las presentaciones en el orden que mejor te parezca, no necesariamente de forma secuencial.

Con esos 3 pasos debes poder atacar la transición entre presentaciones en tu pantalla.

Vaya TFTLCDCyg me has sorprendido con la presentación del gameduino 2, por lo que he visto es un poco caro, pero creo que lo necesito para este proyecto, es una pasada lo que se puede hacer con el.

Lo de las imágenes por la tarjeta SD es lo que estoy haciendo, pero como tu dices en una pantalla de 5" no es lo rápido que se necesita, y ademas crea un efecto desagradable.

A si que si quiero hacer lo que te explicaba ya veo donde tengo que morir.

Supongo que no hay problema para instalar el gameduino en arduino DUE, y entonces puede trabajar conjuntamente con el shield de la TFT? o se puede prescindir de la shield?

Muchísimas gracias, eres un crack del TFT

Saludos.

He estado mirando y por lo que veo el gameduino 2 va con la pantalla de 4,3", a si no se puede poner otra pantalla, osea la que tengo no me sirve para este sistema, y 4,3" la veo un poco pequeña.

Hay algun otro tipo que sea similar que se pueda añadir una pantalla de 5" o de 7"?

La verdad que me gusta como trabaja pero como te digo quizá me resulte un poco pequeña para el sistema que estoy haciendo.

Saludos.

De hecho decidí adquirir un gameduino2, porque el creador de este shield, a finales del 2015 liberó las librerias que permiten hacerlo funcionar en el arduino Due. Originalmente lo diseño para funcionar en UNO o MEGA.

Otro detalle que me llamó mucho la atención, es que el shield del gameduino2 tal como está, se puede conectar directamente sobre el arduino Due, no hay que hacer cambios físicos. El autor hizo que la libreria transporte las señales del cabezal SPI del arduino Due, a los pines 11, 12 y 13, con esto se evitó modificar su proceso de fabricación, y el shield se puede usar sin problemas.

Asi es como se ve sobre el arduino Due:

Decidí construir una interfase para el gameduino y el arduino Due, porque necesito otros elementos como un DS3231, otro lector micro SD para la gestion de datos, los 4 chips MSGEQ7, este es el cable y las dos placas de interfase

Otros tamaños... la libreria del gameduino 2 esta diseñada para manejar la familia de chips FT8XX. El GD2 tiene el chip FT800, de acuerdo con el autor, es posible usar cualquier pantalla que tenga esos chips, pero con algunas limitaciones respecto al tema del acceso al lector SD.

FTDI chip tiene un par de tarjetas de desarrollo con pantallas de 5".

FT800C: VM800C50A-D incluye una pantalla de 5"
FT810C : la placa es VM810C50A-D, incluye una pantalla de 5", con resolución de 800 x 480 px

Ambas opciones se podrían conectar al arduino due y controlarlas mediante a libreria del gameduino 2, pero habría que armar el cableado o la interfase. Bastan 8 hilos para conseguirlo

La desventaja es que no tendrías acceso a la parte de carga de imagenes desde un lector SD, ya que esas tarjetas no tienen el circuito interconectado al chip FT8XX, para tener acceso a la gestion de carga de imagenes.

Un detalle mas que me convenció para decantarme por estas pantallas, es que el FT800 tiene la capacidad para manejar un nivel de pixel de hasta 1/16

Puntos encontra: hay que ajustar el nivel de la retroiluminación a un 92% para que no se perciba que la pantalla se calienta, eso se puede conseguir mediante la propia libreria, dentro del setup. Esto se percibe en el gameduino 2, pero en el FT843 no ocurre.

El ángulo de visión del GD2 es algo reducido, pero no es algo que le reste funcionalidad.

El FT800 tiene un espacio limitado para almacenar información de 256K. Aparentemente es una limitante enorme, pero se puede usar alguna que otra técnica para que no afecte en la práctica

En el FT810 el limite es de 1MB, pero aun no se ha diseñado una placa que incluya un lector SD. Ojalá este año liberen una pantalla así, sería la evolución en este tipo de pantallas para arduino

Vaya, cuanto sabes, da gusto hablar contigo, creo que primero probare el gameduino 2 ya que es una pasada.

Me podrías decir algun sitio de confianza para poder comprarlo.

Saludos.

La diferencia entre 4.3 y 5", no es mucha, estimo que serán un par de lineas de texto. El gameduino 2 sin bisel mide 10.5 x 6.7 cm, tiene una resolución de 480 x 272 px.

Este es uno de los primeros ejemplos que me hicieron investigar el tema de las pantallas basadas en el FT800:

Las dos opciones que cubren todas las prestaciones del FT800 son:

  • Gameduino 2
  • FT843 + ADAM de 4D systems

Ambas tienen habilitado un lector micro SD y cuentan con un amplificador de audio

Estoy haciendo pruebas para adaptar el FT843 para que funcione con la libreria del gameduino 2; de fábrica viene preparado para funcionar con la libreria nativa del FT800, pero es algo pesada, se puede usar pero hay que escribir muchas lineas de codigo.

Estuve revisando el datasheet del adaptador para arduino del FT843 (ADAM por sus siglas en ingles). El soporte para la tarjeta micro SD tiene el siguiente pinout

1         NC
2         SD-CS  (3V3)
3         MOSI   (3V3)
4         3.3 V
5         SCK    (3V3)
6         GND
7         MISO   (3V3)  
8         NC

Solo hay un condensador cerámico de 4.7 uF conectado entre Vcc y tierra.

De acuerdo con el datasheet del adaptador microSD (que recomienda mikroe para usarse en sus placas), el condensador cerámico puede eliminarse. Esta observación también aparece en el datasheet del breakout microSD de Sparkfun. Ambos adaptadores señalan que se deben alimentar con 3.3V exclusivamente. En dispositivos de 5V deben usarse divisores de voltaje o circuitos como el CD4050BE.

Así que puedo suponer que es factible usar un adaptador micro SD de 3.3V para agregarlo a dispositivos FT800 que no tienen esa opción de fábrica. Es muy posible que se pueda usar la libreria del GD2 en placas de desarrollo como el VM810C50A-D o el VM800C50A-D, agregandoles soporte para carga de imagenes.

Me llama mucho la atención la placa VM810C50A-D, pues el FT810 tiene 1M de memoria interna, que es 4 veces mas grande que la que tiene el FT800 como el gameduino2 o el FT843.

Pedí unos lectores micro SD de 3.3V, para hacer pruebas con el FT843 en cuanto termine de construir el adaptador. El lector microSD es este:

http://www.lctech-inc.com/Hardware/Detail.aspx?id=27e765c5-7052-46d7-846b-338e6b74495b

He estado construyendo un controlador de ventiladores para la PC, exploré varias opciones para añadirle un TFT táctil, di con el FT843 y me pareció la mejor opción, solo que me ha tomado mucho tiempo familiarizarme con su librería de control y no he podido llegar ni a la mitad de su potencial. Me llamó la atención el gameduino 2, sobre todo su librería, que me parece tiene un alto grado de optimización, tomando como referencia la librería original diseñada para el FT800.

Aun tengo pendiente el tema de la alimentación eléctrica para los ventuiladores, por lo que ese apartado lo tengo en pausa.

La semana pasada llegaron los lectores micro SD:

Dediqué un tiempo para construir un adaptador para conseguir que el FT843 admita el control con la librería GD2. Encontré que la distancia del cableado entre el ADAM y la pantalla no debe ser mayor a 23 cm, mas allá de esa distancia la pantalla no da señales de vida.

Dejé una distancia total de 18 cms

Opté por ensamblar un módulo lateral sobre el ADAM, ya que conectaré dos spectrum shields. El cableado lo manejé con cable plano de 10 hilos, de esta forma no habrá que lidiar con una veintena de hilos.

Con el lector micro SD también hay que cuidar la distancia del cable de interconexión, ya que mas allá de 15 cms el lector deja de funcionar. Opté por dejarlo en una distancia de 11 cms. La idea es poder colocar una ranura en el frontal del controlador, para tener acceso a la tarjeta micro SD sin tener que desmontar todo el dispositivo del gabinete de la PC.

Los lectores micro SD funcionan a 3V3, de los 6 que llegaron, 3 de ellos no funcionaron correctamente, y 3 si que respondieron como esperaba.

Por fin pude probar todo en conjunto: la libreria GD2, el lector microSD externo y el FT843/ADAM...

Un par de videos como muestra: modifiqué algunos ejemplos que vienen en la libreria GD2 para poder usarlos dentro del programa del controlador.

La libreria neomatrix de adafruit, tiene una instrucción llamada swipe, que entra en conflicto con la libreria GD2, ya que esta tiene también una instrucción llamada swipe. La solución fué bastante simple, solo renombré swipe por swipe1 en la libreria neomatrix.

En lo sucesivo trataré de ir subiendo aspectos generales para el manejo de la libreria GD2.

Proyecto: menu con iconos y fondo de pantalla

Objetivos:

  • Aprender a crear assets de imagenes
  • Usar la pantalla táctil
  • Aprender a crear menus interactivos

Cada presentación que se diseña en el FT800, está limitada a los 256 kb de memoria gráfica que tiene el chip, superando ese limite, el TFT deja de funcionar y nos recompensa con un "pantallazo azul"

Si alguna instrucción está incompleta en su estructura, aunque el IDE nos señale que el sketch no presenta errores, al activarla en pantalla también se mostrará el mensaje con fondo azul. Esto ocurre cuando se desborda una variable o colocamos una instrucción que depende de otra, como por ejemplo llamar una imagen que no hemos cargado en el FT800 previamente.

Paso 1: creación de un set de iconos

Muchas veces queremos usar un grupo de iconos y asociarlos al manejo de menus dentro de un sketch. Hay pantallas que ya vienen con un set de iconos y de fuentes precargados, que podemos usar al diseñar un proyecto. Paro aun con esa bondad estamos sujetos a los iconos y fuentes que el fabricante quiso colocar en su hardware y no hay de otra que sujetarnos a ellos. Aun así son muy contadas las pantallas que pueden hacer esto, en la gran mayoría de TFT´s disponibles para arduino, hay que ingeniárselas con imagenes bmp, raw o jpg.

Otro aspecto que he observado, es que no es posible manejar transparencias y debemos ajustar el diseño a iconos rectangulares o cuadrados, empleando una máscara de fondo para simular una transparencia.

En la libreria GD2, es posible crear arreglos o sets de iconos en formato png y aprovechar los fondos transparentes que se pueden manejar en ese tipo de archivos de imagen.

Cada set de iconos está limitado a 15 archivos de imagen individuales por cada pantalla que diseñemos, sin embargo es posible contar con varios de estos arreglos dentro de un mismo sketch y lo mejor de todo: activarlos en pantalla solo cuando los necesitemos, evitando llegar al limite de los 256 kb de la memoria gráfica del FT800.

Sugiero diseñar arreglos de 14 iconos, reservando el último espacio de memoria para el archivo de imagen que usaremos como fondo de pantalla.

La herramienta que nos permitirá obtener el arreglo de iconos se llama: gd2asset. Es un archivo que funciona desde la linea de comandos de windows.

PD: el tiempo apremia, hay que retomar el trabajo, mas tarde continúo.

El gd2asset permite convertir grupos de hasta 15 imágenes en formatos jpg, bmp y png. También es posible convertir archivos de fuente en formato ttf.

Se pueden ajustar parámetros en la linea de comando tales como resolución en imágenes, o tamaño de letra, en archivos de fuentes.

En el caso que nos ocupa, usaré algunos íconos en formato png de 48x48 px, del set de iconos denominado Oxígen Iconset, creado por KDE, son de uso público (política de uso)

Reunimos todos los archivos de los iconos dentro de la carpeta donde están los archivos del gd2asset.exe; abrimos la consola de comandos e ingresamos a la carpeta indicada. Sugiero que la ruta sea esta:

C:\GD2asset

Así evitamos algún conflicto en la conversión de archivos. Recomiendo asignar nombres cortos para que la captura de nombres no se vuelva tediosa, lo mas simple es un prefijo hecho con letras, seguido de un numero consecutivo. En cada set de iconos debemos usar prefijos diferentes para evitar conflictos de lectura dentro del sketch.

Ingresamos la siguiente linea de comando:

gd2asset -f nombre.gd2 -o nombre.h icono0.png icono1.png ...  icono13.png

Se crearan 2 archivos: nombre.gd2 y nombre.h. El primero (.gd2) se debe guardar en la microSD y el segundo (.h), va dentro de la carpeta que contiene el sketch en el que deseamos usar los iconos. Estos dos archivos forman cada asset.

El nombre de archivo debe iniciar con una letra y tener una longitud máxima de 8 caracteres. No es necesario copiar los archivos fuente de los iconos, ya que toda la información necesaria va dentro de los dos archivos generados por el conversor.

En este caso no aplicaré ningún formato de salida en las imágenes del archivo de íconos.

El espacio de memoria requerido en el FT800 se muestra en el reporte de conversión como GD2 RAM used, en este caso el set de iconos ocupa 60.184 Kb.

Uso del asset en pantalla

Para cargar el contenido de un archivo de asset debemos usar la siguiente secuencia de instrucciones:

//22012016
#include <SPI.h>
#include <GD2.h>

#include "Icons2.h"

void setup() {
  GD.begin();
   LOAD_ASSETS();
}

void loop() {
  GD.Clear();  
  GD.Begin(BITMAPS);
    GD.Vertex2ii(0, 0, 0);
    GD.Vertex2ii(0, 48, 1);
    GD.Vertex2ii(0, 96, 2);
    GD.Vertex2ii(0, 144, 3);
    GD.Vertex2ii(0, 192, 4);
    GD.Vertex2ii(60, 0, 5);
    GD.Vertex2ii(60, 48, 6);
    GD.Vertex2ii(60, 96, 7);
    GD.Vertex2ii(60, 144, 8);
    GD.Vertex2ii(60, 192, 9);
    GD.Vertex2ii(120, 0, 10);
    GD.Vertex2ii(120, 48, 11);
    GD.Vertex2ii(120, 96, 12);
    GD.Vertex2ii(120, 144, 13);
  GD.swap();
}

Este es el resultado:

El FT800 no funciona como los demás controladores disponibles en TFT´s para arduino, es un procesador gráfico que proporciona a la pantalla una tasa de refresco máxima de 60 Hz, así que no veremos pantallas con parpadeos o residuos de pixeles; siempre y cuando cada diseño de pantalla no supere los 256 Kb.

El asset tiene 14 iconos individuales, cada ícono se coloca dentro de un espacio de memoria reservado, el FT800 dispone de 15 espacios de este tipo. Generalmente reservo el último espacio para el archivo de imagen que funciona como fondo de pantalla.

El archivo .h de cada asset, por default tiene esta instrucción que funciona como identificador:

#define LOAD_ASSETS()  GD.safeload("Icons2.gd2");

Se puede colocar un índice para conseguir cargar un set de imágenes diferente para cada diseño de pantalla, como no se cargan todos los assets al mismo tiempo, la memoria del FT800 no se satura. Con este truco podemos disponer virtualmente de cualquier cantidad de archivos de iconos para usarlos en cualquier parte del proyecto. Insisto, solo se puede cargar un grupo de imagenes a la vez.

Por ejemplo podemos numerar cada asset en secuencias como:

LOAD_ASSETSa()
LOAD_ASSETSb()
LOAD_ASSETSc()
LOAD_ASSETS_0()
LOAD_ASSETS_1()
LOAD_ASSETS_2()
LOAD_ASSETS0()
LOAD_ASSETS1()
LOAD_ASSETS2()

Hay un truco que puede darnos acceso a un mayor número de archivos de imagen, consiste en ordenar dentro de cada espacio imagenes en forma vertical. Por ejemplo podríamos colocar 4 imagenes dentro del primer archivo, 4 en el segundo, etc. De esta forma podríamos disponer de hasta 14x4 = 56 celdas individuales. Esta técnica se conoce como creación de sprites. Sigo estudiándola ya que aun no la domino al 100% y los archivos me generan algunos errores de imagen, quizás haya algún aspecto de formato o de tamaño que aun no he podido estudiar a fondo. Mas adelante espero dominarlo.

Sigue: uso de la pantalla táctil

Uso de la pantalla táctil

El acceso a la pantalla táctil está bastante optimizado en la libreria GD2; la función para activarla es:

GD.get_inputs();

Para crear una entrada táctil se usa la siguiente instrucción:

GD.Tag(x);

Se pueden crear hasta 244 entradas táctiles (1-244), en teoría 0 también se podría usar, sin embargo en las pruebas que he hecho asignando esa entrada, la pantalla FT843 se torna inestable.

Es posible asociar entradas táctiles a objetos individuales como números, lineas de texto, gráficos primarios, imágenes, funciones con varias imágenes, incluso a cada uno de las imágenes contenidas en un asset de iconos.

Para evitar que varios objetos tengan la misma entrada táctil, se coloca la siguiente instrucción:

GD.Tag(255);

Justo después de asignar una entrada táctil a un determinado objeto.

Tomando como base el ejemplo con el arreglo de iconos creado previamente y con algunas pequeñas modificaciones, el sketch base queda así:

//22012016
#include <SPI.h>
#include <GD2.h>

#include "Icons2.h"

void setup() {
  GD.begin();
  LOAD_ASSETS0();
  MP();   //menu principal
}

void loop() {}

void MP()
{
 while(1)
 {
  GD.Clear();  
   GD.Begin(BITMAPS);
   carga_iconos();

  GD.swap();
 }
}

void carga_iconos()
{
    GD.Vertex2ii(0, 0, 0);
    GD.Vertex2ii(0, 48, 1);
    GD.Vertex2ii(0, 96, 2);
    GD.Vertex2ii(0, 144, 3);
    GD.Vertex2ii(0, 192, 4);
    GD.Vertex2ii(60, 0, 5);
    GD.Vertex2ii(60, 48, 6);
    GD.Vertex2ii(60, 96, 7);
    GD.Vertex2ii(60, 144, 8);
    GD.Vertex2ii(60, 192, 9);
    GD.Vertex2ii(120, 0, 10);
    GD.Vertex2ii(120, 48, 11);
    GD.Vertex2ii(120, 96, 12);
    GD.Vertex2ii(120, 144, 13);  
}

Me gusta dejar aislada la función

void loop()

Tal como está estructurado el sketch, es posible conseguir la misma funcionalidad que haciéndolo sobre void loop.

Insertemos ahora un icono que usaremos como si fuera un botón de encendido y apagado; este será el objeto al que asignaremos una entrada táctil

void MP()
{
 while(1)
 {
  GD.Clear();  
   GD.Begin(BITMAPS);
   carga_iconos();
   GD.get_inputs();   

   GD.Tag(1);  GD.Vertex2ii(300, 100, 0);  GD.Tag(255); 

  GD.swap();
 }
}

Esta secuencia ya nos permitirá usar la pantalla táctil, asignando una entrada al icono 0 del arreglo de iconos. Para tener la sensación de que estamos pulsando el botón digital, podemos conseguirlo recurriendo a algunas técnicas de animación simples.

El primer paso es asignar un fondo de pantalla en color claro. Por ejemplo, podemos usar un fondo uniforme con la instrucción:

GD.ClearColorRGB(0x108000);

También podemos establecer un degradado vertical, con el comando cmd_gradient, por ejemplo:

GD.cmd_gradient(0, 0, 0x0060c0, 0, 271, 0xc06000);

El segundo paso consiste en agregar un sombreado al botón, ésto se puede conseguir usando una máscara de color oscuro tomando tomando como base la imagen a la que queremos agregar el efecto, en este caso el botón hexagonal.

Para evitar que ajustes como la selección de un color RGB determinado, cambio de zoom, colores de relleno de gadgets; afecten todos los comandos posteriores a un cambio específico, se emplean estas dos instrucciones:

  GD.SaveContext();     

  GD.RestoreContext();

Con ellas es posible almacenar la combinación de colores y efectos previos, sin alterar el diseño de todo el proyecto.

  GD.SaveContext();     
   GD.ColorA(50); GD.ColorRGB(0x000000);  
   GD.Vertex2ii(300, 120, 0);
  GD.RestoreContext();

En esta secuencia dibujamos el icono hexagonal con una degradación del color RGB=0x000000 (negro), ubicándolo 20 pixeles debajo del icono hexagonal principal. Como nos interesa conseguir un efecto de sombreado, hay que dibujarlo antes del icono en colores reales.


Al combinar ambos gráficos obtenemos el sombreado en el icono-botón:

Para asegurar que la animación sea perceptible, hay que crear una bandera de control que monitoree todo el tiempo el estatus del botón. Para ello podemos crear una función que dibuje el botón en la posición 0 = apagado y 1 = encendido.

Designamos una variable o bandera, por ejemplo

int cambio_1 = 0;

Con ello indicamos que al iniciar el sketch el botón estará en la posición de apagado. Si deseamos controlar algo como un rele o bien conseguir un efecto visual con un led, por ejemplo, es conveniente que la bandera sea global.

El botón debemos dibujarlo ahora como una función con dos valores, por ejemplo

void status_1()
{
  if (cambio_1==0){GD.Vertex2ii(128, 150, 0);}
  if (cambio_1==1){GD.Vertex2ii(128, 165, 1);}  
}

También podemos usar un select case. La imagen que da la idea de botón encendido, corresponde a la segunda imagen del arreglo de iconos

La entrada táctil ya no estará dirigida a un solo icono, estará dirigida a las dos posiciones que tomará el botón al estar en modo encendido o en modo apagado:

   GD.Tag(1);  status_1();  GD.Tag(255);

Finalmente debemos asignar lo que se hará cuando pulsemos el botón, para ello basta con colocar un comparador usando una instrucción if, que esté ligada al valor de la entrada táctil 1

if (GD.inputs.tag==1){
          delay(155);
          cambio_1=cambio_1+1;
          if (cambio_1>=2){cambio_1=0;}
        }

No soy partidario de usar delays, sin embargo en las entradas táctiles resulta muy útil colocar un pequeño lapso de espera de entre 145 y 200 ms, esto permite que la pantalla táctil no se sature de datos y dé la impresión de que la estamos presionando constantemente, haciéndonos suponer que no funciona correctamente.

Este es el núcleo principal del sketch:

void MP()
{
 while(1)
 {
//  GD.ClearColorRGB(0x108000);   
  GD.Clear();  
  GD.cmd_gradient(0, 0, 0x0060c0, 0, 271, 0xc06000);
   GD.Begin(BITMAPS);
   carga_iconos();
   GD.get_inputs();   

  GD.SaveContext();     
   GD.ColorA(50); GD.ColorRGB(0x000000);  
   GD.Vertex2ii(300, 120, 0);
  GD.RestoreContext();  

   GD.Tag(1);  status_1();  GD.Tag(255); 
   
    if (GD.inputs.tag==1){
          delay(195);
          cambio_1=cambio_1+1;
          if (cambio_1>=2){cambio_1=0;}
        }          
  GD.swap();
 }
}

void status_1()
{
  if (cambio_1==0){GD.Vertex2ii(300, 100, 0);}
  if (cambio_1==1){GD.Vertex2ii(300, 120, 1);}  
}

Este es el resultado en el TFT

Sigue: creación de un menu principal y de submenus

Base para armar un árbol de menus

Un conjunto de menus puede simplificarse a un grupo de funciones que pueden intercambiarse mediante una entrada táctil. En este esquema podemos disponer de una pantalla principal o menu principal. el número de menus adicionales dependerá de lo que deseemos ver en pantalla, podemos disponer de menus secundarios o sub-menus en los que podríamos ver en tiempo real los datos adquiridos por sensores, un gráfico de comportamiento, una gráfica de calibración, un visor de imágenes, un grupo de opciones para ajuste de parámetros, etc.

Hasta donde he podido experimentar pueden usarse tantos menus como permita el espacio de programación de la placa arduino que estemos usando.

La estructura de cada función o parte del menu debe tener estos elementos:

Identificador de menu
Instrucciones que se ejecutan una vez
Instrucciones que cambian con el tiempo
Instrucciones de entrada táctil

Esta estructura es independiente de la librería del controlador táctil, solo depende del tipo de controlador de pantalla.

En TFT´s con pantalla táctil comunes como las que tienen el controlador ILI9341, SSD1289 o HX8357 por ejemplo, que usan la librería Utouch, las instrucciones que se ejecutan una sola vez (textos o fondos de pantalla), deben colocarse fuera del bucle principal, ya que pueden producir parpadeos o comportamientos intermitentes en la pantalla.

En el caso del controlador FT8XX, esas instrucciones deben ubicarse dentro del bucle principal, ya que de lo contrario pueden producirse errores de coprocesador o "pantallazos azules".

Un menu simple lo podemos conseguir tomando como punto de partida el ejemplo del botón simple que se construyó previamente, basta con adicionar un segundo tag y modificando la posición vertical, para colocarlo por debajo del otro botón.

 GD.SaveContext();     
   GD.ColorA(50); GD.ColorRGB(0x000000);  
   GD.Vertex2ii(300, 120, 0);
   GD.Vertex2ii(300, 180, 0);   
  GD.RestoreContext();  

   GD.Tag(1);  GD.Vertex2ii(300, 100, 0);  GD.Tag(255);    //botón superior
   
    if (GD.inputs.tag==1){
          delay(195);
          menu_1();
        }

   GD.Tag(2);  GD.Vertex2ii(300, 160, 0);  GD.Tag(255);    //botón inferior
   
    if (GD.inputs.tag==2){
          delay(195);
          menu_2();
        }

Omití el cambio de estado en cada botón, ya que al tocarlo, el cambio al menu siguiente es inmediato.

El primer menu lo he llamado menu_1, el segundo lo he designado como menu_2. El menu principal lo he llamado MP, de esta forma podemos ubicar fácilmente cada función o elemento del menu, cuando estemos depurando el programa.

El menu_1 solo dispone de un botón que regresa al menu principal, el menu_2, tiene dos botones: retorno a menu principal y acceso al menu_3, como fondo muestra 5 iconos en posiciones aleatorias.

En el menu_3 coloqué un analizador de espectro en forma de barras segmentadas, dispone de un botón de retorno al menu previo (menu_2) y otro para ir al menu principal. Como fondo tiene un icono en posiciones aleatorias. Este menu solo es accesible desde el menu_2.

Video: menu simple