W801学习笔记十五:掌机系统——状态栏

有些朋友可能已经注意到了,前面的代码中所用到的"show_status_info"方法找不到。在这一章中,我们对此进行补充说明。

在用户界面(UI)中,有一些元素是悬浮在页面场景(SCEAN)之上的,比如说状态栏,还有通知栏等。

在这里,我们编写一个主屏幕(MAINSCREEN),它主要用于显示操作提示、时间、网络连接状态等信息。

MainScreen.h

cpp 复制代码
typedef struct StatusUpdateTask{
	u8 type;			
	u8 data1;			
	u8 data2;				
	u8 data3;	
} StatusUpdateTask;



void init_screen();
void show_status_info(const char *format, ...);
void clear_screen();

void handleMainScreanTask();

实现:

1、添加一个定时器,监控网络状态并更新时间

cpp 复制代码
void timer_int_irq(u8 *arg)
{
	int netS =  isNetworkOk();
	if(last_net_Status !=netS){
		updateNetStatus.type = 1;
		updateNetStatus.data1 = netS;
		last_net_Status =netS;
	}
	
	if(isNtpOk()){
		tls_get_rtc(tblock);
		updateTitleTime.type = 2;
		updateTitleTime.data1 = tblock->tm_hour;
		updateTitleTime.data2 = tblock->tm_min;
		updateTitleTime.data3 = tblock->tm_sec;
	}
}


int sys_timer_init(void)
{

	u8 timer_id;
	struct tls_timer_cfg timer_cfg;
	
	timer_cfg.unit = TLS_TIMER_UNIT_MS;
	timer_cfg.timeout = 400;
	timer_cfg.is_repeat = 1;
	timer_cfg.callback = (tls_timer_irq_callback)timer_int_irq;
	timer_cfg.arg = NULL;
	timer_id = tls_timer_create(&timer_cfg);
	tls_timer_start(timer_id);
	printf("timer start\n");	

	return WM_SUCCESS;
}

2、显示操作提示

cpp 复制代码
void show_status_info(const char *format, ...){
	memset(str_buff, 0, 128);
	va_list args;
	va_start(args, format);
	vsprintf(str_buff, format, args);
	va_end(args);
	Display_Fill_Rectangle(0, SCREEN_HEIGHT - _statusbar_height ,SCREEN_WIDTH - 91 ,SCREEN_HEIGHT -1,_statusbar_back_color);
	Display_String(10, SCREEN_HEIGHT - _statusbar_height +1, &mainScreenOption1, str_buff);
}

完整代码

MainScreen.cpp

cpp 复制代码
#include "string.h"
#include "MainScreen.h"
#include "MainScreenImages.h"
#include "stdarg.h"
#include "stdio.h"

#include "../src/driver/net.h"
#include "../lib/DList.h"
#include "wm_timer.h"

#define _statusbar_height 20
#define _statusbar_back_color BLUE
#define _statusbar_front_color WHITE

char str_buff[128];
struct StatusUpdateTask  updateNetStatus;
struct StatusUpdateTask  updateTitleTime;
int last_net_Status;

char tmBuff[9];
struct tm *tblock;

DisplayOption mainScreenOption1 = {FONT_SIZE_1516, _statusbar_front_color, _statusbar_back_color, 0, 0};


void timer_int_irq(u8 *arg)
{
	int netS =  isNetworkOk();
	if(last_net_Status !=netS){
		updateNetStatus.type = 1;
		updateNetStatus.data1 = netS;
		last_net_Status =netS;
	}
	
	if(isNtpOk()){
		tls_get_rtc(tblock);
		updateTitleTime.type = 2;
		updateTitleTime.data1 = tblock->tm_hour;
		updateTitleTime.data2 = tblock->tm_min;
		updateTitleTime.data3 = tblock->tm_sec;
	}
}


int sys_timer_init(void)
{

	u8 timer_id;
	struct tls_timer_cfg timer_cfg;
	
	timer_cfg.unit = TLS_TIMER_UNIT_MS;
	timer_cfg.timeout = 400;
	timer_cfg.is_repeat = 1;
	timer_cfg.callback = (tls_timer_irq_callback)timer_int_irq;
	timer_cfg.arg = NULL;
	timer_id = tls_timer_create(&timer_cfg);
	tls_timer_start(timer_id);
	printf("timer start\n");	

	return WM_SUCCESS;
}

void setNetStatus(u8 sta){
	if(sta){
		Display_Show_Picture(SCREEN_WIDTH - 22, SCREEN_HEIGHT - _statusbar_height +1, 16, 16, gImage_FullSig);
	}
	else{
		Display_Show_Picture(SCREEN_WIDTH - 22, SCREEN_HEIGHT - _statusbar_height +1, 16, 16, gImage_NoSig);
	}
}

void show_Title_Time(char* tm){
	Display_String(SCREEN_WIDTH - 90, SCREEN_HEIGHT - _statusbar_height +1, &mainScreenOption1, tm);
}

void init_screen(){

	Display_Fill_Rectangle(0, SCREEN_HEIGHT - _statusbar_height ,SCREEN_WIDTH  ,SCREEN_HEIGHT ,_statusbar_back_color);
	
	Display_Fill_Rectangle(0,0 ,SCREEN_WIDTH,SCREEN_HEIGHT -_statusbar_height ,BLACK);
	setNetStatus(0);
	tblock = new struct tm();
	sys_timer_init();
}

void clear_screen(){
	Display_Fill_Rectangle(0,0 ,SCREEN_WIDTH,SCREEN_HEIGHT -_statusbar_height ,BLACK);
}

void init_status_bar(){
	
}

void show_status_info(const char *format, ...){
	memset(str_buff, 0, 128);
	va_list args;
	va_start(args, format);
	vsprintf(str_buff, format, args);
	va_end(args);
	Display_Fill_Rectangle(0, SCREEN_HEIGHT - _statusbar_height ,SCREEN_WIDTH - 91 ,SCREEN_HEIGHT -1,_statusbar_back_color);
	Display_String(10, SCREEN_HEIGHT - _statusbar_height +1, &mainScreenOption1, str_buff);
}


u8 _MainScreanTaskLock=0;


void handleMainScreanTask(){

	if(updateNetStatus.type){
		setNetStatus(updateNetStatus.data1);
		updateNetStatus.type =0;
	}	
	if(updateTitleTime.type){
		sprintf(str_buff, "%02d:%02d:%02d",updateTitleTime.data1,updateTitleTime.data2,updateTitleTime.data3);
		show_Title_Time(str_buff);
		updateTitleTime.type =0;
	}	
}

3、在主循环中渲染状态栏

cpp 复制代码
void UserMain(void)
{
。。。
	
	while(1){
		IScean* cur= ((IScean*)sceanList->prev->data);

		_tmp_Run_Ticks = tls_os_get_time();
		keyAdepterProc(_tmp_Run_Ticks - _last_Run_Ticks);
		res = cur->tick(_tmp_Run_Ticks - _last_Run_Ticks);
		_last_Run_Ticks = _tmp_Run_Ticks;
		
		switch (res) {
			case SceanResult_EXIT:
				delete cur;
				ListPopBack(sceanList);
				((IScean*)sceanList->prev->data)->scean_resume();
				break;
			case SceanResult_Done:
				break;

		}
		FrameCount++;
		
		
		handleMainScreanTask();
	}
}

在实际操作中,有一些需要特别注意的点,以避免陷入误区:

首先,要先渲染应用,然后再绘制状态栏,这样才能保证状态栏浮在应用之上。

其次,可以为应用设置一个配置项,来表明是否为全屏应用,如果是,则无需渲染状态栏。

再者,状态栏通常是根据实际需求进行绘制的,以便提高整体性能。

即便做到了以上这些,还是有可能出现状态栏被覆盖的情况。对此,我们可以考虑以下解决方法:

其一,采用图层缓存的方式,让状态栏的图层位于应用图层之上,但这可能会带来性能方面的问题。

其二,在 LCD 的绘制方法中添加判断,如果超出了应用的显示范围,则修改相关标志位,以便后续刷新状态栏。

其三,不要使用定时器或中断来刷新状态栏,因为单片机本质上是单线程的,定时器和中断等都属于伪多线程,当它们同时进行渲染时,很容易出现花屏现象。

相关推荐
恒锐丰小瑞1 小时前
率能SS8841T 40V/2.5A/双通道H桥驱动芯片,PWM控制接口与低导通电阻(350mΩ),用于POS打印机/安防相机/机器人
单片机·嵌入式硬件·机器人
zcmodeltech2 小时前
钢铁冶金沙盘模型控制系统设计与实现:高炉-连铸-热轧多工序联动方案
分布式·stm32·单片机·嵌入式硬件·交互
wuminyu2 小时前
JDK21中虚拟线程和FFM协同实现高并发源码剖析
java·linux·c语言·jvm·c++
徽京人3 小时前
VS Code 接入Esp 32步骤
vscode·单片机·嵌入式硬件
kkkkkkkkkk_Z4 小时前
学嵌入式和C语言编程数据结构|学习日记Day21:内核链表与队列学习
c语言·数据结构·学习
不正经学生4 小时前
C语言结构体:自定义数据类型,让变量打包出行
java·c语言·开发语言·数据结构·算法
老一岁4 小时前
c问题总结(1)
c语言·开发语言
QH139292318804 小时前
Keysight N5183B N5183B 微波模拟信号发生器
网络·单片机·嵌入式硬件·集成测试·信息与通信
一木 之林4 小时前
三、内存管理、指针与堆栈
c语言·jvm·c++
笨笨饿5 小时前
#110_SCH3000 平台图传系统配置指南:从 DVP 摄像头到 UVC/WiFi 双通道传输
c语言·stm32·单片机·嵌入式硬件·物联网·vim