OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5238|回复: 2

基于增强51设计的12864菜单

[复制链接]

4

主题

24

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
323
金钱
323
注册时间
2016-3-24
在线时间
55 小时
发表于 2017-6-2 21:59:25 | 显示全部楼层 |阅读模式
最近在网上看到了用51单片机和12864设计的菜单,感觉挺好玩,于是也想着做一个来玩一玩。在网上看了一些其他网友分享出来的菜单设计,基本的思想就是定义一个结构体,其中就包含菜单的一些基本项,比如开始序号、结束序号、当前选择项、菜单项目总数、菜单选项文字描述数组等等(只是看了一部分网友分享的一些设计思想,可能说的不太全,忘见谅哈)。如果把菜单项目也一起放进同个结构体里,那么拓展其他二级菜单的话不就会很受限制,就是开辟出来的数组大小我们最起码得先满足的菜单项目比较多的菜单,那么,那些菜单项目比较少的那些开辟出同样大小的数组就显的有点多余,于是在想如果把菜单项目用另外的结构体来定义,再用一个结构体指针指向它就可以了,那么我们开辟的时候就可以根据当前菜单项目的需求,再来开辟结构体数组就可以了。
说干就干,于是定义了下面两个结构体。
[mw_shl_code=applescript,true]typedef struct Menuitem
{
        unsigned char number;                                //编号
        unsigned char item[14];                                //项目
        unsigned char dis_add;                                //显示的位置
        struct Menuitem *_next;                                //下一个项目,构成菜单项目链表
        struct Menu *submenu;                                //子菜单
}MenuItem_MsgTypeDef;

typedef struct Menu
{
        unsigned char range_from;                        //显示开始序号
        unsigned char range_to;                                //显示结束序号
        unsigned char select;                                //当前选择项
        unsigned char item_cnt;                                //菜单项目总数
        unsigned char menulevel;                        //菜单级别
        struct Menu *uppermenu;                                //上一级菜单
        MenuItem_MsgTypeDef *menuItems;                //菜单项目
        void (*fun_page)();                                        //菜单显示页面
}Menu_MsgTypeDef;[/mw_shl_code]
结构体里包含了一些结构体指针,就想做成链表的一种形式,上一个菜单项目包含着指向下一个菜单项目的结构体指针,同时还包含了子菜单结构体指针,如果有子菜单,则指向其子菜单结构体,如果没有,则赋值一个空指针,通过判断结构体指针,就可以知道当前菜单项目是否有子菜单了,当然,还包含了指向上一级菜单的结构体指针,这样一整个菜单就构成了一个链表。最后操作的时候就用一个结构体指针,指向当前操作的菜单,通过改变指针的指向,就可以实现菜单的切换。
这样做起来的好处就是函数处理起来会比较方便,但最大的弊端就是太占内存了,用51单片机开发,我都直接定义到外部RAM去,还好用的芯片外部RAM比较大,可以随便用,不用考虑太多。还有就是整个程序设计看起来会很冗杂,读起来会比较费劲。现在想换一下思路写也无从下手。本人在程序设计这一块还只是小白,把程序贴出来只是希望大神看到之后能够指导指导。

下面附上.c源码
[mw_shl_code=applescript,true]#include "menu.h"#include "LCD12864.h"
#include "key.h"

uchar8_t Start = 0;
extern uchar8_t xdata Key_value;
uchar8_t code menudis[] =   "----游戏菜单----";
uchar8_t code setdis[] =        "------设置------";
uchar8_t code leveldis[] =  "------难度------";
uchar8_t code sounddis[] =  "------声音------";
uchar8_t code bestdis[] =   "------最佳------";
uchar8_t code bestdis1[] =  "Time    Score";
uchar8_t code authordis[] = "------作者------";
uchar8_t code mapdis[] =        "------地图------";
uchar8_t code game_over[] = "GAME OVER";

Menu_MsgTypeDef xdata Mainmenu =
{
        1,                                                                //显示开始序号
        3,                                                                //显示结束序号
        1,                                                                //当前选择项
        Main_Itemnum,                                        //菜单项目总数
        menulevel_1,                                        //菜单级别
        NULL,                                                        //上一级菜单
        &MainmenuItem,                                        //菜单项目
        &Mainmenu_page                                        //菜单显示页面                                               
};

MenuItem_MsgTypeDef xdata MainmenuItem[Main_Itemnum] =
{
//        编号,项目,显示的位置,下一个项目,子菜单
//编号组成(高四位为上一级别的菜单编号,低四位为当前级别的菜单编号)
        {0x01,"开始",0x93,&MainmenuItem[1],NULL},
        {0x02,"设置     \x10",0x8B,&MainmenuItem[2],&submenu_set},
        {0x03,"最佳     \x10",0x9B,&MainmenuItem[3],&submenu_best},
        {0x04,"作者     \x10",0x93,NULL,&submenu_author}
};

Menu_MsgTypeDef xdata submenu_set =
{
        1,                                                                //显示开始序号
        3,                                                                //显示结束序号
        1,                                                                //当前选择项
        sub_setItemnum,                                        //菜单项目总数
        menulevel_2,                                        //菜单级别
        &Mainmenu,                                                //上一级菜单
        &submenu_setItem,                                //菜单项目
        &submenu_set_page                                //菜单显示页面       
};

MenuItem_MsgTypeDef xdata submenu_setItem[sub_setItemnum] =
{
//        编号,项目,显示的位置,下一个项目,子菜单
//编号组成(高四位为上一级别的菜单编号,低四位为当前级别的菜单编号)
        {0x21,"地图     \x10",0x93,&submenu_setItem[1],NULL},
        {0x22,"难度     \x10",0x8B,&submenu_setItem[2],&submenu_grade},
        {0x23,"声音     \x10",0x9B,NULL,NULL}
};

Menu_MsgTypeDef xdata submenu_best =
{
        1,                                                                //显示开始序号
        1,                                                                //显示结束序号
        1,                                                                //当前选择项
        sub_bestItemnum,                                //菜单项目总数
        menulevel_2,                                        //菜单级别
        &Mainmenu,                                                //上一级菜单
        &submenu_bestItem,                                //菜单项目
        &submenu_best_page                                //菜单显示页面       
};

MenuItem_MsgTypeDef xdata submenu_bestItem[sub_bestItemnum] =
{
//        编号,项目,显示的位置,下一个项目,子菜单
        {NULL,"0000    0000",0x89,NULL,NULL},       
};

Menu_MsgTypeDef xdata submenu_author =
{
        1,                                                                //显示开始序号
        1,                                                                //显示结束序号
        1,                                                                //当前选择项
        sub_authorItemnum,                                //菜单项目总数
        menulevel_2,                                        //菜单级别
        &Mainmenu,                                                //上一级菜单
        &submenu_authorItem,                        //菜单项目
        &submenu_author_page                        //菜单显示页面       
};

MenuItem_MsgTypeDef xdata submenu_authorItem[sub_authorItemnum] =
{
//        编号,项目,显示的位置,下一个项目,子菜单
        {NULL,"上树的zhu",0x8A,NULL,NULL},       
};

Menu_MsgTypeDef xdata submenu_grade =
{
        1,                                                                //显示开始序号
        3,                                                                //显示结束序号
        1,                                                                //当前选择项
        sub_gradeItemnum,                                //菜单项目总数
        menulevel_3,                                        //菜单级别
        &submenu_set,                                        //上一级菜单
        &submenu_gradeItem,                                //菜单项目
        &submenu_grade_page                                //菜单显示页面       
};

MenuItem_MsgTypeDef xdata submenu_gradeItem[sub_gradeItemnum] =
{
//        编号,项目,显示的位置,下一个项目,子菜单
//编号组成(高四位为上一级别的菜单编号,低四位为当前级别的菜单编号)
        {0x21,"简单",0x93,&submenu_gradeItem[1],NULL},
        {0x22,"一般",0x8B,&submenu_gradeItem[2],NULL},
        {0x23,"困难",0x9B,NULL,NULL}
};

Menu_MsgTypeDef *currentmenu;                //当前菜单

void Menu_Dis()
{
        Clear_Frame();
        currentmenu = &Mainmenu;       
        currentmenu->fun_page();
        while(!Start)
        {
                if(Key_value)
                {
                        menu_operate(Key_value);
                        Key_value = 0;
                }
        }
        Highlignt_select(currentmenu->select,Clear);                       
}

/*************************************
*函数:Menu_page()
*功能:主菜单显示页
*参数:无
*返回值:无
**************************************/
void Mainmenu_page()
{
        uchar8_t i,j,j_max;
        currentmenu = &Mainmenu;
        write_com(0x01);
        write_com(lcd12864_display_address(0,1));               
        for(i = 0;menudis != '\0';i++)                        //显示“游戏菜单”
        {
                write_data(menudis);       
        }       
        j = currentmenu->range_from;                                //显示开始序号
        j_max = currentmenu->range_to + 1;                        //显示结束序号
        currentmenu->menuItems = &MainmenuItem[0];
        currentmenu->menuItems += (j - 1);                        //指针指向显示开始序号的位置

        for(;j < j_max;j++)
        {
                write_com(currentmenu->menuItems->dis_add);

                for(i = 0;currentmenu->menuItems->item != '\0';i++)
                {
                        write_data(currentmenu->menuItems->item);       
                }
                currentmenu->menuItems = currentmenu->menuItems->_next;
        }
        Highlignt_select(currentmenu->select,Dis);
}

/*************************************
*函数:submenu_set_page()
*功能:设置菜单显示页
*参数:无
*返回值:无
**************************************/
void submenu_set_page()
{
        uchar8_t i,j,j_max;
        currentmenu = &submenu_set;
        write_com(0x01);
        write_com(lcd12864_display_address(0,1));               
        for(i = 0;setdis != '\0';i++)                //显示“设置”
        {
                write_data(setdis);       
        }       
        j = currentmenu->range_from;                                //显示开始序号
        j_max = currentmenu->range_to + 1;                        //显示结束序号
        currentmenu->menuItems = &submenu_setItem[0];
        currentmenu->menuItems += (j - 1);                        //指针指向显示开始序号的位置

        for(;j < j_max;j++)
        {
                write_com(currentmenu->menuItems->dis_add);

                for(i = 0;currentmenu->menuItems->item != '\0';i++)
                {
                        write_data(currentmenu->menuItems->item);       
                }
                currentmenu->menuItems = currentmenu->menuItems->_next;
        }
        Highlignt_select(currentmenu->select,Dis);
}

/*************************************
*函数:submenu_best_page()
*功能:最高分显示页
*参数:无
*返回值:无
**************************************/
void submenu_best_page()
{
        uchar8_t i;
        currentmenu = &submenu_best;
        write_com(0x01);
        write_com(lcd12864_display_address(0,1));               
        for(i = 0;bestdis != '\0';i++)                //显示“最高分”
        {
                write_data(bestdis);       
        }
       
        write_com(lcd12864_display_address(1,2));               
        for(i = 0;bestdis1 != '\0';i++)       
        {
                write_data(bestdis1);       
        }
       
        write_com(currentmenu->menuItems->dis_add);
        for(i = 0;currentmenu->menuItems->item != '\0';i++)
        {
                write_data(currentmenu->menuItems->item);       
        }       
}

/*************************************
*函数:submenu_author_page()
*功能:作者显示页
*参数:无
*返回值:无
**************************************/
void submenu_author_page()
{
        uchar8_t i;
        currentmenu = &submenu_author;
        write_com(0x01);
        write_com(lcd12864_display_address(0,1));               
        for(i = 0;authordis != '\0';i++)                //显示“作者”
        {
                write_data(authordis);       
        }
       
        write_com(currentmenu->menuItems->dis_add);
        for(i = 0;currentmenu->menuItems->item != '\0';i++)
        {
                write_data(currentmenu->menuItems->item);       
        }       
}

/*************************************
*函数:submenu_grade_page()
*功能:设置菜单显示页
*参数:无
*返回值:无
**************************************/
void submenu_grade_page()
{
        uchar8_t i,j,j_max;
        currentmenu = &submenu_grade;
        write_com(0x01);
        write_com(lcd12864_display_address(0,1));               
        for(i = 0;leveldis != '\0';i++)                        //显示“难度”
        {
                write_data(leveldis);       
        }       
        j = currentmenu->range_from;                                //显示开始序号
        j_max = currentmenu->range_to + 1;                        //显示结束序号
        currentmenu->menuItems = &submenu_gradeItem[0];
        currentmenu->menuItems += (j - 1);                        //指针指向显示开始序号的位置

        for(;j < j_max;j++)
        {
                write_com(currentmenu->menuItems->dis_add);

                for(i = 0;currentmenu->menuItems->item != '\0';i++)
                {
                        write_data(currentmenu->menuItems->item);       
                }
                currentmenu->menuItems = currentmenu->menuItems->_next;
        }
        Highlignt_select(currentmenu->select,Dis);
}

/*************************************
*函数:Highlignt_select()
*功能:选择行反白函数
*参数:line——指定哪一行反白,Mode——设置是否反白
*返回值:无
**************************************/
void Highlignt_select(uchar8_t line,uchar8_t Mode)
{
        uchar8_t High;
        if(line <= 3)        High = line;
        else if(line > 3 && line <= 6)        High = line - 3;
        else if(line > 6 && line <= 9)        High = line - 6;
        write_com(lcd12864_display_address(0,High + 1));
        if(Mode == Clear)
        {
                write_data(' ');
                write_data(' ');
        }
        else
        {
                write_data(0x3E);
                write_data(0x3E);
        }
        HighLight_line(High,Mode);       
}

/*************************************
*函数:menu_operate()
*功能:按键选择处理函数
*参数:value——按键值
*返回值:无
**************************************/
void menu_operate(uchar8_t value)
{
        uint16_t func = 0;
        switch(value)                                                        //根据键值执行相应的函数
        {
                case UP_key:select_up();break;
                case DOWN_key:select_down();break;
                case A_key:{
                                                func = select_button();
                                                switch(func)
                                                {
                                                        case 1:break;
                                                        default : break;
                                                }
                                        }break;
                case B_key:back_button();break;
                default : break;       
        }       
}

/*************************************
*函数:select_down()
*功能:选择上一项处理函数
*参数:无
*返回值:无
**************************************/
void select_up()
{
        //清除上一项的反白
        Highlignt_select(currentmenu->select,Clear);
        currentmenu->select--;
        if(currentmenu->select < 1)                                                                                //防止当前选择项的超过菜单总数
                currentmenu->select =1;
        if(currentmenu->select < currentmenu->range_from)
        {
                if(currentmenu->range_to == currentmenu->item_cnt)
                        currentmenu->range_to = currentmenu->range_from + 2;
                currentmenu->range_from = currentmenu->range_from - 3;                                                               
                currentmenu->range_to = currentmenu->range_to - 3;
                currentmenu->fun_page();                                                                         //如果超过选择项超过显示项,则刷新页面
        }
        Highlignt_select(currentmenu->select,Dis);                                                //将当前选择项反白               
}

/*************************************
*函数:select_down()
*功能:选择下一项处理函数
*参数:无
*返回值:无
**************************************/
void select_down()
{
        //清除上一项的反白
        Highlignt_select(currentmenu->select,Clear);
        currentmenu->select++;
        if(currentmenu->select > currentmenu->item_cnt)                                        //防止当前选择项的超过菜单总数
                currentmenu->select = currentmenu->item_cnt;
        if(currentmenu->select > currentmenu->range_to)
        {
                currentmenu->range_from = currentmenu->range_from + 3;
                currentmenu->range_to = currentmenu->range_to + 3;
                if(currentmenu->range_to >= currentmenu->item_cnt)
                        currentmenu->range_to = currentmenu->item_cnt;
                currentmenu->fun_page();                                                                        //如果超过选择项超过显示项,则刷新页面                                               
        }
        Highlignt_select(currentmenu->select,Dis);                                                //将当前选择项反白       
}

/*************************************
*函数:back_button()
*功能:返回按钮处理函数
*参数:无
*返回值:无
**************************************/
void back_button()
{
        if(currentmenu->menulevel == 1)        return;
        Highlignt_select(currentmenu->select,Clear);
        currentmenu = currentmenu->uppermenu;
        currentmenu->fun_page();       
}

/*************************************
*函数:select_button()
*功能:选择按钮处理函数
*参数:无
*返回值:func——选择的功能
**************************************/
uint16_t select_button()
{
        uint16_t func = 0x0000;
        //项目指针指向首项目
        if(currentmenu == &Mainmenu)
                currentmenu->menuItems = &MainmenuItem;
        else if(currentmenu == &submenu_set)
                currentmenu->menuItems = &submenu_setItem;
        else if(currentmenu == &submenu_best)
                currentmenu->menuItems = &submenu_bestItem;
        else if(currentmenu == &submenu_author)
                currentmenu->menuItems = &submenu_authorItem;
        else if(currentmenu == &submenu_grade)
                currentmenu->menuItems = &submenu_gradeItem;
        //项目指针指向选择项
        currentmenu->menuItems = currentmenu->menuItems + (currentmenu->select - 1);
        //判断当前选择项是否有子菜单
        if(currentmenu->menuItems->submenu == NULL)                        //没有子菜单
        {       
                func = currentmenu->menulevel << 4;                                //获取菜单级别
                func = func + currentmenu->menuItems->number;        //与项目编号构成12位的编号
                back_button();
                return func;
        }       
        else                                                                                                //有子菜单
        {
                Highlignt_select(currentmenu->select,Clear);
                currentmenu = currentmenu->menuItems->submenu;
                currentmenu->fun_page();
                return 0;               
        }
}[/mw_shl_code]

以及对应的.h文件
[mw_shl_code=applescript,true]#ifndef _MENU_H_
#define _MENU_H_
#include "stc12_sys.h"

//#################################################
//                                        宏定义
//#################################################
#define NULL                                0x0000

#define Main_Itemnum                4
#define sub_setItemnum                3
#define sub_bestItemnum                1
#define sub_authorItemnum        1
#define sub_gradeItemnum        3
#define sub_soundItemnum        2
#define sub_mapItemnum                1

typedef enum
{
        menulevel_1 = 1,
        menulevel_2,
        menulevel_3,
        menulevel_4,
        menulevel_5
}MenuLevel;

typedef struct Menuitem
{
        unsigned char number;                                //编号
        unsigned char item[14];                                //项目
        unsigned char dis_add;                                //显示的位置
        struct Menuitem *_next;                                //下一个项目,构成菜单项目链表
        struct Menu *submenu;                                //子菜单
}MenuItem_MsgTypeDef;

typedef struct Menu
{
        unsigned char range_from;                        //显示开始序号
        unsigned char range_to;                                //显示结束序号
        unsigned char select;                                //当前选择项
        unsigned char item_cnt;                                //菜单项目总数
        unsigned char menulevel;                        //菜单级别
        struct Menu *uppermenu;                                //上一级菜单
        MenuItem_MsgTypeDef *menuItems;                //菜单项目
        void (*fun_page)();                                        //菜单显示页面
}Menu_MsgTypeDef;

extern Menu_MsgTypeDef xdata Mainmenu;
extern MenuItem_MsgTypeDef xdata MainmenuItem[Main_Itemnum];
extern Menu_MsgTypeDef xdata submenu_set;
extern MenuItem_MsgTypeDef xdata submenu_setItem[sub_setItemnum];
extern Menu_MsgTypeDef xdata submenu_best;
extern MenuItem_MsgTypeDef xdata submenu_bestItem[sub_bestItemnum];
extern Menu_MsgTypeDef xdata submenu_author;
extern MenuItem_MsgTypeDef xdata submenu_authorItem[sub_authorItemnum];
extern Menu_MsgTypeDef xdata submenu_grade;
extern MenuItem_MsgTypeDef xdata submenu_gradeItem[sub_gradeItemnum];
extern Menu_MsgTypeDef *currentmenu;

//#################################################
//                                        函数定义
//#################################################
void Menu_Dis();
void Mainmenu_page();
void submenu_set_page();
void submenu_best_page();
void submenu_author_page();
void submenu_grade_page();
void menu_operate(uchar8_t);
void select_up();
void select_down();
void back_button();
uint16_t select_button();
void Highlignt_select(uchar8_t line,uchar8_t Mode);

#endif[/mw_shl_code]
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

15

帖子

0

精华

初级会员

Rank: 2

积分
120
金钱
120
注册时间
2017-5-26
在线时间
17 小时
发表于 2017-6-2 23:31:08 | 显示全部楼层
回复 支持 反对

使用道具 举报

0

主题

5

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1133
金钱
1133
注册时间
2017-2-15
在线时间
74 小时
发表于 2017-6-13 13:15:34 | 显示全部楼层
收藏了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-1 14:37

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表