精华内容
下载资源
问答
  • OLED多级菜单实现方法

    千次阅读 多人点赞 2019-03-06 16:10:06
    OLED多级菜单实现方法定义一个结构体定义一个结构体数组下面详细介绍key_table code table[n]里面的值是怎么确定的。例程 定义一个结构体 typedef struct { unsigned char current; unsigned chaup;//上键 ...

    定义一个结构体

    typedef struct
    {
         unsigned char current;
         unsigned char up;//上键
         unsigned char down;//下键
         unsigned char enter;//确认键
         void (*current_operation)()
    } key_table;
    

    结构体包含5个变量,分别是函数的索引号即用户想要执行哪个函数的代号,然后有三个键,用户可以自己定义别的按键,最后一个是函数指针,即索引号对应的函数。

    定义一个结构体数组

    
    key_table code table[n]=
    {
         {0,2,1,3,(*fun1)},
         {1,0,2,4,(*fun2)},
         {2,1,0,5,(*fun3)},                  
         {3,0,6,3,(*fun4)},
         {4,1,6,4,(*fun5)},                       
         {5,2,6,5,(*fun6)},
         {6,0,0,0,(*fun7)},
         ............                                           
    };
    

    下面详细介绍key_table code table[n]里面的值是怎么确定的。

    1. 首先可以先这样定义该数组
      key_table code table[n]=
      {
           {0,x,y,z,(*fun1)},
           {1,x,y,z,(*fun2)},
           {2,x,y,z,(*fun3)},
           {3,x,y,z,(*fun4)},
           {4,x,y,z,(*fun5)},
           {5,x,y,z,(*fun6)},
           {6,x,y,z,(*fun7)},
           …
      };
      其中,x,y,z是未知数,先不确定,他们对应的是三个键按下要要执行的索引值,
      如果四个键,就有四个未知数,在确定他们之前,必须要了解自己函数执行什么命令。

    2. 假如开始时,执行数组里面的第一个即table[0],而想在此按上键执行函数fun6
      那么table[0]里面需要这样设置 {0,5,y,z,(*fun1)}
      同样,如果希望按下键执行fun7则需要设置为 {0,x,6 ,z,(*fun1)}
      如果希望按确认键执行fun3则需要设置为 {0,x,y, 2 , (*fun1)}
      如果上面三种情况都想要就设置为 即操作不同的按键执行不同的操作。{0,5,6,2,(*fun1)}

    3. 其它数组元素以此类推。这一步做完了看主程序里面(主要是while(1)里面)

    /*******************find index****************************/
    switch(key)
    {
    	case 0x44:                                                            
    		func_index=table[func_index].up; //向上翻                                         
    		break;
    	case 0x24:                                           
    		func_index=table[func_index].enter;//回车
    		break;
    	case 0x14:                                           
    		func_index=table[func_index].down;//向下翻
    		break;
    	default:break;
    }                                
    current_operation_index=table[func_index].current_operation;
    (*current_operation_index)();//执行当前操作函数
    

    其中,key是返回的按键值,这个用户视情况而定,

    例程

    主要是以结构体为基础设计的,以12864显示函数代替了用户需要的函数功能,只需要修改相应的函数和索引号,就可以达到任意界面切换了

    #include <reg52.h>
    #include "fun.h"
    #include "lcd12864.h"
    #include "delay.h"
    
    #define uchar unsigned char
    sbit keydown=P0^0;
    sbit keyenter=P0^1;
    sbit keyup=P0^2;
    uchar func_index=0;
    void (*current_operation_index)();
    
    typedef struct
    {
    	uchar current;
    	uchar up;//向上翻索引号
    	uchar down;//向下翻索引号
    	uchar enter;//确认索引号
    	void (*current_operation)();
    }key_table;
    key_table code table[30]=
    {
    	{0,3,1,4,(*fun1)},//第一层,显示【清华大学】、北京大学、重庆三峡学院、返回
    	{1,0,2,8,(*fun2)},//第一层,显示清华大学、【北京大学】、重庆三峡学院、返回	
    	{2,1,3,12,(*fun3)},//第一层,显示清华大学、北京大学、【重庆三峡学院】、返回
    	{3,2,0,25,(*fun4)},//第一层,显示清华大学、北京大学、重庆三峡学院、【返回】
    
    	{4,7,5,16,(*fun5)},//第二层,清华大学层下显示【地点】、创建时间、简介、返回
    	{5,4,6,17,(*fun6)},//第二层,清华大学层下显示地点、【创建时间】、简介、返回 
    	{6,5,7,18,(*fun7)}, //第二层,清华大学层下显示地点、创建时间、【简介】、返回
    	{7,6,4,0,(*fun8)},//第二层,清华大学层下显示地点、创建时间、简介、【返回】
    	
    	{8,11,9,19,(*fun9)},//第二层,北京大学层下显示【历史】、政治、简介、返回         	
    	{9,8,10,20,(*fun10)},//第二层,北京大学层下显示历史、【政治】、简介、返回  
    	{10,9,11,21,(*fun11)}, //第二层,北京大学层下显示历史、政治、【简介】、返回
    	{11,10,8,1,(*fun12)},//第二层,北京大学层下显示历史、政治、简介、【返回】 
    
    	{12,15,13,22,(*fun13)},//第二层,重庆三峡学院层下显示【简介】、最佳院系、最佳实验室、返回
    	{13,12,14,23,(*fun14)}, //第二层,重庆三峡学院层下显示简介、【最佳院系】、最佳实验室、返回
    	{14,13,15,24,(*fun15)}, //第二层,重庆三峡学院层下显示简介、最佳院系、【最佳实验室】、返回
    	{15,14,12,2,(*fun16)}, //第二层,重庆三峡学院层下显示简介、最佳院系、最佳实验室、【返回】
    
    	{16,16,16,4,(*fun17)}, //第三层,清华大学地点层
    	{17,17,17,5,(*fun18)}, //第三层,清华大学创时间层
    	{18,18,18,6,(*fun19)}, //第三层,清华大学简介层
    	{19,19,19,8,(*fun20)}, //第三层,北京大学历史层 
    	{20,20,20,9,(*fun21)}, //第三层,北京大学政治层   
    	{21,21,21,10,(*fun22)}, //第三层,北京大学简介层
    	{22,22,22,12,(*fun23)}, //第三层,重庆三峡学院简介层  
    	{23,23,23,13,(*fun24)}, //第三层,重庆三峡学院最佳院系层  
    	{24,24,24,14,(*fun25)}, //第三层,重庆三峡学院最佳实验室层     
    	{25,25,25,0,(*fun26)}, //第0层
                         
    };
    
    int main(void)
    {
    	init_lcd(); //初始化LCD模块
    	while(1)
    	{
    		/*******************find index****************************/
    		if((keyup==0)||(keydown==0)||(keyenter==0))
    		{
    			delay(10);//消抖
    			if(keyup==0)
    			{
    				func_index=table[func_index].up;    //向上翻
    				while(!keyup);//松手检测
    			}
    			if(keydown==0)
      		 	{
        				func_index=table[func_index].down;    //向下翻
        				while(!keydown);//松手检
    			}
    		        if(keyenter==0)                     
    			{                
    		        	func_index=table[func_index].enter;    //确认
    		        	while(!keyenter);
    			}
    			init_lcd();
    		}
    		current_operation_index=table[func_index].current_operation;
    		(*current_operation_index)();//执行当前操作函数
    	}
    }
    
    
    
    展开全文
  • STM32+OLED多级菜单.zip

    2021-05-15 22:57:57
    STM32中实现OLED多级菜单完整工程,博客地址:https://blog.csdn.net/qq_44062900/article/details/115798468
  • STM32中实现OLED多级菜单完整工程,博客地址:https://blog.csdn.net/qq_44062900/article/details/115798468
  • STM32中实现OLED多级菜单(支持修改参数)

    千次阅读 多人点赞 2021-04-17 17:19:06
    STM32中实现OLED多级菜单 1. 效果展示 图片效果 视频效果 STM32中实现OLED多级菜单 参考代码: gui.h文件 #ifndef _GUI_H_ #define _GUI_H_ #include "stm32f10x.h" typedef struct { u8 Cur_Index;//当前...

    STM32中实现OLED多级菜单

    一、完整工程源码下载

    地址:https://download.csdn.net/download/qq_44062900/18755302

    二、硬件连接

    1、OLED12864

    OLED_SCK—>PA0 //时钟管脚
    OLED_MOSI—>PC13 //数据管脚(主机输出从机输入)
    OLED_RES—>PB9 //复位管脚(低电平有效)
    OLED_DC—>PB8 //数据/命令(低电平有效)选择管脚
    OLED_CS—>PB7 //片选管脚(低电平有效)

    2、按键

    KEY_UP(上一页)—>PB12
    KEY_DOWN(下一页)—>PB14
    KEY_LEFT(确认) —>PB13
    KEY_RIGHT(返回)—>PB15

    3、蜂鸣器

    BEEP–>PB4

    三、效果展示

    1、图片效果

    主界面
    在这里插入图片描述

    菜单选项界面
    在这里插入图片描述

    设置界面
    在这里插入图片描述
    在这里插入图片描述

    电池信息界面
    在这里插入图片描述

    2、视频效果

    stm32+OLED实现多级菜单

    四、核心代码

    1、gui.h文件

    #ifndef _GUI_H_
    #define	_GUI_H_
    
    #include "stm32f10x.h"
    
    #define ON 1
    #define OFF 0
    
    typedef struct
    {
    	u8 Cur_Index;//当前索引项
    	u8 previous;//上一页
    	u8 next;//下一页
    	u8 enter;//确认
    	u8 back;//返回
    	void (*current_operation)(u8,u8);//	当前索引执行的函数(界面)
    }Main_Menu;
    
    //各界面的索引值
    enum
    {
    	_Main_UI=0,
    	_Wifi_Option,
    	_Bluetooth_Option,
    	_Setting_Option,
    	_Info_Option,
    	_Wifi_Child,
    	_Bluetooth_Child,
    	_Setting_Child,
    	_Info_Child,
    	_OLED_Lock,
    };
    
    //按键索引值
    enum
    {
    	KEY_PREVIOUS=2,
    	KEY_ENTER,
    	KEY_NEXT,
    	KEY_BACK
    };
    
    void Main_UI(u8 page_index,u8 key_val);
    void Main_Menu_Func(u8 page_index,u8 key_val);
    void Wifi_Child(u8 page_index,u8 key_val);
    void Bluetooth_Child(u8 page_index,u8 key_val);
    void Setting_Child(u8 page_index,u8 key_val);
    void Info_Child(u8 page_index,u8 key_val);
    void OLED_Lock(u8 page_index,u8 key_val);
    void GUI_Refresh(void);
    #endif
    

    2、gui.c文件

    #include "gui.h"
    #include "oled.h"
    #include "oledfont.h"
    #include "key.h"
    #include "led.h"
    #include <stdio.h>
    #include "rtc.h"
    #include <string.h>
    #include "beep.h"
    #include "adc.h"
    #include "oled.h"
    #include "esp8266.h"
    
    static u8 func_index=_Main_UI;//当前页面索引值
    static u8 last_index=_Main_UI;//上一个界面索引值
    static void (*current_operation_func)(u8,u8);//定义一个函数指针
    static u8 BEEP_swi=ON;
    
    //索引表
    Main_Menu table[20]=
    {
    	//Cur_Index,previous,next,enter,back,(*current_operation)(u8,u8)
    	//主界面
    	{_Main_UI,_Main_UI,_Main_UI,_Wifi_Option,_OLED_Lock,Main_UI},
    	//主菜单
    	{_Wifi_Option,_Info_Option,_Bluetooth_Option,_Wifi_Child,_Main_UI,Main_Menu_Func},//Wifi
    	{_Bluetooth_Option,_Wifi_Option,_Setting_Option,_Bluetooth_Child,_Main_UI,Main_Menu_Func},//蓝牙
    	{_Setting_Option,_Bluetooth_Option,_Info_Option,_Setting_Child,_Main_UI,Main_Menu_Func},//设置
    	{_Info_Option,_Setting_Option,_Wifi_Option,_Info_Child,_Main_UI,Main_Menu_Func},//关于信息
    	
    	//子菜单
    	{_Wifi_Child,_Wifi_Child,_Wifi_Child,_Wifi_Child,_Wifi_Option,Wifi_Child},//Wifi子菜单
    	{_Bluetooth_Child,_Bluetooth_Child,_Bluetooth_Child,_Bluetooth_Child,_Bluetooth_Option,Bluetooth_Child},//蓝牙子菜单
    	{_Setting_Child,_Setting_Child,_Setting_Child,_Setting_Child,_Setting_Option,Setting_Child},//设置子菜单
    	{_Info_Child,_Info_Child,_Info_Child,_Info_Child,_Info_Option,Info_Child},//关于信息子菜单
    	{_OLED_Lock,_Main_UI,_Main_UI,_Main_UI,_Main_UI,OLED_Lock},//OLED熄屏
    };
    
    /*
    函数功能:刷新界面
    参数:无
    返回值:无
    */
    void GUI_Refresh(void)
    {
    	u8 key_val=Get_KEY_Value();
    	if(key_val!=0)//只有按键按下才刷屏
    	{
    		last_index=func_index;//更新上一界面索引值
    		switch(key_val)
    		{
    			case KEY_PREVIOUS: func_index=table[func_index].previous;//更新索引值
    					break;
    			case KEY_ENTER: func_index=table[func_index].enter;//更新索引值
    					break;
    			case KEY_NEXT:func_index=table[func_index].next;//更新索引值
    					break;
    			case KEY_BACK:func_index=table[func_index].back;//更新索引值
    					break;
    			default:break;
    		}
    		if(BEEP_swi==ON)
    		{
    			BEEP=1;
    			Delay_Ms(50);
    			BEEP=0;
    		}
    		OLED_Clear(0);//清屏
    	}
    	current_operation_func=table[func_index].current_operation;
    	(*current_operation_func)(func_index,key_val);//执行当前索引对应的函数
    		
    }
    
    
    /*
    函数功能:显示主界面
    参数:u8 page_index,u8 key_val
    返回值:无
    */
    void Main_UI(u8 page_index,u8 key_val)
    {
    	char buff[20];
    	OLED_Display_Image(0,0,11,7,(char*)Signal_11x7,NO_ALGIN);//显示信号塔
    	OLED_Display_Image(14,0,9,9,(char*)Bluetooth_9x9,NO_ALGIN);//显示蓝牙
    	snprintf(buff,sizeof(buff),"%02d-%02d-%02d",Current_Time.year%100,Current_Time.month,Current_Time.day);
    	OLED_Display_String(0,1,8,8,buff,NORMAL,CEN_ALIGN);//显示日期
    	snprintf(buff,sizeof(buff),"%02d:%02d",Current_Time.hour,Current_Time.min);
    	OLED_Display_String(0,2,16,32,buff,NORMAL,CEN_ALIGN);//显示时间
    	OLED_Display_Image(112,0,16,8,(char*)Bat_16x8,NO_ALGIN);//显示电量
    	OLED_Display_Chinese(40,6,16,16,(char *)(Week_Font_16x16+7*32),NO_ALGIN);//星
    	OLED_Display_Chinese(56,6,16,16,(char *)(Week_Font_16x16+8*32),NO_ALGIN);//期
    	OLED_Display_Chinese(72,6,16,16,(char *)(Week_Font_16x16+(Week_Get()-1)*32),NO_ALGIN);//一~七
    	OLED_Display_Image(0,6,16,16,(char*)Menu_16x16,NO_ALGIN);//显示菜单
    	OLED_Display_Image(112,6,16,16,(char*)Lock_16x16,NO_ALGIN);//显示锁屏
    }
    /*
    函数功能:主菜单显示函数
    参数:u8 page_index,u8 key_val
    返回值:无
    */
    void Main_Menu_Func(u8 page_index,u8 key_val)
    {
    	char buff[20];
    	OLED_Display_Image(0,0,11,7,(char*)Signal_11x7,NO_ALGIN);//显示信号塔
    	OLED_Display_Image(14,0,9,9,(char*)Bluetooth_9x9,NO_ALGIN);//显示蓝牙
    	snprintf(buff,sizeof(buff),"%02d:%02d:%02d",Current_Time.hour,Current_Time.min,Current_Time.sec);
    	OLED_Display_String(0,0,8,8,buff,NORMAL,CEN_ALIGN);//显示时间
    	OLED_Display_Image(112,0,16,8,(char*)Bat_16x8,NO_ALGIN);//显示电量
    	OLED_Display_Image(15,4,16,16,(char*)Left_16x16,NO_ALGIN);//显示左箭头
    	OLED_Display_Image(97,4,16,16,(char*)Right_16x16,NO_ALGIN);//显示右箭头
    	OLED_Display_Image(0,6,16,16,(char*)Enter_16x16,NO_ALGIN);//显示确定
    	OLED_Display_Image(112,6,16,16,(char*)Back_16x16,NO_ALGIN);//显示返回箭头
    	switch(page_index)
    	{
    		case _Wifi_Option:OLED_Display_Image(0,2,48,48,(char*)Wifi_48x48,CEN_ALIGN);//显示Wifi图标
    						 break;
    		case _Bluetooth_Option:OLED_Display_Image(0,2,48,48,(char*)Bluetooth_48x48,CEN_ALIGN);//显示蓝牙图标
    						 break;
    		case _Setting_Option:OLED_Display_Image(0,2,48,48,(char*)Setting_48x48,CEN_ALIGN);//显示设置图标
    						 break;
    		case _Info_Option:OLED_Display_Image(0,2,48,48,(char*)Info_48x48,CEN_ALIGN);//显示关于信息图标
    						 break;
    		default:break;
    	}
    }
    
    
    /*
    函数功能:Wifi选项子菜单
    参数:u8 page_index,u8 key_val
    返回值:无
    */
    void Wifi_Child(u8 page_index,u8 key_val)
    {
    	static u8 cur_pos=1;
    	static u8 wifi_status=ON;
    	static u8 wifi_mode=SoftAP_Station;
    	static u8 esp_tcpserver=OFF;
    	static u8 esp_unvarnishedmode=OFF;
    	if(last_index!=_Wifi_Option)//判断是否是第一次进入此界面
    	{
    		switch(key_val)
    		{
    			case KEY_PREVIOUS: cur_pos==1?cur_pos=6:cur_pos--;
    					break;
    			case KEY_ENTER://确定(设置)按键
    			{
    				switch(cur_pos)
    				{
    					case 1:wifi_status=!wifi_status;
    							if(wifi_status==OFF)
    							{
    								esp_tcpserver=OFF;
    								esp_unvarnishedmode=OFF;
    							}
    							break;
    					case 2:if(wifi_status==ON)
    							{
    								wifi_mode==SoftAP_Station?wifi_mode=Station:wifi_mode++;
    								esp_tcpserver=OFF;
    								esp_unvarnishedmode=OFF;
    							}
    							break;
    					case 3:if(wifi_status==ON&&esp_unvarnishedmode==OFF&&
    							(wifi_mode==SoftAP_Station||wifi_mode==SoftAP))esp_tcpserver=!esp_tcpserver;
    							break;
    					case 4:if(wifi_status==ON&&esp_tcpserver==OFF&&
    							(wifi_mode==SoftAP_Station||wifi_mode==Station))esp_unvarnishedmode=!esp_unvarnishedmode;
    							break;
    					case 5:
    							break;
    					case 6:
    							break;
    					default:break;
    				}
    			}
    					break;
    			case KEY_NEXT:cur_pos==6?cur_pos=1:cur_pos++;
    					break;
    			default:break;
    		}
    	}
    	else cur_pos=1;//第一次进入此界面,界面指针清零
    	if(cur_pos<=4)
    	{
    		OLED_Display_String(0,0,8,16,wifi_status?"1.Switch:ON":"1.Switch:OFF",cur_pos==1?REVERSE:NORMAL,NO_ALGIN);
    		OLED_Display_String(0,2,8,16,wifi_mode==SoftAP_Station?"2.Mode:AP+STA":wifi_mode==SoftAP?"2.Mode:AP":"2.Mode:STA",cur_pos==2?REVERSE:NORMAL,NO_ALGIN);
    		OLED_Display_String(0,4,8,16,esp_tcpserver?"3.TCP server:ON":"3.TCP server:OFF",cur_pos==3?REVERSE:NORMAL,NO_ALGIN);
    		OLED_Display_String(0,6,8,16,esp_unvarnishedmode?"4.Mqtt mode:ON":"4.Mqtt mode:OFF",cur_pos==4?REVERSE:NORMAL,NO_ALGIN);
    	}
    	else if(cur_pos<=8)
    	{
    		OLED_Display_String(0,0,8,16,"5.RSSI:",cur_pos==5?REVERSE:NORMAL,NO_ALGIN);
    		OLED_Display_String(0,2,8,16,"6.Esp touch",cur_pos==6?REVERSE:NORMAL,NO_ALGIN);
    	}
    }
    
    
    /*
    函数功能:蓝牙选项子菜单
    参数:u8 page_index,u8 key_val
    返回值:无
    */
    void Bluetooth_Child(u8 page_index,u8 key_val)
    {
    	static u8 cur_pos=1;
    	static u8 BL_status=ON;
    	if(last_index!=_Bluetooth_Option)//判断是否是第一次进入此界面
    	{
    		switch(key_val)
    		{
    			case KEY_PREVIOUS: cur_pos==1?cur_pos=4:cur_pos--;
    					break;
    			case KEY_ENTER://确定(设置)按键
    			{
    				switch(cur_pos)
    				{
    					case 1:BL_status=!BL_status;
    							break;
    					case 2:
    							break;
    					case 3:
    							break;
    					case 4:
    							break;
    					default:break;
    				}
    			}
    					break;
    			case KEY_NEXT:cur_pos==4?cur_pos=1:cur_pos++;
    					break;
    			default:break;
    		}
    	}
    	else cur_pos=1;//第一次进入此界面,界面指针清零
    	OLED_Display_String(0,0,8,16,BL_status?"1.Switch:ON":"1.Switch:OFF",cur_pos==1?REVERSE:NORMAL,NO_ALGIN);
    	OLED_Display_String(0,2,8,16,"2.Addr match",cur_pos==2?REVERSE:NORMAL,NO_ALGIN);
    	OLED_Display_String(0,4,8,16,"3.RSSI:",cur_pos==3?REVERSE:NORMAL,NO_ALGIN);
    	OLED_Display_String(0,6,8,16,"4.Mode set",cur_pos==4?REVERSE:NORMAL,NO_ALGIN);
    }
    
    
    /*
    函数功能:设置选项子菜单
    参数:u8 page_index,u8 key_val
    返回值:无
    */
    void Setting_Child(u8 page_index,u8 key_val)
    {
    	char buff[20];
    	static u8 cur_pos=1;
    	static u8 Remote_form=0;
    	static u8 EEPROM_swi=ON;
    	static u8 Bri_level=8;
    	if(last_index!=_Setting_Option)//判断是否是第一次进入此界面
    	{
    		switch(key_val)
    		{
    			case KEY_PREVIOUS: cur_pos==1?cur_pos=6:cur_pos--;
    					break;
    			case KEY_ENTER://确定(设置)按键
    			{
    				switch(cur_pos)
    				{
    					case 1:
    							break;
    					case 2:Remote_form==2?Remote_form=0:Remote_form++;
    							break;
    					case 3:Bri_level==16?Bri_level=1:Bri_level++;
    						   OLED_SPI_WriteByte(0x81,OLED_CMD);//设置对比度
    						   OLED_SPI_WriteByte(Bri_level*16-1,OLED_CMD);
    							break;
    					case 4:BEEP_swi=!BEEP_swi;
    							break;
    					case 5:EEPROM_swi=!EEPROM_swi;
    							break;
    					case 6:
    							break;
    					default:break;
    				}
    			}
    					break;
    			case KEY_NEXT:cur_pos==6?cur_pos=1:cur_pos++;
    					break;
    			default:break;
    		}
    	}
    	else cur_pos=1;//第一次进入此界面,界面指针清零
    	
    	if(cur_pos<=4)
    	{
    		OLED_Display_String(0,0,8,16,"1.Calib time",cur_pos==1?REVERSE:NORMAL,NO_ALGIN);
    		OLED_Display_String(0,2,8,16,Remote_form==0?"2.Remote:NRF2.4G":Remote_form==1?"2.Remote:Wi-Fi":"2.Remote:BL",cur_pos==2?REVERSE:NORMAL,NO_ALGIN);
    		snprintf(buff,sizeof(buff),"3.Bri set:%d",Bri_level);//显示亮度
    		OLED_Display_String(0,4,8,16,buff,cur_pos==3?REVERSE:NORMAL,NO_ALGIN);
    		OLED_Display_String(0,6,8,16,BEEP_swi?"4.BEEP:ON":"4.BEEP:OFF",cur_pos==4?REVERSE:NORMAL,NO_ALGIN);
    	}
    	else if(cur_pos<=8)
    	{
    		OLED_Display_String(0,0,8,16,EEPROM_swi?"5.EEPROM:ON":"5.EEPROM:OFF",cur_pos==5?REVERSE:NORMAL,NO_ALGIN);
    		OLED_Display_String(0,2,8,16,"6.Low Power",cur_pos==6?REVERSE:NORMAL,NO_ALGIN);
    	}
    	
    
    }
    /*
    函数功能:关于信息页
    参数:u8 page_index,u8 key_val
    返回值;无
    */
    void Info_Child(u8 page_index,u8 key_val)
    {
    	char buff[20];
    	snprintf(buff,sizeof(buff),"1.BAT vol:%.2f V",BAT_Voltage*2);//分压比为2
    	OLED_Display_String(0,0,8,16,buff,NORMAL,NO_ALGIN);
    	OLED_Display_String(0,3,8,16,"2.Version:v1.0",NORMAL,NO_ALGIN);
    }
    /*
    函数功能:OLED熄屏
    参数:u8 page_index,u8 key_val
    返回值;无
    */
    void OLED_Lock(u8 page_index,u8 key_val)
    {
    	OLED_Clear(0);
    }
    
    展开全文
  • STM32 OLED多级菜单显示

    2018-04-03 16:02:23
    基于STM32单片机,使OLED液晶显示屏进行多级菜单显示。
  • STM32 oled多级菜单显示

    千次阅读 多人点赞 2021-03-05 16:41:54
    只要有显示屏的地方,就要用到多级菜单的显示。在很多初学者眼里,多级菜单的显示是很难的,今天我做完了这个小项目,我就来分享一下我做的经历。 首先肯定的是,只要理清思路,就不怕多级菜单显示很难。先上几张...

    前言

          只要有显示屏的地方,就要用到多级菜单的显示。在很多初学者眼里,多级菜单的显示是很难的,今天我做完了这个小项目,我就来分享一下我做的经历。OELD采用中景园0.78寸分辨率128*80。

    首先肯定的是,只要理清思路,就不怕多级菜单显示很难。先上几张照片看看我的显示。

                                   一级菜单

     

                                 二级菜单

      

     

                                 三级菜单

     

                                    四级菜单

    1. 硬件设备:STM32F103C8T6+0.78寸OLED IIC连接方式 两个独立按键
    2. 原理图与PCB图纸:https://gitee.com/zhu_yu_yang/stm32_-oled_-board_-v2.1

    程序实现

    我学的多级菜单显示是多个界面的跳转,这个比较适合初学者。我的硬件上有两个按键,一个主要用来切换选项,另一个用来确定选项。所以我们暂时叫他next键enter键。先定义一个结构体,结构体里面有四个变量,分别代表当前索引号,next键,enter键当前执行函数。我这里只有两个按键,所以这样定义了。假如你有三个按键,你就把另一个按键当做向上动作。假如你有四个按键,另外两个按键分别代表 向上返回。这样你就有向上,向下,返回和确定四个功能键。那你的结构体定义的时候就要增加成员变量了。这里以两个按键为例,分别代表向下动作和确定动作。结构体如下:

    typedef struct
    {
        uint8_t current;//当前状态索引号
        uint8_t next; //向下一个
        uint8_t enter; //确定
        void (*current_operation)(void); //当前状态应该执行的操作
    } Menu_table;

    这里是核心思想,就是按键按下决定当前的索引号,继续定义一个数组:

    Menu_table  table[13]=
    {
        {0,0,1,(*fun0)},//一级界面  时钟界面
        {1,2,6,(*fun1)},//二级界面第一行 CAN Mode
        {2,3,7,(*fun2)},//二级界面第二行 485 Mode
        {3,4,8,(*fun3)},//二级界面第三行 UART Mode
        {4,2,0,(*fun4)},//二级界面第四行 BACK


        {5,6,4,(*fun5)},//三级界面第一行 back

        {6,7,x,(*fun6)},//三级界面第二行 //x,y,z代表四级界面的索引号,在这篇文章里没有详细列出。

        {7,8,y,(*fun7)},//三级界面第三行 

        {8,5,z,(*fun8)},//三级界面第四行 
    };

    uint8_t  func_index = 0;//主程序此时所在界面的索引值
     

    这里解释一下这个数组中 {0,0,1,(*fun0)},//一级界面  时钟界面 ,由于我们在前面先定义了Menu_table结构体,结构体成员变量分别为当前索引号,next,enter和void (*current_operation)(void),第一的0代表当前的索引号,第二个0代表next这个按键按下返回的索引号,第三个1代表enter按键按下返回的索引号。第三个(*fun0)代表索引号为0要执行的函数。一一对应。再结合按键按下的画面就比较有逻辑了。

    再来就是按键按下需要处理的函数

    void  Menu_key_set(void)
    {
      Get_key_next = get_button(button1);
      Get_key_enter = get_button(button2);
      if(Get_key_next == 1)
      {   
        func_index=table[func_index].next;//按键next按下后的索引号
        OLED_Clear();
      }
      if(Get_key_enter == 1)
      {
        func_index=table[func_index].enter;
        OLED_Clear();
      }

      current_operation_index=table[func_index].current_operation;//执行当前索引号所对应的功能函数。
      (*current_operation_index)();//执行当前操作函数
    }
     

    这里解释一下,比如在二级菜单中,分别为 :

    1.CAN Mode

    2.485 Mode

    3.UART mode

    4.BACK

    那么,在一级菜单跳到二级菜单的时候,光标应该在1.CAN Mode 这里,而此时假设按键next按下就要执行光标移动到2.485 Mode 上,假设按键enter按下就要跳转到三级菜单中的第一行。所以,next按键按下就要返回2.485 Mode前面的索引号,程序在根据索引号执行相应的光标移到程序,造成光标在第一行移动到第二行的现象。光标在4.BACK上 按下next 就跳转到1.CAN Mode,只要令此时next键按下返回的索引号是CAN Mode的索引号就行。再索引号所对应的函数里执行光标移到的函数就行。多个按键也是这样的原理。

     

    以上是我对多级菜单的理解,其中还有很多是一知半解,如果有误,欢迎指正。

    我自己画的PCB 原理图与PCB图纸和程序源码:https://gitee.com/zhu_yu_yang/stm32_-oled_-board_-v2.1

    另外参考了:https://blog.csdn.net/calmuse/article/details/79346742

    如果转载,请标明出处。

     

    展开全文
  • 旋转编码开关EC11有一个按键和AB相编码输出,通过相位变化来判断顺时针还是逆时针旋转,由编码产生外部中断配合STM32进行解析,本程序采用软件滤波,得到的编码值直接控制0.96寸OLED多级菜单显示
  • 多级菜单思路,不限OLED,不止Arduino

    摇杆操作OLED多级菜单

    随着越来越多的人机交互需求,带有屏幕的嵌入式设备需要展示的信息也越来越多,多种菜单随着按键输入进行各种深入、各种切换操作。如何方便的管理不同菜单之间的切换操作呢?本篇通过实验来介绍多级菜单的实现思路。

    1. 多级菜单介绍

    在各种屏幕操作中,多级菜单其实是一种思路或者说是一种固定的编程框架。简单来说就是当按键触发时,根据按键定义从数组中取出当前按键需要跳转的界面索引,然后根据索引去执行响应的界面函数。

    2. 具体实现

    1. 首先,我们要定义一个结构体,结构体成员变量一般包括界面索引号、界面函数指针和与实际按键对应的变量,用来存储按键表示的索引号。其中,索引号与界面函数指针是对应的。

    typedef struct
    {
      unsigned char index;
      unsigned char up;
      unsigned char down;
      unsigned char left;
      unsigned char right;
      void (*operation)(void);
    } KEY_TABLE;
    

    本实验中定义了四个按键,故定义了up、down、left、right四个按键变量。

    2. 使用定义的结构体类型来定义一个结构体数组,有多少个界面,数组的元素个数就是多少。

    KEY_TABLE table[9] =
    {
      {0, 0, 0, 0, 0, (*menu11)},
      {1, 0, 0, 0, 0, (*menu12)},
      {2, 0, 0, 0, 0, (*menu21)},
      {3, 0, 0, 0, 0, (*menu22)},
      {4, 0, 0, 0, 0, (*menu23)},
      {5, 0, 0, 0, 0, (*menu31)},
      {6, 0, 0, 0, 0, (*menu32)},
      {7, 0, 0, 0, 0, (*menu33)},
      {8, 0, 0, 0, 0, (*menu34)},
    };
    

    本实验中定义了9个界面,所以如上数组元素有9个,其中界面索引号从0到8,分别对应其界面函数指针。本实验中一级菜单有2个,二级菜单有3个,三级菜单有4个。

    3. 确定各按键按下需要跳转的界面索引。这一步骤确定了各界面之间的切换关系,非常重要。在此之前可以通过草图来整理菜单之间切换关系,如下所示为本实验9个界面之间的关联图。

    多级菜单结构

    举几个例子:

    在index为0,即menu11界面下,确定{0, 0, 0, 0, 0, (*menu11)}中四个按键变量的值:

    • 当按下up键时,显示menu11界面,即index为0的界面,那么此时up=0;
    • 当按下down键时,显示menu12界面,即index为1的界面,那么此时down=1;
    • 当按下left键时,显示menu11界面,即index为0的界面,那么此时down=0;
    • 当按下right键时,显示menu21界面,即index为2的界面,那么此时down=2;

    故得到{0, 0, 1, 0, 2, (*menu11)}

    在index为5,即menu31界面下,确定{5, 0, 0, 0, 0, (*menu31)}中四个按键变量的值:

    • 当按下up键时,显示menu31界面,即index为5的界面,那么此时up=5;
    • 当按下down键时,显示menu32界面,即index为6的界面,那么此时down=6;
    • 当按下left键时,显示menu21界面,即index为2的界面,那么此时down=2;
    • 当按下right键时,显示menu31界面,即index为5的界面,那么此时down=5;

    故得到{5, 5, 6, 2, 5, (*menu31)}

    各个界面之间的跳转关系根据实际的需求进行确立,如下为本实验中完整的结构体数组变量赋值情况。

    KEY_TABLE table[9] =
    {
      {0, 0, 1, 0, 2, (*menu11)},
      {1, 0, 1, 1, 4, (*menu12)},
      {2, 2, 3, 0, 5, (*menu21)},
      {3, 2, 3, 0, 7, (*menu22)},
      {4, 4, 4, 1, 4, (*menu23)},
      {5, 5, 6, 2, 5, (*menu31)},
      {6, 5, 6, 2, 6, (*menu32)},
      {7, 7, 8, 3, 7, (*menu33)},
      {8, 7, 8, 3, 8, (*menu34)},
    };
    

    4. 根据实际按键返回值对应的功能,获取按键对应的界面索引号,然后根据索引号找到并执行对应的界面函数。

    switch (keyValue)//获取按键对应序号
        {
          case 1: funIndex = table[funIndex].right; break;
          case 2: funIndex = table[funIndex].left; break;
          case 3: funIndex = table[funIndex].down; break;
          case 4: funIndex = table[funIndex].up; break;
        }
    current = table[funIndex].operation;//根据需要获取对应需要执行的函数
    (*current)();//执行获取到的函数
    

    3. 实验材料

    • Uno R3开发板
    • 配套USB数据线
    • 面包板及配套连接线
    • 双轴按键摇杆模块
    • OLED显示屏

    4. 实验步骤

    1. 根据原理图搭建电路图。

    OLED屏的VCC、GND分别连接开发板的3.3V、GND,OLED屏的SDA和SCL分别连接开发板的A4和A5。双轴按键摇杆模块的VCC、GND分别连接开发板的5V、GND,模块的X轴输出、Y轴输出分别连接开发板的模拟引脚A0、A1。

    实验原理图如下图所示:

    实验原理图

    实物连接图如下图所示:

    实物连接图

    2. 新建sketch,拷贝代码替换自动生成的代码并进行保存。

    由于代码较长,完整代码可在文末获取。

    3. 连接开发板,设置好对应端口号和开发板类型,进行程序下载。

    程序下载

    5. 实验现象

    多界面切换效果:

    实验现象


    关注公众号「TonyCode」,后台回复“提高”,获取文中代码。
    Arduino学习交流群:868283450
    更多内容,欢迎关注我的公众号。 微信扫一扫下方二维码即可关注:
    扫码加入微信公众号:TonyCode

    展开全文
  • 自己使用的 OLED 多级菜单实现方式

    千次阅读 2019-02-17 19:14:36
    菜单选项的移动方式类似于 windows 文件管理器中的文件选择方式(查看方式为图标方式),目前实现了菜单翻页功能,只读页面翻页显示功能,数值修改功能等,思路就是把所有选项看成一整列,但是一整列里面分成多行多...
  • oled多级菜单实现方法

    万次阅读 多人点赞 2016-05-26 18:52:50
    1、首先定义一个机构体如下 typedef struct  {  unsigned char current;  unsigned chaup;//上键  unsigned chadown;//下键  unsigned chaenter;//确认键  void (*current_operation)();... } key_ta
  • 制作航模遥控器需要用到多级菜单,参考了很多博客的实现方式,最终采用了这种树形拓扑结构。这种实现方式便于扩充,容易移植和理解,现把菜单的完整框架整理如下,希望能给读者带来帮助。
  • 通过树结构连接多级菜单的每一项。 其优点是能够非常简便快捷地制作出需要的菜单,只需要在main.c中反复调用一个函数来添加一级菜单、另一个函数来添加这一级菜单中的项目。 OLED_MultiMenu.c内容 #include ...
  • 该项目已上传至github,欢迎访问:github 最终效果图如下 示例代码: from ssd1306 import SSD1306_I2C from machine import I2C import menu oled_iic=I2C(scl='B15',sda='D9') #...oled=SSD1306_I2C(128,64,oled_ii...
  • oled显示 多级菜单显示 原创文章 39获赞 12访问量 4026 关注 私信 展开阅读全文 作者:IT老翟
  • 0.96寸OLED(四)多级菜单实现

    千次阅读 多人点赞 2021-02-06 19:29:05
    本次是基于0.96寸OLED多级菜单设计,找了一下网上的菜单写法,发现很多是那种利用一个数组记录界面的,我觉得这样不是很直观。我希望写成那种可以不断延伸拓展的界面,界面数量,菜单级数可以任意指定的类型。 就...

空空如也

空空如也

1 2 3 4 5 6
收藏数 105
精华内容 42
关键字:

oled多级菜单