系列文章目录
前言
用过手环或者手表的朋友,手表页面切换主要有两种方式。第一种是利用触摸屏进行页面的切换,第二种是利用物理按键例如手表侧面的按钮。然后就会涉及到如何进行页面的管理,从一个页面如何切换到另外页面,如果我想要返回,返回到哪个页面。本文介绍如何利用栈的方式进行LVGL页面的管理以及利用FreeRTOS进行页面管理。
实验现象一:利用STM32F7开发板上面的物理按键实现从手表主页面切换到菜单页面,再次按下切换到主页面
实验现象二:利用触摸屏进行页面切换。FreeRTOS进行任务管理
一、如何利用按键进行页面切换
1、利用一个进程要不断的扫描按键检测按键是否按下。并且利用一个长度为1的队列进行保存按键值。需要注意的是KeyTask的任务阻塞时间要设置小一下,因为按键检测时间间隔较短
。
//Key task
osThreadId_t KeyTaskHandle;
const osThreadAttr_t KeyTask_attributes = {
.name = "KeyTask",
.stack_size = 128 * 8,
.priority = (osPriority_t) osPriorityNormal,
};
KeyTaskHandle = osThreadNew(KeyTask, NULL, &KeyTask_attributes);
Key_MessageQueue = osMessageQueueNew(1, 1, NULL);
void KeyTask(void *argument)
{
uint8_t keystr=0;
while(1)
{
switch(KeyScan())
{
case 0:
//printf("keyvalue=0\r\n");
break;
case 1:
keystr = 1;
osMessageQueuePut(Key_MessageQueue, &keystr, 0, 1);
break;
}
osDelay(1);
}
}
2、另外一个进程进行切面的切换。
读取队列的值。在裸机系统中,两个程序间需要共享某个资源通常使用全局变量来实现;但在含操作系统(下文就拿FreeRTOS举例)的开发中,则使用消息队列
完成。在FreeRTOS系统中,引入了消息队列来实现某个资源共享,其不仅仅实现临界资源共享,也给临界资源提供保护,使得程序更加稳定。
//ScrRenew task
osThreadId_t ScrRenewTaskHandle;
const osThreadAttr_t ScrRenewTask_attributes = {
.name = "ScrRenewTask",
.stack_size = 128 * 8,
.priority = (osPriority_t) osPriorityLow1,
};
ScrRenewTaskHandle = osThreadNew(ScrRenewTask, NULL, &ScrRenewTask_attributes);
通过读取队列的值,检测如果按键按下则将当前的页面出栈,加载菜单页面然后将主页面和菜单页面id进行进栈。
void ScrRenewTask(void *argument)
{
uint8_t keystr=0;
user_Stack_Push(&ScrRenewStack,(long long int)&ui_HomePage);
while(1)
{
if(osMessageQueueGet(Key_MessageQueue,&keystr,NULL,0)==osOK)
{
if(keystr == 1)
{
//
user_Stack_Pop(&ScrRenewStack);
//
if(user_Stack_isEmpty(&ScrRenewStack))
{
ui_MenuPage_screen_init();
lv_scr_load_anim(ui_MenuPage,LV_SCR_LOAD_ANIM_MOVE_RIGHT,0,0,true);
user_Stack_Push(&ScrRenewStack,(long long int)&ui_HomePage);
user_Stack_Push(&ScrRenewStack,(long long int)&ui_MenuPage);
}
else if(ScrRenewStack.Data[ScrRenewStack.Top_Point-1] == (long long int)&ui_HomePage)
{
ui_HomePage_screen_init();
lv_scr_load_anim(ui_HomePage,LV_SCR_LOAD_ANIM_MOVE_RIGHT,0,0,true);
}
else if(ScrRenewStack.Data[ScrRenewStack.Top_Point-1] == (long long int)&ui_MenuPage)
{
ui_MenuPage_screen_init();
lv_scr_load_anim(ui_MenuPage,LV_SCR_LOAD_ANIM_MOVE_RIGHT,0,0,true);
}
}
osDelay(10);
}
}
进栈、出栈、判断栈是否为空,清空栈,用于保存LVGL页面对象的ID
#include "PageStack.h"
uint8_t user_Stack_Push(user_Stack_T* stack, StackData_t datain)
{
if(stack->Top_Point == MAX_DEPTH - 1)
{return -1;}
stack->Data[stack->Top_Point++] = datain;
return 0;
}
uint8_t user_Stack_Pop(user_Stack_T* stack)
{
if(stack->Top_Point == 0)
{return -1;}
stack->Data[--stack->Top_Point] = NULL;
return 0;
}
uint8_t user_Stack_isEmpty(user_Stack_T* stack)
{
if(stack->Top_Point == 0)
{return 1;}
return 0;
}
void user_Stack_Clear(user_Stack_T* stack)
{
while(!user_Stack_isEmpty(stack))
{
user_Stack_Pop(stack);
}
}
二、FreeRTOS进行任务管理
举例说明,两个手表表盘通过两个进程进行管理。
SeaTimeTaskHandle = osThreadNew(SeaTimeTask, NULL, &SeaTimeTask_attributes);
CirWatchTaskHandle = osThreadNew(CirWatchTask, NULL, &CirWatchTask_attributes);
两个进程不断的进行扫描栈顶元素,如果栈顶元素是SeaTimeTask页面,则进行数据的更新。
void SeaTimeTask(void)
{
while(1)
{
if(ScrRenewStack.Data[ScrRenewStack.Top_Point-1] == (long long int)&ui_Screen1)
{
// vTaskSuspendAll();
/* Get the RTC current Time */
HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);
/* Get the RTC current Date */
HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN);
lv_img_set_angle(ui_Sea_secImage5, GetTime.Seconds * 60);//s秒表
lv_img_set_angle(ui_Sea_minImage4, GetTime.Minutes * 60);//m分钟
lv_img_set_angle(ui_Sea_hourImage3, GetTime.Hours * 300);//h时
// xTaskResumeAll();
}
osDelay(50);
}
}
void CirWatchTask(void)
{
uint8_t timeStr[10];
uint8_t dataStr[10];
while(1)
{
if(ScrRenewStack.Data[ScrRenewStack.Top_Point-1] == (long long int)&ui_Screen2)
{
/* Get the RTC current Time */
HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);
/* Get the RTC current Date */
HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN);
//
sprintf(timeStr, "%02d:%02d:%02d", GetTime.Hours, GetTime.Minutes, GetTime.Seconds);
lv_label_set_text(ui_Label1,timeStr);
sprintf(dataStr, "%02d/%02d", GetData.Month, GetData.Date);
lv_label_set_text(ui_Label7,dataStr);
}
osDelay(50);
}
}