Go Down

Topic: Algunos consejos para usar TFT´s (Read 54229 times) previous topic - next topic

TFTLCDCyg

#15
Jan 17, 2016, 07:21 pm Last Edit: Jan 17, 2016, 07:34 pm by TFTLCDCyg
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.
https://www.youtube.com/watch?v=pf9U5C5TH90

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.

https://www.youtube.com/watch?v=db2fyZ-zBHU

TFTLCDCyg

#16
Jan 21, 2016, 09:38 pm Last Edit: Jan 21, 2016, 09:47 pm by TFTLCDCyg
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.

TFTLCDCyg

#17
Jan 23, 2016, 12:02 am Last Edit: Jan 23, 2016, 12:13 am by TFTLCDCyg
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:
Code: [Select]
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:
Code: [Select]
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:

Code: [Select]
//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:
Code: [Select]
#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:

Code: [Select]
LOAD_ASSETSa()
LOAD_ASSETSb()
LOAD_ASSETSc()


Code: [Select]
LOAD_ASSETS_0()
LOAD_ASSETS_1()
LOAD_ASSETS_2()


Code: [Select]
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

TFTLCDCyg

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:
Code: [Select]
GD.get_inputs();

Para crear una entrada táctil se usa la siguiente instrucción:
Code: [Select]
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:
Code: [Select]
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í:
Code: [Select]
//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
Code: [Select]
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


Code: [Select]
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:
Code: [Select]
GD.ClearColorRGB(0x108000);


También podemos establecer un degradado vertical, con el comando cmd_gradient, por ejemplo:
Code: [Select]
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:
Code: [Select]
  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.

Code: [Select]
  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
Code: [Select]
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
Code: [Select]
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:
Code: [Select]
   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

Code: [Select]
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:

Code: [Select]
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

TFTLCDCyg

#19
Feb 07, 2016, 08:14 am Last Edit: Feb 07, 2016, 10:55 pm by TFTLCDCyg
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:

Code: [Select]
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.


Code: [Select]
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

TFTLCDCyg

En lo que llega el shield sobre el que instalaré todos los componentes del controlador, he estado experimentando algunas variantes en las que podría usar el FT843 o la pantalla ILI9341 que usaré como pantalla secundaria.

FT800 en arduino MEGA
La versión mas reciente de la librería para el gameduino 2 funciona sin problemas en el arduino Due, también funciona en el MEGA, en el Teensy 3.2 y me parece que en el Rasberri Pi.

Por consiguiente el FT843 podría funcionar en esas placas mediante la librería GD2, con los ajustes adecuados para que los parámetros de inicialización correspondan a los del gameduino 2.

El diseño del gameduino 2 corresponde a un shield para arduino UNO. La librería tiene algunos ajustes para funcionar directamente sobre el arduino Due, para que funcione en el MEGA hay que hacer algunos ajustes en el hardware, se deben unir los pines 51 a 11 (MOSI), 50 a 12 (MISO) y 52 a 13 (SCK). Hay dos posibilidades para conseguirlo: unirlos mediante cableado o bien construir un shield, intercalando un dip switch-3, con la finalidad de desconectar las uniones cuando no se use la pantalla FT800.





Dos pantallas ILI9341 en Teensy 3.2
Aparentemente el Due, el Mega o el Uno, pueden manejar dos pantallas ILI9341 al mismo tiempo, mostrando información distinta en cada una de ellas. En las pruebas que hice experimenté en el arduino UNO, pero estaba el problema de la memoria, tenía muy poca disponible y no me permitió avanzar. En el MEGA resultó muy lento el control de las dos pantallas, las entradas táctiles no funcionan correctamente

El Due lo quiero para controlar el gameduino 2, si instalo una segunda pantalla como la ILI9341 de 2.4", el GD2 deja de funcionar.

Construí un shield para experimentar con el teensy 3.2 que llegó hace un par de semanas. En una de las caras, el shield permite conectar directamente el gameduino 2; en la otra cara, permite instalar una pantalla ILI9341 de 2.2", 2.4" o de 2.8".





El árbol de conexionado que usé es el siguiente:
Code: [Select]
ILI9341            Teensy 3.2
VCC                   VIN
GND                   GND
CS                     10
RESET                3.3V
D/C                     9
SDI (MOSI)             11
SCK                    13
LED                   VIN    (resistencia de 100 ohms)
SD0(MISO)              12
T_CLK                   6
T_CS                    5
T_DIN                   4
T_DO                    3
T_IRQ                   2

La librería para usar el panel táctil es la Utouch.

El problema que encontré es que el lector SD de la pantalla ILI9341 no funciona al usarlo en el teensy. Aparentemente hay que modificar el circuito puenteando las resistencias smd que se ubican bajo la carcasa del lector SD, hice algunas pruebas y no conseguí hacerlo funcionar.

Decidí instalar uno de los lectores micro SD que conseguí para el FT843, funcionan de forma nativa a 3.3V. Conecté el lector al bus SPI, tanto la librería SD como la SDfat responden.



Hasta aquí todo parece funcionar con el shield, decidí complicar las cosas y conecté la segunda pantalla ILI9341. Si se conecta en forma paralela pin a pin respecto a la primer pantalla, se consigue que ambas pantallas muestren la misma información.

Si se define una segunda instancia de configuración y se conecta el pin CS a otro pin digital (20 o 21), se consigue controlar cada pantalla de forma independiente.



Con algunas modificaciones en la rutina de lectura de archivos bmp, es posible enviar imágenes diferentes en cada pantalla

TFTLCDCyg

#21
Feb 18, 2016, 08:57 am Last Edit: Feb 18, 2016, 10:35 am by TFTLCDCyg
Conseguí una pantalla ILI9341 de 3.2" que se conecta a 16 bits. Se requieren 33 hilos para conectar el lector SD (6), el panel táctil (5) y el TFT (22). Era la pantalla que quería desde que migré de los LCD´s gráficos a TFT´s, pero por falta de presupuesto no la había podido conseguir.

Hace unos días conseguí un par de protoboards para mega que ajustan muy bien en el due, por lo que decidí armar una placa de pruebas para la pantalla, logré insertar en la libreria UTFT un iniciador basado en el ILI9341 5SPI. También funciona con el constructor del ILI9327, pero hay que modificar la resolución en el archivo UTFT.ccp.


El shield permite conectar directamente la pantalla en un zócalo de 34 pines, o bien se puede construir una extensión para conseguir una mayor flexibilidad al usar la pantalla en un proyecto. Adicioné un zócalo de 6 pines en el que se puede instalar un lector microSD.

Acá está la base de expansión del FT843 hecha con la otra protoboard:


Ya puedo concentrarme en otros aspectos del controlador como el diseño de los registros de avance de los proyectos del trabajo:


Por fin puedo dedicarle tiempo al manejo de imágenes con la librería GD2, razón por la que tuve que pausar el diseño del controlador.
Video: desplazamiento de iconos

Nomada


TFTLCDCyg

Gracias, espero que a alguien por allá fuera le sirva de algo.

Dibujo de indicadores analógicos en el FT843

Estoy instalando los sensores de temperatura NTC en el proto-shield. En lo que consigo algunas resistencias SMD en el rango de 6 a 8 K, le dediqué un tiempo al diseño de la función que permitirá dibujar gauges, diales o indicadores de aguja.

Hasta ayer los intentos me habían llevado al limite de la horizontal, acotado por el rango de ángulos entre 0 y 180. El enfoque era convertir el valor de la variable, el valor máximo de la escala del dial y el ángulo máximo. En ese concepto el ángulo inicial siempre es 0. Como los indicadores de aguja tienen su valor máximo hacia el extremo derecho del dial, me topé con el limite de 180 grados.

Code: [Select]
Tetha = (180 * Variable/ValorMaximo);

Si recordamos algunos conceptos matemáticos del circulo unitario, bajo el cuadrante I, el cuadrante que sigue es el cuadrante IV, allí el ángulo que seguiría de 180 (si lo vemos al revés), es el ángulo 359, no el 181.

Por esta razón al dibujar en el TFT obtenía agujas o marcas fuera de lugar donde esperaría que estuvieran, encima no hay que olvidar que las coordenadas del eje y están invertidas. Decidí dejar los diales en el rango de 0 a 180 grados.

Estoy poco familiarizado con las funciones heredadas de C que tiene el IDE de arduino y de poco a poco he aprendido a usar. Toca el turno a la función map().

Al usar esa función para calcular el ángulo equivalente a una lectura, se puede conseguir superar la barrera de la horizontal y curiosamente, la orientación invertida del eje y. Por ejemplo, la instrucción:
Code: [Select]
Tetha = map(Variable, 0, ValorMaximo, -30, 210);
Permite dibujar un dial horizontal que inicia en el ángulo -20 (corresponde a 200 en coordenadas normales) y termina en el ángulo 210 (340 en coordenadas normales)

Llevada al extremo, la función permite dibujar diales verticales o de rango corto como el que tienen algunos indicadores de presión. Este es un ejemplo con tres indicadores:


Video: indicadores analogicos

GDCR

Hola, estoy trabajando con una pantalla LCD Touch TFT_320QVT, ella trae una memoria SD para cargar las imágenes en .RAW y montarlas asi en la LCD, hasta ahí todo normal, el problema es que quiero guardar datos de la lectura de sensores en la misma SD pero no lo he logrado, en la libreria TinyFAT dice que se pueden leer y escribir datos en ella pero he probado con los ejemplos y ninguno me funciona, crea los archivos pero no escribe nada en ellos, los deja vacios. Estoy pensando en utilizar el modulo aparte de memorias SD solo para guardar los datos y dejar la SD de la pantalla solo para montar las imagenes, es lo unico que se me ocurre. Me seria de gran ayuda que si sabes como guardar datos en la misma memoria me colabores, Gracias

TFTLCDCyg

#25
Feb 28, 2016, 10:46 pm Last Edit: Feb 28, 2016, 10:57 pm by TFTLCDCyg
Hola, estoy trabajando con una pantalla LCD Touch TFT_320QVT, ella trae una memoria SD para cargar las imágenes en .RAW y montarlas asi en la LCD, hasta ahí todo normal, el problema es que quiero guardar datos de la lectura de sensores en la misma SD pero no lo he logrado, en la libreria TinyFAT dice que se pueden leer y escribir datos en ella pero he probado con los ejemplos y ninguno me funciona, crea los archivos pero no escribe nada en ellos, los deja vacios. Estoy pensando en utilizar el modulo aparte de memorias SD solo para guardar los datos y dejar la SD de la pantalla solo para montar las imagenes, es lo unico que se me ocurre. Me seria de gran ayuda que si sabes como guardar datos en la misma memoria me colabores, Gracias
Para la gestión de datos e imagenes RAW, debes definir dos instancias de acceso a la libreria:

Code: [Select]
UTFT_tinyFAT myFilesB(&myGLCD); 
SdFat sd;      //Carga de imagenes RAW 

SdFat sd1;     //Gestión de datos
SdFile myFile;


Dentro del setup te sugiero que uses estas lineas, para activar cada una de las instancias de acceso al lector SD:
Code: [Select]
  if (!sd.begin(chipSelect, SPI_FULL_SPEED)) {sd.begin(chipSelect, SPI_HALF_SPEED);}
 if (!sd1.begin(chipSelect, SPI_FULL_SPEED)) {sd1.begin(chipSelect, SPI_HALF_SPEED);}


Separa por funciones los procesos de gestión de datos, por ejemplo:

Code: [Select]
1 Crear archivo/guardar datos
2 Leer datos
3 Eliminar archivo

TFTLCDCyg

Indicadores analógicos: uso de CPU y uso de RAM en el TFT

He estado recopilando los programas individuales para hacer funcionar cada uno de los componentes del controlador. En este proceso, retomé un aspecto que me hubiese gustado poder desarrollar personalmente, pero por cuestiones de tiempo y de poco dominio de C, Phyton o similares, no he podido profundizar: la comunicación a por el puerto serie de arduino con la PC. Me refiero a enviar datos de la PC al arduino como por ejemplo, temperaturas, uso del CPU o uso de la RAM.

Hace un tiempo encontré un proyecto con indicadores analógicos que me pareció bastante completo:

http://www.lungstruck.com/projects/pc-meter/

Video: indicadores de uso de CPU/RAM analógicos

En aquel momento no pude replicar el proyecto ya que no alcanzaba a entender como es que funcionaba el software de apoyo y mucho menos las funciones clave que permiten conseguir los dos valores: %CPU y %RAM.

Nuevamente revisé el código y por fin pude extraer los elementos que permiten leer los valores de uso del CPU y uso de la RAM. Estas son las funciones núcleo del programa:

Code: [Select]
//Inicia CPU array/total con ceros
void initCpuValues()
{
  for (int counter = 0; counter < CPU_READINGS; counter++)
    cpuReadings[counter] = 0;
    cpuTotal = 0;
}


void LeeCPURAM()
{
  while (Serial.available() > 0)
   {
   Serial.readBytesUntil('\r', buffer, 5);
   //Thought this might be needed based on example I studied, seems okay without
   //buffer[4] = '\0';
   switch (buffer[0])
   {
    case 'C':
     cpuTotal = cpuTotal - cpuReadings[cpuIndex];
     cpuReadings[cpuIndex] = min(atoi(&buffer[1]), 100);
     cpuTotal = cpuTotal + cpuReadings[cpuIndex];
 // Uso de CPU
     UsoCorei73770 = cpuTotal / CPU_READINGS;  //desmarcar luego de las pruebas
    
     //Advance index
     cpuIndex = cpuIndex + 1;
     if (cpuIndex >= CPU_READINGS)
       cpuIndex = 0;
     break;

    case 'M':
//Uso de RAM
    UsoRAM = min(atoi(&buffer[1]), 100);

     break;
     }
  
   //Reset for next measurement
   perc = 0;
   memset(buffer, ' ', 5);
   //Update last serial received
   lastSerialRecd = millis();
  }
}



Estas variables deben ser globales:

Code: [Select]
//Constantes para PC Meter
const long SERIAL_TIMEOUT = 0;  //How long to wait until serial "times out"
const int CPU_READINGS = 3;        //Number of readings to avg. for CPU load%

//Variables
unsigned long lastSerialRecd = 0;     //Time last serial read
float cpuReadings[CPU_READINGS];        //array of cpu load% readings
float cpuTotal = 0;                     //CPU load running total
int cpuIndex = 0;                     //current position in array for cpu load%

  char buffer[5];                //buffer
  int perc = 0;                  //reading
  
  float  UsoCorei73770;  //tengo un core i7 3370, de allí el nombre de la variable
  float UsoRAM;


Estas lineas van dentro del setup:

Code: [Select]
 Serial.begin(9600);
  initCpuValues();
  lastSerialRecd = millis();  //Give meter some time to start receiving data


El programa que permite obtener los datos y enviarlos por usb hasta el arduino se llama PC Meter, lo creó el autor del proyecto en Visual C#. Tiene algunos inconvenientes, que no creo se hayan resuelto todavía:

- Bloquea la carga de sketchs al arduino, desconectando la captura todo funciona normalmente
- Impide la hibernación de windows, cerrándolo se evita el problema
- Impide el reinicio de la PC, cerrándolo se acaba el problema

Hay algunas otras complicaciones con los medidores analógicos usados en el proyecto original, pero que no se tendrán en el TFT, ya que acá no hay una conversión digital a voltaje, todo es digital.

Tomé como base el sketch de indicadores analógicos, y adicioné algunos textos.

Video: uso CPU y RAM

La velocidad de actualización me parece algo lenta, y le falta algo de fluidez, parece ser que dentro del programa PC Meter hay algunos delays que inciden en la velocidad de refresco, sin embargo ya tengo acceso a los datos comportamiento de la PC.


TFTLCDCyg

#27
May 30, 2016, 08:21 am Last Edit: May 30, 2016, 08:29 am by TFTLCDCyg
He estado tratando de comprender mejor el funcionamiento del FT800. Se agradece la tasa de refresco de la pantalla y eso reduce mucho del esfuerzo de programación, pero a veces pueden diseñarse pantallas algo confusas, cargadas de "velocidad", que dificultan su uso dentro de un sketch.

Se pueden usar atajos como delays, pero soy enemigo de ese recurso, desde que aprendí a usar el ejemplo Blink without Delay. Aunque arduino no está diseñado para ejecutar multifunciones, es posible combinar varios contadores basados en millis() que nos permiten saltar de alguna forma esa barrera.

Optimización del movimiento de las agujas de los indicadores analógicos

Cuando diseñé el lector analógico para monitorear el uso de CPU/RAM de la PC, me dí cuenta de que al usar valores aleatorios en los indicadores, se hace presente la abrumadora velocidad de la pantalla. Es poco apreciable en rangos de entre 4 hasta 10 unidades, sin embargo en rangos de 15 o mas unidades entre lecturas, se observan saltos en las agujas.

Para conseguir que el desplazamiento de la aguja tenga una respuesta mas definida, es necesario incluir una componente que proporcione una velocidad gradual de desplazamiento, dando la impresión de que la agua o (una lectura) tiene la inercia que confiere un resorte o una respuesta gradual. La secuencia de análisis tiene estos pasos:

1) Adquisición de la primer lectura para tomarla como base.
Code: [Select]
void LecturaSensor1(){
   T1 = random(100);
}

T1a = T1, T1g = T1

2) Se asigna un intervalo de lectura: 1 s (1000 ms), 2 seg (2000 ms), etc. Controlado por millis(), en lugar de delay()
3) Se toma una segunda lectura del sensor.
4) Se determina si se trata de un incremento (velocidad positiva), decremento (velocidad negativa), o que no hay cambios en la lectura (velocidad= 0)

Code: [Select]
  unsigned long currentMillis1 = millis();       
  if(currentMillis1 - previousMillis1 > interval1)
  {
    previousMillis1 = currentMillis1;       

    LecturaSensor1();
    T1b = T1;
    DT1 = T1b - T1a;
    if (DT1>0){DT1g=1;}else{if (DT1<0){DT1g=-1;}else{DT1g=0;}}
  }


Como resultado podemos conseguir el signo de valor del cambio: +(si hay un incremento), -(si hay una reducción) o 0 (si no hay cambios)

5) Se aplica la velocidad al valor base. Lo forma mas simple es aumentar gradualmente el valor de la lectura base, hasta igualar el valor de la segunda lectura.
Code: [Select]
   if (T1g==T1b){T1g=T1b;}else{T1g = T1g + DT1g;}

6) Gráficar el cambio gradual de la lectura base. Este paso es el que nos permite mostrar los cambios de la lectura de un sensor de forma atenuada, tal como lo hace un velocímetro o el mercurio dentro de un termómetro.

Vídeo: indicadores analógicos optimizados

Al llegar al valor objetivo, (es decir la segunda lectura, T1b), la variable (T1g) final, se convierte en el nuevo valor base (T1a), repitiendo el ciclo de tratamiento de la lectura. El menor intervalo entre la adquisición de lecturas, lo recomiendo establecer entre 500 y 700 ms.

PD: no podemos escaparnos de los códigos complejos, llega un momento en el que hay que codificar acciones tan simples como evaluar una variable, cuyo valor puede tomar tres o mas caminos y eso nos lleva a escribir lineas y lineas. Trataré de depurar el código para hacerlo mas comprensible.

TFTLCDCyg

Recientemente llegaron los conversores de Riverdi para cable plano a zócalo de pines. Este tipo de adaptador permite conectar de forma directa las pantallas de la serie FT80x y FT81x. Mi idea es poder construir un shield que me permita conectar cualquier tipo de pantalla de Riverdi, basada en los chips de FTDI, sin tener que lidiar con rollos de cables de prototipado.

Espero en los próximos días armar el rompecabezas para por fin conectar la pantalla capacitiva de 4.3" FT801, que tengo de pisapapeles desde hace meses. Ya les compartiré los avances. Me temo que tendré que modificar una vez mas la librería GD2, esperemos que de forma nativa funcione correctamente.

PD: como he dicho siempre, no soy vendedor ni distribuidor, simplemente me di a la tarea de filtrar las especificaciones que ofrecen los constructores de este tipo de pantallas, y me he inclinado por ese proveedor. Tampoco voy a construir algo para vender, simplemente quiero contar con buenas piezas para el hobbie.


TFTLCDCyg

#29
Jun 19, 2016, 09:16 pm Last Edit: Jun 19, 2016, 09:23 pm by TFTLCDCyg
El principio de funcionamiento de la pantalla FT801 está considerado dentro de las librerias para el gameduino 2: (la gameduino2 y la GD2, que corresponde a la versión multifuncional FT80x/FT81x)

Las lineas de conexión para cualquier pantalla FT80x a un arduino Due son:

Code: [Select]
FT80x    Due
GND      GND
VCC      3V3
MOSI     MOSI
MISO     MISO
SCK      SCK
CS       pin digital disponible


Las lineas extra que tiene cualquier pantalla FT80x: INT y PD, no se usan en las librerias para gameduino 2.

Adicionalmente, la mayoría de pantallas FT80x no tienen un lector SD, y pocas tienen instalado el amplificador en la salida de audio.

Para adicionar un lector SD, se puede usar un lector microSD. En los experimentos previos para anexar un lector, me di cuenta que debe estar diseñado para 3.3V, y no debe tener instalado un regulador de voltaje 5V/3.3V. Para minimizar las fallas, cada linea debe unirse a las lineas MOSI/MISO/SCK de la  pantalla

La memoria micro SD recomiendo que sea de 4Gb, clase 4, preferentemente kingston, formateada en FAT32.

¿Por qué usar las librerias del gameduino 2, en lugar de las diseñadas por FTDI?. Es bastante simple.

Veamos el ejemplo hello world que viene en la libreria FTDI para el FT843


Code: [Select]
/* This application demonstrates the usage of FT800 library on FT_ADAM_4DLCD_FT843 platform */

/* Arduino standard includes */
#include "SPI.h"
#include "Wire.h"

/* Platform specific includes */
#include "FT_ADAM_4DLCD_FT843.h"

/* Global object for FT800 Implementation */
FT800IMPL_SPI FTImpl(FT_CS_PIN,FT_PDN_PIN,FT_INT_PIN);

/* Api to bootup ft800, verify FT800 hardware and configure display/audio pins */
/* Returns 0 in case of success and 1 in case of failure */
int16_t BootupConfigure()
{
uint32_t chipid = 0;
FTImpl.Init(FT_DISPLAY_WQVGA_480x272);//configure the display to the WQVGA

delay(20);//for safer side
chipid = FTImpl.Read32(FT_ROM_CHIPID);

/* Identify the chip */
if(FT800_CHIPID != chipid)
{
Serial.print("Error in chip id read ");
Serial.println(chipid,HEX);
return 1;
}

/* Set the Display & audio pins */
FTImpl.SetDisplayEnablePin(FT_DISPENABLE_PIN);
    FTImpl.SetAudioEnablePin(FT_AUDIOENABLE_PIN);
FTImpl.DisplayOn();
FTImpl.AudioOn(); 
return 0;
}

/* API to display Hello World string on the screen */
void HelloWorld()
{
/* Change the below string for experimentation */
const char Display_string[12] = "Hello World";

/* Display list to display "Hello World" at the centre of display area */
FTImpl.DLStart();//start the display list. Note DLStart and DLEnd are helper apis, Cmd_DLStart() and Display() can also be utilized.
FTImpl.ColorRGB(0xFF,0xFF,0xFF);//set the color of the string to while color
FTImpl.Cmd_Text(FT_DISPLAYWIDTH/2, FT_DISPLAYHEIGHT/2, 29, FT_OPT_CENTER, Display_string);//display "Hello World at the center of the screen using inbuilt font handle 29 "
FTImpl.DLEnd();//end the display list
FTImpl.Finish();//render the display list and wait for the completion of the DL
}

/* bootup the module and display "Hello World" on screen */
void setup()
{
/* Initialize serial print related functionality */
Serial.begin(9600);

/* Set the Display Enable pin*/   
Serial.println("--Start Application--");
if(BootupConfigure())
{
//error case - do not do any thing
}
  else
{
HelloWorld();
}
Serial.println("--End Application--");
}

/* Nothing in loop api */
void loop()
{
}

Sketch uses 26,800 bytes (5%) of program storage space. Maximum is 524,288 bytes.

Al familiarizarme con la libreria FTDI, me di cuenta que se puede prescindir de muchas lineas de código, pero otras deben usarse todo el tiempo, ya que se comunican directamente con el micro FT80x, y al no usarlas se producen errores de procesamiento (pantallazos azules XD).

Este es el ejemplo hello world de la libreria GD2:

Code: [Select]
#include <SPI.h>
#include <GD2.h>

void setup(){ Serial.begin(1000000); // JCB
  GD.begin(0);}

void loop(){GD.ClearColorRGB(0x103000);
  GD.Clear();
  GD.cmd_text(GD.w / 2, GD.h / 2, 31, OPT_CENTER, "Hello world");
  GD.swap();}

Sketch uses 13,664 bytes (2%) of program storage space. Maximum is 524,288 bytes.

Creo que las diferencias son mas que evidentes.

No es solo conectar la nueva pantalla, hay que hacer algunos ajustes en la libreria GD2 para que las pantallas FT80x se comporten como lo hace la pantalla del gameduino 2.

Go Up