ESP32联动LVGL开发日记(二)-简单显示任务创建
上一章,我安装了软件和简单演示了一下使用例程,有兴趣的话也可以切换一下其他例程进行一下显示。在开始之前推荐一个LVGL学习的网站:百问网-LVGL,这个网站简直是学习LVGL的利器。
一.近期学习成果(显示+按键操作,本节只讲创建一个显示)
按键显示及特效操作视频:
ESP32联动LVGL学习开发日记(二)
二.lv_port_esp32中的LVGL组件介绍
①主目录:
②components:
③LVGL的整体系统框架
④本教程主要讲解如何使用LVGL创建显示一个区域及显示一个按键
三.显示一个屏幕区域
①要使用LVGL在屏幕上创建一个显示,需要先初始化以下几个部分:
a-初始化lvgl,初始化驱动屏幕的外设(ST7789使用的是SPI)
/* Initialize lvgl */
lv_init();
/* Initialize SPI or I2C bus used by the drivers */
lvgl_driver_init();
b-设置显示的缓存buf,一个或者两个,并初始化他们:
(此处的代码可以直接用demo里的代码,注释掉guitask里面的create_demo_application()函数,开始修改guitask函数。)
lv_color_t *buf1 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
assert(buf1 != NULL);
/* Use double buffered when not working with monochrome displays */
#ifndef CONFIG_LV_TFT_DISPLAY_MONOCHROME
lv_color_t *buf2 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
assert(buf2 != NULL);
#else
static lv_color_t *buf2 = NULL;
#endif
c-初始化lvgl的显示组件
(这里也可以直接使用demo里面的函数部分)
/* Initialize the working buffer depending on the selected display.
* NOTE: buf2 == NULL when using monochrome displays. */
lv_disp_buf_init(&disp_buf, buf1, buf2, size_in_px);
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.flush_cb = disp_driver_flush;
/* When using a monochrome display we need to register the callbacks:
* - rounder_cb
* - set_px_cb */
#ifdef CONFIG_LV_TFT_DISPLAY_MONOCHROME
disp_drv.rounder_cb = disp_driver_rounder;
disp_drv.set_px_cb = disp_driver_set_px;
#endif
disp_drv.buffer = &disp_buf;
lv_disp_drv_register(&disp_drv);
d-创建并启动一个周期性计时器中断来调用lv_tick inc
(非常重要,非常重要,不创建启动,LVGL显示就无法更新,血的教训)
/* Create and start a periodic timer interrupt to call lv_tick_inc */
const esp_timer_create_args_t periodic_timer_args = {
.callback = &lv_tick_task,
.name = "periodic_gui"};
esp_timer_handle_t periodic_timer;
ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, LV_TICK_PERIOD_MS * 1000));
至此显示所需要的基础初始化就设置完成了,接下来要进行屏幕的创建了
②在屏幕上创建一个显示:
a-创建一个显示,并加载,设置显示的区域大小。并在此显示区域上创建一个label文本,编辑文本的位置和内容(具体的API函数请在文章顶部的百问网详细了解)
lv_obj_t *scr1 = lv_obj_create(lv_scr_act(), NULL); //创建scr
// lv_obj_set_pos(scr1, 10, 7); //set scr pos
lv_obj_set_size(scr1, 240, 135); //creat btn size
lv_scr_load(scr1); /* 加载屏幕*/
lv_scr_act(); /* 活动屏幕*/
lv_obj_t *label1 = lv_label_create(scr1, NULL); // /*Create a Label on the currently active screen*/
lv_obj_set_pos(label1, 70, 5); /* 移动父类对象,子类对象跟着移动 .*/
lv_label_set_text(label1, "Hello lclr8air");
显示效果:
b-使用类似方式在创建一个按键显示
在屏幕scr1上创建一个按键,使能根据内容自动设置大小,设置位置。在上面创建一个文本,设置显示内容,位置
//==============btn1=================
lv_obj_t *btn1 = lv_btn_create(scr1, NULL); //创建子对象btn1在父类对象中
lv_btn_set_fit(btn1, true); /* 使能自动设置大小根据内容 */
lv_obj_set_pos(btn1, 20, 30); //creat btn pos
lv_obj_t *labelA = lv_label_create(btn1, NULL); //创建子对象btn1在父类对象中
lv_obj_set_pos(labelA, 0, 0); /* 移动父类对象,子类对象跟着移动 .*/
lv_label_set_text(labelA, "AaBbCcDd");
显示效果:
四.附上主函数全部代码
/* LVGL Example project
*
* Basic project to test LVGL on ESP32 based projects.
*
* This example code is in the Public Domain (or CC0 licensed, at your option.)
*
* Unless required by applicable law or agreed to in writing, this
* software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_freertos_hooks.h"
#include "freertos/semphr.h"
#include "esp_system.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "esp_types.h"
/* Littlevgl specific */
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#include "lvgl_helpers.h"
/*********************
* DEFINES
*********************/
#define Test 1
#define TAG "demo"
#define GPIO_KEY_NUM1 0
#define GPIO_KEY_NUM2 35
#define GPIO_KEY_PR 37
#define GPIO_KEY_UP 38
#define GPIO_KEY_DN 39
#define GPIO_INPUT_PIN_SEL ((1ULL << GPIO_KEY_PR) | (1ULL << GPIO_KEY_UP) | (1ULL << GPIO_KEY_DN)) //选定gpio
#define ESP_INTR_FLAG_DEFAULT 0 //设置一个flag标志位
static xQueueHandle gpio_evt_queue = NULL; //消息队列
#define LV_TICK_PERIOD_MS 1
uint16_t Counts_Gui = 0;
uint16_t Counts_Key = 0;
uint16_t DIR_Flag = 0;
gpio_config_t KeyGPIO;
/**********************
* STATIC PROTOTYPES
**********************/
static void lv_tick_task(void *arg);
static void guiTask(void *pvParameter);
/* Creates a semaphore to handle concurrent call to lvgl stuff
* If you wish to call *any* lvgl function from other threads/tasks
* you should lock on the very same semaphore! */
SemaphoreHandle_t xGuiSemaphore;
//------------------------------TOOLS----------------------------------
//---------------------------TASK-------------------------------------
static void lv_tick_task(void *arg)
{
(void)arg;
lv_tick_inc(LV_TICK_PERIOD_MS);
}
static void guiTask(void *pvParameter)
{
(void)pvParameter;
xGuiSemaphore = xSemaphoreCreateMutex();
lv_init();
/* Initialize SPI or I2C bus used by the drivers */
lvgl_driver_init();
lv_color_t *buf1 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
assert(buf1 != NULL);
/* Use double buffered when not working with monochrome displays */
#ifndef CONFIG_LV_TFT_DISPLAY_MONOCHROME
lv_color_t *buf2 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
assert(buf2 != NULL);
#else
static lv_color_t *buf2 = NULL;
#endif
static lv_disp_buf_t disp_buf;
uint32_t size_in_px = DISP_BUF_SIZE;
#if defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_IL3820
|| defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_JD79653A || defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_UC8151D || defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_SSD1306
/* Actual size in pixels, not bytes. */
size_in_px *= 8;
#endif
/* Initialize the working buffer depending on the selected display.
* NOTE: buf2 == NULL when using monochrome displays. */
lv_disp_buf_init(&disp_buf, buf1, buf2, size_in_px);
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.flush_cb = disp_driver_flush;
/* When using a monochrome display we need to register the callbacks:
* - rounder_cb
* - set_px_cb */
#ifdef CONFIG_LV_TFT_DISPLAY_MONOCHROME
disp_drv.rounder_cb = disp_driver_rounder;
disp_drv.set_px_cb = disp_driver_set_px;
#endif
disp_drv.buffer = &disp_buf;
lv_disp_drv_register(&disp_drv);
/* Create and start a periodic timer interrupt to call lv_tick_inc */
const esp_timer_create_args_t periodic_timer_args = {
.callback = &lv_tick_task,
.name = "periodic_gui"};
esp_timer_handle_t periodic_timer;
ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, LV_TICK_PERIOD_MS * 1000));
//-----------------------Creat Obj--------------------------------
//==============scr=================
// lv_obj_t *scr1 = lv_scr_act();//创建scr
lv_obj_t *scr1 = lv_obj_create(lv_scr_act(), NULL); //创建scr
// lv_obj_set_pos(scr1, 10, 7); //set scr pos
lv_obj_set_size(scr1, 240, 135); //creat btn size
lv_scr_load(scr1); /* 加载屏幕*/
lv_scr_act(); /* 活动屏幕*/
lv_obj_t *label1 = lv_label_create(scr1, NULL); // /*Create a Label on the currently active screen*/
lv_obj_set_pos(label1, 70, 5); /* 移动父类对象,子类对象跟着移动 .*/
lv_label_set_text(label1, "Hello lclr8air");
//==============btn1=================
lv_obj_t *btn1 = lv_btn_create(scr1, NULL); //创建子对象btn1在父类对象中
lv_btn_set_fit(btn1, true); /* 使能自动设置大小根据内容 */
lv_obj_set_pos(btn1, 20, 30); //creat btn pos
lv_obj_t *labelA = lv_label_create(btn1, NULL); //创建子对象btn1在父类对象中
lv_obj_set_pos(labelA, 0, 0); /* 移动父类对象,子类对象跟着移动 .*/
lv_label_set_text(labelA, "AaBbCcDd");
//-----------------------Begin--------------------------------
// MY_GUI();
// lv_demo_benchmark();
printf("LVGL init OK!\r\n"); /* 获取BOOT按键电平并打印 */
// create_demo_application();
while (1)
{
/* Delay 1 tick (assumes FreeRTOS tick is 10ms */
vTaskDelay(pdMS_TO_TICKS(10));
// Counts_Gui++;
// if (Counts_Gui == 100)
// {
// printf("Toggle!\r\n"); /* 获取并打印 */
// lv_btn_toggle(btn2);
// Counts_Gui = 0;
// }
/* Try to take the semaphore, call lvgl related function on success */
if (pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY))
{
lv_task_handler();
xSemaphoreGive(xGuiSemaphore);
}
}
/* A task should NEVER return */
free(buf1);
#ifndef CONFIG_LV_TFT_DISPLAY_MONOCHROME
free(buf2);
#endif
vTaskDelete(NULL);
}
/**********************
* APPLICATION MAIN
**********************/
void app_main()
{
/* If you want to use a task to create the graphic, you NEED to create a Pinned task
* Otherwise there can be problem such as memory corruption and so on.
* NOTE: When not using Wi-Fi nor Bluetooth you can pin the guiTask to core 0 */
xTaskCreatePinnedToCore(guiTask, "gui", 4096 * 2, NULL, 0, NULL, 0); //注册中断函数
}