ESP32 使用LVGL 带FreeRTOS

LVGL使用

  • 1、显示图片
  • 2、显示中文
  • 3、完整代码
  • 4、显示效果

开发环境 VS Code
ESP32 TTGO TTGO屏幕135x240

  LVGL全称Light and Versatile Graphics Library,是一个轻量级开源的嵌入式GUI库,界面精美,资源消耗小,可移植度高,全库采用纯 c 语言开发。

64 kB 闪存和 8 kB RAM 足以用于简单的用户集成
从 30 多个随时可以使用小部件中选择,并轻松自定义它们
在任何平台上使用 LVGL,如STM32、K210、Arduino、ESP32、树莓等
驱动单色、OLED、TFT 显示屏、监视器或任何其他显示器

arduino LVGL学习文档:https://docs.lvgl.io/latest/en/html/get-started/arduino.html#get-the-lvgl-ardunio-library

实现效果:实现图片显示,中文显示,文字滚动显示,绘制线条。

  前段时间在K210移植了LVGL,跑着还可以,最近想拿ESP32试试,Arduino 有现成的LVGL库,可以直接使用,不需要自己在下载源码了。

ESP32 使用LVGL 带FreeRTOS_第1张图片

1、显示图片

使用LVGL自带的工具实现图片的转换。
在线图片转换:https://lvgl.io/tools/imageconverter
ESP32 使用LVGL 带FreeRTOS_第2张图片
点击 Convert会生成一个cat.c文件,之后需要稍微修改一下cat.c,如果不修改会出现下面的错误:
在这里插入图片描述
修改的部分:
ESP32 使用LVGL 带FreeRTOS_第3张图片
显示图片代码:

/* 引入图片,相当于extern */
    LV_IMG_DECLARE(cat);
    lv_obj_t *image1 = lv_img_create(lv_scr_act(),NULL);/* 创建image 控件*/
    lv_img_set_src(image1,&cat); /* 为控件设置图片*/
    lv_obj_align(image1,NULL,LV_ALIGN_IN_TOP_MID,0,0);/* 设置控件的对齐方式,相对坐标*/

2、显示中文

中文的实现需要进行字体的取模,可以使用官方在线工具,也可以使用本地工具。
本地工具下载地址:https://wwi.lanzous.com/b00ob32qh
密码:haqs
在线工具:https://lvgl.io/tools/fontconverter
  建议使用本地工具,本地工具直接调用系统字体进行取模转换,在线工具需要自己指定字体TTF文件。
ESP32 使用LVGL 带FreeRTOS_第4张图片
点击保存,生成一个gb2312_puhui32.c的文件,里面包含字体文件。下一步,修改gb2312_puhui32.c文件。
ESP32 使用LVGL 带FreeRTOS_第5张图片
汉字显示代码:

/* 引入字体,等同于 extern */
    LV_FONT_DECLARE(gb2312_puhui32);
    static lv_style_t style_cn; /* 定义新的样式,请注意使用 static 或者全局变量 */
    lv_style_init(&style_cn);
    lv_style_set_text_font(&style_cn, LV_STATE_DEFAULT, &gb2312_puhui32);
    //汉字显示
    lv_obj_t *label3 = lv_label_create(scr,NULL); /* 创建 label 控件 */
    //lv_obj_set_style(label3,&style_cn); /* 为控件设置新的 style */
    lv_obj_add_style(label3, LV_LABEL_PART_MAIN, &style_cn);
    lv_obj_set_pos(label3,0,0); /* 设置控件的坐标 */
    lv_label_set_text(label3,"小先生"); /* 设置文字 */
    lv_obj_align(label3,NULL,LV_ALIGN_IN_TOP_MID,0,100); /* 设置控件的对齐方式-相对坐标 */

3、完整代码

使用了FreeRTOS操作系统,LVGL运行需要时钟节拍,选择使用了定时器来产生时钟节拍,lv_task_handlerLVGL系统工作函数。


#include 
#include 
#include 
#include   
#include 

#if CONFIG_FREERTOS_UNICORE
#define ARDUINO_RUNNING_CORE 0
#else
#define ARDUINO_RUNNING_CORE 1
#endif

hw_timer_t * timer = NULL;
const int Timeout = 50;//ms
TFT_eSPI tft = TFT_eSPI(135,240); /* TFT instance */
static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10];

void Task1( void *pvParameters );//
void Task2( void *pvParameters );//图片1


#if USE_LV_LOG != 0
/* Serial debugging */
void my_print(lv_log_level_t level, const char * file, uint32_t line, const char * dsc)
{

    Serial.printf("%s@%d->%s\r\n", file, line, dsc);
    Serial.flush();
}
#endif

/* Display flushing */
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);
}

/* Reading input device (simulated encoder here) */
bool read_encoder(lv_indev_drv_t * indev, lv_indev_data_t * data)
{
    static int32_t last_diff = 0;
    int32_t diff = 0; /* Dummy - no movement */
    int btn_state = LV_INDEV_STATE_REL; /* Dummy - no press */

    data->enc_diff = diff - last_diff;;
    data->state = btn_state;

    last_diff = diff;

    return false;
}
void IRAM_ATTR onTimer(){
  lv_task_handler(); /* LVGL 工作函数 */
}

void setup()
{

    Serial.begin(115200); /* prepare for possible serial debug */
    lv_init();
   timer = timerBegin(0, 80, true);//开启定时器 选择timer0,分频系数为80,向上计数
   timerAttachInterrupt(timer, &onTimer, true);//开启定时器中断函数
   timerAlarmWrite(timer, Timeout * 1000, true);//  保护值  开启自动重载
   timerAlarmEnable(timer);//使能定时器
#if USE_LV_LOG != 0
    lv_log_register_print_cb(my_print); /* register print function for debugging */
#endif

    //tft.init();
    tft.begin(); /* TFT init */
    tft.setRotation(1); /* Landscape orientation */
    tft.fillScreen(TFT_WHITE);
    tft.setTextSize(2);
    tft.setCursor(0, 0);
    tft.setTextDatum(MC_DATUM);
    void lv_style_init(void);
    
    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 = 135;
    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_ENCODER;
    indev_drv.read_cb = read_encoder;
    lv_indev_drv_register(&indev_drv);

    xTaskCreatePinnedToCore(
    Task1     //任务函数
    ,  "Task1"   /* 任务名字 没啥用,就是描述*/
    ,  1024   /*堆栈大小,单位为字节*/
    ,  NULL  /*作为任务输入传递的参数*/
    ,  1  // /*任务的优先级*/Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,  NULL 
    ,  ARDUINO_RUNNING_CORE); //指定运行任务的CPU

  xTaskCreatePinnedToCore(
    Task2
    ,  "Task2"
    ,  1024  // Stack size
    ,  NULL
    ,  2  // Priority
    ,  NULL 
    ,  ARDUINO_RUNNING_CORE);//
}


void loop()
{
  ;
}

/*---------------------- Tasks ---------------------*/

void Task1(void *pvParameters)  // This is a task.
{
  tft.fillScreen(TFT_WHITE);
  (void) pvParameters;

  for (;;) // A Task shall never return or exit.
  {
    
  }
}
void Task2(void *pvParameters)  // This is a task.
{
  
  (void) pvParameters;

  for (;;) // A Task shall never return or exit.
  {
    tft.fillScreen(TFT_WHITE);
    /* 引入图片,相当于extern */
    LV_IMG_DECLARE(cat);
    lv_obj_t *image1 = lv_img_create(lv_scr_act(),NULL);/* 创建image 控件*/
    lv_img_set_src(image1,&cat); /* 为控件设置图片*/
    lv_obj_align(image1,NULL,LV_ALIGN_IN_TOP_MID,0,0);/* 设置控件的对齐方式,相对坐标*/
    vTaskDelay(1000);  // one tick delay (15ms) in between reads for stability
    tft.fillScreen(TFT_WHITE);

    LV_IMG_DECLARE(love);
    lv_img_set_src(image1,&love); /* 为控件设置图片*/
    lv_obj_align(image1,NULL,LV_ALIGN_IN_TOP_MID,0,0);/* 设置控件的对齐方式,相对坐标*/
    vTaskDelay(1000);  // one tick delay (15ms) in between reads for stability
    lv_obj_del(image1);
    tft.fillScreen(TFT_WHITE);

    lv_obj_t *scr = lv_disp_get_scr_act(NULL); /* 获取当前屏幕 */

    lv_obj_t *label1 = lv_label_create(scr,NULL); /* 创建 label 控件 */
    lv_label_set_recolor(label1, true); /* 允许文字重新着色 */
    lv_label_set_text(label1,"#000080 Moonbeam ##6666ff Moonbeam "); /* 设置文字 空格一定要有 */
    lv_obj_align(label1,NULL,LV_ALIGN_IN_TOP_MID,0,0); /* 设置位置 */
    vTaskDelay(1000); 
    lv_obj_del(label1);
    tft.fillScreen(TFT_WHITE);

    lv_obj_t *label2 = lv_label_create(scr,NULL); /* 创建 label 控件 */
    lv_label_set_text(label2,"abcdefghijklmnopqrstabsjdjnvjjchchccbc,"); /* 设置长文本  不支持汉字 */
    lv_label_set_long_mode(label2,LV_LABEL_LONG_SROLL_CIRC); /* 设置长文本的模式为循环滚动显示 */
    lv_obj_set_width(label2, 240);
    //lv_obj_align(label2, NULL, LV_ALIGN_CENTER, 0, 10); /* 设置位置 */
    vTaskDelay(3000);
    lv_obj_del(label2);
    tft.fillScreen(TFT_WHITE);

    

    /* 引入字体,等同于 extern */
    LV_FONT_DECLARE(gb2312_puhui32);
    static lv_style_t style_cn; /* 定义新的样式,请注意使用 static 或者全局变量 */
    lv_style_init(&style_cn);
    lv_style_set_text_font(&style_cn, LV_STATE_DEFAULT, &gb2312_puhui32);
    //汉字显示
    lv_obj_t *label3 = lv_label_create(scr,NULL); /* 创建 label 控件 */
    //lv_obj_set_style(label3,&style_cn); /* 为控件设置新的 style */
    lv_obj_add_style(label3, LV_LABEL_PART_MAIN, &style_cn);
    lv_obj_set_pos(label3,0,0); /* 设置控件的坐标 */
    lv_label_set_text(label3,"小先生"); /* 设置文字 */
    lv_obj_align(label3,NULL,LV_ALIGN_IN_TOP_MID,0,100); /* 设置控件的对齐方式-相对坐标 */
    vTaskDelay(1000);
    lv_obj_del(label2);
    tft.fillScreen(TFT_WHITE);


    /*Create an array for the points of the line*/
    static lv_point_t line_points[] = { {5, 5}, {5, 70}, {70, 180}, {180, 60}, {240, 10} };

    /*Create style*/
    static lv_style_t style_line;
    lv_style_init(&style_line);
    lv_style_set_line_width(&style_line, LV_STATE_DEFAULT, 8);
    lv_style_set_line_color(&style_line, LV_STATE_DEFAULT, LV_COLOR_BLUE);
    lv_style_set_line_rounded(&style_line, LV_STATE_DEFAULT, true);

    /*Create a line and apply the new style*/
    lv_obj_t * line1;
    line1 = lv_line_create(lv_scr_act(), NULL);
    lv_line_set_points(line1, line_points, 5);     /*Set the points*/
    lv_obj_add_style(line1, LV_LINE_PART_MAIN, &style_line);     /*Set the points*/
    lv_obj_align(line1, NULL, LV_ALIGN_CENTER, 0, 0);
    vTaskDelay(3000);
    lv_obj_del(line1);
    tft.fillScreen(TFT_WHITE);


    /*Create a LED and switch it OFF*/
    lv_obj_t * led1  = lv_led_create(lv_scr_act(), NULL);
    lv_obj_align(led1, NULL, LV_ALIGN_CENTER, -80, 0);
    lv_led_off(led1);

    /*Copy the previous LED and set a brightness*/
    lv_obj_t * led2  = lv_led_create(lv_scr_act(), led1);
    lv_obj_align(led2, NULL, LV_ALIGN_CENTER, 0, 0);
    lv_led_set_bright(led2, 190);

    /*Copy the previous LED and switch it ON*/
    lv_obj_t * led3  = lv_led_create(lv_scr_act(), led1);
    lv_obj_align(led3, NULL, LV_ALIGN_CENTER, 80, 0);
    lv_led_on(led3);
    vTaskDelay(2000);
    lv_obj_del(led1);
    lv_obj_del(led2);
    lv_obj_del(led3);
  }
}

4、显示效果

ESP32 使用LVGL 带FreeRTOS

你可能感兴趣的:(VS,Code,ESP32)