传感器页面、屏幕刷新任务学习

一、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 upEM7028_hrs_Enable();//receive the sensor wakeup message, sensor wakeupif(!Sensor_EM_Erro){//Hr messurevTaskSuspendAll();hr_temp = HR_Calculate(EM7028_Get_HRS1(),user_HR_timecount);xTaskResumeAll();if(ui_HRValue != hr_temp && hr_temp>50 && hr_temp<120){//set textui_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.hui_SPO2Page.hui_ENVPage.hui_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_ProcessBlood_50ms_processBlood_500ms_process:这些函数大概率与血液相关的数据处理有关,也许是按照不同的时间间隔(如 50ms500ms)进行特定的血液数据处理操作,具体处理内容要参考函数定义。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 upEM7028_hrs_Enable();//receive the sensor wakeup message, sensor wakeupif (!Sensor_EM_Erro){//Hr messurevTaskSuspendAll();hr_temp = HR_Calculate(EM7028_Get_HRS1(),user_HR_timecount);xTaskResumeAll();if (ui_HRValue!= hr_temp && hr_temp>50 && hr_temp<120){//set textui_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 upEM7028_hrs_Enable();//receive the sensor wakeup message, sensor wakeupif(!Sensor_EM_Erro){//Hr messurevTaskSuspendAll();hr_temp = HR_Calculate(EM7028_Get_HRS1(),user_HR_timecount);xTaskResumeAll();if(ui_HRValue != hr_temp && hr_temp>50 && hr_temp<120){//set textui_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 pressedif(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 pressedelse 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.hui_MenuPage.hui_GameSelectPage.hui_SetPage.hui_OffTimePage.hui_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 pressedif (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 pressedelse 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就相当于返回键。不过存在主页向菜单界面的返回过程。

有些功能传感器只让他在对应的界面开启,省电。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/18630.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

BigQuery中jobUser和dataViewer的角色有什么不同

真题实战 Scenario: Your company utilizes BigQuery as the enterprise data warehouse, with data spread across multiple Google Cloud projects. Queries on BigQuery must be billed to a specific project, separate from where the data resides. Users should have q…

AWTK-WIDGET-WEB-VIEW 实现笔记 (3) - MacOS

MacOS 上实现 AWTK-WIDGET-WEB-VIEW 有点麻烦&#xff0c;主要原因是没有一个简单的办法将一个 WebView 嵌入到一个窗口中。所以&#xff0c;我们只能通过创建一个独立的窗口来实现。 1. 创建窗口 我对 Object-C 不熟悉&#xff0c;也不熟悉 Cocoa 框架&#xff0c;在 ChatGPT…

fiddler抓包24_App流量统计

​课程大纲 使用Fiddler可以实现“APP流量统计”功能。具体操作如下&#xff1a; ① 选中app所有请求&#xff0c;点击右侧菜单标签“Statistics”。 ② 查看请求统计数据&#xff0c;即APP流量统计&#xff1a;“Bytes Sent”&#xff08;发送的字节数&#xff09;、“Bytes R…

小白投资理财 - 解读 CCI

小白投资理财 - 解读 CCI 什么是 CCICCI 计算方法CCI 指标的使用首先超买和超卖接下来是背离 CCI 缺点总结 顺着河流能够渡河&#xff0c;逆向河流只会挂彩&#xff0c;今天就来了解一下 CCI&#xff08;Commodity Channel lndex&#xff09;中文称之为顺势指标 什么是 CCI 它…

2024 RISC-V中国峰会 安全相关议题汇总

安全之安全(security)博客目录导读 第四届 RISC-V 中国峰会&#xff08;RISC-V Summit China 2024&#xff09;于8月21日至23日在杭州成功举办。此次峰会汇聚了 RISC-V 国际基金会、百余家重点企业及研究机构&#xff0c;约3000人线下参与&#xff0c;并在19日至25日间举办了超…

Linux守护Pythom脚本运行——Supervisor学习总结

Supervisor能做什么&#xff1f; 在工作中有时会遇到在Linux服务器上编写各种脚本来实现日志的推送、数据的传输、流量的监控等&#xff0c;这些脚本在整个系统运行中也需要和其他服务端应用程序一样持续且稳定运行&#xff0c;为了达到这种目的就需要使用进程守护工具来对正在…

机器学习基础05_随机森林线性回归

一、随机森林 机器学习中有一种大类叫集成学习&#xff08;Ensemble Learning&#xff09;&#xff0c;集成学习的基本思想就是将多个分类器组合&#xff0c;从而实现一个预测效果更好的集成分类器。集成算法大致可以分为&#xff1a;Bagging&#xff0c;Boosting 和 Stacking…

leetcode-44-通配符匹配

题解&#xff1a; 代码&#xff1a; 参考&#xff1a; (1)牛客华为机试HJ71字符串通配符 (2)leetcode-10-正则表达式匹配

C++类和对象介绍

目录 一、类的创建 二、访问权限 三、struct与class 四、类域 五、类的大小 一、类的创建 C中【class】为定义类的关键字&#xff0c;【{}】中为类的主体&#xff0c;注意类定义结束时后⾯分号不能省略。一般来说&#xff0c;类规范由两部分组成&#xff1a; 类的声明&…

【自学笔记】推荐系统

文章目录 引入一些记号原理 协同过滤算法使用均值归一化 基于内容的推荐原理基于TensorFlow的代码 从大目录里推荐检索排名 引入 一些记号 记号含义其他 n n n总人数 m m m总样本数 k k k特征数 y i ( j ) y_{i}^{(j)} yi(j)​第 j j j个人对第 i i i个样本的评分 y i , j ∈ …

vue基础

1. vue是什么&#xff1f; Vue.js &#xff08;读音 /vju ː /, 类似于 view &#xff09; 是一套构建用户界面的渐进式框架。 Vue 只关注视图层&#xff0c; 采用自底向上增量开发的设计。 Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。 官…

简单学点位运算(Java)

1. 位运算符 Java中常用的位运算符如下&#xff1a; 2. 详解 &#xff08;1&#xff09;按位与 & 规则&#xff1a;同一位上全是 1 时&#xff0c;结果为 1&#xff0c;否则为 0。用途&#xff1a; 清零某些位&#xff1a;x & 0xF0可以保留高 4 位&#xff0c;清除…

637. 二叉树的层平均值【 力扣(LeetCode) 】

文章目录 零、原题链接一、题目描述二、测试用例三、解题思路四、参考代码 零、原题链接 637. 二叉树的层平均值 一、题目描述 给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。 二、测试用例 示例 1&a…

111页PPT丨服装零售行业数字化时代的业务与IT转型规划

安踏的数字化转型项目在方法论、计划和组织方面展现出了明确的目标、系统的规划和有效的执行。以下是对这三个方面的详细分析&#xff1a; 方法论 安踏的数字化转型方法论主要围绕以下几个核心点展开&#xff1a; 服务于整体战略&#xff1a;数字化转型不是孤立的项目&#…

人工智能技术的应用前景与我们的应对策略

​ 大家好&#xff0c;我是程序员小羊&#xff01; 随着人工智能&#xff08;AI&#xff09;技术的快速发展&#xff0c;其在社会生活、产业转型以及科技进步中发挥着日益重要的作用。AI正逐步改变着我们的生活和工作方式&#xff0c;同时也带来了技术和伦理上的诸多挑战。本文…

基于Java Springboot论坛系统

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据…

Vue2教程001:初识Vue

文章目录 1、初识Vue1.1、Vue2前言1.2、创建Vue实例1.3、插值表达式1.4 Vue响应式特性 1、初识Vue 1.1、Vue2前言 Vue是什么&#xff1f; 概念&#xff1a;Vue是一个用于构建用户界面的渐进式框架。 Vue的两种使用方式&#xff1a; Vue核心包开发 场景&#xff1a;局部模块…

113页PPT制造业研发工艺协同及制造一体化

研发工艺协同及制造一体化解决方案是制造业数字化转型的重要组成部分&#xff0c;它涵盖了从产品设计到生产的全过程&#xff0c;旨在提高生产效率、降低成本、提升产品质量&#xff0c;并增强企业的市场竞争力。以下是对该解决方案的详细阐述&#xff1a; 一、方案概述 研发…

红外遥控信号解码

红外遥控信号解码 之前就已经做过红外遥控的解码了&#xff0c;但是一直没有做记录&#xff0c;最近的项目又使用到了红外遥控&#xff0c;索性就把他捡起来记录一下&#xff0c;对于信号的解码&#xff0c;我一般的习惯都是先用逻辑分析仪抓取一下信号波形&#xff0c;然后对…

Spring:纯注解开发模式-Ioc对bean的管理

我们知道&#xff08;请见 注解开发定义bean&#xff09;&#xff0c;可以使用注解来配置bean,但是依然有用到配置文件&#xff0c;在配置文件中对包进行了扫描&#xff0c;Spring在3.0版已经支持纯注解开发 Spring3.0开启了纯注解开发模式&#xff0c;使用Java类替代配置文件…