传感器页面、屏幕刷新任务学习
一、user_SensorPageTask 传感器页任务
/* Private includes -----------------------------------------------------------*/
//includes
#include "user_TasksInit.h"
#include "user_ScrRenewTask.h"
#include "user_SensorPageTask.h"
#include "ui_HRPage.h"
#include "ui_SPO2Page.h"
#include "ui_ENVPage.h"
#include "ui_CompassPage.h"
#include "main.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint32_t user_HR_timecount=0;
/* Private function prototypes -----------------------------------------------*/
extern uint8_t GET_BP_MAX (void);
extern uint8_t GET_BP_MIN (void);
extern void Blood_Process (void);
extern void Blood_50ms_process (void);
extern void Blood_500ms_process(void);
extern int em70xx_bpm_dynamic(int RECEIVED_BYTE, int g_sensor_x, int g_sensor_y, int g_sensor_z);
extern int em70xx_reset(int ref);
/**
* @brief HR data renew task
* @param argument: Not used
* @retval None
*/
void HRDataRenewTask(void *argument)
{
uint8_t value_strbuf[4];
uint8_t IdleBreakstr=0;
uint16_t dat=0;
uint8_t hr_temp=0;
while(1)
{
if(ScrRenewStack.Data[ScrRenewStack.Top_Point-1] == (long long int)&ui_HRPage)
{
osMessageQueuePut(IdleBreak_MessageQueue, &IdleBreakstr, 0, 1);
/*
//sensor wake up
EM7028_hrs_Enable();
//receive the sensor wakeup message, sensor wakeup
if(!Sensor_EM_Erro)
{
//Hr messure
vTaskSuspendAll();
hr_temp = HR_Calculate(EM7028_Get_HRS1(),user_HR_timecount);
xTaskResumeAll();
if(ui_HRValue != hr_temp && hr_temp>50 && hr_temp<120)
{
//set text
ui_HRValue = hr_temp;
sprintf(value_strbuf, "%d", ui_HRValue);
lv_label_set_text(ui_HRPageNumLabel, value_strbuf);
}
}
*/
}
osDelay(50);
}
}
/**
* @brief Sensor data renew task
* @param argument: Not used
* @retval None
*/
void SensorDataRenewTask(void *argument)
{
uint8_t value_strbuf[6];
uint8_t IdleBreakstr=0;
while(1)
{
if(ScrRenewStack.Data[ScrRenewStack.Top_Point-1] == (long long int)&ui_SPO2Page)
{
osMessageQueuePut(IdleBreak_MessageQueue, &IdleBreakstr, 0, 1);
//sensor wake up
}
else if(ScrRenewStack.Data[ScrRenewStack.Top_Point-1] == (long long int)&ui_CompassPage)
{
osMessageQueuePut(IdleBreak_MessageQueue, &IdleBreakstr, 0, 1);
}
osDelay(300);
}
}
这段 C 语言代码看起来是一个嵌入式项目中的一部分,涉及到心率(HR)数据更新任务、传感器数据更新任务等相关功能,通过消息队列与其他任务进行交互,并且根据屏幕页面的显示情况(通过ScrRenewStack
栈结构中的内容来判断)来决定是否执行相应的数据更新操作,大概率是用于在特定的用户界面页面显示对应的传感器实时数据
1.1 头文件包含部分
#include "user_TasksInit.h"
#include "user_ScrRenewTask.h"
#include "user_SensorPageTask.h"
#include "ui_HRPage.h"
#include "ui_SPO2Page.h"
#include "ui_ENVPage.h"
#include "ui_CompassPage.h"
#include "main.h"
user_TasksInit.h
:可能包含了任务初始化相关的函数声明、结构体等,用于初始化整个系统中的各种任务,确保各个任务能正常启动和运行。
user_ScrRenewTask.h
:推测与屏幕刷新相关任务有关,也许包含了屏幕更新操作的函数声明、涉及屏幕相关结构体(如代码中出现的ScrRenewStack
)的定义等内容,用于协调不同页面的更新逻辑。
user_SensorPageTask.h
:应该是和传感器页面相关任务的定义,可能包含了传感器数据获取、处理以及在对应页面显示相关的函数声明等,用于管理传感器数据在界面上的展示
ui_HRPage.h
、ui_SPO2Page.h
、ui_ENVPage.h
、ui_CompassPage.h
:这些头文件分别对应心率页面、血氧饱和度页面、环境页面、指南针页面等不同用户界面页面相关的定义,比如各页面上显示数据的变量声明(如ui_HRValue
)、页面元素(如标签等)的结构体定义以及相关显示操作函数的声明等,用于获取和更新不同页面上的各类信息
uint32_t user_HR_timecount=0;
定义了一个 uint32_t
类型的全局变量 user_HR_timecount
,初始值设为 0
。从函数中对它的使用情况(虽然目前在代码中使用场景有限)推测,它可能与心率数据的计算、计时相关,比如记录一段时间间隔用于心率的测量或者心率数据更新的时间周期等相关操作。
1.2 函数声明部分(外部函数声明)
extern uint8_t GET_BP_MAX (void);
extern uint8_t GET_BP_MIN (void);
extern void Blood_Process (void);
extern void Blood_50ms_process (void);
extern void Blood_500ms_process(void);
extern int em70xx_bpm_dynamic(int RECEIVED_BYTE, int g_sensor_x, int g_sensor_y, int g_sensor_z);
extern int em70xx_reset(int ref);
GET_BP_MAX
和 GET_BP_MIN
:从函数名推测,可能是用于获取血压的最大值和最小值,返回值类型为 uint8_t
,不过具体的获取逻辑和数据来源需要查看其定义所在的源文件。Blood_Process
、Blood_50ms_process
、Blood_500ms_process
:这些函数大概率与血液相关的数据处理有关,也许是按照不同的时间间隔(如 50ms
、500ms
)进行特定的血液数据处理操作,具体处理内容要参考函数定义。em70xx_bpm_dynamic
:可能是基于 em70xx
相关传感器来动态计算每分钟心跳次数(BPM)的函数,接受多个传感器相关的参数(如接收到的字节数据以及不同轴向的传感器数据等),返回一个 int
类型的结果,表示计算得到的心率相关数值。em70xx_reset
:应该是用于对 em70xx
相关设备或模块进行复位操作的函数,接受一个 int
类型的参数 ref
(具体含义需查看函数定义)来确定复位的相关设置等情况。
1.3 HRDataRenewTask
函数:心率刷新任务
void HRDataRenewTask(void *argument)
{
uint8_t value_strbuf[4];
uint8_t IdleBreakstr=0;
uint16_t dat=0;
uint8_t hr_temp=0;
while (1)
{
if (ScrRenewStack.Data[ScrRenewStack.Top_Point-1] == (long long int)&ui_HRPage)
{
osMessageQueuePut(IdleBreak_MessageQueue, &IdleBreakstr, 0, 1);
/*
//sensor wake up
EM7028_hrs_Enable();
//receive the sensor wakeup message, sensor wakeup
if (!Sensor_EM_Erro)
{
//Hr messure
vTaskSuspendAll();
hr_temp = HR_Calculate(EM7028_Get_HRS1(),user_HR_timecount);
xTaskResumeAll();
if (ui_HRValue!= hr_temp && hr_temp>50 && hr_temp<120)
{
//set text
ui_HRValue = hr_temp;
sprintf(value_strbuf, "%d", ui_HRValue);
lv_label_set_text(ui_HRPageNumLabel, value_strbuf);
}
}
*/
}
osDelay(50);
}
}
定义了多个局部变量,包括 uint8_t
类型的数组 value_strbuf
(用于存储要显示的心率数值的字符串形式,长度为 4,可根据实际需要调整大小)、IdleBreakstr
(可能用于向消息队列发送与空闲状态打破相关的消息,初始值设为 0
),uint16_t
类型的 dat
(目前在现有代码中未使用,可能后续用于存储其他相关数据)以及 uint8_t
类型的 hr_temp
(用于临时存储计算得到的心率数值)
函数主体是一个无限循环 while(1)
,意味着这个任务会持续运行,不断地检测是否满足心率数据更新的条件并做相应处理
if(ScrRenewStack.Data[ScrRenewStack.Top_Point-1] == (long long int)&ui_HRPage)
{
osMessageQueuePut(IdleBreak_MessageQueue, &IdleBreakstr, 0, 1);
/*
//sensor wake up
EM7028_hrs_Enable();
//receive the sensor wakeup message, sensor wakeup
if(!Sensor_EM_Erro)
{
//Hr messure
vTaskSuspendAll();
hr_temp = HR_Calculate(EM7028_Get_HRS1(),user_HR_timecount);
xTaskResumeAll();
if(ui_HRValue != hr_temp && hr_temp>50 && hr_temp<120)
{
//set text
ui_HRValue = hr_temp;
sprintf(value_strbuf, "%d", ui_HRValue);
lv_label_set_text(ui_HRPageNumLabel, value_strbuf);
}
}
*/
}
页面判断及消息队列操作逻辑(if
分支):
通过判断 ScrRenewStack.Data[ScrRenewStack.Top_Point-1]
是否等于 (long long int)&ui_HRPage
来确定当前显示的页面是否是心率页面(ui_HRPage
)。如果是,就通过 osMessageQueuePut
函数向 IdleBreak_MessageQueue
消息队列发送 IdleBreakstr
消息,这可能是用于通知其他相关任务当前页面切换或者操作导致空闲状态被打破,以便进行相应的处理(比如恢复屏幕亮度等操作,具体取决于接收处理该消息队列的其他任务逻辑)。
lv_obj_t * ui_HRPage;
在UI界面定义的一个指针,屏幕刷新栈里存的是这种地址。且这个指针应该是整个页面的父节点。
应该每个运行的ui都会入栈吧,暂时没看到ui入栈的逻辑,坑先填下
代码中有一段被注释掉的逻辑,原本是用于传感器唤醒以及心率测量和显示更新的相关操作。
先是调用 EM7028_hrs_Enable()
函数来唤醒传感器(这里的 EM7028
应该是某种心率传感器相关的模块,从函数名推测),然后在没有传感器错误(!Sensor_EM_Erro
)的情况下,通过暂停所有任务(vTaskSuspendAll()
),相当于调度锁吧 调用 HR_Calculate
函数(结合 EM7028_Get_HRS1()
函数获取的传感器数据以及 user_HR_timecount
变量,推测是用于计算心率数值)计算得到心率临时值 hr_temp
,接着恢复所有任务(xTaskResumeAll()
)。最后,在满足一定条件(ui_HRValue
与 hr_temp
不相等且 hr_temp
在合理的心率范围 50
到 120
之间)时,更新界面上显示的心率值(将 ui_HRValue
赋值为 hr_temp
),并通过 sprintf
函数将数值转换为字符串存储到 value_strbuf
中,再使用 lv_label_set_text
函数(应该是基于某种图形库,如 LVGL,用于设置页面上标签显示文本的函数)将新的心率数值显示到对应的页面标签(ui_HRPageNumLabel
)上。
如果当前页面ui与屏幕刷新栈中存放的第一个ui地址一致,就代表着要进行心率测量的工作。
先终止空闲任务,启动心率传感器,如果成功启用,挂起所有任务不允许调度,测量一次数据 然后解挂 数据正常的话就保留并更新对应的ui标签。阻塞时间设置为50ms
二、user_ScrRenewTask 屏幕刷新任务
/* Private includes -----------------------------------------------------------*/
//includes
#include "user_TasksInit.h"
#include "user_ScrRenewTask.h"
#include "main.h"
#include "lvgl.h"
#include "ui_HomePage.h"
#include "ui_MenuPage.h"
#include "ui_GameSelectPage.h"
#include "ui_SetPage.h"
#include "ui_OffTimePage.h"
#include "ui_DateTimeSetPage.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
extern osMessageQueueId_t Key_MessageQueue;
user_Stack_T ScrRenewStack;
/* Private function prototypes -----------------------------------------------*/
/**
* @brief Screen renew task
* @param argument: Not used
* @retval None
*/
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)
{
//key1 pressed
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);
//HR sensor sleep
//EM7028_hrs_DisEnable();
//sensor sleep
//LSM303DLH_Sleep();
//SPL_Sleep();
}
else if(ScrRenewStack.Data[ScrRenewStack.Top_Point-1] == (long long int)&ui_GameSelectPage)
{
ui_GameSelectPage_screen_init();
lv_scr_load_anim(ui_GameSelectPage,LV_SCR_LOAD_ANIM_MOVE_RIGHT,0,0,true);
}
else if(ScrRenewStack.Data[ScrRenewStack.Top_Point-1] == (long long int)&ui_SetPage)
{
ui_SetPage_screen_init();
lv_scr_load_anim(ui_SetPage,LV_SCR_LOAD_ANIM_MOVE_RIGHT,0,0,true);
}
else if(ScrRenewStack.Data[ScrRenewStack.Top_Point-1] == (long long int)&ui_DateTimeSetPage)
{
ui_DateTimeSetPage_screen_init();
lv_scr_load_anim(ui_DateTimeSetPage,LV_SCR_LOAD_ANIM_MOVE_RIGHT,0,0,true);
}
}
//key2 pressed
else if(keystr == 2)
{
user_Stack_Clear(&ScrRenewStack);
ui_HomePage_screen_init();
lv_scr_load_anim(ui_HomePage,LV_SCR_LOAD_ANIM_MOVE_RIGHT,0,0,true);
user_Stack_Push(&ScrRenewStack,(long long int)&ui_HomePage);
//HR sensor sleep
//EM7028_hrs_DisEnable();
//sensor sleep
//LSM303DLH_Sleep();
//SPL_Sleep();
}
}
osDelay(10);
}
}
这段 C 语言代码定义了一个名为 ScrRenewTask
的函数,看起来是在一个基于操作系统(从 osMessageQueueGet
等函数推测)且使用了 LVGL 图形库的嵌入式项目环境中运行的任务函数,其主要功能是根据接收到的按键消息来更新屏幕显示内容,通过操作一个自定义的栈结构 ScrRenewStack
来管理屏幕页面的切换逻辑,并调用相应页面的初始化函数以及利用 LVGL 提供的动画加载函数实现页面切换动画效果,同时还涉及到一些传感器进入睡眠状态的相关操作
2.1 头文件包含部分(Private includes)
#include "user_TasksInit.h"
#include "user_ScrRenewTask.h"
#include "main.h"
#include "lvgl.h"
#include "ui_HomePage.h"
#include "ui_MenuPage.h"
#include "ui_GameSelectPage.h"
#include "ui_SetPage.h"
#include "ui_OffTimePage.h"
#include "ui_DateTimeSetPage.h"
user_TasksInit.h
:可能包含了任务初始化相关的函数声明、结构体等,用于初始化整个系统中的各种任务,确保各个任务能正常启动和运行。
user_ScrRenewTask.h
:推测包含了与屏幕更新任务相关的其他函数声明、结构体定义或者宏定义等内容,也许和 ScrRenewTask
函数协同工作或者提供一些额外的支持功能,比如对 ScrRenewStack
栈结构的相关操作函数声明(虽然部分函数如 user_Stack_Push
等在代码前面已经出现过定义,但也可能在这里有更完整的声明集合)。
实际上头文件里只有相关函数的声明
lvgl.h
:这是轻量级图形库(LVGL)的头文件,包含了 LVGL 中各种图形界面元素、操作函数(如 lv_scr_load_anim
用于加载屏幕并设置动画效果等)的声明,用于实现屏幕显示和交互相关的功能,创建丰富的用户界面
ui_HomePage.h
、ui_MenuPage.h
、ui_GameSelectPage.h
、ui_SetPage.h
、ui_OffTimePage.h
、ui_DateTimeSetPage.h
:这些头文件分别对应着不同的用户界面页面(首页、菜单页、游戏选择页、设置页、关机时间设置页、日期时间设置页等)相关的定义,比如各页面的结构体定义、页面初始化函数(如 ui_HomePage_screen_init
等)的声明以及页面上各元素相关的定义等,用于在切换到对应页面时进行正确的初始化和显示操作
页面刷新 顾名思义就是对不同的ui进行切换的操作。
2.2 变量定义
extern osMessageQueueId_t Key_MessageQueue;
user_Stack_T ScrRenewStack;
消息队列标识符变量声明(外部声明):osMessageQueueId_t Key_MessageQueue;
通过 extern
关键字声明这是一个在其他源文件中定义的消息队列标识符变量,用于接收按键相关的消息,在本函数中会通过 osMessageQueueGet
函数从这个队列中获取按键消息来决定屏幕更新的操作。
主要是应对按键消息
屏幕更新栈结构变量定义
user_Stack_T ScrRenewStack;
定义了一个 user_Stack_T
类型的栈结构变量,从函数后续的操作来看,这个栈用于存储当前显示页面或者即将显示页面的相关指针(通过强制转换为 long long int
类型后入栈,这里的做法有点不太常规,更合适的可能是使用指针类型来直接操作,但也许是基于整体项目的特定设计),以帮助管理屏幕页面的切换顺序和状态
2.3 ScrRenewTask 刷新屏幕任务
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)
{
//key1 pressed
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);
//HR sensor sleep
//EM7028_hrs_DisEnable();
//sensor sleep
//LSM303DLH_Sleep();
//SPL_Sleep();
}
else if (ScrRenewStack.Data[ScrRenewStack.Top_Point - 1] == (long long int)&ui_GameSelectPage)
{
ui_GameSelectPage_screen_init();
lv_scr_load_anim(ui_GameSelectPage, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 0, 0, true);
}
else if (ScrRenewStack.Data[ScrRenewStack.Top_Point - 1] == (long long int)&ui_SetPage)
{
ui_SetPage_screen_init();
lv_scr_load_anim(ui_SetPage, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 0, 0, true);
}
else if (ScrRenewStack.Data[ScrRenewStack.Top_Point - 1] == (long long int)&ui_DateTimeSetPage)
{
ui_DateTimeSetPage_screen_init();
lv_scr_load_anim(ui_DateTimeSetPage, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 0, 0, true);
}
}
//key2 pressed
else if (keystr == 2)
{
user_Stack_Clear(&ScrRenewStack);
ui_HomePage_screen_init();
lv_scr_load_anim(ui_HomePage, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 0, 0, true);
user_Stack_Push(&ScrRenewStack, (long long int)&ui_HomePage);
//HR sensor sleep
//EM7028_hrs_DisEnable();
//sensor sleep
//LSM303DLH_Sleep();
//SPL_Sleep();
}
}
osDelay(10);
}
}
定义了一个 uint8_t
类型的局部变量 keystr
,初始值设为 0
,用于接收从 Key_MessageQueue
消息队列中获取的按键消息内容,通过判断其值来确定是哪个按键被按下,进而执行相应的屏幕更新操作。
uint8_t keystr = 0;
user_Stack_Push(&ScrRenewStack, (long long int)&ui_HomePage);
初始化屏幕栈操作:
在进入主循环之前,先通过 user_Stack_Push(&ScrRenewStack, (long long int)&ui_HomePage);
将首页(ui_HomePage
)的地址(通过强制转换为 long long int
类型)压入 ScrRenewStack
栈中,这可能是用于初始化屏幕显示的初始状态,表示默认先显示首页内容,为后续的页面切换操作建立起始点。
if (osMessageQueueGet(Key_MessageQueue, &keystr, NULL, 0) == osOK)
按键消息获取及判断逻辑(if
分支):
通过 osMessageQueueGet(Key_MessageQueue, &keystr, NULL, 0)
函数从 Key_MessageQueue
消息队列中获取按键消息,并判断返回值是否为 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);
//HR sensor sleep
//EM7028_hrs_DisEnable();
//sensor sleep
//LSM303DLH_Sleep();
//SPL_Sleep();
}
else if (ScrRenewStack.Data[ScrRenewStack.Top_Point - 1] == (long long int)&ui_GameSelectPage)
{
ui_GameSelectPage_screen_init();
lv_scr_load_anim(ui_GameSelectPage, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 0, 0, true);
}
else if (ScrRenewStack.Data[ScrRenewStack.Top_Point - 1] == (long long int)&ui_SetPage)
{
ui_SetPage_screen_init();
lv_scr_load_anim(ui_SetPage, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 0, 0, true);
}
else if (ScrRenewStack.Data[ScrRenewStack.Top_Point - 1] == (long long int)&ui_DateTimeSetPage)
{
ui_DateTimeSetPage_screen_init();
lv_scr_load_anim(ui_DateTimeSetPage, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 0, 0, true);
}
}
按键 1 按下的处理逻辑(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);
}
首先调用 user_Stack_Pop(&ScrRenewStack);
函数将栈顶元素弹出,这可能是表示要返回上一个页面或者进行页面切换的前置操作,通过调整栈的状态来反映页面的切换情况。
接着通过 user_Stack_isEmpty(&ScrRenewStack)
判断栈是否为空,如果栈为空,意味着当前没有页面记录在栈中(可能是经过一系列页面切换操作后回到了最初的状态或者出现了异常情况),此时执行以下操作:
调用 ui_MenuPage_screen_init();
函数初始化菜单页(ui_MenuPage
),这个函数应该是在 ui_MenuPage.h
头文件中声明的,用于对菜单页进行各种元素初始化、资源加载等操作,使其准备好显示。然后使用 lv_scr_load_anim(ui_MenuPage, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 0, 0, true);
函数通过 LVGL 图形库加载菜单页,并设置页面切换动画效果为向右移动(LV_SCR_LOAD_ANIM_MOVE_RIGHT
),后面的参数 0, 0, true
可能分别对应动画的一些其他配置参数(比如动画持续时间、延迟时间等,具体需参考 LVGL 文档),实现从当前页面切换到菜单页时带有动画的显示效果。
最后通过 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);
//HR sensor sleep
//EM7028_hrs_DisEnable();
//sensor sleep
//LSM303DLH_Sleep();
//SPL_Sleep();
}
else if (ScrRenewStack.Data[ScrRenewStack.Top_Point - 1] == (long long int)&ui_GameSelectPage)
{
ui_GameSelectPage_screen_init();
lv_scr_load_anim(ui_GameSelectPage, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 0, 0, true);
}
else if (ScrRenewStack.Data[ScrRenewStack.Top_Point - 1] == (long long int)&ui_SetPage)
{
ui_SetPage_screen_init();
lv_scr_load_anim(ui_SetPage, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 0, 0, true);
}
else if (ScrRenewStack.Data[ScrRenewStack.Top_Point - 1] == (long long int)&ui_DateTimeSetPage)
{
ui_DateTimeSetPage_screen_init();
lv_scr_load_anim(ui_DateTimeSetPage, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 0, 0, true);
}
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);
}
如果栈不为空,会进一步通过 if - else if
分支根据栈顶元素(通过 ScrRenewStack.Data[ScrRenewStack.Top_Point - 1]
获取,这里同样存在前面提到的栈操作边界检查等潜在问题)所指向的页面进行不同的处理:
当栈顶元素指向首页(ui_HomePage
)时,调用 ui_HomePage_screen_init();
函数初始化首页并通过 lv_scr_load_anim(ui_HomePage, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 0, 0, true);
加载首页并设置动画效果,实现重新显示首页的操作,可能用于返回首页或者刷新首页显示等情况。
也就是如果当前页面的上一个页面是主页面 按键按下后会加载主页面。因为按键按下后会首先弹出当前页面地址
再讲一下逻辑,它的入栈是先填后入栈,它的索引永远都会跟多移动一位,指向栈内第一个空闲的位置。而出栈呢,是先自减再将元素弹出。刚好出第一个的时候,索引的地址就为第一个元素的起始地址。再减一用于查询的话刚好就对应次高位的地址。就是查询在栈中当前界面的前一个界面是什么
当栈顶元素指向菜单页(ui_MenuPage
)时,调用 ui_MenuPage_screen_init();
函数初始化菜单页,并通过 lv_scr_load_anim(ui_MenuPage, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 0, 0, true);
加载菜单页并设置动画效果,同时还注释掉了一些传感器进入睡眠状态的操作代码(如 EM7028_hrs_DisEnable();
等,这些函数应该是用于关闭对应的传感器以节省电量等,具体要根据传感器的实际功能和项目需求来看),这可能表示在切换到菜单页时,除了更新页面显示,还可以进行一些相关硬件设备的节能操作(如果取消注释启用这些代码的话)
类似地,当栈顶元素分别指向游戏选择页(ui_GameSelectPage
)、设置页(ui_SetPage
)、日期时间设置页(ui_DateTimeSetPage
)时,都会分别调用对应的页面初始化函数以及使用 lv_scr_load_anim
函数加载页面并设置动画效果,实现切换到相应页面的操作。
这个ui栈也是有深度的,最高也就5层,主界面 为底层 往上最多跌4层。
如果按下的是按键2呢,我的开发板没有按键2,应该是手表上的
else if (keystr == 2)
{
user_Stack_Clear(&ScrRenewStack);
ui_HomePage_screen_init();
lv_scr_load_anim(ui_HomePage, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 0, 0, true);
user_Stack_Push(&ScrRenewStack, (long long int)&ui_HomePage);
//HR sensor sleep
//EM7028_hrs_DisEnable();
//sensor sleep
//LSM303DLH_Sleep();
//SPL_Sleep();
}
当按键 2 被按下时,首先调用 user_Stack_Clear(&ScrRenewStack);
函数清空 ScrRenewStack
栈,这意味着清除所有页面切换的历史记录,将页面状态重置到初始状态。然后调用 ui_HomePage_screen_init();
函数初始化首页,并通过 lv_scr_load_anim(ui_HomePage, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 0, 0, true);
加载首页并设置动画效果,实现回到首页的操作,同样也注释掉了一些传感器进入睡眠状态的相关代码,其作用和按键 1 按下时对应部分类似,可用于在特定操作后进行硬件设备的节能管理。最后通过 user_Stack_Push(&ScrRenewStack, (long long int)&ui_HomePage);
将首页地址重新压入栈中,更新栈的状态以反映当前显示的页面情况。
相当于手机上的home键,按键1就相当于返回键。不过存在主页向菜单界面的返回过程。
有些功能传感器只让他在对应的界面开启,省电。
原文地址:https://blog.csdn.net/NEWEVA__zzera22/article/details/143830942
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!