菜单最初显示是这样的,下面上代码。代码布防其实并发全部又本人所写,但大部分代码本人都进行过
修改。
#define MENULEVEL 2 //当前菜单表个数
#define OPTIONMETE 19 //当前选项个数,包括一个特别功能选项
//#define SIZE sizeof(Address_buf)
//————————————-
//
// 菜单结构定义
//
//————————————-
struct Option{
unsigned char KeyLevel; //菜单选项所属菜单表号
unsigned char EnterIndex; //选项进入索引号
unsigned char CancelIndex; //选项退出索引号
unsigned char KeyWord[16]; //菜单选项文字描述数组
unsigned char WordMete; //菜单选项描述文字字节数
};
//————————————-
//
// 具体菜单选项定义,定义一个结构数组
// 存储在编码区,节省内存RAM
// 功能的进入索引应大于OPTIONMETE
// 在FunctionAction(void)函数的case选项
// 中应定义出索引对应的功能函数。
//————————————-
struct Option sOption[OPTIONMETE] = {
{0,OPTIONMETE-1,0,”设置报警界限”,12}, //0
{0,OPTIONMETE-1,0,”设置报警延时”,12}, //1 //一级菜单
{0,OPTIONMETE-1,0,”设置时钟时间”,12}, //2
{0,OPTIONMETE-1,0,”设置密码开关”,12}, //3
{0,6,0,”系统版本”,8}, //4
{0,OPTIONMETE-1,0,”退出菜单”,8}, //5
{1,OPTIONMETE-1,3,"****硬件****",12}, //6
{1,OPTIONMETE-1,3,"GSDC_V1.5",9}, //7
{1,OPTIONMETE-1,3,"****软件****",12}, //8
{1,OPTIONMETE-1,3,"GUI:",4}, //9//“系统版本”选项二级菜单
{1,OPTIONMETE-1,3,"Worm_V0.95",10}, //10
{1,OPTIONMETE-1,3,"Program:",8}, //11
{1,OPTIONMETE-1,3,"GSDC_Program",12}, //12
{1,OPTIONMETE-1,3,"V1.6.1",6}, //13
{1,OPTIONMETE-1,3,"****服务****",12}, //14
{1,OPTIONMETE-1,3," TCP终端设备",12}, //15
{1,OPTIONMETE-1,3,"客服电话:",10}, //16
{1,OPTIONMETE-1,3," ",10}, //17
{0,0,0,"",0} //18//特殊,无操作索引
};
//————————————–
//
// 菜单表分类数组
//
//————————————–
unsigned char Level[MENULEVEL][3] = {//每层表单对应 开始索引号、结束索引号、选项数目
{0,5,6},
{6,17,12},
};
unsigned char FirstLineDisIndex = 0; //屏幕第一行显示的索引号
unsigned char SelectLine = 1; //当前选择的行
unsigned char SelectIndex = 0; //当前选定行对应的索引号
unsigned char LastIndex = 0; //进入功能函数前的索引号,判断具体功能使用
/此部分为菜单的预定义部分应放在文件的最开头/
//—————————————-
//
// 判断当前索引是否是表单第一项功能函数
// 函数原形:u8 MenuLevelStart (void);
// 没有参数,返回Bit标志,是第一项返回1,不是返回0
// 调用方式:u8 MenuLevelStart (void);
//
//—————————————-
u8 MenuLevelStart (void) //判断当前索引是否为当前层第一个选项
{
unsigned char i = MENULEVEL;
do
{
i–;
if(SelectIndex == Level[i][0]) return 1;
}while(i);
return 0;
}
//—————————————-
//
// 判断当前索引是否是表单最后一项功能函数
// 函数原形:u8 MenuLevelEnd (void);
// 没有参数,返回Bit标志,是最后一项返回1,不是返回0
// 调用方式:u8 MenuLevelEnd (void);
//
//—————————————-
u8 MenuLevelEnd (void)
{
unsigned char i = MENULEVEL;
do
{
i–;
if(SelectIndex == Level[i][1]) return 1;
}while(i);
return 0;
}
//—————————————-
//
// 菜单上移一项函数
// 函数原形:void MenuUpOneOption (void);
// 没有参数,没有返回值
// 调用方式:void MenuUpOneOption (void);
//
//—————————————-
void MenuUpOneOption (void)
{
if(MenuLevelStart ()) //如果当前为表单第一项
{
if(Level[sOption[SelectIndex].KeyLevel][2]>=4) //并且表单中选项数目大于等于4个
{
FirstLineDisIndex = Level[sOption[SelectIndex].KeyLevel][1]-3;
//第一行显示索引号为倒数第四项
SelectIndex = Level[sOption[SelectIndex].KeyLevel][1]; //选择索引为表单最后一项
SelectLine = 4; //标记选择行为第四行
DIS12864M (); //刷新屏幕显示
}
else //如果选项数目并不大于四个
{
SelectIndex = Level[sOption[SelectIndex].KeyLevel][1]; //选择索引为当前表单最后一个
SelectLine = Level[sOption[SelectIndex].KeyLevel][2]; //显示行表单数目(最后一个)
DIS12864M (); //刷新屏幕显示
}
}
else //如果当前不是开始索引
{
if(SelectLine==1) //并且已经在屏幕最上边一行
{
FirstLineDisIndex–; //显示索引上移
SelectIndex–; //选择索引自减
SelectLine = 1; //选择行还是第一行
DIS12864M (); //刷新屏幕
}
else //如果不是第一行
{
SelectLine–; //选择行自减
SelectIndex–; //选择索引自减
DIS12864M (); //刷新屏幕显示
}
}
}
//—————————————-
//
// 菜单下移一项函数
// 函数原形:void MenuDownOneOption (void);
// 没有参数,没有返回值
// 调用方式:void MenuDownOneOption (void);
//
//—————————————-
void MenuDownOneOption (void)
{
if(MenuLevelEnd ()) //如果当前是表单最后一个索引
{
FirstLineDisIndex = Level[sOption[SelectIndex].KeyLevel][0];
//第一行显示索引为表单第一个选项
//选择索引为表单第一个选项索引
SelectLine = 1; //选择行为第一行
DIS12864M (); //刷新显示
}
else //如果不是最后的索引
{
if(SelectLine!=4) //如果当前不是屏幕最底行
{
SelectIndex++; //选择索引自加
SelectLine++; //选择行下移
SetALineReverse (SelectLine); //刷新选择行
DIS12864M (); //刷新显示
}
else //如果是屏幕最低行
{
FirstLineDisIndex++; //第一行显示下移
SelectIndex++; //选择索引自加
DIS12864M(); //刷新显示
}
}
}
//—————————————-
//
// 某些功能函数,完成菜单中的具体功能
//
//—————————————-
void password_authentification(void) //登录密码校验函数
{
u8 pallword_sum=0;
u8 pallword_value[6]={‘1’,’2’,’3’,’4’,’5’,’6’};
u8 pallword[6];
u8 pal_sum=0;
u8 i=0;
LCD_Chinese_disp(0,0,”—-登录界面—-<”);
LCD_Chinese_disp(1,0,”请输入6 位密码 <”); //
LCD_Chinese_disp(2,0,”按END 键结束 <”);
LCD_Chinese_disp(3,0,” <”);
delay_ms(500);
while(1)
{
pallword_sum=0;
if((KEY_Scan()!=0x00)&&(KEY_Scan()!=’D’)&&(KEY_Scan()!=’C’))
{
pallword[pal_sum]=KEY_Scan();
LCD_Chinese_disp(3,pal_sum,”* <”);
delay_ms(300);
pal_sum++;
if(pal_sum>5)
{
pal_sum=0;
}
}else if(KEY_Scan()=='D') //按下确认键
{
for(i=0;i<6;i++)
{
if(pallword[i]==pallword_value[i])
{
pallword_sum++;
}
pallword[i] = ' ';
}
pal_sum = 0;
if(pallword_sum == 6)
{
pwr_sig = 1;
DIS12864M (); //刷新菜单
break; //六位密码全部正确
}else //密码不正确处理
{
LCD_Chinese_disp(3,0,"操作密码错误! <");
delay_ms(1000);
LCD_Chinese_disp(3,0," <");
}
}else if(KEY_Scan()=='C') //按下退出键
{
pwr_sig = 0;
break; //输入密码时按退出键
}
}
}
void shut_down(void) //菜单“退出系统”选项的功能实现
{
FirstLineDisIndex = 0; //屏幕第一行显示的索引号
SelectLine = 1; //当前选择的行
SelectIndex = 0; //当前选定行对应的索引号
LastIndex = 0; //进入功能函数前的索引号,判断具体功能使用
down = 1;
}
//—————————————-
//
// 具体功能散转函数
// 函数原形:void FunctionAction
// 没有参数,没有返回值
// 调用方式:void FunctionAction (void);
//
//—————————————-
void FunctionAction (void) ////////////////////////////////
{
switch(LastIndex) //根据进入前的索引判断具体函数
{
case 5:shut_down(); break; //退出菜单功能索引
case 0:Arm_SEN_set(); break; //报警灵敏度设置
case 1:Arm_Delay_set(); break; //报警延时设置
case 2:Time_set(); break; //时间设置功能索引
case 3:Password_switch_set(); break; //密码校验开关
default:shut_down();break; //如果没有具体操作,显示没有这个功能
}
}
//—————————————-
//
// 进入某项功能函数
// 函数原形:void MenuEnterOption (void);
// 没有参数,没有返回值
// 调用方式:void MenuEnterOption (void);
//
//—————————————-
void MenuEnterOption (void)
{
LastIndex = SelectIndex; //标记进入前的索引号(以便判断具体功能)
SelectIndex = sOption[SelectIndex].EnterIndex;
//更新选择索引为之前索引号对应进入索引
if(SelectIndex != OPTIONMETE-1) //如果当前索引不是功能选择索引 /////////////////////////////////////////////////////////////
{
//第一行显示为进入表单第一项
SelectLine = 1; //设定第一行为选择行
DIS12864M (); //刷新菜单
}
else FunctionAction (); //如果是功能选择项,进入功能分支判断函数
}
//—————————————-
//
// 菜单退出功能函数
// 函数原形:void MenuCancelOption (void);
// 没有参数,没有返回值
// 调用方式:void MenuCancelOption (void);
//
//—————————————-
void MenuCancelOption (void)
{
if(SelectIndex != OPTIONMETE-1) //如果不是从功能返回
SelectIndex = sOption[SelectIndex].CancelIndex; //选择索引为选项返回索引
else //如果是从功能返回
SelectIndex = LastIndex; //索引等于进入前保存索引
if(Level[sOption[SelectIndex].KeyLevel][2]>=4) //如果返回表单选项数目大于4个
{
if(SelectIndex > Level[sOption[SelectIndex].KeyLevel][1]-3)
//根据返回选项确定显示首项
{
FirstLineDisIndex = Level[sOption[SelectIndex].KeyLevel][1]-3;
SelectLine = 4-(Level[sOption[SelectIndex].KeyLevel][1]-SelectIndex);
DIS12864M (); //刷新显示
}
else //一般显示方式
{
FirstLineDisIndex = SelectIndex; //第一行显示索引
SelectLine = 1; //选择第一行
DIS12864M (); //刷新菜单
}
}
else //如果返回表单选项数目不足4个
{
FirstLineDisIndex = Level[sOption[SelectIndex].KeyLevel][0];
//第一行显示索引为表单第一项
//选择行标志为当前选择索引对应行
DIS12864M (); //刷新菜单
}
}
//—————————————-
//
// 菜单操作按键处理散转函数
// 函数原形:void KeyCodeAction (unsigned char KeyCode);
// 键码作为参数,没有返回值
// 调用方式:void KeyCodeAction (unsigned char KeyCode);
// 实际使用应根据自己的按键重新编写case项
//
//—————————————-
void KeyCodeAction (unsigned char KeyCode)
{
switch (KeyCode)
{
case ‘*’:
{
beep_bi(); //蜂鸣器响一声
MenuUpOneOption();
delay_ms(100);
break; //如果是向上按键,则菜单向上,以下类似
}
case ‘#’:
{
beep_bi(); //蜂鸣器响一声
MenuDownOneOption();
delay_ms(100);
break;
}
case ‘D’:
{
beep_bi_bi(); //蜂鸣器响两声
MenuEnterOption();
delay_ms(100);
break;
}
case ‘C’:
{
beep_bi(); //蜂鸣器响一声
MenuCancelOption();
delay_ms(100);
break;
}
default: break;
}
}
//—————————————-
//
// 菜单更新函数
// 函数原形:void MenuReflash (void);
// 没有参数,没有返回值
// 调用方式:void MenuReflash (void);
// 实际应配合自己的按键编码获取程序使用
//
//—————————————-
void MenuReflash (void)
{
unsigned char Keytemp; //保存按键编码变量
Keytemp = KEY_Scan(); //保存按键编码
if(Keytemp!=0x00) //如果按键编码有效
{
KeyCodeAction(Keytemp); //根据按键说明字母散转
down_sum = 2000; //如果进入菜单后有按键操作,则重新计时。
}
}
void enter_menu(void)
{
u8 pallword_sum=0;
u8 pallword_value[6]={‘1’,’2’,’3’,’4’,’5’,’6’};
u8 pallword[6];
u8 pal_sum=0;
u8 i=0;
u16 esc_time_num = 0;
if(Password_SW) //判断是否需要输入密码1时需要输入,0时不需要输入。
{
if((KEY_Scan() == '0')||(KEY_Scan() == '1')||(KEY_Scan() == '2')
||(KEY_Scan() == '3')||(KEY_Scan() == '4')||(KEY_Scan() == '5')
||(KEY_Scan() == '6')||(KEY_Scan() == '7')||(KEY_Scan() == '8')
||(KEY_Scan() == '9'))
{
while(1)
{
BL_set_L; //打开背光
if((KEY_Scan()!=0x00)&&(KEY_Scan()!='D')&&(KEY_Scan()!='C')&&(KEY_Scan()!='A')&&(KEY_Scan()!='B'))
{
pallword[pal_sum]=KEY_Scan();
beep_bi(); //蜂鸣器响一声
LCD_Chinese_disp(0,0,"----登录界面----<");
LCD_Chinese_disp(1,0,"请输入6 位密码 <"); //
LCD_Chinese_disp(2,0,"按END 键结束 <");
if(pal_sum == 0)
{
LCD_Chinese_disp(3,pal_sum,"* <");
}else
{
LCD_Chinese_disp(3,pal_sum,"* <");
}
delay_ms(300);
pal_sum++;
if(pal_sum>5)
{
pal_sum=0;
}
esc_time_num = 0; //清楚自动退出密码输入界面的计时。
}else if(KEY_Scan()=='A')
{
for(i=0;i<6;i++) //检查6位密码是否正确
{
if(pallword[i]==pallword_value[i])
{
pallword_sum++;
}
pallword[i] = ' ';
}
pal_sum = 0;
if(pallword_sum == 6) //如果全部都正确执行布防命令
{
//////////////////////////////////////////////////////////////////
break;
}else
{
BL_set_L; //打开背光
LCD_Chinese_disp(0,0,"----登录界面----<");
LCD_Chinese_disp(1,0,"请输入6 位密码 <"); //
LCD_Chinese_disp(2,0,"按END 键结束 <");
LCD_Chinese_disp(3,0,"密码错误! <");
beep_du(); //长警告音
delay_ms(1000);
delay_ms(1000);
break;
}
}else if(KEY_Scan()=='B')
{
for(i=0;i<6;i++) //检查6位密码是否正确
{
if(pallword[i]==pallword_value[i])
{
pallword_sum++;
}
pallword[i] = ' ';
}
pal_sum = 0;
if(pallword_sum == 6) //如果全部都正确执行布防命令
{
/////////////////////////////////////////////////////////////////////////
break;
}else
{
BL_set_L; //打开背光
LCD_Chinese_disp(0,0,"----登录界面----<");
LCD_Chinese_disp(1,0,"请输入6 位密码 <"); //
LCD_Chinese_disp(2,0,"按END 键结束 <");
LCD_Chinese_disp(3,0,"密码错误! <");
beep_du(); //长警告音
delay_ms(1000);
delay_ms(1000);
break;
}
}else if(KEY_Scan()=='C')
{
beep_du(); //长警告音
break;
}else if(KEY_Scan()=='D')
{
for(i=0;i<6;i++) //检查6位密码是否正确
{
if(pallword[i]==pallword_value[i])
{
pallword_sum++;
}
pallword[i] = ' ';
}
pal_sum = 0;
if(pallword_sum == 6) //如果全部都正确执行布防命令
{
beep_bi_bi(); //蜂鸣器响两声
BL_set_L; //进入菜单时打开背光
DIS12864M (); //刷新菜单
delay_ms(50);
while(1)
{
MenuReflash(); //进入主菜单
down_sum--;
if(down_sum<=0) //如果进入菜单20秒无操作,则自动退出菜单。
{
shut_down();
down_sum = 2000;
}
if(down)
{
delay_ms(100);
down = 0;
break;
}
delay_ms(10);
}
break;
}else
{
LCD_Chinese_disp(0,0,"----登录界面----<");
LCD_Chinese_disp(1,0,"请输入6 位密码 <"); //
LCD_Chinese_disp(2,0,"按END 键结束 <");
LCD_Chinese_disp(3,0,"密码错误! <");
beep_du(); //长警告音
delay_ms(1000);
delay_ms(1000);
break;
}
}else //如果长时间保持无按键按下时退回到主界面
{
if(esc_time_num == 2000)
{
esc_time_num = 0;
break;
}else
{
esc_time_num++;
delay_ms(10);
}
}
}
}
}else //不需要输入密码时菜单和快捷撤布防的命令处理
{
if(KEY_Scan()=='A')
{
beep_bi_bi(); //蜂鸣器响两声
BL_set_L; //打开背光
}else if(KEY_Scan()=='B')
{
beep_bi_bi(); //蜂鸣器响两声
BL_set_L; //打开背光
}else if(KEY_Scan()=='C')
{
beep_du(); //长警告音
BL_set_L; //打开背光
}else if(KEY_Scan()=='D')
{
beep_bi_bi(); //蜂鸣器响两声
BL_set_L; //进入菜单时打开背光
DIS12864M (); //刷新菜单
while(1)
{
MenuReflash(); //进入主菜单
down_sum--;
if(down_sum<=0) //如果进入菜单20秒无操作,则自动退出菜单。
{
shut_down();
down_sum = 2000;
}
if(down)
{
delay_ms(100);
down = 0;
break;
}
delay_ms(10);
}
LCD_clear(); //清空液晶屏显示
}
}
}
如果需要移植此段代码的朋友需要注意几个函数,一个是液晶显示刷新函数,一个是指示器显示函数。
本人这两个函数是这样写的:
//—————————————-
//
// 刷新菜单功能函数
// 函数原形:void DIS12864M (void);
// 没有参数,没有返回值
// 调用方式:void DIS12864M (void);
//
//—————————————-
void DIS12864M (void)
{
unsigned char LineMete = Level[sOption[SelectIndex].KeyLevel][2]; //循环量,显示行数
write_com(0x30); //进入液晶普通指令模式
write_com(0x01); //清屏
delay_ms(100);
SetALineReverse(SelectLine); //填充所需反白
do //分别显示各行菜单项
{
LCD_Chinese_disp(0,1,sOption[FirstLineDisIndex].KeyWord);
if(LineMete == 0) break;
LCD_Chinese_disp(1,1,sOption[FirstLineDisIndex+1].KeyWord);
if(LineMete == 0) break;
LCD_Chinese_disp(2,1,sOption[FirstLineDisIndex+2].KeyWord);
if(LineMete == 0) break;
LCD_Chinese_disp(3,1,sOption[FirstLineDisIndex+3].KeyWord);
}while(0);
SetALineReverse(SelectLine); //填充所需反白
}