Para manejar gráficos con Arduino existen muchos modelos de pantallas, ya sean OLED,   LCD, TFT, o una combinación de ambas TFT-LCD, Táctiles, en blanco y negro, a color, tamaño.

Existen varias cuestiones a tener en cuenta para elegir una y otra. Pero al fin y al cabo, hay que buscar la que mejor se adapte a nuestro objetivo. Por ejemplo, cualquiera de ellas nos seviría para representar información escrita como la navegación de archivos en una tarjeta SD; pero en cambio no todas nos servirían para la creación de un videojuego con gráficos elaborados.

Para cada una de ellas hay que conocer el modelo, pero al fin y al cabo hay que saber que las pantallas funcionan como un conjunto de píxeles ordenados en filas y en columnas a los que se puede acceder independientemente para activarlos y representar información.

NOkia-110-LCD-memory-map

NOKIA LCD Scheme

 

Pantallas LCD o de cristal líquido

Pantallazo-3CGVvKWEUQAAyCE-


Pantallas TFT

images1 IL9340


Yo personalmente utilizo la pantalla ST7735 que es un modelo de 160×128 píxeles que se puede conectar facilmente a la placa Arduino Esplora y que se puede controlar con las librerías de Adafruit.

ST7735_GLCD_pins

Esta librería contiene las funciones de configuración para hacer funcionar el display. Lo que hay que saber al principio de todo es que cualquier color que se aplique a los píxeles se mantendrá hasta que no se diga lo contrario; es decir, que no hace falta hacer un loop para mantener el color de un pixel si éste no va a cambiar.

Lo primero de todo que hay que hacer es especificar los pines SPI dentro de la clase, que en este caso son los listados como:

  • CS → Chip select(7)
  • DC aunque en la librería se refiere con RS  → Data Command (0)
  • RST → Reset (1)
  • SCLK → Señal de reloj (15)

La selección de estos pines se basan en la configuración establecida por la Leonardo, ya que Esplora se basa en esta placa.

Un aspecto importante a comentar es que algunos píxeles pueden no cubrirse por completo, sobre todo si se rota la imagen, algunos margenes permanecen con otro color si es que se ha cambiado entre una orientación y otra.

 

  • initB(void) → for ST7735B displays
  • initR(uint8_t options = INITR_GREENTAB), → // for ST7735R  displays que es el que hay que utilizar para configurar nuestro modelo. initR inicializa el chip ST7735R chip, que define el modelo de pantalla que se utiliza y dependerá del plastiquito con el que venga. Existen 3 modelos definidos (INITR_GREENTAB, INITR_REDTAB, INITR_BLACKTAB). En nuestro caso es el INITR_GREENTAB.
  • setRotation(uint8_t r) → Existen 4 modos definidos, para establecer el landscape. 0 – en posición de lectura vertical, 1 – forma correcta de lectura para leer con Esplora en horizontal 2 en vertical hacia el otro lado y 3 horizontal boca abajo.
  • invertDisplay(boolean i) → invierte los colores definidos
  • fillScreen(uint16_t color) → Útil para limpiar la pantalla de basurilla sobrante. Llena toda de un color definido.
  • drawPixel(int16_t x, int16_t y, uint16_t color) → Dibujar un solo pixel definiendo sus coordenadas. La pantalla es de 160×128 por lo que su punto medio se situa en 80×64.
  • drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) → Dibujar una linea vertical, primero se define la posicion de origen y despues su longitud y color
  • drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) → Lo mismo pero en horizontal.
  • fillRect(int16_t x, int16_t y, int16_t w, int16_t h,uint16_t color) → Rellena un rectángulo definiendo su origen, anchura y altura.
  • setAddrWindow(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1) → ni idea de lo que hace.
  • pushColor(uint16_t color) → Ni idea

En este ejemplo vamos a ver como crear una malla con un número de filas y columnas definido. De esta manera discretizaremos el espacio para despues modelar nuestros propios dibujos pixelizados o definir una pantalla de juego con cuadrados de movimiento.


/*
  Design and created by Blascarr

  ArduPixel
  Name    : Blascarr
  Description: DrawingCLines
  version : 1.0

  Grid with lines with rows and columns defined for Arduino Esplora with TFT display. 
  
  It works with Adafruit_ST7735 library

  **
  **
*/

#define mosi 16
#define cs   7
#define dc   0
#define rst  1
 
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>            // SPI communications library
#include <Esplora.h>         // Arduino Esplora specific library

Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, rst);

// Option 2: use any pins but a little slower!
#define TFT_SCLK 13   // set these to be whatever pins you like!
#define TFT_MOSI 11   // set these to be whatever pins you like!
//Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);

void setup(void) {
  Serial.begin(9600);
  Serial.print("Hello! Adafruit ST7735 rotation test");

  tft.initR(INITR_GREENTAB);   // initialize a ST7735S chip, black tab

  Serial.println("init");

  tft.setTextWrap(false); // Allow text to run off right edge
  tft.fillScreen(ST7735_BLACK);

  Serial.println("This is a test of the rotation capabilities of the TFT library!");
  Serial.println("Press <SEND> (or type a character) to advance");
  tft.setRotation(1);
  matrix(7,17,0xFFFF);
}

void loop(){
  
}

void matrix(uint8_t rows, uint8_t columns,uint16_t color){
  int width=160;
  int height=128;
  uint8_t dx=width/rows;
  uint8_t dy=height/columns; 
  uint8_t rdx=width%rows;
  uint8_t rdy=height%columns; 
  
  for (uint8_t i=0; i<=rows; i++) {
    tft.drawFastVLine(i*dx+rdx/2,rdy/2,height-rdy, color);
    for (uint8_t j=0; j<=columns; j++) {
      tft.drawFastHLine(rdx/2,j*dy+rdy/2,width-rdx, color);
    }
  }
}



Al comienzo quizás es todo muy básico si realizamos operaciones bidimensionales, cuyos movimientos solo son movimientos en los ejes X e Y. Pero existe un tercer grado de libertad que es la rotación. Y quizás la mejor manera de afrontar este problema sea el uso de operaciones con matrices, y este concepto en programación puede ser complejo en su manipulación.

Con el ejemplo siguiente vamos a crear sistemas de referencia que se iran moviendo y girando en el entorno de nuestro display, pero esta vez las manipularemos con estas matrices de transformación, gracias a la siguiente librería.

 

 


/*
  Design and created by Blascarr

  ArduPixel
  Name    : Blascarr
  Description: DrawingStar
  version : 1.0

  Star polygon with transformation matrix for Arduino Esplora with TFT display. 
  We can stablish different parameters like angle and length and iteration of the process.
  
  Exercise for graphics development with matrix references on TFT.
  With MatrixMath we provide a matrix interpretation to stablish reference 2D on the display and create different movements based on rotation and translation on TFT display without pixel dependencie.

  
  It works with Adafruit_ST7735 library
  It works with MatrixMath.h
  **
  **
*/

#define mosi 16
#define cs   7
#define dc   0
#define rst  1
 
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>             // SPI communications library
#include <Esplora.h>         // Arduino Esplora specific library
#include <MatrixMath.h>

#define N  (3)

Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, rst);

float rot[N][N];
float aux[N][N];
float newMatrix[N][N];

// Option 2: use any pins but a little slower!
#define TFT_SCLK 13   // set these to be whatever pins you like!
#define TFT_MOSI 11   // set these to be whatever pins you like!
//Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);

void setup(void) {
  Serial.begin(9600);
  Serial.print("Hello! Adafruit ST7735 rotation test");

  tft.initR(INITR_GREENTAB);   // initialize a ST7735S chip, black tab

  Serial.println("init");

  tft.setTextWrap(false); // Allow text to run off right edge
  tft.fillScreen(ST7735_BLACK);

  //Initialization matrix

  for (int i = 0; i < N; i++){
      for (int j = 0; j < N; j++){
        if (i == j){
          rot[i][j] = 1.0f;      
          aux[i][j] = 1.0f;  
        } else{
          rot[i][j] = 0.0f;
          aux[i][j] = 0.0f;  
        }
      }
  }
  
  Serial.println("This is a test of the rotation capabilities of the TFT library!");
  Serial.println("Press &lt;SEND&gt; (or type a character) to advance");
  tft.setRotation(1);
  tft.fillScreen(ST7735_BLACK);
  rotateLine(45,80,-124);
}

void loop(){
  
}

void rotateLine(uint8_t n, float star_l, float angle){
  int width=160;
  int height=128;
  float v1[N];      // This is a the first point of the square
  float v2[N];      // This is a the second point of the square
 
  float w1[N];
  float w2[N];
  for (int i = 0; i < N; i++){
    w1[i] = 0.0f;  
    w2[i] = 0.0f; 
  }
  
  float v_p[N];
  v_p[0]=0;
  v_p[1]=0;
  v_p[2]=1;
  
  float v_x[N];
  v_x[0]=30;
  v_x[1]=0;
  v_x[2]=1;
  
  float v_y[N];
  v_y[0]=0;
  v_y[1]=30;
  v_y[2]=1;
  
  float aux_p[N];
  float aux_x[N];
  float aux_y[N];
  
  v1[0]=0;
  v1[1]=0;
  v1[2]=1;
  
  v2[0]=0;
  v2[1]=star_l;
  v2[2]=1;
  
  float tx = width/2;
  float ty = height/2-star_l/2;
  float angle_i = 72;
  float ang2rad=360/PI;
  
  rot[0][0]= cos(angle_i/ang2rad);
  rot[0][1]= sin(angle_i/ang2rad);
  rot[0][2]= tx;
  rot[1][0]= -sin(angle_i/ang2rad);
  rot[1][1]= cos(angle_i/ang2rad);
  rot[1][2]= ty;

  //Inicializacion del punto
  Matrix.Multiply((float*)rot,(float*)v2,N,N,1,(float*)w2);
  
  //Para realizar este ejercicio moviendo el punto central, tenemos que establecer una nueva referencia, desde la cual se va a mover, en lugar de utilizar el origen de la esquina superior izquierda.
  int divs = n;
  Serial.print("Angulo: \t ");
  Serial.println(angle);
    
  for (int i=0; i<divs; i++) {
    float ang2rad=360/(2*PI);
    
    
    aux[0][0]= cos(angle/ang2rad);
    aux[0][1]= sin(angle/ang2rad);
    aux[0][2]= 0;
    aux[1][0]= -sin(angle/ang2rad);
    aux[1][1]= cos(angle/ang2rad);
    aux[1][2]= star_l;
    
    Matrix.Multiply((float*)rot,(float*)aux,N,N,N,(float*)newMatrix);
    w1[0]=w2[0];
    w1[1]=w2[1];
    w1[2]=w2[2];
    Matrix.Multiply((float*)newMatrix,(float*)v2,N,N,1,(float*)w2);
    tft.drawLine(w1[0],w1[1],w2[0],w2[1],0xFFFF);

    rot[0][0]= newMatrix[0][0];
    rot[0][1]= newMatrix[0][1];
    rot[0][2]= newMatrix[0][2];
    rot[1][0]= newMatrix[1][0];
    rot[1][1]= newMatrix[1][1];
    rot[1][2]= newMatrix[1][2];
    
    //Debug Axis
    /*Matrix.Multiply((float*)rot,(float*)aux,N,N,N,(float*)newMatrix);
    aux_p[0]=w2[0];
    aux_p[1]=w2[1];
    aux_p[2]=w2[2];
    Matrix.Multiply((float*)newMatrix,(float*)v_p,N,N,1,(float*)aux_p);
    //tft.drawLine(tx,ty,aux_p[0],aux_p[1],0xFFFF);
    Matrix.Multiply((float*)newMatrix,(float*)v_x,N,N,1,(float*)aux_x);
    tft.drawLine(aux_p[0],aux_p[1],aux_x[0],aux_x[1],0x07E0); // Green Color
    Matrix.Multiply((float*)newMatrix,(float*)v_y,N,N,1,(float*)aux_y);
    tft.drawLine(aux_p[0],aux_p[1],aux_y[0],aux_y[1],0x001F); // Blue Color
    */
    //Matrix.Print((float*)rot,N,N,"rot");
    //Matrix.Print((float*)w,N,1,"w");
    
  }
}

Una vez realizado este primer ejercicio para la manipulación de gráficos en 2D, podemos extender las matrices de transformación a un modelo 3D, con la extensión de estas matrices 3×3 a matrices de transformación 4×4.

Pero los gráficos a modelar se consiguen con otros modelos interpretados con aristas, polígonos y caras como los siguientes.

UNO9341

Este modo de integración se hace con una revisión de la librería de Adafruit para el modelo ST7735 que libera memoría y agiliza entre 20 y 100 veces la velocidad de procesado. Ya que nuestra placa tiene sus limitaciones para crear estos efectos hemos de favorecer este proceso al máximo.

http://crawlingrobotfortress.blogspot.com.es/2015/12/better-3d-graphics-engine-on-arduino.html

En el siguiente vínculo, se puede acceder al Github.

 

 

Existen otras librerías muy útiles que se pueden usar en función del tipo de pantalla que dispongamos.

  • TFTLibrary
  • OpenGLCD es una librería abierta con un soporte amplio para culquier tipo de pantalla, pero requiere de una configuración previa.