目录
愿景:开发一种具有多层次界面跳转返回的功能性人机交互界面。
你们的点赞,投币,关注是对我创作最大的支持!
前言
因嫌每次焊好一块新版子,都得在主函数里分别调用相关Test函数来测试板子外设接口是否正常,我将大多数函数集合成一个名为Hardware_Test的函数,其实就只是将死循环测试,改成有条件退出的语句,然后依次调用每个测试函数,这样就可以只下载一次代码就可以完成所有外设的测试,省去了复制粘贴、编译下载的麻烦,可以节约不少精力和时间。
可又出现了新问题——如果一个外设有问题或需要反复测试,那么用这个Hardware_Test函数就需要每次等待其他外设测试过后,才能重新再次测试有问题的外设,非常不方便,同学也说,能不能编写一个菜单,想测试哪个外设就直接调用不就好了。“不满足是向上的车轮。”于是一个新的想法在我心里萌芽了......于是有了这篇文章。
菜单开发
愿景:
开发一种具有多层次界面跳转返回的功能性人机交互界面。
概要:
基本功能概括:
1、显示选项提示(字符串)并具有切换功能。
2、选项所对应操作的实现。
拓展优化点:
3、按下按键可暂停主程序的运行,并查看相关参数;
4、进行参数的调整(包括PID参数)。
可行性分析:
1、字符串显示,将“<--”复制到前面字符串尾,以示选中:
strcat(Row[Flag_row-1]," <--");
2、以结构体将对应选项的操作数据与字符串相结合:
#define CAN 6 //页面所能容纳最大行数
#define NUM 6 //显示行数
#define SIZE 20 //一行最大所能的显示的字符串长度(除去" <--")
typedef struct page //定义页面结构体page的别名为menu
{
struct page *prev; //上级页面
char *option_name[CAN]; //选项名
void (*option[NUM])(void); //函数指针数组(包含对应操作)
struct page *next[NUM]; //下级页面
} menu;
3、关闭中断服务函数TIM7_IRQHandler的定时器,并执行Menu();查看相关参数并修改。
if(*(Page->option[Flag_row-1])) //此选项有对应函数
{
func = Page->option[Flag_row-1];
func(); //函数开始执行
if(func == Task_begin) //如果是执行中断任务调度函数,就进入等待中断函数
{
wait_interruput(); //等待中断函数,如果按键按下就关闭中断服务函数,跳出这个死循环,返回菜单界面
}
}
详细步骤:
首先,明确所需选取的数据类型:
数据结构:
page1_1_1 ...
/
page1_1__page1_1_2 ...
/ ...
page1/__page1_2__page1_2_2 ...
\ ...
\ page1_3__page1_3_2 ...
\
. page1_3_3 ...
.
. ... ...
因是树状结构,故用非线性结构的树状多分枝链表来储存管理相关数据。
这里就不得不说一下数据相关的知识了:计算机数据结构基本概念与简单应用
这里相当于把双向链表与树结合起来,树的多分支以示各页的总体关系,双向链表以示上下级页面的关系。
其次,根据所选用数据类型写出伪代码:
Menu()
begin
menu_init(); //菜单初始化
while 1
key_num <= Key_Scan()
switch key_num
case Up:
operate_Up()
case Down:
operate_Down()
case Esc:
operate_Esc()
case Enter:
operate_Enter();
end swich
UI_show(); //界面显示
end
这里先写出了一个大体的伪代码框架,理清了接下来写各个模块的代码,这一步是很重要的。
最后分块写出余下子模块代码:
#define NUM 6 //显示行数
u8 Flag_row; //行数标记
menu *Page; //页面切换
char Row[CAN][SIZE]; // 定义一个二维字符数组来存储选项名
//用户界面显示
void UI_show(void)
{
strcpy(Row[0],Page->option_name[0]);
strcat(Row[0]," <--"); //初始时第一行特殊处理(选中)
for(u8 i=0;i<NUM;i++)
{
if(i == Flag_row-1)
{
continue; //如果是选中的那行(<--)就不重新赋值,保留
}
strcpy(Row[i],Page->option_name[i]);
}
page_show(); //单页显示
}
这里展示了UI_show()函数。
#define CAN 6 //页面所能容纳最大行数
//单页显示
void page_show(void)
{
OLED_Clear();
for(u8 i=0;i<CAN;i++)
{
OLED_ShowString(0,i*10,Row[i],12);
}
OLED_Refresh_Gram();
}
再来补充链表的初始化:
menu page1 =
{
NULL, //上级页面
{
"Operation Mode", //显示内容
"Para Setting",
"Hardware Test",
"( )",
"( )",
"Others..."
},
{
NULL, //对应操作
NULL,
NULL,
NULL,
NULL,
NULL
},
//下级页面
{
&page1_1,
&page1_2,
&page1_3, //没有内容故为NULL
NULL,//&page1_4,
NULL,//&page1_5,
NULL//&page1_6
}
};
界面效果展示:
图拍展示:
视频展示:
OLED菜单
后记:
对于一个项目,我们应该先明确目标,理清思路再着手开始,不要盲目就弄,首先得问自己:要做什么,要怎么做?祝大家也弄出属于自己的菜单,加油!
你们的点赞,投币,关注是对我创作最大的支持!