0.96寸OLED(四)多级菜单实现 您所在的位置:网站首页 菜单制作 0.96寸OLED(四)多级菜单实现

0.96寸OLED(四)多级菜单实现

#0.96寸OLED(四)多级菜单实现| 来源: 网络整理| 查看: 265

文章目录 前言一、结构体定义二、相关函数1.页面刷新2.页面清除3.菜单更新4.GUI按键检测5.初始化 二、函数注意1.仅运行一次的函数2.菜单切换的函数3.重复循环的函数4.主函数循环和调用方法

前言

本次是基于0.96寸OLED的多级菜单设计,找了一下网上的菜单写法,发现很多是那种利用一个数组记录界面的,我觉得这样不是很直观。我希望写成那种可以不断延伸拓展的界面,界面数量,菜单级数可以任意指定的类型。 在这里插入图片描述 就像XMIND思维导图工具一样,因此我写了一个简单的多级菜单管理界面。

下面直接上代码

一、结构体定义

首先创造一些结构体存放界面所需的变量

#ifndef __GUI_096_H #define __GUI_096_H #include "main.h" #include "oled.h" #define Menu_level 5 //菜单级数 #define Menu_Length 20 //单个菜单长度 typedef struct oled_fun { uint8_t string[20]; //菜单名 void (*func) (void); //菜单函数 }GUI_Menu; typedef enum GUI_Button { Gui_Up, Gui_Down, Gui_Right, Gui_Left, Gui_No, }GUI_Button; typedef struct Oled_Gui { uint8_t Pause; //Gui暂停标志位 uint8_t Menu_Len; //Gui菜单长度 GUI_Button Button; //Gui按键 uint8_t Begin_Index; //Gui菜单起始 uint8_t Now_Inedx; //Gui菜单选中 GUI_Menu Menu[Menu_Length]; //Gui菜单 void (*Last_Func[Menu_level]) (void); //Gui上级函数记录 void (*Now_Func) (void); //Gui选中函数 }Gui; extern Gui My_Gui; void gui_init(); void Menu_Refresh(void); void Menu_Clear(); void Menu_Update(uint8_t len,GUI_Menu* the_next); #endif/// 二、相关函数 1.页面刷新 void Menu_Refresh() { OLED_Clear(); for(int i=My_Gui.Begin_Index;i memset( (uint32_t *)(&(My_Gui.Menu[0])), 0, My_Gui.Menu_Len*sizeof(My_Gui.Menu[0])); My_Gui.Menu_Len=0; My_Gui.Begin_Index=0; My_Gui.Now_Inedx=0; OLED_Clear(); OLED_Refresh(); } 3.菜单更新 void Menu_Update(uint8_t len,GUI_Menu* the_next) { memset( (uint32_t *)(&(My_Gui.Menu[0])), 0, My_Gui.Menu_Len*sizeof(My_Gui.Menu[0])); My_Gui.Begin_Index=0; My_Gui.Now_Inedx=0; My_Gui.Menu_Len=len; for(int i=0;i //GUI没有暂停的情况下处理按键 if(My_Gui.Pause==0) { if(My_Gui.Button==Gui_Up) { My_Gui.Button=Gui_No; if(My_Gui.Now_Inedx>0) { //向上移位选项然后刷新屏幕 My_Gui.Now_Inedx--; if(My_Gui.Now_Inedx My_Gui.Now_Inedx++; if(My_Gui.Now_Inedx-My_Gui.Begin_Index>3) My_Gui.Begin_Index=My_Gui.Now_Inedx-3; Menu_Refresh(); } } else if(My_Gui.Button==Gui_Right) { My_Gui.Button=Gui_No; //选择函数 if(My_Gui.Menu[My_Gui.Now_Inedx].func!=NULL) { //现函数进入上级存储 for(int i=0;i My_Gui.Last_Func[i]=My_Gui.Now_Func; break; } } //修改现函数 My_Gui.Now_Func=My_Gui.Menu[My_Gui.Now_Inedx].func; My_Gui.Now_Inedx=0; My_Gui.Begin_Index=0; My_Gui.Pause=1; //暂停GUI } } else if(My_Gui.Button==Gui_Left) { My_Gui.Button=Gui_No; //取出存储的函数 for(int i=Menu_level-1;i>=0;i--) { if(My_Gui.Last_Func[i]!=NULL) { My_Gui.Now_Func=My_Gui.Last_Func[i]; My_Gui.Last_Func[i]=NULL; break; } } My_Gui.Now_Inedx=0; My_Gui.Begin_Index=0; My_Gui.Pause=1; } } else My_Gui.Button=Gui_No; } 5.初始化 GUI_Menu Menu1[]={{"A",.func=func_A}, {"AA",.func=func_B}, {"AAA",.func=func_C}, {"AAAA",.func=func_D}, {"AAAAA",.func=func_D}, {"AAAAAA",.func=func_D}, {"AAAAAAA",.func=func_D}, {"AAAAAAAA",.func=func_D}, }; void gui_init() { for(int i=0;i{"B",.func=func_A}, {"中景园",.func=func_B}, }; void func_C(void) { Menu_Update(2,Menu2); HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); } 3.重复循环的函数

这类函数需要用户自己添加结束条件

void func_B(void) { Menu_Clear(); while(flag==1) { //用户自己添加内容 } } 4.主函数循环和调用方法

开一个定时器内部进行不断调用

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) { if(htim->Instance==TIM4) { //HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin); //HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin); } else if(htim->Instance==TIM3) { gui_init_tick(); } }

主函数的写法就很简单了

#include "sys.h" int main(void) { hard_steup(); while(1) { if(My_Gui.Pause==1) { My_Gui.Now_Func(); My_Gui.Pause=0; } } }


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有