重要步骤
在LVGL移植文档https://docs.lvgl.io/8.3/porting/project.html中, 总共有5个重要步骤:
- 调用lv_init() :lvgl的初始化核心
- 初始化我们自己的屏幕驱动相关,I2C,SPI,ST7789,CST816T等
- 调用lv_port_disp_init()(负责显示部分) 和 lv_port_indev_init()(负责输入部分)
- 调用lv_tick_inc(x) :这个是负责维持lvgl核心库的心跳
- 调用lv_timer_handler(): 负责lvgl中的相关任务
前面1,2,3个步骤都是与初始化相关,我们把它们写在启动任务中
static void start_task() {
taskENTER_CRITICAL();
lv_init();
lv_port_disp_init();
lv_port_indev_init();
vTaskDelete(start_handler);
taskEXIT_CRITICAL();
}
lv_tick_inc(x)
我们需要维持lvgl自身的心跳,以便让它能够处理它自身内部的任务,例如动画的渲染,长按单击事件的判断等等, 我们将这个函数放到FreeRTOS的调用函数中
例如,我们在main.c文件中定义如下名称函数:
void vApplicationTickHook( void ){
lv_tick_inc(1);
}
注意,定义了这个函数,我们还需要打开它对应的宏,在FreeRTOSConfig.h文件中第57行
#define configUSE_TICK_HOOK 1
lv_timer_handler()
lvgl中的所有的任务处理都在这个函数里,lvgl是线程不安全的,这个函数同时只能有一个线程调用它,保险起见我们需要给它的调用加一把锁
声明一把锁
SemaphoreHandle_t xMutex;
初始化这把锁
xMutex = xSemaphoreCreateMutex();
创建一个任务
xTaskCreate(lvgl_timer_task, "lvgl_timer_task", 1024, NULL, 4, NULL);
编写任务的内容
void lvgl_timer_task(void * pvParameters)
{
xMutex = xSemaphoreCreateMutex();
lv_obj_t * btn2 = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn2,100,100);
lv_obj_align(btn2, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_flag(btn2, LV_OBJ_FLAG_CHECKABLE);
lv_obj_t * label2 = lv_label_create(btn2);
lv_label_set_text(label2, "Toggle");
lv_obj_center(label2);
while(1)
{
if(pdTRUE == xSemaphoreTake(xMutex,portMAX_DELAY))
{
lv_timer_handler();
xSemaphoreGive(xMutex);
}
vTaskDelay(pdMS_TO_TICKS(1));
}
}
创建刷新的任务
static void lvgl_refresh_task() {
lv_obj_t * label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "count:");
lv_obj_set_style_text_color(label, lv_palette_main(LV_PALETTE_BLUE), 0);
lv_obj_set_pos(label,10,10);
int count = 0;
while(1) {
lv_label_set_text_fmt(label,"count:%d",count);
count++;
vTaskDelay(pdMS_TO_TICKS(1000));
printf("task1 \r\n");
}
}
完整示例代码
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "bsp_usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "lvgl.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"
#include "i2c.h"
#include "st7789.h"
#include "semphr.h"
static TaskHandle_t start_handler;
static SemaphoreHandle_t xMutex;
void Usart0_recv(uint8_t *data, uint32_t len) {
printf("Usart0_recv:%s \r\n",data);
}
static void lvgl_refresh_task() {
lv_obj_t * label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "count:");
lv_obj_set_style_text_color(label, lv_palette_main(LV_PALETTE_BLUE), 0);
lv_obj_set_pos(label,10,10);
int count = 0;
while(1) {
lv_label_set_text_fmt(label,"count:%d",count);
count++;
vTaskDelay(pdMS_TO_TICKS(1000));
printf("task1 \r\n");
}
}
void lvgl_timer_task(void * pvParameters)
{
xMutex = xSemaphoreCreateMutex();
lv_obj_t * btn2 = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn2,100,100);
lv_obj_align(btn2, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_flag(btn2, LV_OBJ_FLAG_CHECKABLE);
lv_obj_t * label2 = lv_label_create(btn2);
lv_label_set_text(label2, "Toggle");
lv_obj_center(label2);
printf("lcd_refresh_tas\r\n");
while(1)
{
if(pdTRUE == xSemaphoreTake(xMutex,portMAX_DELAY))
{
lv_timer_handler();
xSemaphoreGive(xMutex);
}
vTaskDelay(pdMS_TO_TICKS(1));
}
}
static void start_task() {
taskENTER_CRITICAL();
bsp_usart_dma_init(115200);
printf("start123\r\n");
I2C_init();
lv_init();
lv_port_disp_init();
lv_port_indev_init();
xTaskCreate(lvgl_timer_task, "lvgl_timer_task", 1024, NULL, 4, NULL);
xTaskCreate(lvgl_refresh_task, "lvgl_refresh_task", 256, NULL, 4, NULL);
vTaskDelete(start_handler);
taskEXIT_CRITICAL();
}
int main(void)
{
nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
systick_config();
xTaskCreate(start_task, "start_task", 512, NULL, 1, &start_handler);
vTaskStartScheduler();
while(1) {
}
}
void vApplicationTickHook( void ){
lv_tick_inc(1);
}