ESP32 使用LVGL 带FreeRTOS

开发环境 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库,可以直接使用,不需要自己在下载源码了。

在这里插入图片描述

1、显示图片

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

/* 引入图片,相当于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文件。
在这里插入图片描述
点击保存,生成一个gb2312_puhui32.c的文件,里面包含字体文件。下一步,修改gb2312_puhui32.c文件。
在这里插入图片描述
汉字显示代码:

/* 引入字体,等同于 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 <Arduino.h>
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <freertos/FreeRTOS.h>  
#include <freertos/task.h>

#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

  • 19
    点赞
  • 93
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 您好,移植LVGLESP32可以参考以下步骤: 1. 首先,需要在ESP32上安装FreeRTOS操作系统。 2. 然后,需要在ESP32上安装LVGL库。可以使用ESP-IDF的组件管理器来安装LVGL库。 3. 接下来,需要在ESP32上配置LVGL库。可以使用ESP-IDF的make menuconfig命令来配置LVGL库。 4. 然后,需要在ESP32上编写应用程序代码,使用LVGL库来创建用户界面。 5. 最后,可以使用VSCode来编写、调试和上传应用程序代码到ESP32。 希望这些步骤可以帮助您成功地将LVGL移植到ESP32上。 ### 回答2: 首先,为了将LVGL移植到ESP32中,需要确保您的开发板可以使用ESP-IDF。由于ESP-IDF是ESP32的官方开发框架,因此我们将使用它来构建我们的LVGL应用程序。 步骤1:配置ESP-IDF 在开始LVGL移植之前,您需要确保ESP-IDF在您的系统上正确安装并配置。可以在官方网站上找到有关如何安装和配置ESP-IDF的详细说明。 步骤2:安装LVGL 要安装LVGL,请使用ESP-IDF提供的组件,运行如下命令: ``` idf.py menuconfig ``` 然后选择Component Config>LVGL Configuration>Enable LVGL. 在此之后,您可以运行如下命令进行构建和烧录: ``` idf.py build idf.py -p PORT flash ``` 请注意将PORT替换为您的ESP32开发板连接的端口。 步骤3:配置VSCode 要在VSCode中设置ESP-IDF,请运行以下命令: ``` idf.py set-target esp32 ``` 接下来,运行以下命令以自动生成ESP-IDF所需的.vscode目录和c_cpp_properties.json文件: ``` idf.py create-template vscode ``` 步骤4:创建LVGL应用程序 现在,您已经准备好创建您的第一个LVGL应用程序,使用命令行工具或VSCode中的终端,运行以下命令来创建一个新的ESP-IDF项目: ``` idf.py create-project lvgl-project ``` 然后,将以下代码添加到main.c文件中: ``` #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "lvgl/lvgl.h" void lv_app(void *args) { lv_init(); lv_obj_t *label = lv_label_create(lv_scr_act(), NULL); lv_label_set_text(label, "Hello world!"); while(1) { lv_task_handler(); vTaskDelay(10); } } int app_main() { xTaskCreate(lv_app, "lv_app", 4096, NULL, 5, NULL); return 0; } ``` 此代码将在LVGL屏幕上显示“Hello World”。运行以下命令以构建并烧写应用程序: ``` idf.py build idf.py -p PORT flash monitor ``` 现在,您应该能够在ESP32开发板上看到您的第一个LVGL应用程序运行! 总结 通过以上步骤,您可以将LVGL移植到ESP32上,并使用VSCode进行开发。在这个过程中,大家需要确保已经配置好了ESP-IDF和LVGL,并且熟悉如何使用VSCode进行开发。现在,开始您的LVGL开发之旅吧! ### 回答3: ESP32是一款性价比较高的MCU,而LVGL是一款功能强大的GUI库,将两者结合起来可以实现许多有趣的项目。针对ESP32移植LVGL到VSCode的步骤如下: 1. 下载并安装ESP-IDF,配置好环境变量。可以参考ESP-IDF文档进行操作。在下载时,建议下载最新的稳定版。 2. 安装VSCode和插件。VSCode是一款开源的代码编辑器,插件可以增强其功能。需要安装的插件有C/C++插件、ESP-IDF插件、LVGL插件和PlatformIO插件。 3. 在VSCode中打开ESP-IDF项目。ESP-IDF中有很多例程,找到适合自己的例程并打开,然后在ESP-IDF菜单栏的“终端”下拉菜单中选择“新终端”打开命令行工具。 4. 运行命令,安装LVGL。在命令行工具中输入“make menuconfig”进入配置界面,然后到“component config -> LVGL -> LVGL Configuration”进行配置并保存。 5. 编写代码。VSCode可以通过插件创建LVGL项目,选择合适的开发板和屏幕分辨率,然后完成项目创建。在项目中编写C语言代码来实现功能。 6. 编译和调试。使用PlatformIO插件可以编译代码并烧录到ESP32上,调试也可以通过VSCode的调试工具来进行。 总的来说,ESP32移植LVGL到VSCode需要进行一些常规的配置和命令行操作,但是掌握了其中的细节之后便可以达到较好的效果。注意这只是整体步骤的概括,具体细节还需根据实际情况和项目来具体实施。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值