欢迎来到矽芯硬翌的科技主义教室!
记录STM32入土路上的艰苦旅程,加油UPUPUP!
@Author: 矽芯硬翌!
👇想要我的财宝吗?想要的话可以全部给你,去找出来吧,这世上所有的一切都在那里!
👇
ONE PIECE地址: ✨ 矽芯硬翌的博客✨
前言
记录一下学习STM32GUI的路程,也是为了自己以后可以快速翻阅代码查漏补缺 加油以下是介绍littleVGL的任务系统,下面案例可供参考
一、littleVGL任务系统
- littleVGL 的任务管理系统类似于软件定时器,他们俩者之间具有许多相同的特性。,它支持6个任务优先级,高优先级的任务可以抢占低优先级的任务,注意,此任务管理系统是非实时的,因为任务的时效性是取决于 lv_task_handler()函数的调用,而 lv_task_handler()函数一般放在 main 函数主循环中进行调用,所以你也要确保 main 函数主循环中不能有其他过大的延时存在。
- littleVGL 的任务管理系统主要是由 3 个数据类型和 13 个 API 接口组成的
二、主要的数据类型
2.1 任务优先级数据类型
下面是任务优先级数据类型:
2.2 任务管理句柄数据类型
lv_task_t 是任务句柄数据类型,也可以说是任务对象数据类型,俩者的意思是一样的,只是不同的叫法,以后我统统以句柄为例,我们一般是不直接修改 lv_task_t 句柄的属性的,都是通过其他的 API 接口来操作的。
下面是任务优先级数据类型:
三、API接口
- 事务处理器:
lv_task_handler(void);
lv_task_handler 这个 API 接口是非常重要的,littleVGL 内部的所有事务都是通过这个接口来处理的,所以我称它为事务处理器,它需要不断的被周期性调用,我们通常把它放到 main 函数的主循环中去。 - 创建任务:
lv_task_t * lv_task_create(lv_task_cb_t task_xcb, uint32_t period, lv_task_prio_t prio, void * user_data);
参考lv_task_t基本数据类型
创建任务一般都是通过这个API接口来进行的,可以一步到位,其实 lv_task_create 的实现原理是先通过调用 lv_task_create_basic 来创建最基本的任务,然后再通过其他的 API 接口来对其进行属性设置。 - 删除任务:
void lv_task_del(lv_task_t * task);
当我们不需要某任务时,需要通过此接口来删除任务,释放在堆上占用的资源。 - 设置任务回调函数:
void lv_task_set_cb(lv_task_t * task, lv_task_cb_t task_cb);
一般不常用,除非你的项目有动态修改回调函数的需求 - 使任务立即准备就绪:
void lv_task_ready(lv_task_t * task);
通过调用此 API 接口,我们可以使刚创建出来的任务立即处于就绪状态,然后在下一个lv_task_handler 调用时,使任务回调函数立即得到运行,而不用去等它的第一个运行周期,注意了这里说的是第一个周期不用等了,但是后面的周期还是要等的。 - 使任务回调函数只运行一次:
void lv_task_once(lv_task_t * task);
通过调用此 API 接口,我们可以让任务的回调函数只运行一次,而非周期性调用,在一次调用完成之后,littleVGL 内部会通过 lv_task_del 接口来自动删除此任务的。 - 复位任务 :
void lv_task_reset(lv_task_t * task);
举个例子来方便理解,假如任务 A 的回调周期是 1000ms,现在已经等待了 300ms,按理来说还需等待 700ms,任务 A 的回调函数才会被运行,但是如果此时使用 lv_task_reset 接口来复位任务 A 的话,那么之前等待的 300ms 会被作废,而是重新开始等待一个 1000ms 的完整周期。
四、示例代码
任务系统配置:
#include "task_test.h"
#include "lvgl.h"
#include "key.h"
#include "beep.h"
#include "usart.h"
#include "delay.h"
/*
*
* ┏┓ ┏┓
* ┏┛┻━━━┛┻┓
* ┃ ┃
* ┃ ━ ┃
* ┃ > < ┃
* ┃ ┃
* ┃... ⌒ ... ┃
* ┃ ┃
* ┗━┓ ┏━┛
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┃ 神兽保佑
* ┃ ┃ 代码无bug
* ┃ ┃
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
*/
typedef struct{
char name[20];
u8 age;
}USER_DATA;
lv_task_t *task1 = NULL;//任务句柄指针
USER_DATA user_data = { //user_data为用户自定义参数,数据结构一般为结构体
.name = {"xiong jia yu"},
.age = 25
}; //结构体初始化
//任务回调函数
void task1_cb(lv_task_t* task)
{
USER_DATA* dat = (USER_DATA*)(task->user_data);//获取用户的自定义参数
//打印tick时间(一个tick为1ms)和用户自定义参数
printf("task1_cb_tick:%d,name:%s,age:%d\r\n",lv_tick_get(),dat->name,dat->age);
//蜂鸣器鸣叫20ms进行提示
BEEP = 1;
delay_ms(30);
BEEP = 0;
}
//例程入口函数
void task_test_start()
{
//创建task1任务
task1 = lv_task_create(task1_cb,5000,LV_TASK_PRIO_MID,&user_data);
}
//按键处理
void key_handler()
{
u8 key = KEY_Scan(0);
if(task1==NULL)
return;
if(key==KEY0_PRES)
{
//使任务复位,如果你以固定的时间间隔不断的重复按下KEY0键(间隔时间要小于5000ms的回调周期),
//你会发现task1_cb回调函数再也得不到运行了,因为task1任务在被重复性的复位,
//每一次复位将会导致重新等待一个完整的回调周期
lv_task_reset(task1);
printf("task_reset_tick:%d\r\n",lv_tick_get());
}else if(key==KEY1_PRES)
{
//使任务立即准备就绪,当你按下KEY1键时,你会发现task1_cb回调函数会在下一个lv_task_handler调用时被立即运行,
//通过串口打印,你会发现task_ready_tick的值比task1_cb_tick的值只小几个数
lv_task_ready(task1);
printf("task_ready_tick:%d\r\n",lv_tick_get());
}else if(key==WKUP_PRES)//删除任务
{
//删除任务,当你按下KEY2键后,你会发现task1_cb回调函数将永远不会再被执行了
lv_task_del(task1);
task1 = NULL;
printf("task_del_tick:%d\r\n",lv_tick_get());
}
}
main.c:
/*
* @Author: your name
* @Date: 2020-09-08 20:28:51
* @LastEditTime: 2020-09-09 10:06:10
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \USER\main.c
*/
#include "led.h"
#include "delay.h"
#include "key.h"
#include "beep.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"
#include "24cxx.h"
#include "w25qxx.h"
#include "touch.h"
#include "timer.h"
#include "lvgl.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"
#include "task_test.h"
int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
BEEP_Init(); //蜂鸣器初始化
LCD_Init(); //LCD液晶初始化
KEY_Init(); //按键初始化
TIM3_Int_Init(999,71); //定时器初始化(1ms中断),用于给lvgl提供心跳节拍
tp_dev.init(); //触摸初始化
lv_init(); //lvgl系统初始化
lv_port_disp_init(); //lvgl显示接口初始化,放在lv_init()的后面
lv_port_indev_init(); //lvgl输入接口初始化,放在lv_init()的后面
task_test_start(); //运行例程
while(1)
{
tp_dev.scan(0);//触摸扫描
lv_task_handler();//lvgl的事务处理
key_handler();//按键处理
}
}