下面我们就模仿手机菜单为例进行说明,首先需要说明几点:
1. 本例只有5个按键,所以没有退出按键,退出需要通过函数实现。
2.本例液晶只可以显示4行汉子,每行显示8个汉字(128*64),所以一行显示标题,3行实现菜单显示和翻滚。
3.光标所以项反白显示。
4.对于按键与显示等,本例不在说明,只说明菜单实现方式。
// 按键值定义#define KV_NO (0x00) // 无#define KV_UP (0x02) // 上#define KV_DN (0x04) // 下#define KV_MD (0x08) // 中#define KV_LF (0x10) // 左#define KV_RT (0x20) // 右/*************************************************************************************** Variable definition **************************************************************************************/// 菜单参数typedef struct _MENU_PRMT{ uint8 ExitMark; // 退出菜单(0-不退出,1-退出) uint8 Cursor; // 光标值(当前光标位置) uint8 PageNo; // 菜单页(显示开始项) uint8 Index; // 菜单索引(当前选择的菜单项) uint8 DispNum; // 显示项数(每页可以现在菜单项) uint8 MaxPage; // 最大页数(最大有多少种显示页)} MENU_PRMT;//------------------------------------------------------------------------------------// 菜单执行typedef struct _MENU_TABLE{ uint8 *MenuName; // 菜单项目名称 void (*ItemHook)(void); // 要运行的菜单函数} MENU_TABLE;//---------------------------------- 主菜单 ---------------------------------------MENU_PRMT GSetPrmt; // 常规设置参数MENU_TABLE GeneralSet[] = // 常规设置{ {"1. 情景模式 ", Menu_Profile }, // 情景模式 {"2. 时间与日期 ", Menu_SetClock }, // 时间与日期 {"3. 语言 ", Menu_Null }, // 选择语言 {"4. 话机设置 ", Menu_Null }, // 话机设置 {"5. 语音设置 ", Menu_Null }, // 语音设置 {"6. 安全设置 ", Menu_Null }, // 安全设置 {"7. 网络设置 ", Menu_Null }, // 网络设置 {"8. 个人快捷设置 ", Menu_Null }, // 个人快捷设置 {"9. 恢复出厂设置 ", Menu_Null }, // 恢复出厂设置 {"10.退出菜单 ", Menu_Null }, // 退出菜单};//----------------------------------- 二级菜单 -------------------------------------MENU_PRMT ProfilePrmt; // 情景模式参数MENU_TABLE Profile[] = // 情景模式{ {"1. 标准 ", Menu_Null }, // 标准 {"2. 会议 ", Menu_Null }, // 会议 {"3. 户外 ", Menu_Null }, // 户外 {"4. 振动 ", Menu_Null }, // 振动 {"5. 耳机 ", Menu_Null }, // 耳机 {"6. 蓝牙模式 ", Menu_Null }, // 蓝牙模式 {"7. 离线模式 ", Menu_Null }, // 离线模式 {"8. 退出菜单 ", Menu_ExitProfile }, // 退出菜单};MENU_PRMT ClockPrmt; // 时间与日期参数MENU_TABLE Clock[] = // 时间与日期{ {"1. 时间/日期设置", Menu_Null }, // 时间/日期设置 {"2. 格式设置 ", Menu_Null }, // 格式设置 {"3. 设置城市 ", Menu_Null }, // 设置城市 {"4. 时区与时间 ", Menu_Null }, // 时区与时间 {"5. 退出时钟设置 ", Menu_ExitClockSet}, // 退出时钟设置};/*************************************************************************************** FunctionName : Menu_Null()* Description : 空函数* EntryParameter : None* ReturnValue : None**************************************************************************************/void Menu_Null(void){ ;}/*************************************************************************************** FunctionName : Menu_KeySan()* Description : 获取按键值* EntryParameter : None* ReturnValue : 返回按键值**************************************************************************************/uint8 Menu_KeySan(void){ uint8 key = KV_NO; key = KeyGetValue(); // 获取按键 if (key != KV_NO) { BuzzerSound(1); // 有键按下,响一声 while(KeyGetValue() != KV_NO) // 等待按键释放 { ; } } return key;}/*************************************************************************************** FunctionName : Menu_PrmtInit()* Description : 初始化菜单参数* EntryParameter : prmt - 菜单参数, num - 显示项, page - 显示页* ReturnValue : None**************************************************************************************/void Menu_PrmtInit(MENU_PRMT *prmt, uint8 num, uint8 page){ prmt->ExitMark = 0; // 清除退出菜单标志prmt->Cursor = 0; // 光标清零prmt->PageNo = 0; // 页清零prmt->Index = 0; // 索引清零prmt->DispNum = num; // 页最多显示项目数prmt->MaxPage = page; // 最多页数}/*************************************************************************************** FunctionName : Menu_Display()* Description : 显示菜单* EntryParameter : page - 显示页,dispNum - 每一页的显示项,cursor - 光标位置* ReturnValue : None**************************************************************************************/void Menu_Display(MENU_TABLE *menu, uint8 page, uint8 dispNum, uint8 cursor){uint8 i;for (i=0; i<dispNum; i++){if (cursor == i){LCMDisplayStrRvs(0, (i+1)*2, menu[page+i].MenuName); // 反白显示菜单项}else{LCMDisplayStr(0, (i+1)*2, menu[page+i].MenuName); // 显示菜单项 }}}/*************************************************************************************** FunctionName : Menu_Move()* Description : 菜单移动* EntryParameter : prmt - 菜单参数, key - 按键值* ReturnValue : 有确认返回0,否则返回1**************************************************************************************/uint8 Menu_Move(MENU_PRMT *prmt, uint8 key){ uint8 rValue = 1; switch (key) { case KV_UP: // 向上 if (prmt->Cursor != 0) // 光标不在顶端 { prmt->Cursor--; // 光标上移 } else // 光标在顶端 { if (prmt->PageNo != 0) // 页面没有到最小 { prmt->PageNo--; // 向上翻 } else { prmt->Cursor = prmt->DispNum-1; // 光标到底 prmt->PageNo = prmt->MaxPage-1; // 最后页 } } break; case KV_DN: // 向下 if (prmt->Cursor < prmt->DispNum-1) // 光标没有到底,移动光标 { prmt->Cursor++; // 光标向下移动 } else // 光标到底 { if (prmt->PageNo < prmt->MaxPage-1) // 页面没有到底,页面移动 { prmt->PageNo++; // 下翻一页 } else // 页面和光标都到底,返回开始页 { prmt->Cursor = 0; prmt->PageNo = 0; } } break; case KV_MD: // 确认 prmt->Index = prmt->Cursor + prmt->PageNo; // 计算执行项的索引 rValue = 0; break; case KV_LF: // 左键跳到顶部 prmt->Cursor = 0; prmt->PageNo = 0; break; case KV_RT: // 右键跳到底部 prmt->Cursor = prmt->DispNum-1; // 光标到底 prmt->PageNo = prmt->MaxPage-1; // 最后页 break; default:break; } return rValue; // 返回执行索引}/*************************************************************************************** FunctionName : Menu_Process()* Description : 处理菜单项* EntryParameter : menuName - 菜单名称,prmt - 菜单参数,table - 菜单表项, num - 菜单项数* ReturnValue : None**************************************************************************************/void Menu_Process(uint8 *menuName, MENU_PRMT *prmt, MENU_TABLE *table, uint8 num){ uint8 key; Menu_PrmtInit(prmt, PAGE_DISP_NUM, num-PAGE_DISP_NUM+1); // 显示项数和页数设置 do { LCMDisplayStr(0, 0, menuName); // 菜单标题显示 Menu_Display(table, prmt->PageNo, prmt->DispNum, prmt->Cursor); // 显示菜单项 key = Menu_KeySan(); // 获取按键 if (Menu_Move(prmt, key) == 0x00) // 菜单移动 { LCMClearScreen(LCM_WHITE); // 清屏 table[prmt->Index].ItemHook(); // 执行相应项 } } while (prmt->ExitMark == 0);}/*************************************************************************************** FunctionName : MenuGeneralSet()* Description : 常规设置* EntryParameter : None* ReturnValue : None**************************************************************************************/void MenuGeneralSet(void){ uint8 menuNum; menuNum = sizeof(GeneralSet)/sizeof(GeneralSet[0]); // 菜单项数 Menu_Process(" -= 常规设置 =- ", &GSetPrmt, GeneralSet, menuNum);}/*************************************************************************************** FunctionName : Menu_Profile()* Description : 情景模式* EntryParameter : None* ReturnValue : None**************************************************************************************/void Menu_Profile(void){ uint8 menuNum; menuNum = sizeof(Profile)/sizeof(Profile[0]); // 菜单项数 Menu_Process(" -= 情景模式 =- ", &ProfilePrmt, Profile, menuNum);}/*************************************************************************************** FunctionName : Menu_ExitProfile()* Description : 退出情景模式* EntryParameter : None* ReturnValue : None**************************************************************************************/void Menu_ExitProfile(void) { ProfilePrmt.ExitMark = 0x01; // 退出情景模式 LCMClearScreen(LCM_WHITE); // 清屏 } /*************************************************************************************** FunctionName : Menu_SetClock()* Description : 时间与日期设置* EntryParameter : None* ReturnValue : None**************************************************************************************/void Menu_SetClock(void){ uint8 menuNum; menuNum = sizeof(Clock)/sizeof(Clock[0]); // 菜单项数 Menu_Process(" -= 时间日期 =- ", &ClockPrmt, Clock, menuNum);}/*************************************************************************************** FunctionName : Menu_ExitClockSet()* Description : 退出日期与时钟* EntryParameter : None* ReturnValue : None**************************************************************************************/void Menu_ExitClockSet(void) { ClockPrmt.ExitMark = 0x01; // 退出时钟设置 LCMClearScreen(LCM_WHITE); // 清屏 }