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 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 单片机菜单-菜单数据结构 -> 正文阅读

[嵌入式]单片机菜单-菜单数据结构

在单片机中如果需要一个可以便于维护的菜单程序,那么设计一个便于封装的菜单数据结构就是必不可少的了。
最近观看B站UP主有手也不会发布的视频后,发现其写的菜单数据结构尤为好用,这里用于记录,有误之处还望大家指正!
按键采用Multibutton开源框架有兴趣可去GitHub上搜索,也可私信我,我发源码。

struct MenuItem
{
    unsigned char menu_cnt;             //当前菜单项目总数
    unsigned char * display_str;        //当前菜单要显示的字符
    void (*subs)();                     //选择某一菜单后要显示的功能函数
    struct MenuItem *children_menus;    //当前项目的子菜单
    struct MenuItem *parent_menus;      //当前项目的父菜单
};

从头到尾依次是:本级菜单所拥有的项目总数,当前项目所需要显示的菜单信息,所需要执行对应的菜单项目的回调函数,当前菜单的子菜单也就是下一级菜单,当前菜单的父菜单也就是上一级菜单。

在这本例移植中我是用了OLED12864进行显示
菜单数据,在此例子中共有两级菜单,每级菜单有三个项目

struct MenuItem parent_menu[] = {
{3, (unsigned char *) "meat", NULL, NULL, NULL},
{3, (unsigned char *) "vegetable", NULL, NULL, NULL},
{3, (unsigned char *) "drinks", NULL, NULL, NULL},
};

struct MenuItem childeren_menu1[] = {
{3, (unsigned char *) "pork", fun1, NULL, parent_menu},
{3, (unsigned char *) "beef", fun2, NULL, parent_menu},
{3, (unsigned char *) "mutton", fun3, NULL, parent_menu},
};

struct MenuItem childeren_menu2[] = {
{3, (unsigned char *) "cabbage", fun4, NULL, parent_menu},
{3, (unsigned char *) "tomato", fun5, NULL, parent_menu},
{3, (unsigned char *) "potato", fun6, NULL, parent_menu},
};

struct MenuItem childeren_menu3[] = {
{3, (unsigned char *) "milk", fun7, NULL, parent_menu},
{3, (unsigned char *) "cola", fun8, NULL, parent_menu},
{3, (unsigned char *) "orange juice", fun9, NULL, parent_menu},
};

菜单显示函数

select_menu  		//此变量是菜单结构体指针
select_item_num		//此变量是记录当前要显示本级菜单的第几个项目
void menu_display(void)
{
    unsigned char i;
    OLED_SetScreen(0);//清除OLED的缓存,即清屏
    for (i = 0;i < select_menu->menu_cnt;i++) {
        OLED_ShowString(32, i*12, (select_menu+i)->display_str, FONT_SIZE);//OLED显示对应的菜单项目名字信息
        if (i == select_item_num) OLED_ShowString(16, i*12, "->", FONT_SIZE);//如果是对应的项目则显示
    }
    OLED_RefreshGram();//将数据写入OLED中并显示
}

//主循环中放入如下
//allow_switch表示是否允许切换 
	while(1)
	{
		if (allow_switch) {
			allow_switch = 0;
			menu_display();
		}
	}

按键1单击表示本级菜单向下移动,双击表示返回上一级菜单
按键2单击表示本级菜单向上移动,双击表示进入下一级菜单

按键1处理回调函数

//recode变量可忽略,用于我自己的调试
void button1_callback_fun(void *btn, uint8_t event)
{
	unsigned char i;
	if ((event & SINGLE_CLICK) == SINGLE_CLICK) {//单击
		LED1_TOGGLE;//LED1翻转,用于调试时便于观察
		allow_switch = 1;//允许切换
		select_item_num++;//显示项目往下移
		if (select_item_num >= select_menu->menu_cnt) select_item_num = 0;//如果大于最大的显示项目回到第一个显示项目
	} else if ((event & DOUBLE_CLICK) == DOUBLE_CLICK) {//双击
		LED2_TOGGLE;//LED2翻转,用于调试时便于观察
		for (i = 0;i < select_menu->menu_cnt;i++) {//遍历是本级菜单哪一个项目要进入上一级菜单
			if (i == select_item_num) {//找到要进入上一级菜单的项目
				allow_switch = 1;//允许切换
				if ((select_menu->parent_menus != NULL) && (recode != 1)) {//上一级菜单是否为空
					select_menu = (select_menu+select_item_num)->parent_menus;//将菜单指针定位到上一级菜单
					select_item_num = 0;//回到上一级菜单从第一个项目开始
				}
				else if (recode == 1) {//可忽略
					recode = 0;
				}
			}
		}
		delay_ms(500);
	}

}

按键2处理回调函数

void button2_callback_fun(void *btn, uint8_t event)
{
	unsigned char i;
	if ((event & SINGLE_CLICK) == SINGLE_CLICK) {//单击
		LED2_TOGGLE;//LED2翻转,用于调试时便于观察
		allow_switch = 1;//允许切换
		select_item_num--;//菜单往上移
		if (select_item_num < 0) select_item_num = select_menu->menu_cnt-1;//如果回到第一个项目仍然需要往上移,则回到最后一个项目
	} else if ((event & DOUBLE_CLICK) == DOUBLE_CLICK) {//双击
		LED3_TOGGLE;//LED3翻转,用于调试时便于观察
		for (i = 0;i < select_menu->menu_cnt;i++) {//遍历是本级菜单哪一个项目要进入下一级菜单
			if (i == select_item_num) {//找到要进入下一级菜单的项目
				allow_switch = 1;//允许切换
				if (select_menu->children_menus != NULL) select_menu = (select_menu+select_item_num)->children_menus;//下一级菜单是否为空
				else if (select_menu->subs != NULL) (select_menu+select_item_num)->subs();//如果回调函数不为空则执行对应的回调函数
				select_item_num = 0;//显示第一个项目
			}
		}
		delay_ms(500);
	}
}
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-03-21 21:07:25  更:2022-03-21 21:10:12 
 
开发: 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年11日历 -2024/11/26 6:40:47-

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