精华内容
下载资源
问答
  • 单片机多级菜单设计,非常实用,适合单片机这种资源少的处理器
  • 单片机多级菜单的简单实现 多级菜单的思路 最近想把stm32上的oled显示屏做的好看一些,于是动手写了写一个多级菜单,思路很简单,每个页面用单独的函数封装好,每个功能也是用单独的函数进行封装,用了3个按键,两个...

    单片机多级菜单的简单实现

    多级菜单的思路

    最近想把stm32上的oled显示屏做的好看一些,于是动手写了写一个多级菜单,思路很简单,每个页面用单独的函数封装好,每个功能也是用单独的函数进行封装,用了3个按键,两个切换键,一个确定键。

    1. 首先来看看用啥判断页面的(这偷个懒,希望没人打我)
    //页面标志位
    uint8_t s1 = 0;			//主页面功能号
    uint8_t s2 = 0;			//主次页面判断标志位
    uint16_t s3 = 1;		//次页面功能号
    
    1. 主页面的显示函数,这是个很枯燥的一个显示函数。将功能图标显示出来,Draw_BMP()中的第一个形参判断图片是否反白,0是不反白,1是反白。
    void function_primary(void) //一级界面,显示功能图标
    {	
       Draw_BMP(0,0,0,32,4,BMP5);
       Draw_BMP(0,48,0,80,4,BMP6);
       Draw_BMP(0,95,0,127,4,BMP7);
       Draw_BMP(0,0,4,32,8,BMP8);
       Draw_BMP(0,48,4,80,8,BMP9);
       Draw_BMP(0,95,4,127,8,BMP10);
       switch(s1)		//一级页面功能号
       {
       	case 1: Draw_BMP(1,0,0,32,4,BMP5); break;
       	case 2: Draw_BMP(1,48,0,80,4,BMP6); break;
       	case 3: Draw_BMP(1,95,0,127,4,BMP7); break;
       	case 4: Draw_BMP(1,0,4,32,8,BMP8); break;
       	case 5: Draw_BMP(1,48,4,80,8,BMP9); break;
       	case 6: Draw_BMP(1,95,4,127,8,BMP10); break;
       	default:	break;
       }
    }
    
    1. 二级页面的显示函数,其实和一级页面差不多,无非是换了个标志位。这里就放一个次页面的就好了,其他的想加几个就复制几个。同样OLED_P8x16Str()中的第一个形参判断文字是否反白,0是不反白,1是反白。
    void function_level1(void)
    {
    	sprintf(buf,"1.1");
    	OLED_P8x16Str(0u,0u,0u,(uint8_t *)buf);
    	sprintf(buf,"1.2");
    	OLED_P8x16Str(0u,0u,2u,(uint8_t *)buf);
    	sprintf(buf,"1.3");
    	OLED_P8x16Str(0u,0u,4u,(uint8_t *)buf);
    	sprintf(buf,"1.4  exit");
    	OLED_P8x16Str(0u,0u,6u,(uint8_t *)buf);
    	switch(s3)	//次页面功能号
    	{
    		case 1:sprintf(buf,"1.1");
    			OLED_P8x16Str(1u,0u,0u,(uint8_t *)buf);
    			break;
    		case 2:sprintf(buf,"1.2");
    			OLED_P8x16Str(1u,0u,2u,(uint8_t *)buf);
    			break;
    		case 3:sprintf(buf,"1.3");
    			OLED_P8x16Str(1u,0u,4u,(uint8_t *)buf);
    			break;
    		case 4:sprintf(buf,"1.4  exit");
    			OLED_P8x16Str(1u,0u,6u,(uint8_t *)buf);
    			break;
    		default:break;
    	}
    }
    
    1. 这里是确定按键,负责选中主界面或次界面的某个功能,按下后进行判断是哪个功能被选中并执行
    void function(void)			//主页面切换至次界面
    {	
    	if(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin)==RESET)
    	{
    		HAL_Delay(200);
    		if(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin) == SET)
    		{	
    			if(s2 == 0)		//位于主界面
    			{
    				switch(s1)		//判断切换至哪个次界面
    					{
    						case 1: OLED_CLS();
    								s2 = 1;
    								function_level1();
    								break;
    						case 2: OLED_CLS();
    								s2 = 2;
    								function_level2();
    								break;
    						case 3: OLED_CLS();
    								s2 = 3;
    								function_level3();
    								break;
    						case 4: OLED_CLS();
    								s2 = 4;
    								function_level4();
    								break;
    						case 5: OLED_CLS();
    								s2 = 5;
    								function_level5();
    								break;
    						case 6: OLED_CLS();
    								s2 = 6;
    								function_level6();
    								break;
    						default:OLED_CLS(); 
    								break;
    					}
    				}
    				if(s2 != 0)		//判断是否位于次界面
    				{
    					if(s3 == 4)		//位于次界面时,选中次界面中功能四,执行切换回主界面
    					{
    						OLED_CLS();
    						function_primary();
    						s2 = 0;			//s2恢复初值
    						s3 = 1;			//s3恢复初值
    					}
    				}
    			}
    		}
    }
    
    1. 这里则是移动按键,负责选中某个功能对应的显示名称,并且将该功能对应的显示反白。这边放的是功能号递增
    void key_scan1(void)		//功能切换按键1
    {
    	if(HAL_GPIO_ReadPin(KEYS_GPIO_Port,KEYS_Pin) == RESET)
    	{
    		switch(s2)		//判断是主界面中哪个功能的次界面
    		{
    			case 0:
    			HAL_Delay(200);
    			if(HAL_GPIO_ReadPin(KEYS_GPIO_Port,KEYS_Pin) == SET)
    			{
    				OLED_CLS();
    				s1+=1;
    			}
    			if(s1 > 6)
    				s1 = 1;
    			else
    				s1 = s1;
    			display();
    			break;
    			
    			case 1:
    			HAL_Delay(200);
    			if(HAL_GPIO_ReadPin(KEYS_GPIO_Port,KEYS_Pin) == SET)
    			{
    				OLED_CLS();
    				s3+=1;
    			}
    			if(s3 > 4)
    				s3 = 1;
    			else
    				s3 = s3;
    			function_level1();
    			break;
    				
    			case 2:
    			HAL_Delay(200);
    			if(HAL_GPIO_ReadPin(KEYS_GPIO_Port,KEYS_Pin) == SET)
    			{
    				OLED_CLS();
    				s3+=1;
    			}
    			if(s3 > 4)
    				s3 = 1;
    			else
    				s3 = s3;
    			function_level2();
    			break;
    				
    			case 3:
    			HAL_Delay(200);
    			if(HAL_GPIO_ReadPin(KEYS_GPIO_Port,KEYS_Pin) == SET)
    			{
    				OLED_CLS();
    				s3+=1;
    			}
    			if(s3 > 4)
    				s3 = 1;
    			else
    				s3 = s3;
    			function_level3();
    			break;
    		//后面你有多少功能就加多少case语句判断,格式一样
    		......
    		default:
    		break;
    			}
    	}
    }	
    
    1. 这里是执行功能号递减的按键,只放上面对应要修改的部分,这里要说明一下,按键的函数是对所有的界面判断了功能号,即对s2进行判断,当 s2 = 0 的时候,显示的是一级界面,后面的才是二级界面的功能号。(s2作为功能号,放的是所有功能的序号。即后面有三级界面啥的,功能号都放着里面)
    • 注意:每个页面可能对应的功能不同,s1,s3作为主次界面的判断标志,其界面内拥有的功能数量可能有所不同,可以自行修改。
    			case 0:
    			HAL_Delay(200);
    			if(HAL_GPIO_ReadPin(KEYS_GPIO_Port,KEYS_Pin) == SET)
    			{
    				OLED_CLS();
    				s1-=1;
    			}
    			if(s1 < 1)
    				s1 = 6;
    			else
    				s1 = s1;
    			display();
    			break;
    
    1. 最后在main函数这个大循环里,只要加上那三个按键的函数就行了
      while (1)
      {
    		function();		//先执行确定,显示出主页面
    		key_scan1();	//再进行功能选择
    		key_scan2();
      }
    
    1. 到这边这个多级菜单也算是完成了,其实这些代码都是没啥难度,想明白思路基本就是敲完一个模板,其他的就C+V操作,改好参数就好了,要实现具体的切换功能键选中后再执行相应的功能,直接在显示的函数里加就好了。其实还有许多复杂的方法可以写多级菜单,链表啊啥的,奈何学艺不精,数据结构想从理论运用到实际还是有难度的。不过这简单的代码虽然看上去还是挺枯燥没啥味道,用起来还是可以的。最后个人认为按键最好加硬件消抖,用户体验提高不少。
    展开全文
  • 单片机多级菜单编程实现(ZT)建立一个树状的菜单结构,用链表实现 链表中包含: 1、指向同级左右菜单和指向父菜单、子菜单的四个菜单结构体指针; 2、进入该菜单时需要执行的初始化函数指针 3、退出该菜单时需要执行...

    单片机多级菜单编程实现(ZT)建立一个树状的菜单结构,用链表实现

    链表中包含:
    1、指向同级左右菜单和指向父菜单、子菜单的四个菜单结构体指针;
    2、进入该菜单时需要执行的初始化函数指针
    3、退出该菜单时需要执行的结束函数指针
    4、该菜单内的按键处理函数指针数组的指针操作菜单模块需要的按键操作有:左、右、确
    认、退出。
    采用这种办法,可以方便的添加或删减菜单。并且只需要在其头文件中修改初始变量就可
    以实现,完全无须修改C文件中的任何函数。


    具体结构定义 
    我的定义,做个参考:
    #define MENU_HLP_EN //菜单帮助信息使能

    typedef struct

    void (*pMenuTaskInit)(void); //指向菜单任务初始化函数的指针
    void (*pMenuTaskEnd)(void); //指向菜单任务结束函数的指针
    }MENU_TASK_TYP;

    typedef struct MenuTyp

    INT8U *MenuName; //菜单名称字符串
    WORK_MOD WorkMod; //工作状态编号
    MENU_TASK_TYP *pMenuTask; //指向菜单任务的指针
    void (**pTaskKeyDeal)(void); //指向菜单任务按键处理函数数组的指针
    #ifdef MENU_HLP_EN
    INT8U *MenuHlp; //菜单帮助字符串
    #endif
    struct MenuTyp *pParent; //指向上层菜单的指针
    struct MenuTyp *pChild; //指向子菜单的指针
    struct MenuTyp *pRight; //指向右菜单的指针
    struct MenuTyp *pLeft; //指向左菜单的指针
    }MENU_TYP;


    我根据网上的资料做的一个菜单: 
    /****************菜单数据结构**********************/
    struct KeyTabStruct{
    uint8 MenuIndex; //当前状态索引号
    uint8 MaxItems; //本级菜单最大条目数
    uint8 ShowLevel; //菜单显示内容
    uint8 PressOk; //按下"回车"键时转向的状态索引号
    uint8 PressEsc; //按下"返回"键时转向的状态索引号
    uint8 PressDown; //按下"向下"键时转向的状态索引号
    uint8 PressUp; //按下"向上"键时转向的状态索引号
    void (*CurrentOperate)(); //当前状态应该执行的功能操作
    };
    uint8 MenuID; //菜单ID号
    uint8 MenuNextID; //下级菜单ID号
    //CurMenuID=本菜单ID
    //MaxMenuItem=同级菜单最大项数
    //OkMenuID=子菜单层所对应的菜单ID,ID=999为菜单已经到底了
    //EscMenuID=父菜单层所对应的菜单ID,ID=999为菜单已经到顶了
    //DownMenuID=弟菜单层所对应的菜单ID,ID=999为菜单是独生子
    //UpMenuID=兄菜单层所对应的菜单ID,ID=999为菜单是独生子
    //CurFunction=本菜单所对应的菜单函数指针
    const struct KeyTabStruct KeyTab[MAX_KEYTABSTRUCT_NUM]={
    //CurMenuID, axMenuItem, MenuShowLevel, OkMenuID, EscMenuID, DownMenuID, UpMenuID, CurFunction{MENU_EDIT, 0, 0, MENU_DATA_VIEW, MENU_NO, MENU_NO, MENU_NO, *MenuEdit},
    {MENU_DATA_VIEW, 3, 1, MENU_DATA_VIEW_FIRE, MENU_EDIT, MENU_SYS_EDIT, MENU_PRINT_DATA,*MenuEdit},
    {MENU_DATA_VIEW_FIRE, 5, MENU_NO, MENU_NO, MENU_DATA_VIEW, MENU_DATA_VIEW_TROUBLE, MENU_STEP_FOLLOW, *MenuDataViewIn},

    {MENU_DATA_VIEW_TROUBLE, 5, MENU_NO, MENU_NO, MENU_DATA_VIEW, MENU_DATA_VIEW_REPEAT, MENU_DATA_VIEW_FIRE, *MenuDataViewIn},

    {MENU_DATA_VIEW_REPEAT, 5, MENU_NO, 
    MENU_NO, MENU_DATA_VIEW, MENU_FACE_CHECK, 
    MENU_DATA_VIEW_TROUBLE, *MenuDataViewIn},
    {MENU_FACE_CHECK, 5, MENU_NO, 
    MENU_NO, MENU_DATA_VIEW, MENU_STEP_FOLLOW, 
    MENU_DATA_VIEW_REPEAT, *MenuFaceCheck},
    {MENU_STEP_FOLLOW, 5, MENU_NO, 
    MENU_NO, MENU_DATA_VIEW, MENU_DATA_VIEW_FIRE, MENU_FACE_CHECK,
    *MenuStepFollow},
    {MENU_SYS_EDIT, 3, 
    2, MENU_SUM_SET, MENU_EDIT, 
    MENU_PRINT_DATA, MENU_DATA_VIEW, *MenuEdit},
    {MENU_SUM_SET, 6, MENU_NO, 
    MENU_NO, MENU_SYS_EDIT, MENU_EDIT_INSULATE, 
    MENU_TIME_SET, *MenuSumSet},
    {MENU_EDIT_INSULATE, 6, MENU_NO, 
    MENU_NO, MENU_SYS_EDIT, MENU_EDIT_HZ, MENU_SUM_SET,
    *MenuEditInsulate},
    {MENU_EDIT_HZ, 6, MENU_NO, 
    MENU_NO, MENU_SYS_EDIT, MENU_LD_CONTROL, 
    MENU_EDIT_INSULATE, *MenuEditHZ},
    {MENU_LD_CONTROL, 6, 
    MENU_NO, MENU_NO, MENU_SYS_EDIT, MENU_LD_DELAY,
    MENU_EDIT_HZ, *MenuLDControl},
    {MENU_LD_DELAY, 6, 
    MENU_NO, MENU_NO, MENU_SYS_EDIT, MENU_TIME_SET, 
    MENU_LD_CONTROL, *MenuLDDelay},
    {MENU_TIME_SET, 6, MENU_NO, 
    MENU_NO, MENU_SYS_EDIT, MENU_SUM_SET, MENU_LD_DELAY,
    *MenuTimeSet},
    {MENU_PRINT_DATA, 3, 3, 
    MENU_PRINT_DATA_FIRE, MENU_EDIT, MENU_DATA_VIEW, 
    MENU_SYS_EDIT, *MenuEdit},
    {MENU_PRINT_DATA_FIRE, 4, 
    MENU_NO, MENU_NO, MENU_PRINT_DATA, 
    MENU_PRINT_DATA_TROUBLE, MENU_PRINT_SET, *MenuPrintDataIn},
    {MENU_PRINT_DATA_TROUBLE, 4, MENU_NO, 
    MENU_NO, MENU_PRINT_DATA, MENU_PRINTER_CHECK, 
    MENU_PRINT_DATA_FIRE, *MenuPrintDataIn},
    {MENU_PRINTER_CHECK, 4, MENU_NO, 
    MENU_NO, MENU_PRINT_DATA, MENU_PRINT_SET, 
    MENU_PRINT_DATA_TROUBLE, *MenuPrintDataIn},
    {MENU_PRINT_SET, 4, MENU_NO, 
    MENU_NO, MENU_PRINT_DATA, MENU_PRINT_DATA_FIRE, 
    MENU_PRINTER_CHECK, *MenuPrintSet},
    };
    /**************************************编程菜单显示数据
    ******************************/
    const struct MenuDispData MenuEditShow[][MENU_MAX] = {
    {{MENU_NO , 0, 0, "选择: 消音→退出"}, //主菜单
    {MENU_DATA_VIEW , 1, 6, "⒈数据查看"},
    {MENU_SYS_EDIT , 2, 6, "⒉系统编程"},
    {MENU_PRINT_DATA , 3, 6, "⒊数据打印"}},
    {{MENU_NO , 0, 0, "数据查看: 消音→退出"}, //数据查

    {MENU_DATA_VIEW_FIRE , 1, 4, "⒈火警"},
    {MENU_DATA_VIEW_TROUBLE, 2, 4, "⒉故障"},
    {MENU_DATA_VIEW_REPEAT , 3, 4, "⒊重码"},
    {MENU_FACE_CHECK , 1,12, "⒋面板检测"},
    {MENU_STEP_FOLLOW , 2,12, "⒌单步跟踪"}},
    {{MENU_NO , 0, 0, "系统编程: 消音→退出"}, //系统编程
    {MENU_SUM_SET , 1, 0, "⒈容量设置"},
    {MENU_EDIT_INSULATE , 2, 0, "⒉隔离点"},
    {MENU_EDIT_HZ , 3, 0, "⒊汉字描述"},
    {MENU_LD_CONTROL , 1,12, "⒋联动控制"},
    {MENU_LD_DELAY , 2,12, "⒌模块延时"},
    {MENU_TIME_SET , 3,12, "⒍时钟调整"}},
    {{MENU_NO , 0, 0, "数据打印: 消音→退出"}, //数据打印
    {MENU_PRINT_DATA_FIRE , 1, 0, "⒈火警数据"},
    {MENU_PRINT_DATA_TROUBLE,2, 0, "⒉故障数据"},
    {MENU_PRINTER_CHECK , 3, 0, "⒊打印机自检"},
    {MENU_PRINT_SET , 1,12, "⒋打印设置"}}, 
    };
    /***********************************等待按键**********************************/
    void WaitKey(void)

    uint32 time;
    time = RTCFlag;
    WhichKey = KEY_NONE;
    while(!EscFlag){
    if(RTCFlag - time >= EDIT_TIME)
    EscFlag = TRUE;
    if(WhichKey != KEY_NONE){
    KeySound(300); //按键音
    return;



    /*********************************显示多级菜单
    **********************************/
    void MenuEdit()

    uint32 i,j=0;
    uint32 oldid;
    j = KeyTab[MenuID].ShowLevel;
    if(WhichKey == KEY_ESC || WhichKey == KEY_OK){
    ClearScreen();
    for(i=0;i<KeyTab[MenuNextID].MaxItems+1;i++)
    ShowString(MenuEditShow[j][i].Lin,MenuEditShow[j]
    [i].Column,MenuEditShow[j][i].Pdata,0); //初始化显示
    oldid = 
    0; 
    //没有原先选择的项
    }else{
    if(WhichKey == KEY_UP)
    oldid = KeyTab[MenuNextID].PressDown; 
    else
    oldid = KeyTab
    [MenuNextID].PressUp; 
    //指示原先的项

    for(i=1;i<KeyTab[MenuNextID].MaxItems+1;i++){
    if(MenuEditShow[j][i].Id == oldid)
    ShowString(MenuEditShow[j][i].Lin,MenuEditShow[j]
    [i].Column,MenuEditShow[j][i].Pdata,0); //正常显示原先的项
    else{
    if(MenuEditShow[j][i].Id == MenuNextID)
    ShowString(MenuEditShow[j][i].Lin,MenuEditShow
    [j][i].Column,MenuEditShow[j][i].Pdata,1); //反显当前选择的项
    } 

    WhichKey = KEY_NONE;
    } 
    /******************************系统编程*******************************/
    uint32 Edit(void)
    { 
    struct KeyTabStruct NowKeyTab; //指示当前的菜单值
    uint32 escflag = FALSE;
    ResetFlag = FALSE;
    ChangeFlag = FALSE;
    EscFlag = FALSE;
    MenuID = MENU_EDIT;
    NowKeyTab = KeyTab[MenuID];
    MenuNextID = NowKeyTab.PressOk;
    (*NowKeyTab.CurrentOperate)(); //显示主菜单
    do{ 
    if(WhichKey == KEY_NONE)
    WaitKey(); //等待按键
    switch(WhichKey){
    case KEY_ESC : if(NowKeyTab.PressEsc != MENU_NO)

    MenuID = 
    NowKeyTab.PressEsc;
    MenuNextID = 
    NowKeyTab.MenuIndex;
    NowKeyTab = KeyTab
    [MenuID];
    NowKeyTab.PressOk = 
    MenuNextID;
    (*NowKeyTab.CurrentOperate)
    (); //显示当前菜单
    }else
    escflag = 
    TRUE; //退出编程状态
    break;
    case KEY_OK : if(NowKeyTab.PressOk != MENU_NO)

    MenuID = 
    NowKeyTab.PressOk;
    NowKeyTab = KeyTab
    [MenuID];
    MenuNextID = 
    NowKeyTab.PressOk;

    (*NowKeyTab.CurrentOperate)
    (); //执行当前按键的操作
    break;
    case KEY_UP : if((MenuNextID != MENU_NO) && 
    (KeyTab[MenuNextID].PressUp != MENU_NO)){
    NowKeyTab.PressOk = 
    KeyTab[MenuNextID].PressUp;
    MenuNextID = KeyTab
    [MenuNextID].PressUp;

    (*NowKeyTab.CurrentOperate)(); //执行当前按键的操作

    break;
    case KEY_DOWN: if((MenuNextID != MENU_NO) && 
    (KeyTab[MenuNextID].PressDown != MENU_NO)){
    NowKeyTab.PressOk = 
    KeyTab[MenuNextID].PressDown;
    MenuNextID = KeyTab
    [MenuNextID].PressDown;

    (*NowKeyTab.CurrentOperate)(); //执行当前按键的操作

    break;
    case KEY_RESET: ResetFlag = TRUE;
    break;
    default : break;
    } 
    }while(!ResetFlag && !EscFlag && !escflag); 
    if(ChangeFlag && !EscFlag && !ResetFlag)
    EditDataChange(); 
    if(ResetFlag)
    return SYS_RESET;
    else{ 
    return 0;


    关于这个菜单的说明:

    1.我用的是ARM处理器,所以51的时候把const改成code,uint32改成unsigned char。
    2.在网上的资料中,结构体数组是存在RAM中的,我把它放在也flash中了,然后再定义一个
    结构体变量,就样就可以省很多RAM,比较适合51.
    3.在网上资料中,因为保存了原来的选择,当你离开编程状态重新进行后,会发现选择上会
    是原来进行的顺序,我改动之后,退出上一级菜单还是你选的那一项,但重新进入后就是第
    一个指定项。
    4.增加UP和DOWN显示,可以反显最新选定的选项,正常显示原来的选项。

    展开全文
  • 单片机多级菜单程序

    2016-01-19 20:04:28
    菜单程序采用结构体及指针设计,可方便实现移值,修改
  • //本级菜单最大条目数 unsigned int KeyTab_PressOk; //按下"回车"键时转向的状态索引号 unsigned int KeyTab_PressEsc; //按下"返回"键时转向的状态索引号 unsigned int KeyTab_PressDown; //按下"向下"键时...
  • 多级菜单 12864串口显示的多级菜单 基于msp430单片机多级菜单
  • 51单片机lcd多级菜单

    2010-05-10 18:41:59
    51单片机lcd多级菜单的实现,上LCD和按键实现多级菜单切换
  • 单片机实现多级菜单

    万次阅读 多人点赞 2016-09-20 22:01:51
    单片机实现多级菜单 1、首先定义一个机构体如下 typedef struct  {  uchar current;  uchar up;//上键  uchar down;//下键  uchar enter;//确认键  void (*current_operation)();  } key_table;...

    单片机实现多级菜单


    1、首先定义一个机构体如下
    typedef struct
       {
         uchar current;
         uchar up;//上键
         uchar down;//下键
         uchar enter;//确认键
         void (*current_operation)();
         } key_table;


    结构体包含5个变量,分别是函数的索引号即用户想要执行哪个函数的代号,然后有三个键,用户可以自己定义别的按键,最后一个是函数指针,即索引号对应的函数。然后在定义一个结构体数组,如下
    key_table code table[n]=
    {
         {0,2,1,3,(*fun1)},
         {1,0,2,4,(*fun2)},
         {2,1,0,5,(*fun3)},                  
         {3,0,6,3,(*fun4)},
         {4,1,6,4,(*fun5)},                       
         {5,2,6,5,(*fun6)},
         {6,0,0,0,(*fun7)},
         ............                                           
    };
    其中n为函数数组大小。下面详细介绍key_table code table[n]里面的值是怎么确定的。
    首先可以先这样定义该数组
    key_table code table[n]=
    {
         {0,x,y,z,(*fun1)},
         {1,x,y,z,(*fun2)},
         {2,x,y,z,(*fun3)},                  
         {3,x,y,z,(*fun4)},
         {4,x,y,z,(*fun5)},                       
         {5,x,y,z,(*fun6)},
         {6,x,y,z,(*fun7)},
         ............                                           
    };
    其中,x,y,z是未知数,先不确定,他们对应的是三个键按下要指示的索引值,如果四个键,就有四个未知数,在确定他们之前,必须要了解自己函数执行什么命令。加入开始时时执行数组里面的第一个即table[0],而想在此按上键执行函数fun6,那么table[0]里面需要这样设置
    {0,5,y,z,(*fun1)},同样,如果希望按下键执行fun7则需要设置为
    {0,x,6,z,(*fun1)},如果希望按确认键执行fun3则需要设置为
    {0,x,y,2,(*fun1)};如果上面三种情况都想要就设置为
    {0,5,6,2,(*fun1)}.其它数组元素一次类推。这一步做完了看主程序里面(主要是while(1)里面)。
    /*******************find index****************************/
                  switch(key)
                  {
    case 0x44:                                                            func_index=table[func_index].up;    //向上翻                                           break;
    case 0x24:                                           func_index=table[func_index].enter;//回车
    break;
    case 0x14:                                           func_index=table[func_index].down;//向下翻
    break;
    default:break;

                      }                                current_operation_index=table[func_index].current_operation;
    (*current_operation_index)();//执行当前操作函数

    其中,key是返回的按键值,这个用户视情况而定,
    下面是详细的例子,
    主要是以结构体为基础设计的,以12864显示函数代替了用户需要的函数功能,只需要修改相应的函数和索引号,就可以达到任意界面切换了是小弟研究了还久才搞定的,虽然网上也有这些,但是都不够系统,只有基本的东西,这篇例子希望能够给读者一些有用的东西,仅供参考哦!

    #include <reg52.h>
    #include "fun.h"
    #include "lcd12864.h"
    #include "delay.h"
    #define uchar unsigned char
    sbit keydown=P0^0;
    sbit keyenter=P0^1;
    sbit keyup=P0^2;
    uchar func_index=0;
    void (*current_operation_index)();
    typedef struct
       {
             uchar current;
             uchar up;//向上翻索引号
             uchar down;//向下翻索引号
             uchar enter;//确认索引号
             void (*current_operation)();
             } key_table;
    key_table code table[30]=
    {
            {0,3,1,4,(*fun1)},//第一层,显示【清华大学】、北京大学、重庆三峡学院、返回
             {1,0,2,8,(*fun2)},//第一层,显示清华大学、【北京大学】、重庆三峡学院、返回
             {2,1,3,12,(*fun3)},//第一层,显示清华大学、北京大学、【重庆三峡学院】、返回                     
             {3,2,0,25,(*fun4)},//第一层,显示清华大学、北京大学、重庆三峡学院、【返回】
             {4,7,5,16,(*fun5)},//第二层,清华大学层下显示【地点】、创建时间、简介、返回                                                   
             {5,4,6,17,(*fun6)},//第二层,清华大学层下显示地点、【创建时间】、简介、返回      
             {6,5,7,18,(*fun7)}, //第二层,清华大学层下显示地点、创建时间、【简介】、返回                                                                             
             {7,6,4,0,(*fun8)},//第二层,清华大学层下显示地点、创建时间、简介、【返回】      
             {8,11,9,19,(*fun9)},//第二层,北京大学层下显示【历史】、政治、简介、返回                                                
             {9,8,10,20,(*fun10)},//第二层,北京大学层下显示历史、【政治】、简介、返回  
             {10,9,11,21,(*fun11)}, //第二层,北京大学层下显示历史、政治、【简介】、返回                                                                                
             {11,10,8,1,(*fun12)},//第二层,北京大学层下显示历史、政治、简介、【返回】         
             {12,15,13,22,(*fun13)},//第二层,重庆三峡学院层下显示【简介】、最佳院系、最佳实验室、返回                                                        
             {13,12,14,23,(*fun14)}, //第二层,重庆三峡学院层下显示简介、【最佳院系】、最佳实验室、返回                                                               
             {14,13,15,24,(*fun15)}, //第二层,重庆三峡学院层下显示简介、最佳院系、【最佳实验室】、返回                                                               
             {15,14,12,2,(*fun16)}, //第二层,重庆三峡学院层下显示简介、最佳院系、最佳实验室、【返回】   
             {16,16,16,4,(*fun17)}, //第三层,清华大学地点层                                                                    
             {17,17,17,5,(*fun18)}, //第三层,清华大学创时间层                                                      
             {18,18,18,6,(*fun19)}, //第三层,清华大学简介层
             {19,19,19,8,(*fun20)}, //第三层,北京大学历史层                                                                    
             {20,20,20,9,(*fun21)}, //第三层,北京大学政治层                                                           
             {21,21,21,10,(*fun22)}, //第三层,北京大学简介层
             {22,22,22,12,(*fun23)}, //第三层,重庆三峡学院简介层                                                                  
             {23,23,23,13,(*fun24)}, //第三层,重庆三峡学院最佳院系层                                                        
             {24,24,24,14,(*fun25)}, //第三层,重庆三峡学院最佳实验室层        
             {25,25,25,0,(*fun26)}, //第0层      

    };
    void main()
    {  
              init_lcd(); //初始化LCD模块  
       while(1)
       {     
             /*******************find index****************************/
                                if((keyup==0)||(keydown==0)||(keyenter==0))
                                {
                                         delay(10);//消抖
                                         if(keyup==0)
                                         {
                                         func_index=table[func_index].up;    //向上翻
                                         while(!keyup);//松手检测
                                         }
                                         if(keydown==0)
                                         {
                                         func_index=table[func_index].down;    //向下翻
                                         while(!keydown);
                                         }
                                         if(keyenter==0)
                                         {
                                         func_index=table[func_index].enter;    //确认
                                         while(!keyenter);
                                         }
                                  init_lcd();
                               }                                    
                                current_operation_index=table[func_index].current_operation;
                                (*current_operation_index)();//执行当前操作函数
                       }
    }
    展开全文
  • 转自:... 单片机实现多级菜单   1、首先定义一个机构体如下 typedef struct  {  uchar current;  uchar up;//上键  uchar down;//下键  uchar enter;//确认键  vo...

    转自:https://blog.csdn.net/u010980705/article/details/52600980

    单片机实现多级菜单

     

    1、首先定义一个机构体如下
    typedef struct
       {
         uchar current;
         uchar up;//上键
         uchar down;//下键
         uchar enter;//确认键
         void (*current_operation)();
         } key_table;


    结构体包含5个变量,分别是函数的索引号即用户想要执行哪个函数的代号,然后有三个键,用户可以自己定义别的按键,最后一个是函数指针,即索引号对应的函数。然后在定义一个结构体数组,如下
    key_table code table[n]=
    {
         {0,2,1,3,(*fun1)},
         {1,0,2,4,(*fun2)},
         {2,1,0,5,(*fun3)},                  
         {3,0,6,3,(*fun4)},
         {4,1,6,4,(*fun5)},                       
         {5,2,6,5,(*fun6)},
         {6,0,0,0,(*fun7)},
         ............                                           
    };
    其中n为函数数组大小。下面详细介绍key_table code table[n]里面的值是怎么确定的。
    首先可以先这样定义该数组
    key_table code table[n]=
    {
         {0,x,y,z,(*fun1)},
         {1,x,y,z,(*fun2)},
         {2,x,y,z,(*fun3)},                  
         {3,x,y,z,(*fun4)},
         {4,x,y,z,(*fun5)},                       
         {5,x,y,z,(*fun6)},
         {6,x,y,z,(*fun7)},
         ............                                           
    };
    其中,x,y,z是未知数,先不确定,他们对应的是三个键按下要指示的索引值,如果四个键,就有四个未知数,在确定他们之前,必须要了解自己函数执行什么命令。加入开始时时执行数组里面的第一个即table[0],而想在此按上键执行函数fun6,那么table[0]里面需要这样设置
    {0,5,y,z,(*fun1)},同样,如果希望按下键执行fun7则需要设置为
    {0,x,6,z,(*fun1)},如果希望按确认键执行fun3则需要设置为
    {0,x,y,2,(*fun1)};如果上面三种情况都想要就设置为
    {0,5,6,2,(*fun1)}.其它数组元素一次类推。这一步做完了看主程序里面(主要是while(1)里面)。
    /*******************find index****************************/
                  switch(key)
                  {
    case 0x44:                                                            func_index=table[func_index].up;    //向上翻                                           break;
    case 0x24:                                           func_index=table[func_index].enter;//回车
    break;
    case 0x14:                                           func_index=table[func_index].down;//向下翻
    break;
    default:break;

                      }                                current_operation_index=table[func_index].current_operation;
    (*current_operation_index)();//执行当前操作函数

    其中,key是返回的按键值,这个用户视情况而定,
    下面是详细的例子,
    主要是以结构体为基础设计的,以12864显示函数代替了用户需要的函数功能,只需要修改相应的函数和索引号,就可以达到任意界面切换了是小弟研究了还久才搞定的,虽然网上也有这些,但是都不够系统,只有基本的东西,这篇例子希望能够给读者一些有用的东西,仅供参考哦!

    #include <reg52.h>
    #include "fun.h"
    #include "lcd12864.h"
    #include "delay.h"
    #define uchar unsigned char
    sbit keydown=P0^0;
    sbit keyenter=P0^1;
    sbit keyup=P0^2;
    uchar func_index=0;
    void (*current_operation_index)();
    typedef struct
       {
             uchar current;
             uchar up;//向上翻索引号
             uchar down;//向下翻索引号
             uchar enter;//确认索引号
             void (*current_operation)();
             } key_table;
    key_table code table[30]=
    {
            {0,3,1,4,(*fun1)},//第一层,显示【清华大学】、北京大学、重庆三峡学院、返回
             {1,0,2,8,(*fun2)},//第一层,显示清华大学、【北京大学】、重庆三峡学院、返回
             {2,1,3,12,(*fun3)},//第一层,显示清华大学、北京大学、【重庆三峡学院】、返回                     
             {3,2,0,25,(*fun4)},//第一层,显示清华大学、北京大学、重庆三峡学院、【返回】
             {4,7,5,16,(*fun5)},//第二层,清华大学层下显示【地点】、创建时间、简介、返回                                                   
             {5,4,6,17,(*fun6)},//第二层,清华大学层下显示地点、【创建时间】、简介、返回      
             {6,5,7,18,(*fun7)}, //第二层,清华大学层下显示地点、创建时间、【简介】、返回                                                                             
             {7,6,4,0,(*fun8)},//第二层,清华大学层下显示地点、创建时间、简介、【返回】      
             {8,11,9,19,(*fun9)},//第二层,北京大学层下显示【历史】、政治、简介、返回                                                
             {9,8,10,20,(*fun10)},//第二层,北京大学层下显示历史、【政治】、简介、返回  
             {10,9,11,21,(*fun11)}, //第二层,北京大学层下显示历史、政治、【简介】、返回                                                                                
             {11,10,8,1,(*fun12)},//第二层,北京大学层下显示历史、政治、简介、【返回】         
             {12,15,13,22,(*fun13)},//第二层,重庆三峡学院层下显示【简介】、最佳院系、最佳实验室、返回                                                        
             {13,12,14,23,(*fun14)}, //第二层,重庆三峡学院层下显示简介、【最佳院系】、最佳实验室、返回                                                               
             {14,13,15,24,(*fun15)}, //第二层,重庆三峡学院层下显示简介、最佳院系、【最佳实验室】、返回                                                               
             {15,14,12,2,(*fun16)}, //第二层,重庆三峡学院层下显示简介、最佳院系、最佳实验室、【返回】   
             {16,16,16,4,(*fun17)}, //第三层,清华大学地点层                                                                    
             {17,17,17,5,(*fun18)}, //第三层,清华大学创时间层                                                      
             {18,18,18,6,(*fun19)}, //第三层,清华大学简介层
             {19,19,19,8,(*fun20)}, //第三层,北京大学历史层                                                                    
             {20,20,20,9,(*fun21)}, //第三层,北京大学政治层                                                           
             {21,21,21,10,(*fun22)}, //第三层,北京大学简介层
             {22,22,22,12,(*fun23)}, //第三层,重庆三峡学院简介层                                                                  
             {23,23,23,13,(*fun24)}, //第三层,重庆三峡学院最佳院系层                                                        
             {24,24,24,14,(*fun25)}, //第三层,重庆三峡学院最佳实验室层        
             {25,25,25,0,(*fun26)}, //第0层      

    };
    void main()
    {  
              init_lcd(); //初始化LCD模块  
       while(1)
       {     
             /*******************find index****************************/
                                if((keyup==0)||(keydown==0)||(keyenter==0))
                                {
                                         delay(10);//消抖
                                         if(keyup==0)
                                         {
                                         func_index=table[func_index].up;    //向上翻
                                         while(!keyup);//松手检测
                                         }
                                         if(keydown==0)
                                         {
                                         func_index=table[func_index].down;    //向下翻
                                         while(!keydown);
                                         }
                                         if(keyenter==0)
                                         {
                                         func_index=table[func_index].enter;    //确认
                                         while(!keyenter);
                                         }
                                  init_lcd();
                               }                                    
                                current_operation_index=table[func_index].current_operation;
                                (*current_operation_index)();//执行当前操作函数
                       }
    }

    展开全文
  • 基于单片机多级菜单实现方法及其改进,主要实现了菜单的进一步优化
  • C51与单片机系统多级菜单的模块化设计
  • LCD多级菜单显示,并能进行上下翻页,单片机C语言,在KEIL下运行
  • 单片机C语言,多级菜单程序

    热门讨论 2009-09-24 14:20:52
    使用C语言编写的多级菜单程序,在51机器上测试通过,最多可三级
  • 单片机LCD简单多级菜单实现

    万次阅读 2016-12-11 23:36:48
    多年以前,我写过一篇12864lcd显示屏多级菜单代码实现 博客,当时草率的实现了一个菜单画面,然并没有实际用处,因为作为菜单的选取响应动作并没有在其中实现。这个就是补充了。
  • 单片机C语言下LCD多级菜单的一种 单片机C语言下LCD多级菜单的一种
  • 单片机C语言下LCD多级菜单的一种实现方法
  • C语言是学习单片机的过程中必须要经历的一个环节,但是并不是说学习单片机C语言就要像C语言开发程序员一样要掌握C语言的全部,因此我们只要掌握C语言中可以操作单片机的那一部分就可以了,今天我们要说的就是C语言...
  • 基于单片机的LCD液晶显示中涉及的多级菜单程序的源码(c语言)移植及移植中需要注意的源码解析移植文档,可以满足大多数应用,其中很多思想很值得借鉴
  • 单片机C语言下LCD多级菜单的一种实现方法.PDF

空空如也

空空如也

1 2 3 4
收藏数 77
精华内容 30
关键字:

单片机多级菜单