原创:用于单片机的轻量级菜单
有时要用单片机写一些大点的程序,但又没必要使用一些操作系统的时候,我写出了下面这种轻量级菜单状态机,配备一个显示设备加5个输入(上下左右和按下)
先看看效果图
上面的 ABC, BCD,EFG分别是一个菜单列表的菜单
菜单的结构框图为
对于单个菜单的结构为
对于每个菜单,分别有指向它上面的菜单,下面的菜单,它的子菜单,它的父菜单,它的菜单列表,和这个菜单对应执行的函数的指针
对于一组菜单列表为
使用非常方便,我们来看下对于刚才效果图所展示的菜单的使用
首先定义有几个菜单列表
和一个指向当前状态的菜单
菜单的初始化
首先先给每个菜单列表里添加相应的菜单
然后把各个菜单列表连接起来
上图中RefreshMenu函数是根据CurrentMenu来刷新液晶屏的,这个要各位自己实现
然后再主函数里不停的执行
MenuHandler是这样处理得到的按键的
以上只给出了如何使用
其实还有些函数如 获得当前菜单为当前菜单列表中第几项 等子函数没列出来,这些通过都是链表的指针实现的
贡献出代码
头文件
#ifndef _MENU_H #define _MENU_H #include "sys.h" #define IndexType unsigned char //¶¨Òå²Ëµ¥Ë÷ÒýºÅÀàÐÍ #define MenuStringLengh 15 #define MaxMenuLengh 9 struct MenuType { struct MenuType *UpMenu; struct MenuType *DownMenu; struct MenuType *NextMenu; //¸Ã²Ëµ¥¶ÔÓ¦µÄ×Ӳ˵¥ struct MenuType *BackMenu; //Éϼ¶²Ëµ¥µÄ²Ëµ¥Ïî struct MList *CurrentMuenList; //Ö¸Ïòµ±Ç°²Ëµ¥Áбí char Context[MenuStringLengh]; //µ±Ç°²Ëµ¥¶ÔÓ¦µÄÎı¾ void (*function)(); //µ±Ç°²Ëµ¥Ïî¶ÔÓ¦µÄº¯Êý }; //MenuType; typedef struct MList { int MenuLengh; //²Ëµ¥ÖÐÓжàÉٲ˵¥Ïî int MenuLevel; //²Ëµ¥µÄ²ã¼¶£¬Ö÷²Ëµ¥Îª1£¬Ö÷²Ëµ¥µÄ×Ӳ˵¥Îª2£¬ÀàÍÆ struct MenuType *FirstMenu; struct MenuType *LastMenu; } MenuList; void MenuInit(void); void MenuHandler(u8 key); void RefreshMenu(void); #endif
C文件
#include "menu.h" #include "stdlib.h" #include "lcd.h" #include "key.h" #include "delay.h" #include "string.h" #include "menufunction.h" MenuList MainMenu={0,0,0,0}; MenuList SubMenu={0,0,0,0}; MenuList level3Menu1={0,0,0,0}; MenuList level3Menu2={0,0,0,0}; MenuList level2Menu1={0,0,0,0}; MenuList level4Menu1={0,0,0,0}; void functiontest1(void); void functiontest2(void); struct MenuType *CurrentMenu; //´ÓÒ»¸ö²Ëµ¥ÁбíÖлñµÃÒ»¸ö²Ëµ¥ struct MenuType* GetMenuFromList(MenuList *mymenulist,u8 index) { struct MenuType *t = mymenulist->FirstMenu;; if(index <= mymenulist->MenuLengh && index>0 ) { while(--index) { t = t->DownMenu; } return t; } return 0; } //µÃµ½µ±Ç°²Ëµ¥ÔÚµ±Ç°²Ëµ¥ÁбíÖеĵڼ¸Ïî u8 GetMenuIndexFromList(struct MenuType *mymenu) { u8 res = 1; if(mymenu->CurrentMuenList != 0) { while(mymenu->UpMenu != 0) { res++; mymenu = mymenu->UpMenu; } return res; } return 0; } //°ÑÒ»¸ö²Ëµ¥Ìí¼Óµ½²Ëµ¥ÁбíÀï void AddMenu(MenuList *mymenulist, char *text, void (*fun)()) { struct MenuType *t; int i=0; t = (struct MenuType *)malloc(sizeof(struct MenuType)); t->function = fun; t->CurrentMuenList = mymenulist; while(*text!='\0') { t->Context[i] = *text; i++; text++; } t->Context[i] = '\0'; if(mymenulist->MenuLengh == 0) { mymenulist->FirstMenu = t; mymenulist->LastMenu = t; } else { t->UpMenu = mymenulist->LastMenu; mymenulist->LastMenu->DownMenu = t; mymenulist->LastMenu = t; } mymenulist->MenuLengh++; } //°ÑÒ»¸ö²Ëµ¥ÁбíÌí¼ÓΪһ¸ö²Ëµ¥µÄ×Ӳ˵¥ void MenuLinkMenulist(struct MenuType *mymenu, MenuList *mymenulist) { u8 i; struct MenuType *t = mymenulist->FirstMenu; if(mymenulist->MenuLengh != 0) { mymenu->NextMenu = mymenulist->FirstMenu; for(i=0;i<mymenulist->MenuLengh;i++) { t->BackMenu = mymenu; t = t->DownMenu; } } } void MenuInit(void) { AddMenu(&MainMenu,"ABC",0); AddMenu(&MainMenu,"BCD",0); AddMenu(&MainMenu,"EFG",functiontest1); MainMenu.MenuLevel = 1; AddMenu(&SubMenu,"sub1",0); AddMenu(&SubMenu,"sub2",functiontest2); SubMenu.MenuLevel = 2; AddMenu(&level3Menu1,"ZJY",0); AddMenu(&level3Menu1,"XZ",0); AddMenu(&level3Menu1,"WT",0); AddMenu(&level3Menu1,"LY",0); level3Menu1.MenuLevel = 3; AddMenu(&level3Menu2,"DDG",0); AddMenu(&level3Menu2,"LMY",0); AddMenu(&level3Menu2,"LLY",0); AddMenu(&level3Menu2,"CYH",0); AddMenu(&level3Menu2,"ZQC",0); level3Menu2.MenuLevel = 3; AddMenu(&level2Menu1,"LLL1",0); AddMenu(&level2Menu1,"LLL2",0); AddMenu(&level2Menu1,"LLL3",0); AddMenu(&level2Menu1,"SendNum",PrintNumApp); level2Menu1.MenuLevel = 2; AddMenu(&level4Menu1,"level4",0); AddMenu(&level4Menu1,"LEVEL4",0); level4Menu1.MenuLevel = 4; MenuLinkMenulist(GetMenuFromList(&MainMenu,2),&SubMenu); MenuLinkMenulist(GetMenuFromList(&MainMenu,3),&level2Menu1); MenuLinkMenulist(GetMenuFromList(&SubMenu,1),&level3Menu1); MenuLinkMenulist(GetMenuFromList(&level2Menu1,3),&level3Menu2); MenuLinkMenulist(GetMenuFromList(&level3Menu2,4),&level4Menu1); CurrentMenu = MainMenu.FirstMenu; RefreshMenu(); } void ShowCurrentMenu(void) { LCD_ShowString(0,300," "); LCD_ShowString(0,300,"Current:"); LCD_ShowString(64,300,(u8 *)CurrentMenu->Context); } void MenuHandler(u8 key) { switch(key) { case KEY_UP: if(CurrentMenu->UpMenu != 0) { CurrentMenu = CurrentMenu->UpMenu; RefreshMenu(); } break; case KEY_DOWN: if(CurrentMenu->DownMenu != 0) { CurrentMenu = CurrentMenu->DownMenu; RefreshMenu(); } break; case KEY_LEFT: if(CurrentMenu->BackMenu != 0) { CurrentMenu = CurrentMenu->BackMenu; RefreshMenu(); } break; case KEY_RIGHT: if(CurrentMenu->NextMenu != 0) { CurrentMenu = CurrentMenu->NextMenu; RefreshMenu(); } break; case KEY_PRESS: if(CurrentMenu->function != 0) { CurrentMenu->function(); RefreshMenu(); } break; } } //ÏÔʾһ¸ö²Ëµ¥Áбí //x ÏÔʾ²Ëµ¥ÔÚX·½ÏòµÄ×ø±ê void ShowMenuList(MenuList *mymenulist,unsigned int x) { int i; unsigned int stringlengh; unsigned int startX; struct MenuType *t = mymenulist->FirstMenu; POINT_COLOR=BLACK; for(i=0;i<mymenulist->MenuLengh;i++) { stringlengh = strlen(t->Context); startX = x + 40-stringlengh*4; startX = startX<x ? x : startX ; LCD_ShowString(startX,20+20*i,(u8 *)t->Context); //ÏÔʾ²Ëµ¥×Ö·û´® LCD_DrawRectangle(x,20+20*i,x+80,40+20*i); //»²Ëµ¥Ïî·½¿ò if(t->NextMenu != 0) { LCD_DrawLine(x+75,27+20*i,x+75,33+20*i); LCD_DrawLine(x+76,28+20*i,x+76,32+20*i); LCD_DrawLine(x+77,29+20*i,x+77,31+20*i); LCD_DrawLine(x+78,30+20*i,x+78,30+20*i); } t = t->DownMenu; } POINT_COLOR=RED; } //¸ßÁÁµ±Ç°²Ëµ¥ //x ÏÔʾ²Ëµ¥ÏîÔÚX·½ÏòµÄ×ø±ê void HighLightMenu(struct MenuType *mymenu,unsigned int x) { unsigned int stringlengh; unsigned int startX; struct MenuType *t = mymenu; u8 index; index = GetMenuIndexFromList(t); stringlengh = strlen(mymenu->Context); startX = x + 40-stringlengh*4; startX = startX<x ? x : startX ; LCD_Fill(x+1,index*20+1,x+79,index*20+19,BLUE); BACK_COLOR = BLUE; POINT_COLOR=WHITE; LCD_ShowString(startX,20*index+1,(u8 *)t->Context); if(t->NextMenu != 0) { LCD_DrawLine(x+75,7+20*index,x+75,13+20*index); LCD_DrawLine(x+76,8+20*index,x+76,12+20*index); LCD_DrawLine(x+77,9+20*index,x+77,11+20*index); LCD_DrawLine(x+78,10+20*index,x+78,10+20*index); } POINT_COLOR=RED; BACK_COLOR = WHITE; } //¸ù¾Ýµ±Ç°×´Ì¬Ë¢Ð²˵¥½çÃæ void RefreshMenu(void) { u8 currentlevel = 0; struct MenuType *t = CurrentMenu; LCD_Fill(0,20,240,200,WHITE); //»æÖƵ±Ç°´ò¿ªµÄ²Ëµ¥ currentlevel = t->CurrentMuenList->MenuLevel; if(currentlevel == 0) { LCD_ShowString(60,40,"MenuLevelError"); } else { currentlevel = currentlevel>3 ? 3 : currentlevel; do { ShowMenuList(t->CurrentMuenList, currentlevel*80-80); t = t->BackMenu; currentlevel--; } while(currentlevel>0); //¸ßÁÁµ±Ç°Ñ¡ÖеIJ˵¥ t = CurrentMenu; currentlevel = t->CurrentMuenList->MenuLevel; currentlevel = currentlevel>3 ? 3 : currentlevel; do { HighLightMenu(t,currentlevel*80-80); t = t->BackMenu; currentlevel--; } while(currentlevel>0); } } void functiontest1() { LCD_ShowString(60,180,"testfunction1"); } void functiontest2() { LCD_ShowString(60,180,"testfunction2"); }
注释乱码,渣keil,函数的英文名写的挺清楚的也能看