【实用模板】【原创】基于树结构的OLED多级菜单(STM32RCT6)

效果图:

经过调整,解决了频闪问题,菜单用得很顺畅。

最上面一行显示这一级菜单的标题。

通过STM32自带的三个按键(KEY0,KEY1,WK_UP)分别作为“下一项”,“确认”和“返回”。

OLED_MultiMenu.c为本人编写的文件,只需加入到正点原子官方OLED例程中即可使用。

【实用模板】【原创】基于树结构的OLED多级菜单(STM32RCT6)_第1张图片

通过树结构连接多级菜单的每一项。

其优点是能够非常简便快捷地制作出需要的菜单,只需要在main.c中反复调用一个函数来添加一级菜单、另一个函数来添加这一级菜单中的项目。

OLED_MultiMenu.c内容

#include "OLED_MultiMenu.h"
#include "malloc.h"
#include "string.h"
#include "key.h"

#define row 3  //由于我马上用这个模板去做中文多级菜单了,这里的两个宏定义已无法更改
#define FontSize 2

/*

多级菜单的框架建立:
1.创建根节点
2.创建新的一层(输入层名字和父节点)。
3.在该层创建一项(输入项名字和父节点)。

OLED显示:
1.层名字显示在顶上,项名字在下面。
2.一个函数控制一个可按键移动的指针,函数推动结点的遍历,每按一次执行一次结点自带的函数。


*/

//层结点的函数,列出该层所有的项目,输入的是层结点
TreeNode *OpenMenu(TreeNode *T)
{
	TreeNode *H;
	OLED_CLS();
	OLED_ShowStr(24,0,(unsigned char *)T->Name,2);
	if(T->Num==-1)
	T = T->right->right;
	T = T->right;
	H = T;
	while(T!=NULL && (T->Num-1)/row==(T->left->Num-1)/row)
	{
		OLED_ShowStr(8,2*(1+T->Num)-2,(unsigned char *)T->Name,FontSize);
		T = T->right;
	}
	return H;
}

//项目结点的函数,用于移动指针,输入的是大孩子
TreeNode *Choose_Item(TreeNode *T)
	{
		TreeNode *H;
		H = T;
		
	if((T->Num)==1)//当要去第一个时
	{
		TreeNode *P;
		P = T;
		while(P->right!=NULL)
			P = P->right;
		if(P->Num%row!=0)
			OLED_ShowStr(64,(P->Num%row+1)*2-2,"    ",FontSize);
		else if(P->Num%row==0)
			OLED_ShowStr(64,(row+1)*2-2,"    ",FontSize);
		OLED_ShowStr(64,2,"<---",FontSize);
	}
	
	else if((H->Num-1)/row!=(H->left->Num-1)/row)//
	{
		OLED_ShowStr(64,(row+1)*2-2,"    ",FontSize);
		OLED_ShowStr(64,2,"<---",FontSize);
	}
	
	else if(T->Num%row==0)//当要去最下面一个时
	{
		OLED_ShowStr(64,row*2-2,"    ",FontSize);
		OLED_ShowStr(64,(row+1)*2-2,"<---",FontSize);
	}
	
	else
	{
		OLED_ShowStr(64,(T->Num%row)*2-2,"    ",FontSize);
		OLED_ShowStr(64,((T->Num)%row+1)*2-2,"<---",FontSize);
	}
	
	
	
	if((T->left->Num)%row==0)
	{
		TreeNode *G;
		G = T;
		OLED_ShowStr(0,2,"     ",2);
		OLED_ShowStr(0,4,"     ",2);
		OLED_ShowStr(0,6,"     ",2);
		while(G->Num - T->NumNum%row!=0)
				OLED_ShowStr(8,(1+(G->Num)%row)*2-2,(unsigned char *)G->Name,FontSize);
			else if(G->Num%row==0)
			{
				OLED_ShowStr(8,(row+1)*2-2,(unsigned char *)G->Name,FontSize);
				break;
			}
			G = G->right;
		}
	}
	
	return T;
}


//创建根节点
TreeNode *Root_Init(char Name[20])
{
	TreeNode *R = (TreeNode *)mymalloc(sizeof(TreeNode));//R意为Root,根。
	if(R == NULL)
		return NULL;
	R->front = NULL;
	R->next = NULL;
	R->left = NULL;
	R->right = NULL;
	strcpy(R->Name,Name);
	R->current_fun = NULL;
	R->Grade = 0;
	R->Num = -1;
	return R;
}

//创建新的一层(输入层名字和父节点)
TreeNode *New_Layer(char Name[20],TreeNode *T)
{
	if(T->next!=NULL)                                    //层只能有一个
		return NULL;
	TreeNode *H = (TreeNode *)mymalloc(sizeof(TreeNode));//H意为环节。
	if(H == NULL)
		return NULL;
	H->front = T;
	T->next = H;
	H->next = NULL;
	H->left = NULL;
	H->right = NULL;
	strcpy(H->Name,Name);
	H->current_fun = NULL;
	H->Grade = T->Grade+1;
	H->Num = 0;
	return H;
}

//在该层创建一项(输入项名字和父节点)。
TreeNode *New_Item(char Name[20],TreeNode *T)
{
	
	TreeNode *H = (TreeNode *)mymalloc(sizeof(TreeNode));//H意为环节。
	if(H == NULL)
		return NULL;
	H->front = T;
	H->next = NULL;
	H->left = T;
	T->right = H;
	H->right = NULL;
	strcpy(H->Name,Name);
	H->current_fun = NULL;
	H->Grade = T->Grade;
	H->Num = T->Num+1;
	return H;
}

//按键控制OLED
TreeNode *Key_Control(TreeNode *R)
{
	u8 t;
	t=KEY_Scan(0);		//得到键值
	switch(t)
	{				 
		case KEY0_PRES: //确认按钮
			if(R->next!=NULL)
			{
				R=R->next;
				R = OpenMenu(R);
				R=Choose_Item(R);
			}
			break;
		case KEY1_PRES: //下翻按钮
			if(R->Num==-1 || R->Num==0 )
				break;
			if(R->right==NULL)
			{
				while(R->Num!=1)
					R = R->left;
			}
			else
			{
				R = R->right;
			}
			R=Choose_Item(R);
			break;
			case WKUP_PRES: //返回按钮
			if(R->left->front->Num==-1)
				break;
			if(R->front!=NULL)
			{
				while(R->Num!=0)
				R=R->left;
				if(R->front->Num!=-1)
				{
					R=R->front;
				while(R->Num!=0)
				R=R->left;
				}
				OLED_CLS();	
				R = OpenMenu(R);
				R=Choose_Item(R);
			}
			break;
		default:
			delay_ms(10);	
	}
	return R;
}

 OLED_MultiMenu.h内容

#ifndef __OLED_MULTIMENU_H
#define __OLED_MULTIMENU_H	 
#include "delay.h"
#include "OLED_I2C.h"
#include "sys.h"

typedef struct TreeNode{
	u8 Grade;
	int Num;
	char Name[20];
	struct TreeNode *front,*next,*left,*right;
	void (*current_fun)(void);
}TreeNode;



#define KEY0_PRES	1		//KEY0  
#define KEY1_PRES	2		//KEY1 
#define WKUP_PRES	3		//WK_UP  

TreeNode *Root_Init(char Name[20]);
TreeNode *New_Layer(char Name[20],TreeNode *T);
TreeNode *New_Item(char Name[20],TreeNode *T);
TreeNode *Key_Control(TreeNode *R);
				    
#endif

main.c文件中初始化多级菜单样例:

#include "led.h"
#include "sys.h"
#include "key.h"
#include "stm32f10x.h"
#include "OLED_I2C.h"
#include "delay.h"
#include "OLED_MultiMenu.h"

int main(void)
{
  
	TreeNode *H;
	TreeNode *P;
	TreeNode *P1;
	TreeNode *P11;
	delay_init();	    	 //延时函数初始化	  
	LED_Init();		  	 	//初始化与LED连接的硬件接口
	KEY_Init();
	I2C_Configuration();
	OLED_Init();
	LED0=0;				
	OLED_CLS();	
	H = Root_Init("MultiMenu");//根节点
	P = H;
	H = New_Layer("DIY_Window",H);//第一级菜单名字
	H = New_Item("CYYL",H);
	H = New_Item("LORA",H);
	P1 = New_Layer("LORA-MENU",H);//第一级菜单名字
	P1 = New_Item("AIRS",P1);
	P1 = New_Item("COMM",P1);
	P1 = New_Item("ADDR",P1);
	H = New_Item("LXXN",H);
	P1 = New_Layer("LXXN-MENU",H);//第二级菜单名字
	P1 = New_Item("AJKZ",P1);
	P1 = New_Item("KSSY",P1);
	P11 = New_Layer("LAB-MENU",P1);//第三级菜单名字
	P11 = New_Item("SENS",P11);
	P11 = New_Item("INFO",P11);
	P11 = New_Item("3S",P11);
	H = New_Item("SDKA",H);
	P1 = New_Layer("SDKA-MENU",H);//第一级菜单名字
	P1 = New_Item("USCA",P1);
	P1 = New_Item("SRAM",P1);
	while(1)
	{
		P=Key_Control(P);
		delay_ms(10);
	}		 
}

 

你可能感兴趣的:(OELD,多级菜单,树结构,stm32,c语言)