Tutorial de LVGL 02 – Definição do projeto

O segundo vídeo do tutorial de LVGL 02 já está programado para 9:00 da data de publicação desse artigo. Nele temos a continuidade do código, com uma explicação rápida das partes que se repetirão em qualquer projeto, além de outros pontos importantes. Para não causar comas com soníferos minutos de teoria, resolvi iniciar a migração da interface do misturador de cores CMYK, seguindo um roteiro. No vídeo você verá:

  • Design do projeto, com a definição dos widgets e abas.
  • Demonstração de calibração do touchscreen.
  • Estrutura de código mínimo que precede a implementação dos componentes da tela.
  • Criação das abas definidas no projeto.
  • Criação dos componentes “flutuantes” da tela.

Tudo isso em 8 minutos de vídeo. Um cigarro consome sua saúde e 10 minutos da sua vida; um café consome uns 5 minutos se já estiver coado; um barbear consome uns 10 minutos; uma maquiagem consome umas 3 horas. Assistir o vídeo será no mínimo interessante, dedique esses minutos em apoio ao esforço desprendido e inscreva-se no canal DobitaobyteBrasil no Youtube, pOr fAvOr!

Para complementar o vídeo, o código utilizado no tutorial até o momento é esse:

#include <Arduino.h>
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <EasyPCF8574.h>
#include <WiFi.h>

#define DISPLAY_WIDTH  240
#define display_HEIGHT 320

#define SSID   "SuhankoFamily"
#define PASSWD "fsjmr112"

EasyPCF8574 pcfSmart(0x27,0xFF);
TFT_eSPI tft = TFT_eSPI(); /* driver do touch */

//BUFFER DE FRAME DO DISPLAY
static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10];

//GUARDA AS COORDENADAS X e Y DO TOUCH
uint16_t t_x = 0, t_y = 0;

//LIMITADOR DO TOQUE PARA NAO HAVER REPETICAO DE EVENTO
unsigned long time_to_next = millis();

//PROTÓTIPOS DE FUNÇÕES
bool my_input_read(lv_indev_drv_t * drv, lv_indev_data_t*data);
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p);

void colorPickerLocal(void);
void CMYKselector();
void RGBselector();
void startButton();
void colorSample();
void loginScreen();
void dashboard();
void tabs();

void tabs(){
    /* CRIA UM OBJETO TABVIEW */
    lv_obj_t *tabview;
    tabview = lv_tabview_create(lv_scr_act(), NULL);

    /* CRIA 4 ABAS NA TABVIEW */
    lv_obj_t *tab1 = lv_tabview_add_tab(tabview, "RGB");
    lv_obj_t *tab2 = lv_tabview_add_tab(tabview, "CMYK");
    lv_obj_t *tab3 = lv_tabview_add_tab(tabview, "Dash");
    lv_obj_t *tab4 = lv_tabview_add_tab(tabview, "Conf");

    /* UMA ANIMAÇÃO SIMPLES (OPCIOINAL)*/
    lv_tabview_set_anim_time(tabview, 1000);

    //--------------------------TAB 1: arc-------------------------------------------
    lv_obj_t *l1 = lv_label_create(tab1, NULL);
    lv_label_set_text(l1, "Aba RGB");
    lv_obj_align(l1, NULL, LV_ALIGN_IN_TOP_MID, 0, 0);

    //--------------------------TAB 2: arc-------------------------------------------
    lv_obj_t *l2 = lv_label_create(tab2, NULL);
    lv_label_set_text(l2, "Aba CMYK");
    lv_obj_align(l2, NULL, LV_ALIGN_IN_TOP_MID, 0, 10);

    //--------------------------TAB 3: arc-------------------------------------------
    lv_obj_t *l3 = lv_label_create(tab3, NULL);
    lv_label_set_text(l3, "Aba Dashboard");
    lv_obj_align(l3, NULL, LV_ALIGN_IN_TOP_MID, 0, 10);

    //--------------------------TAB 4: arc-------------------------------------------
    lv_obj_t *l4 = lv_label_create(tab4, NULL);
    lv_label_set_text(l4, "Aba Config");
    lv_obj_align(l4, NULL, LV_ALIGN_IN_TOP_MID, 0, 10);
 

    //---------------------------- ULTIMA CAMADA -----------------------------------
    /* ESSA CAMADA VAI NA SCREEN PRINCIPAL, "FLUTUANDO" SOBRE A TABVIEW. 
    AQUI TEMOS UM LABEL E O BOTÃO DE LOGOFF. */
    
    lv_obj_t *bb = lv_label_create(lv_scr_act(), NULL);
    lv_label_set_text(bb, "Do bit Ao Byte - LVGL");
    lv_obj_align(bb, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, -10);

    lv_obj_t * btn_logoff = lv_btn_create(lv_scr_act(), NULL);
    lv_obj_align(btn_logoff,NULL,LV_ALIGN_IN_BOTTOM_RIGHT,0,-24);
    lv_obj_set_width(btn_logoff,30);
    lv_obj_set_height(btn_logoff,30);
    //lv_obj_set_event_cb(btn_logoff, event_logoff);

    lv_obj_t *icon_logoff = lv_label_create(btn_logoff, NULL);
    lv_label_set_text(icon_logoff, LV_SYMBOL_POWER);

}

//-------------------------------------------------------------------------------//
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p){
    uint32_t w = (area->x2 - area->x1 + 1);
    uint32_t h = (area->y2 - area->y1 + 1);

    tft.startWrite();
    tft.setAddrWindow(area->x1, area->y1, w, h);
    tft.pushColors(&color_p->full, w * h, true);
    tft.endWrite();

    lv_disp_flush_ready(disp);
}

bool my_input_read(lv_indev_drv_t * drv, lv_indev_data_t*data){
    if ((millis()-time_to_next) > 1000){
        if (tft.getTouch(&t_x, &t_y)){
            data->state = LV_INDEV_STATE_PR ;
            data->point.x = t_x;
            data->point.y = t_y;
            time_to_next = millis();
            Serial.println("ok");
        }
        else{
            data->state = LV_INDEV_STATE_REL;
            data->point.x = 0;
            data->point.y = 0;
        }
    }
    
    return false; /*No buffering now so no more data read*/
}

void colorPickerLocal(void){
    lv_obj_t * cpicker;

    cpicker = lv_cpicker_create(lv_scr_act(), NULL);
    lv_obj_set_size(cpicker, 200, 200);
    lv_obj_align(cpicker, NULL, LV_ALIGN_CENTER, 0, 0);
}

void setup() {
    Serial.begin(9600);

    if (!pcfSmart.startI2C(21,22)){
        Serial.println("Not started. Check pin and address.");
        while (true);
    }

    lv_init();

    uint16_t calData[5] = { 313, 3260, 491, 3315, 6 };

    tft.begin(); /* TFT init */
    tft.setRotation(0); /* Landscape orientation */


    tft.setTouch(calData);

    lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);

    /*Initialize the display*/
    lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = 240;
    disp_drv.ver_res = 320;
    disp_drv.flush_cb = my_disp_flush;
    disp_drv.buffer = &disp_buf;
    lv_disp_drv_register(&disp_drv);

    /*Initialize the (dummy) input device driver*/
    lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER; //pointer para mouse e touch
    indev_drv.read_cb = my_input_read;
    lv_indev_drv_register(&indev_drv);


    //Tutorial LVGL - 02
    tabs();
}

void loop() {
    lv_task_handler();
    delay(5);
}

Tutorial de LVGL 02: Definição do projeto

Como a personalização da interface será feita do zero, pude modelar livremente os recursos que pretendo implementar. A interface atual do misturador de cores é assim:

Tutorial de LVGL 02 - tela inicial do misturador de cores

No primeiro passo apresentado nesse segundo vídeo tutorial, a interface está assim:

Tutorial de LVGL 02 - nova tela do misturador de cores

No próximo vídeo será implementado o controle RGB (que hoje não existe no misturador de cores), para selecionar a cor a partir de um color picker na tela. Para que possa ser reproduzido, é bom acompanhar desde o princípio para que as coisas sejam fáceis e fluidas.

Até a próxima!

 

Revisão: Ricardo Amaral de Andrade

Djames Suhanko

Sobre o autor: Djames Suhanko é Perito Forense Digital. Já atuou com deployer em sistemas de missão critica em diversos países pelo mundão. Programador Shell, Python, C, C++ e Qt, tendo contato com embarcados ( ora profissionalmente, ora por lazer ) desde 2009.