原创:用于单片机的轻量级菜单

 
有时要用单片机写一些大点的程序,但又没必要使用一些操作系统的时候,我写出了下面这种轻量级菜单状态机,配备一个显示设备加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
View Code

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");
}    
View Code

注释乱码,渣keil,函数的英文名写的挺清楚的也能看

posted on 2015-03-30 23:34  =Interact=  阅读(2722)  评论(1编辑  收藏  举报