IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C语言映射表在嵌入式串口解析、UI设计中的应用 -> 正文阅读

[C++知识库]C语言映射表在嵌入式串口解析、UI设计中的应用

关注、星标公众号,直达精彩内容

520088fa2913832e804ad2f02ed95a67.png

来源:网络素材

整理:嵌入式云IOT技术圈

一直很想写关于映射表在MCU开发中的各种应用,在工作中我也经常用,不仅美观,而且写出来的程序可拓展性极高,看到群里已经有网友对映射表的应用做了相应的总结,而且简单易懂,上来就是肝,我们来看看吧:

一、映射表在串口数据解析中的应用

1、数据结构

typedef?struct?
{
????char?CMD[CMDLen];
????unsigned?char?(*cmd_operate)(char?*data);
}Usart_Tab;

2、指令、函数映射表

static?const?Usart_Tab?InstructionList[CMDMax]=
{
????{"PWON",PowOn},
????{"PWOFF",PowOff},
????{"HDCP",HdcpOnOff},
????{"/V",QueryKaVersion},
????{"EDIDUpgrade",UpdataEDID},
????{"Psave",Psave},
????{"Precall",Precall},
????{"Pclear",Pclear},
};

3、串口解析函数实现

unsigned?char?DataAnalysis(char?*buf)
{
??unsigned?char?i,Result;
??char?*NEXT=NULL;
??for(i=0;i<CMDMax;i++)
??{
????NEXT=StrCmp(buf,(char*)InstructionList[i].CMD);
????if(NEXT!=NULL)
????{
??????usartfuncp=InstructionList[i].cmd_operate;
??????Result=(*usartfuncp)(NEXT);
????}
??}
??return?Result;
}

二、映射表在UI设计中的应用

1、数据结构

菜单枚举:

typedef?enum
{
??stage1=0,
??stage2,
??stage3,
??stage4,
??stage5,
??stage6,
??stage7,
??stage8,
??stage9,
}SCENE;

数据结构:

typedef?struct?{
??void?(*current_operate)();?//当前场景的处理函数
??SCENE?Index;???????????????//当前场景的标签
??SCENE?Up;??????????????????//按下Up键跳转的场景
??SCENE?Down;????????????????//按下Down键跳转的场景
??SCENE?Right;???????????????//按下Left键跳转的场景
??SCENE?Left;????????????????//按下Right键跳转的场景
}STAGE_TAB;

2、函数映射表

STAGE_TAB?stage_tab[]={
??#.????operate???????Index????Up?????Down????Left???Right???
??{Stage1_Handler,??stage1,??stage4,??stage7,??stage3,?stage2},
??{Stage2_Handler,??stage2,??stage5,??stage8,??stage1,?stage3},
??{Stage3_Handler,??stage3,??stage6,??stage9,??stage2,?stage1},
??{Stage4_Handler,??stage4,??stage7,??stage1,??stage6,?stage5},
??{Stage5_Handler,??stage5,??stage8,??stage2,?stage4,??stage6},
??{Stage6_Handler,??stage6,??stage9,??stage3,?stage5,??stage4},
??{Stage7_Handler,??stage7,??stage1,??stage4,?stage9,??stage8},
??{Stage8_Handler,??stage8,??stage2,??stage5,?stage7,??stage9},
??{Stage9_Handler,??stage9,??stage3,??stage6,?stage8,??stage7},
};

3、定义两个变量保存当前场景和上一个场景

char?current_stage=stage1;
char?prev_stage=current_stage;

4、按下Up按键 跳转到指定场景current_stage的值根据映射表改变

current_stage?=stage_tab[current_stage].Up;

5、场景改变后 根据映射表执行相应的函数Handler

if(current_stage!=prev_stage)
{
??stage_tab[current_stage].current_operate();
??prev_stage=current_stage;
}

以上文章转载自:

CSDN博客链接:https://blog.csdn.net/appleJanLinux

三、单片机实现屏幕界面,多层菜单(综合版)

1、数据结构

(1)行元素结构体

typedef?struct{
?uint16_t?enterViewIndex;//按下确定键跳转的界面
?char?*?text;????????????//当前行显示的文本
?HandlerFunc?handler;????//显示函数
}RowListTypeDef;

HandlerFunc是函数指针,此函数即可作为行元素的显示函数,又可作为按键处理函数,其类型为:

typedef?void(*HandlerFunc)(uint16_t?index,?char*?p,?uint8_t?key);

三个形参的作用分别是:

@param?index:?指向此函数的RowListTypeDef在数组中的下标
@param?p:?指向当前RowListTypeDef元素的text指针指向的字符串
@param key:?若按下按键的值大于等于6(KEY_ADD),则此形参会是非0值(KEY_NONE);若小于6,则传入0(KEY_NONE)

(2)界面结构体

typedef?struct?{
?const?RowListTypeDef?*?const?list;//指向当前层所指向的行元素
?uint16_t?lengthOfList;????????????//指向的行元素的长度
?uint16_t?parentViewIndex;?????????//本元素所属层的标号
?uint16_t?startRow;????????????????//记录在上一层时的开始行索引
?uint8_t?currRow;??????????????????//记录在上一层时的行索引
}ViewListTypeDef;

定义ViewListTypeDef型数组是可以使用VIEW_MEMBER_FORMAT(x)帮助编写;如:

ViewListTypeDef?menu[]?=?{
?VIEW_MEMBER_FORMAT(rowListHome),
?VIEW_MEMBER_FORMAT(rowListSettingRoot),
?VIEW_MEMBER_FORMAT(rowListView1),
?VIEW_MEMBER_FORMAT(rowListView2),
?VIEW_MEMBER_FORMAT(rowListView3),
VIEW_MEMBER_FORMAT(rowListView1_1),
};

其中VIEW_MEMBER_FORMAT宏定义为

#define?ROW_LENGTH(x)???????((uint16_t)(sizeof(x)/sizeof(RowListTypeDef)))
#define?VIEW_MEMBER_FORMAT(x)???????{x,ROW_LENGTH(x),0,0,0}

(3)游标结构体

//游标,只需要定义一个即可????==>?8字节(byte)
typedef?struct?{
?uint8_t?currRow;???????????//当前指向元素
?uint8_t?keyval;????????????//记录按键
??uint16_t?currViewIndex;???//当前指向层
?uint16_t?startRow;?????????//屏幕第一行显示的行元素索引
?uint16_t?rowNum;???????????//记录当前层的行元素数
}CursorTypeDef;

函数作用

本控件函数很少,只有两个,即:

void?View_Init(ViewListTypeDef?*?v,?CursorTypeDef?*?c)

此函数的作用是初始化界面控件:将用户定义好的ViewListTypeDef数组的地址和CursorTypeDef地址初始化到控件

void?View_Loop(void)

此函数作用是在处理界面数据。注意:需要将此函数放入主循环中,每隔一段时间调用一次。

间隔时间典型值是100ms。

注意:并不是本控件消耗的时间多,而是屏幕驱动程序消耗的时间太多,本人的屏幕驱动是模拟的SPI时序而不是单片机硬件SPI,故屏幕驱动消耗的时间太多。控件每次需要不到1000个机器周期,而驱动程序是其上百倍。

若使用硬件外设驱动屏幕,则可以将间隔时间适当调小一点,同时注意不要低于屏幕刷新周期。

设计界面时只需要定义几个数组即可。

首先定义RowListTypeDef类型数组,根据界面数定义数组个数,根据每个界面包含的行元素数定义每个数组的长度。

然后定义ViewListTypeDef类型数组,定义一个即可,数组长度是界面数决定的。

例如,定义一个实现界面的大数组:

const?RowListTypeDef?rowListHome[]?=?{??
?//{.enterViewIndex??|??.x??|??.text??|??.handler},
???{1,"home",NULL},
};

const?RowListTypeDef?rowListSRoot[]?=?{??
?//{.enterViewIndex??|??.x??|??.text??|??.handler},
?{2,"Row?1",NULL},
?{3,"Row?2",NULL},
?{4,"Row?3",NULL},
};

const?RowListTypeDef?rowListView1[]?=?{??
?//{.enterViewIndex??|??.x??|??.text??|??.handler},
?{5,"Row?1-1",NULL},?
?{VIEW_NONE,"Row?1-2",NULL},
?{VIEW_NONE,"Row?1-3",NULL},
?{VIEW_NONE,"Row?1-4",NULL},
?{VIEW_NONE,"Row?1-5",NULL},
?{VIEW_NONE,"Row?1-6",NULL},
?{VIEW_NONE,"Row?1-7",NULL},
?{VIEW_NONE,"Row?1-8",NULL},
?{VIEW_NONE,"Row?1-9",NULL},
};

const?RowListTypeDef?rowListView2[]?=?{??
?//{.enterViewIndex??|??.x??|??.text??|??.handler},
?{VIEW_NONE,"Row?2-1",NULL},
?{VIEW_NONE,"Row?2-2",NULL},
?{VIEW_NONE,"Row?2-3",NULL},
?{VIEW_NONE,"Row?2-4",NULL},
?{VIEW_NONE,"Row?2-5",NULL},
?{VIEW_NONE,"Row?2-6",NULL},
?{VIEW_NONE,"Row?2-7",NULL},
?{VIEW_NONE,"Row?2-8",NULL},
};

const?RowListTypeDef?rowListView3[]?=?{??
?//{.enterViewIndex??|??.x??|??.text??|??.handler},
?{VIEW_NONE,"Row?3-1",NULL},
?{VIEW_NONE,"Row?3-2",NULL},
?{VIEW_NONE,"Row?3-3",NULL},
?{VIEW_NONE,"Row?3-4",NULL},
?{VIEW_NONE,"Row?3-5",NULL},
?{VIEW_NONE,"Row?3-6",NULL},
?{VIEW_NONE,"Row?3-7",NULL},
?{VIEW_NONE,"Row?3-8",NULL},
?{VIEW_NONE,"Row?3-9",NULL},
?{VIEW_NONE,"Row?3-10",NULL},
?{VIEW_NONE,"Row?3-11",NULL},
?{VIEW_NONE,"Row?3-12",NULL},
?{VIEW_NONE,"Row?3-13",NULL},
?{VIEW_NONE,"Row?3-14",NULL},
?{VIEW_NONE,"Row?3-15",NULL},
};

const?RowListTypeDef?rowListView1_1[]?=?{??
?//{.enterViewIndex??|??.x??|??.text??|??.handler},
?{VIEW_NONE,"Row?1-1-1",NULL},?
?{VIEW_NONE,"Row?1-1-2",NULL},
?{VIEW_NONE,"Row?1-1-3",NULL},
?{VIEW_NONE,"Row?1-1-4",NULL},
?{VIEW_NONE,"Row?1-1-5",NULL},
?{VIEW_NONE,"Row?1-1-6",NULL},
?{VIEW_NONE,"Row?1-1-7",NULL},
?{VIEW_NONE,"Row?1-1-8",NULL},
};

ViewListTypeDef?menu[]?=?{
?//.currIndex?|?.parentViewIndex?|?.list?|?.lengthOfList?|?.display
?VIEW_MEMBER_FORMAT(rowListHome),
?VIEW_MEMBER_FORMAT(rowListSRoot),
?VIEW_MEMBER_FORMAT(rowListView1),
?VIEW_MEMBER_FORMAT(rowListView2),
?VIEW_MEMBER_FORMAT(rowListView3),
?VIEW_MEMBER_FORMAT(rowListView1_1),
};

程序格式

程序需要定义一个全局变量游标CursorTypeDef,如:

CursorTypeDef?cursor;

然后在main函数中调用控件初始化程序View_Init

View_Init(menu,&cursor);

在程序主循环中每隔一段时间调用程序View_Loop.例如每隔100ms调用一次

当有按键按下时,只需要根据按键的不同给cursor.keyval变量赋不同的值即可.例如:

rotaryval?=?ReadRotaryEncoder();
if(rotaryval?==?ROTARY_LEFT)
{
????cursor.keyval?=?KEY_UP;
}else?if(rotaryval?==?ROTARY_RIGHT)
{
????cursor.keyval?=?KEY_DOWN;
}

其中按键值有以下:

#define?KEY_NONE????0??????//没有按下按键
#define?KEY_ENTER???1??????//按下<确定>键
#define?KEY_RETURN??2?????//按下<返回>键(返回上一层)
#define?KEY_HOME????3??????//按下<首页>键
#define?KEY_DOWN????4??????//按下<下>键
#define?KEY_UP??????5??????//按下<上>键
#define?KEY_ADD?????6??????//按下<加>键
#define?KEY_SUB?????7??????//按下<减>键

代码文件

gitee:https://gitee.com/figght/zBitsView.git
GitHub:https://github.com/figght/zBitsView.git
来源整理于网络素材,版权归原作者所有,如有侵权,请联系删除,谢谢。
???????????????? ?END ?????????????????
关注我的微信公众号,回复“加群”按规则加入技术交流群。

欢迎关注我的视频号:

a856bb602c07fde23061439f214a973f.png

点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-20 15:36:17  更:2021-09-20 15:38:10 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 13:04:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计