STM32中实现OLED多级菜单(支持修改参数)

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);
}
实现 stm32f407oled 多级菜单的一个简单方法是使用 OLED 显示屏和按键。以下是实现步骤: 1. 初始化 OLED 显示屏和按键,设置按键断。 2. 定义多级菜单的数据结构,包括菜单名称、子菜单个数、子菜单指针等信息。 3. 在主函数初始化所有菜单,并设置当前菜单指针为根菜单。 4. 在按键,根据按键的不同操作,更新当前菜单指针,并显示当前菜单的内容。 5. 在菜单项执行时,根据菜单项的不同操作,执行相应的函数或者切换到子菜单。 以下是基本代码示例: ```c #include "oled.h" #include "key.h" // 菜单项操作函数 void menu1_func(); void menu2_func(); void menu3_func(); // 菜单项数据结构 typedef struct { char *name; // 菜单名称 int sub_menu_cnt; // 子菜单个数 struct menu_item *sub_menus; // 子菜单指针 void (*func)(); // 菜单项操作函数 } menu_item; // 菜单数据结构 menu_item root_menu = {"Root", 3, NULL, NULL}; menu_item menu1 = {"Menu 1", 0, NULL, menu1_func}; menu_item menu2 = {"Menu 2", 0, NULL, menu2_func}; menu_item menu3 = {"Menu 3", 0, NULL, menu3_func}; // 初始化所有菜单 void init_menu() { root_menu.sub_menus = (menu_item *)malloc(sizeof(menu_item) * root_menu.sub_menu_cnt); root_menu.sub_menus[0] = menu1; root_menu.sub_menus[1] = menu2; root_menu.sub_menus[2] = menu3; } // 当前菜单指针 menu_item *cur_menu = &root_menu; // 按键断处理函数 void EXTI0_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line0) != RESET) { delay_ms(20); // 消抖 if (KEY0 == 0) // 按键按下 { cur_menu = cur_menu->sub_menus[0]; // 进入子菜单 OLED_Clear(); OLED_ShowString(0, 0, cur_menu->name, 16); OLED_ShowString(0, 2, "1. Menu 1", 16); OLED_ShowString(0, 4, "2. Menu 2", 16); OLED_ShowString(0, 6, "3. Menu 3", 16); } EXTI_ClearITPendingBit(EXTI_Line0); } } int main(void) { OLED_Init(); KEY_Init(); init_menu(); OLED_ShowString(0, 0, cur_menu->name, 16); OLED_ShowString(0, 2, "1. Menu 1", 16); OLED_ShowString(0, 4, "2. Menu 2", 16); OLED_ShowString(0, 6, "3. Menu 3", 16); while (1) { // 主循环 } } void menu1_func() { // 执行菜单项操作 } void menu2_func() { // 执行菜单项操作 } void menu3_func() { // 执行菜单项操作 } ``` 以上代码只是一个简单示例,可以根据实际需求进行修改和完善。
评论 49
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fog.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值