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 的绘制方法中添加判断,如果超出了应用的显示范围,则修改相关标志位,以便后续刷新状态栏。

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

相关推荐
yutian060638 分钟前
Keil MDK下载程序后MCU自动重启设置
单片机·嵌入式硬件·keil
XH华2 小时前
初识C语言之二维数组(下)
c语言·算法
析木不会编程3 小时前
【小白51单片机专用教程】protues仿真独立按键控制LED
单片机·嵌入式硬件·51单片机
Uu_05kkq6 小时前
【C语言1】C语言常见概念(总结复习篇)——库函数、ASCII码、转义字符
c语言·数据结构·算法
枯无穷肉7 小时前
stm32制作CAN适配器4--WinUsb的使用
stm32·单片机·嵌入式硬件
不过四级不改名6778 小时前
基于HAL库的stm32的can收发实验
stm32·单片机·嵌入式硬件
嵌入式科普8 小时前
十一、从0开始卷出一个新项目之瑞萨RA6M5串口DTC接收不定长
c语言·stm32·cubeide·e2studio·ra6m5·dma接收不定长
嵌入式大圣8 小时前
单片机UDP数据透传
单片机·嵌入式硬件·udp
A懿轩A8 小时前
C/C++ 数据结构与算法【栈和队列】 栈+队列详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·栈和队列
云山工作室9 小时前
基于单片机的视力保护及身姿矫正器设计(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计·毕设