当前位置: 首页 > news >正文

嵌入式软件架构--显示界面架构(工厂流水线模型,HOME界面,命令界面)

显示界面

界面设计

一共设计有8个界面,通过界面号访问
在这里插入图片描述
硬件包含8个数码管和12个按键
*号键用来删除
#号键用来确认和命令提示

在这里插入图片描述

界面的抽象

在这里插入图片描述

//界面号枚举
typedef enum
{HOME_UI,CMD_UI,CALL_UI,OPEN_UI,ERROR_UI,SUCCEED_UI,PASSWORD_UI,SET_PW_UI
}UI_E;
//界面消息结构
typedef struct{MSG_QUEUE_S *pQueue;//字符消息队列由右侧12个按键产生MSG_QUEUE_S *pOpenQueue;//开门消息队列用左侧四个控制按键产生ASBUF_S echo;//存储用户输入的按键消息用于回显UI_E 		newUi;//新界面号UI_E    	oldUi;//旧界面号 
}DIS_MSG;typedef struct{void (*init)(void);//界面初始化函数UI_E (*proc)(DIS_MSG );//界面消息轮询函数
}UI_S;

用户输入存储缓冲

#define ABUF_LEN	8
#define WIN0	0
#define WIN1    1
typedef struct{INT8 dat[ABUF_LEN];//存储用户输入UINT8 idx;//当前存储个数
}ABUF_S;
//函数实现放在文章末尾
void initAbuf(ABUF_S *pBuf);
void saveAbuf(ABUF_S *pBuf,INT8 dat);
BOOL isABufFull(ABUF_S *pBuf);
UINT8 AbufCnt(ABUF_S *pBuf);
void delAbuf(ABUF_S *pBuf);
BOOL abufCmp(ABUF_S  *p1, ABUF_S *p2);

工厂流水线模型

流水线就是上一个工位的产出流入下一个工位的输入,上下工位通过加工品沟通。
事件传递流程
在这里插入图片描述
界面的切换原理
将界面封装成结构体里面包含每个界面的初始化函数和消息循环函数,初始化函数只需要调用一次,消息循环函数轮询等待消息,它的返回值是界面号,如果返回的界面号与上次存储的界面号不一致我们就切换界面。当需要切面界面时,就调用新界面的初始化函数初始化界面并且不断调用新界面的消息循环函数等待新消息,直到下一次界面切换。如果返回的界面号与上次存储的界面号一致不切换界面。
根据上面的原理搭建界面架构
1,路由按键消息

//initkey函数中initMsgQueue(&Queue0);initMsgQueue(&Queue1);p->route[KEY_CHAR_EVENT]=&Queue0;//将12个字符按键消息路由到QUEUE0p->route[KEY_DOWN_EVENT]=&Queue1;//将4个控制按键消息路由到QUEUE1
//路由消息
void keyMain(void *pMsg)
{KEY_S *p = pMsg;//keyScan(p,p->pf());if(p->keyF){//按键单击事件createRouteMsg(p,&p->keyF,KEY_CHAR_EVENT);}
}

2,界面初始化与切换

#include "display.h"
DIS_MSG DisMsg;//显示消息变量
/*
每添加一个界面就要将其界面初始化函数和消息轮询函数添加到数组中
并且添加的界面顺序一定要与.h中的界面号能对应上,因为我们是通过
界面号来访问这些函数
*/
UI_S const Ui[]={{home_init,home_proc},{cmd_init,cmd_proc}};
void displayInit(void){DisMsg.newUi=HOME_UI;DisMsg.oldUi=HOME_UI;cmd_init();DisMsg.pOpenQueue=Key.route[1];DisMsg.pQueue=Key.route[0];
}
/*
函数功能:界面切换函数
参数说明:参数1:
返回值:void
*/
void displayMain(void * pMsg){DisMsg.newUi=Ui[DisMsg.oldUi].proc(&DisMsg);//不断调用对应界面的消息轮询函数if(DisMsg.newUi!=DisMsg.oldUi){//如果返回的界面号不同则切换界面DisMsg.oldUi=DisMsg.newUi;Ui[DisMsg.newUi].init();//调用新界面的初始化函数}
}

HOME界面

/*
函数功能:HOME界面初始化函数
参数说明:参数1:
返回值:void
*/
void home_init(void){setWinCmd(&Dleds,WIN0 ,LED_TEXT,0,0,0,NULL);setWinNum(&Dleds,1);setWinSize(&Dleds,WIN0,0,8);writeLed(&Dleds,WIN0,"%-8s","L-71");
}
/*
函数功能:HOME界面消息轮询函数
参数说明:参数1:
返回值:void
*/
UI_E home_proc(DIS_MSG *pMsg){initMsgQueue(pMsg->pOpenQueue);if(msgQueueNum(pMsg->pQueue)){return CMD_UI;}return HOME_UI;
}

命令界面

1,把用户输入的信息先存储到echo,然后显示
2,对用户输入的命令进行解析
输入#,(判断是1#或者0#)
输入超时,101
输入*,删除一个字符
输入0-9放入echo,再解析

在这里插入图片描述
0,中间全局变量

DIS_MSG DisMsg;//按键消息
UINT32 Clk;//时间戳用来判断超时
UINT8 MatchCode;//保存开门键

1,定义命令解析结构体

//命令匹配结构体
typedef struct{UINT8 len;//命令长度INT8 dat[4];UI_E  ui;//返回界面号UINT8 match;//匹配码 开门键
}CMD_S;

预设命令

CMD_S  const ImmCmd[] = 
{{2,"0#",PASSWORD_UI},//0#  进入密码界面{2,"1#",SET_PW_UI},//1#  进入密码设置界面
};
CMD_S const TimeOutCmd[]=
{{3,"101",CALL_UI,VK_ENTER},//命令长度,门牌号,返回界面号,开门键{3,"201",CALL_UI,VK_SHIFT},{3,"102",CALL_UI,VK_CONTROL},{3,"202",CALL_UI,VK_ALT},
};

2,初始化命令界面

/*
函数功能:命令界面初始化函数
参数说明:参数1:
返回值:void*/
void cmd_init(void){initAbuf(&DisMsg.echo);//回显缓冲区初始化setWinCmd(&Dleds,WIN0 ,LED_TEXT,0,0,0,NULL);//普通文本显示setWinNum(&Dleds,1);setWinSize(&Dleds,WIN0,0,8);//设置显存起始位置长度writeLed(&Dleds,WIN0,"%-8s",DisMsg.echo.dat);	//输入回显  刚开始为空
}

3,命令消息循环函数
具体流程:
a,检查队列是否有消息,读取消息,对消息按键码进行分类解析。
如果是*表示要删除一个用户输入的字符,回显,界面不切换
如果是#表示进行命令匹配看到底是要进入密码界面还是密码设置界面
如果都不是说明为0-9即用户在输入门牌号
b,超时判断:每次进来都会进行输入超时判断,将用户输入与预设的超时命令
进行匹配,如果匹配正确则保留开门键匹配码,匹配不上则返回ERROR_UI到错误界面。

/*
函数功能:命令循环解析函数
参数说明:参数1:消息
返回值:界面号
*/
UI_E cmd_proc(DIS_MSG *pMsg){MSG_S msg;BOOL status;CMD_S tempCmd;if(msgQueueNum(pMsg->pQueue)){//有消息getMsgQueue(pMsg->pQueue,&msg);Clk=msg.time;switch(msg.code){case '*'://删除一个字符并回显{delAbuf(&pMsg->echo);writeLed(&Dleds,WIN0,"%-8s",DisMsg.echo.dat);return	CMD_UI;}case '#':{saveAbuf(&pMsg->echo,msg.code);//保存字符writeLed(&Dleds,WIN0,"%-8s",DisMsg.echo.dat);//回显//匹配命令status=testCmd(&pMsg->echo,&tempCmd,ImmCmd,sizeof(ImmCmd)/sizeof(CMD_S));if(status == TRUE ){return tempCmd.ui;//两种情况密码界面还是设置界面}return ERROR_UI;	}default://0-9字符{saveAbuf(&pMsg->echo,msg.code);//保存字符writeLed(&Dleds,WIN0,"%-8s",DisMsg.echo.dat);//回显return CMD_UI;}}}if(timeOut(Clk,2000)==TRUE){//超时判断status=testCmd(&pMsg->echo,&tempCmd,TimeOutCmd,sizeof(TimeOutCmd)/sizeof(CMD_S));if(status == TRUE ){return tempCmd.ui;MatchCode=tempCmd.match;//存储开门键}return ERROR_UI;		}	return CMD_UI;
}

命令比较函数


/*
函数功能:命令比较函数
参数说明:参数1:用户输入的按键字符信息参数2:返回匹配成功命令参数3:预设命令参数4:命令结构数组长度即包含多少命令
返回值:TRUE:命令匹配成功FALSE:命令匹配失败
*/
//testCmd(&pMsg->echo,&tempCmd,ImmCmd,sizeof(ImmCmd)/sizeof(CMD_S));
BOOL testCmd(ABUF_S *p,CMD_S * pTemp,CMD_S const * pCmd,UINT8 len){UINT8 i;for(i=0;i<len;i++){if(p->idx == pCmd[i].len){//先拿长度过滤一下if(!strcmp(p->dat,pCmd[i].dat)){*pTemp =pCmd[i];//这是匹配成功要返回的命令结构return TRUE;}}}return FALSE;
}

超时判断函数

//TimeStamp是UINT32一个全局时间戳,在systick_handler函数中每1ms自增
BOOL timeOut(UINT32 clk,UINT32 delayTime)
{if(TimeStamp - clk >= delayTime){return TRUE;}else{return FALSE;}
}

TimeStamp从0不断自增到0xffffffff,当超出最大值又从0开始增加,当cmd_proc中记录的clk大于TimeStamp时,TimeStamp-clk的结果还是正确的。
在这里插入图片描述
以下是ABUF_S 相关函数的实现。

void initAbuf(ABUF_S *pBuf){UINT8 i;pBuf->idx=0x00;for(i=0;i<ABUF_LEN;i++){pBuf->dat[i]=0;}
}
void saveAbuf(ABUF_S *pBuf,INT8 dat){if(pBuf->idx<=ABUF_LEN){pBuf->dat[pBuf->idx]=dat;pBuf->idx++;}
}
BOOL isABufFull(ABUF_S *pBuf){return (pBuf->idx <=ABUF_LEN)? TRUE:FALSE;
}UINT8 AbufCnt(ABUF_S *pBuf){return pBuf->idx;
}
void delAbuf(ABUF_S *pBuf){if(pBuf->idx){pBuf->idx--;pBuf->dat[pBuf->idx]=0x00;}
}
BOOL abufCmp(ABUF_S  *p1, ABUF_S *p2){return (p1->idx==p2->idx && !strcmp(p1->dat,p2->dat))?TRUE:FALSE;}
http://www.dtcms.com/a/520050.html

相关文章:

  • Ubuntu20.04 + QT5.14.2 + Android23的开发平台搭建总结
  • 【思维链条CoT与React模式深度解析】AI智能体的核心推理框架
  • svchost第一个是rpcss第二个是termsvcs第三个是NetworkService第四个是LocalService第五个是netsvcs----备忘
  • 餐饮网站模板免费下载jetpack wordpress
  • Hadoop High Availability 简介
  • Tier 1 供应商EDI对接:Forvia EDI需求分析
  • 2025最新策略答案引擎优化(AEO):在AI搜索引擎中获得更多曝光
  • SpringAI Redis RAG 搜索
  • 服务器和域名都有了 怎么做网站网站seo诊断分析报告
  • SpringBoot的Web开发
  • 基于springboot的大创管理系统开发与设计
  • GitHub 热榜项目 - 日榜(2025-10-23)
  • RAG:让大模型“既懂又查”的智能系统
  • cms网站建设的优缺点wordpress两个站合并
  • 数据结构——B树及其基本操作
  • java.text.MessageFormat的用法
  • 公司网站怎么做分录平面设计怎么网上接单
  • Java爬虫性能优化:以喜马拉雅音频元数据抓取为例
  • 使用 Java 对 PDF 添加水印:提升文档安全与版权保护
  • CRMEB-PHP订单改价模块详解
  • 丽水 网站建设注册163免费邮箱
  • 网站建设微信开发怎么做订阅号
  • TypeScript Array(数组)
  • E160系列全国产超外差无线射频模块技术解析与应用指南
  • 20251023在Ubuntu20.04.6上编译AIO-3576Q38开发板的Android14
  • 故障后数据备份
  • C++(23):lambda可以模版参数
  • 全平台Ansible一键安装脚本:Ubuntu/Debian/RHEL全支持
  • leetcode 23 合并K个升序链表
  • Element Plus组件v-loading在el-dialog组件上使用无效