Display redondo GC9A01A com Arduino

Posted by

Vamos falar sobre o display LCD redondo GC9A01A 240×240, uma pequena adição bacana para a caixa de ferramentas de qualquer amador. Estamos falando de um display LCD TFT RGB de 240×240 pixels em um formato redondo. Ele se comunica com um microcontrolador via SPI e pode fazer 262k cores em modo completo; 8 cores em modo ocioso.

As conexões (hardware) são bem diretas, quatro pinos de dados mais 3V3 e GND. Quatro resistores são necessários em série com os pinos de dados porque o display é 3V3 e o Arduino funciona a 5V. Usei resistores de 680 Ohm.

Display GC9A01A mostrando a URL do blog FritzenLab
Display GC9A01A mostrando a URL do blog FritzenLab
Display GC9A01APinos do Arduino UNO
RSTNão conectado
CS10
DC9
SDA11
SCL13
GNDGND
VCC3V3
Pinagem do display

Comecei com uma demonstração deste post do blog. O código e a imagem estão abaixo, é um medidor/medidor de voltagem. Coisa bem complexa, o código não é meu.

#include "SPI.h"
   #include "Adafruit_GC9A01A.h"

   #define TFT_DC 9
   #define TFT_CS 10
 
   Adafruit_GC9A01A tft (TFT_CS, TFT_DC);
 
   #define BLACK      0x0000                                                               // some extra colors
   #define BLUE       0x001F
   #define RED        0xF800
   #define GREEN      0x07E0
   #define CYAN       0x07FF
   #define MAGENTA    0xF81F
   #define YELLOW     0xFFE0
   #define WHITE      0xFFFF
   #define ORANGE     0xFBE0
   #define GREY       0x84B5
   #define BORDEAUX   0xA000
   #define AFRICA     0xAB21                                                               // current dial color

   #define DEG2RAD 0.0174532925 

   int multiplier;
   int    frametime = 1000; 
   int    x_pos;
   int    y_pos; 
   int    center_x = 120;                                                                  // center x of dial on 240*240 TFT display
   int    center_y = 120;                                                                  // center y of dial on 240*240 TFT display
   float  pivot_x, pivot_y,pivot_x_old, pivot_y_old;
   float  p1_x,p1_y,p2_x,p2_y,p3_x, p3_y, p4_x, p4_y, p5_x, p5_y; 
   float  p1_x_old,p1_y_old, p2_x_old, p2_y_old, p3_x_old, p3_y_old;
   float  p4_x_old, p4_y_old, p5_x_old, p5_y_old;
   float  angleOffset = 3.14;
   float  arc_x;
   float  arc_y;
   int    radius = 120;                                                                    // center y of circular scale                                                   
   float  angle_circle = 0;
   float  needleAngle = 0;
   int    iteration = 0;
   int    j;                                                            
   float  volt = 220;
   int    needle_multiplier = 1;
   float  needle_setter;             
                                                                                           // voltage rolling averaging stuff 
   const byte nvalues = 10;                                                                // rolling average window size
   static byte current = 0;                                                                // index for current value
   static byte cvalues = 0;                                                                // count of values read (<= nvalues)
   static float sum = 0;                                                                   // rolling sum
   static float values[nvalues];
   float averagedVoltage = 235;                                                            // to start with
   
void setup() {

  randomSeed (analogRead(0));  

   tft.begin();    
   Serial.begin (9600); 
   Serial.println (""); 
   Serial.println (""); 
   tft.setRotation (0);  
   
   tft.fillScreen (BLACK);
   tft.drawCircle (center_x, center_y,120, BLACK);             
   pivot_x = center_x;
   pivot_y = center_y+50;

   p1_x_old = center_x; p1_y_old = center_y+50;
   p2_x_old = center_x; p2_y_old = center_y+50;
   p3_x_old = center_x; p3_y_old = center_y+50;
   p4_x_old = center_x; p4_y_old = center_y+50;
   p5_x_old = center_x; p5_y_old = center_y+50;

   volt = 240;                                                                             // initial value setting the needle
   create_dial ();
   needle_setter = volt;
   needleAngle = (((needle_setter)*DEG2RAD*1.8)-3.14);
   needle();  
   draw_pivot ();
}


void loop (){
  
   iteration++;
   Serial.println ();      
   Serial.print ("iteration ");
   Serial.println (iteration); 
   volt = random (230,250);                                                                // voltage simulator  
   Serial.print ("simulated volt out of ZMPT101B: ");
   Serial.println (volt);  
   averagedVoltage = movingAverage(volt);
   Serial.print ("averaged volt =      ");
   Serial.println (averagedVoltage);
   Serial.println ();  
   Serial.println ();   

   displayNumerical ();
   needle_setter = averagedVoltage;     
   needle();
   draw_pivot (); 
   
   delay (frametime);
} 

void needle (){                                                                            // dynamic needle management

   tft.drawLine (pivot_x, pivot_y, p1_x_old, p1_y_old, AFRICA);                            // remove old needle  
   tft.fillTriangle (p1_x_old, p1_y_old, p2_x_old, p2_y_old, p3_x_old, p3_y_old, AFRICA);  // remove old arrow head
   tft.fillTriangle (pivot_x, pivot_y, p4_x_old, p4_y_old, p5_x_old, p5_y_old, AFRICA);    // remove old arrow head
    
   needleAngle = (((needle_setter)*0.01745331*1.8)-3.14);
   p1_x = (pivot_x + ((radius)*cos(needleAngle)));                                         // needle tip
   p1_y = (pivot_y + ((radius)*sin(needleAngle))); 

   p2_x = (pivot_x + ((radius-15)*cos(needleAngle-0.05)));                                 // needle triange left
   p2_y = (pivot_y + ((radius-15)*sin(needleAngle-0.05))); 

   p3_x = (pivot_x + ((radius-15)*cos(needleAngle+0.05)));                                 // needle triange right
   p3_y = (pivot_y + ((radius-15)*sin(needleAngle+0.05))); 

   p4_x = (pivot_x + ((radius-90)*cos(angleOffset+(needleAngle-0.2))));                    // needle triange left
   p4_y = (pivot_y + ((radius-90)*sin(angleOffset+(needleAngle-0.2)))); 

   p5_x = (pivot_x + ((radius-90)*cos(angleOffset+(needleAngle+0.2))));                    // needle triange right
   p5_y = (pivot_y + ((radius-90)*sin(angleOffset+(needleAngle+0.2)))); 
  
   p1_x_old = p1_x; p1_y_old = p1_y;                                                       // remember previous needle position
   p2_x_old = p2_x; p2_y_old = p2_y;                                                                         
   p3_x_old = p3_x; p3_y_old = p3_y;                                                                      

   p4_x_old = p4_x; p4_y_old = p4_y;                                                       // remember previous needle counterweight position
   p5_x_old = p5_x; p5_y_old = p5_y;                                                                      

   tft.drawLine (pivot_x, pivot_y, p1_x, p1_y, BLACK);                                     // create needle 
   tft.fillTriangle (p1_x, p1_y, p2_x, p2_y, p3_x, p3_y, BLACK);                           // create needle tip pointer
   tft.drawLine (center_x-80, center_y+70, center_x+80,center_y+70, WHITE);                // repair floor 
   tft.fillTriangle (pivot_x, pivot_y, p4_x, p4_y, p5_x, p5_y, BLACK);                     // create needle counterweight
}


void create_dial (){

   tft.fillCircle (center_x, center_y,120, AFRICA);                                        // general dial field
   tft.drawCircle (center_x, center_y,118,GREY);  
   tft.drawCircle (center_x, center_y,117,BLACK);
   tft.drawCircle (center_x, center_y,116,BLACK);  
   tft.drawCircle (center_x, center_y,115,GREY);

   for (j= 30; j<75    ; j+=5)
       {
        needleAngle = ((j*DEG2RAD*1.8)-3.14);
        arc_x = (pivot_x + ((radius+15)*cos(needleAngle)));                                // needle tip
        arc_y = (pivot_y + ((radius+15)*sin(needleAngle))); 
        tft.drawPixel  (arc_x,arc_y,BLACK);
        tft.fillCircle (arc_x,arc_y,2, BLACK);
        }

   tft.setTextColor (BLACK,AFRICA);    
   tft.setTextSize (2);
   tft.setCursor (center_x+15, center_y+40);
   tft.print ("V - AC");                                                                                                                                                                          
   tft.drawLine (center_x-80, center_y+70, center_x+80,center_y+70, WHITE);                // create floor  
}


void draw_pivot (){
 
   tft.fillCircle (pivot_x, pivot_y,8,RED);               
   tft.drawCircle (pivot_x, pivot_y,8,BLACK);            
   tft.drawCircle (pivot_x, pivot_y,3,BLACK);      
}

 
void displayNumerical (){

   tft.fillRect (center_x-82, center_y+40, 62,16,AFRICA);
   tft.setTextColor (BLACK);    
   tft.setTextSize (2);
   tft.setCursor (center_x-80, center_y+40);
   tft.print (averagedVoltage,1);   
}


float movingAverage(float value) {

   sum += value;                    
   if (cvalues == nvalues)                                                                 // if the window is full, adjust the sum by deleting the oldest value
     sum -= values[current];

   values[current] = value;                                                                // replace the oldest with the latest

   if (++current >= nvalues)
     current = 0;

   if (cvalues < nvalues)
     cvalues += 1;

   return sum/cvalues;
}
Medidor com GC9A01A
Medidor com GC9A01A

Há mais informações sobre o display, a ficha técnica do GC9A01A está aqui.

A biblioteca da Adafruit

Eu também executei a demonstração do Adafruit aqui (Github). Para isso, você precisa primeiro instalar a biblioteca oficial no Arduino IDE. Vá em “Sketch > Add library > Library manager” e digite “GC9A01A”, selecione e instale o Adafruit. A imagem abaixo é de uma das telas da biblioteca Adafruit.

O código pode ser acessado no Arduino IDE em “File > Examples > Adafruit GC9A01A > graphicstest”. Lembre-se de que você precisa instalar a biblioteca como visto acima.

Display GC9A01A na protoboard
Display GC9A01A com biblioteca Adafruit, na protoboard

Então eu fiz um código simples para mostrar a URL do blog, como visto abaixo. Ele é baseado (e usa) na biblioteca Adafruit.

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_GC9A01A.h"

#define TFT_DC  9
#define TFT_CS 10

Adafruit_GC9A01A tft(TFT_CS, TFT_DC);

void setup() {
  // put your setup code here, to run once:
  tft.begin();
  tft.fillScreen(GC9A01A_BLUE);
  yield();
  tft.setCursor(30, 100);
  tft.setTextColor(GC9A01A_GREEN);
  tft.setTextSize(3);
  tft.println("FritzenLab");
  tft.setCursor(90, 120);
  tft.println(".net");

}

void loop() {
  // put your main code here, to run repeatedly:
  
  
}

O resultado é bem legal:

O display GC9A01A mostrando o endereço do blog
O display GC9A01A mostrando o endereço do blog

Também melhorei um pouco animando o texto, como pode ser visto no vídeo abaixo:

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_GC9A01A.h"

#define TFT_DC  9
#define TFT_CS 10

Adafruit_GC9A01A tft(TFT_CS, TFT_DC);

void setup() {
  // put your setup code here, to run once:
  tft.begin();
  tft.fillScreen(GC9A01A_BLUE);
  yield();
  

}

void loop() {
  // put your main code here, to run repeatedly:
  for(int i=0; i < tft.height(); i=i+10){
    tft.setCursor(30, i);
    tft.setTextColor(GC9A01A_GREEN);
    tft.setTextSize(3);
    tft.println("FritzenLab");
    tft.setCursor(90, i+20);
    tft.println(".net");
    //delay(10);
    tft.fillScreen(GC9A01A_BLUE);
    }

Pra finalizar

Apesar de não ser o display mais rápido de todos os tempos, ele pode fazer um pouco de animação. Vimos isso no exemplo do Gauge/meter e também na demonstração do Adafruit. Olhar para ele é legal, diferente de tantos displays que já vi por aí. Definitivamente farei um projeto com ele no futuro.

Quer saber mais sobre displays? Acabei de escrever recentemente sobre o OLED i2c de 0,96″ aqui. Além disso, se você quiser comprar seu próprio display para teste, compre o GC9A01A no meu link de afiliado Banggood.

Uma resposta

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *