单片机c语言下lcd多级菜单的一种实现方法

图形点阵式液晶可显示用户自定义的任意符号

和图形,并可卷动显示。它作为单片机系统人机交

互界面的重要组成部分被广泛应用于实时检测和显

示的仪器仪表中,例如手机上的显示屏就是图形点

阵液晶。

采用图形点阵式液晶显示较之其它显示方式主

要有以下优点:

(1) 工作电压低、功耗极低。工作电压仅为3~

5 v ,工作电流≤10 μa/ cm2 ,特别适用于低功耗的

仪器仪表中。

(2) 液晶显示属被动显示,受外界光线干扰小。

(3) 图形点阵式液晶可显示的信息量大、分辨

率高。

(4) 不产生电磁干扰。

(5) 可*性高,使用寿命长。

本文所介绍的lcd 采用128 ×64 点阵的液晶

屏,因此可显示16 ×16 点阵的汉字4 行8 列。菜单

为多级嵌套形式,最长的有13 层,主要完成对某个

测点各方面的设置或查询,可通过”向上”、”向下”、

“回退”、”确认”4 个键或遥控器来实现对菜单的选

择。具体功能:

“向上”键:在本层菜单的项目中向上移动进行

选择;

“向下”键:在本层菜单的项目中向下移动进行

选择;

“回退”键:取消本层的菜单设置,返回上层菜

“确认”键:确认本层的菜单设置,进入下级菜

可根据用户在菜单中的选择项对测点进行某些

设置,或者进行某些特殊的显示,例如对某个测点的

实时曲线显示等。

程序设计

根据需求,首先建立一个结构,并定义一个结构

变量kbdtabst ruct 。结构变量就是把多个不同类

型的变量结合在一起形成的一个组合型变量,构成

一个结构的各个变量称为结构元素。该结构中共有

6 个结构元素,分别是5 个字符型和1 个指针变量,

5 个字符型变量分别为当前及各个按键的索引号,

也就是*作的状态号,最后1 个指针变量指向需执

行函数。这样就可以做一个结构数组,在结构数组

里为每一个菜单项编制一个单独的函数,并根据菜

单的嵌套顺序排好本菜单项的索引号,以及本级菜

单项的上、下卷动的索引号和上、下级菜单的索引号。

具体程序如下所述:

typedef st ruct

uchar keystateindex ; / / 当前状态索引号

uchar keydnstate ; / / 按下”向下”键时转向的状态索引号

uchar keyupstate ; / / 按下”向上”键时转向的状态索引号

uchar keycrstate ; / / 按下”回车”键时转向的状态索引号

uchar keybackstate ; / / 按下”退回”键时转向的状态索引号

void ( 3 currentoperate) ( ) ; / / 当前状态应该执行的

功能*作

} kbdtabst ruct ;

define size - of keybd - menu 55 / / 菜单总长度

kbdtabst ruct code keytab[ size - of - keybd - menu ] =

{0 ,0 ,0 ,1 ,0 , ( 3 mainjob1) } ,

{1 ,7 ,2 ,8 ,0 , ( 3 dsp point) } , / / 第一层

{2 ,1 ,3 ,8 ,0 , ( 3 dspcurve) ) , / / 第一层

{3 ,2 ,4 ,36 ,0 , ( 3 dsp kout) } , / / 第一层

{4 ,3 ,5 ,50 ,0 , ( 3 disclosedown) } , / / 第一层

程序设计

根据需求,首先建立一个结构,并定义一个结构

变量kbdtabst ruct 。结构变量就是把多个不同类

型的变量结合在一起形成的一个组合型变量,构成

一个结构的各个变量称为结构元素。该结构中共有

6 个结构元素,分别是5 个字符型和1 个指针变量,

5 个字符型变量分别为当前及各个按键的索引号,

也就是*作的状态号,最后1 个指针变量指向需执

行函数。这样就可以做一个结构数组,在结构数组

里为每一个菜单项编制一个单独的函数,并根据菜

单的嵌套顺序排好本菜单项的索引号,以及本级菜

单项的上、下卷动的索引号和上、下级菜单的索引号。

具体程序如下所述:

typedef st ruct

uchar keystateindex ; / / 当前状态索引号

uchar keydnstate ; / / 按下”向下”键时转向的状态索引号

uchar keyupstate ; / / 按下”向上”键时转向的状态索引号

uchar keycrstate ; / / 按下”回车”键时转向的状态索引号

uchar keybackstate ; / / 按下”退回”键时转向的状态索引号

void ( 3 currentoperate) ( ) ; / / 当前状态应该执行的

功能*作

} kbdtabst ruct ;

define size - of keybd - menu 55 / / 菜单总长度

kbdtabst ruct code keytab[ size - of - keybd - menu ] =

{0 ,0 ,0 ,1 ,0 , ( 3 mainjob1) } ,

{1 ,7 ,2 ,8 ,0 , ( 3 dsp point) } , / / 第一层

{2 ,1 ,3 ,8 ,0 , ( 3 dspcurve) ) , / / 第一层

{3 ,2 ,4 ,36 ,0 , ( 3 dsp kout) } , / / 第一层

{4 ,3 ,5 ,50 ,0 , ( 3 disclosedown) } , / / 第一层

下面是一个具体的例子:

unsigned char tempin,tempout,temprun;

unsigned char Key_Value();

unsigned char Change_Value(unsigned char);

void Delay_1(unsigned int m);

void Run_Satus();

char * MainMenuTitle = “主菜单”;

const char * MainMenuItems[] = {

“1.室内温度调整”,

“2.室外温度调整”,

“3.运行时间调整”,

“4.ESC退出”,

TMenu MainMenu;

void OnSelectMainMenu(int index)

if (index < 0 || index >= sizeof(MainMenuItems) / sizeof(char *)) return;

ClearScreen();

switch (index) {

case 0:

TextOut(0, 1, “室内调整开始 “);

tempin=Change_Value(tempin);

TextOut(0, 1, “室内调整完毕”);

Delay_1(300000);

break;

case 1:

TextOut(0, 1, “室外调整开始 “);

tempout=Change_Value(tempout);

TextOut(0, 1, “室外调整完毕”);

Delay_1(300000);

break;

case 2:

TextOut(0, 1, “运行时间调整开始”);

tempout=Change_Value(temprun);

TextOut(0, 1, “运行时间完毕”);

Delay_1(300000);

break;

case 3:

break;

ClearScreen();

UINT OnMainMenuOk(void * arg)

TMenu * pMenu = (TMenu *)arg;

if (pMenu) OnSelectMainMenu(pMenu->Current);

return 0;

UINT OnMainMenuCancel(void * arg)

TMenu * pMenu = (TMenu *)arg;

if (pMenu) {

CloseMenu(pMenu);

return 0;

UINT OnMainMenuOtherKey(void * arg)

TMenu * pMenu = (TMenu *)arg;

char key;

if (pMenu) {

key = pMenu->EventArg;

OnSelectMainMenu(key - ‘1’);

DrawMenu(pMenu);

return 0;

void InitMenu()

InitializeMenu(&MainMenu, MainMenuTitle, MainMenuItems, sizeof

(MainMenuItems) / sizeof(char *));

MainMenu.OnOk = OnMainMenuOk;

MainMenu.OnOtherKey = OnMainMenuOtherKey;

MainMenu.OnCancel = OnMainMenuCancel;

unsigned char Key_Value()

unsigned char KeyTemp;

KeyTemp=GetKey();

switch(KeyTemp)

case(VK_ESCAPE):

return(0);

break;

case(VK_ENTER):

return(1);

break;

case(VK_UP):

return(2);

break;

case(VK_DOWN):

return(3);

break;

unsigned char Change_Value(unsigned char temp2)

unsigned char temp3;

temp3=temp2;

while((Key_Value()!=0)&&(Key_Value()!=1))

if(Key_Value()==2)temp3++;

else if(Key_Value()==3)temp3–;

ClearLine(1);

TextOut(0, 1, “调整状态%d”, temp3);

if(Key_Value()==1)return(temp3);

else if(Key_Value()==0) return(temp2);

void Delay_1(unsigned int m)

while(m–);

void Run_Satus()

ClearScreen();

TextOut(0, 0, “室内温度%d”,tempin);

TextOut(0, 1, “室外温度%d”,tempout);

TextOut(0, 2, “运行时间%d”,temprun);

TextOut(0, 3, “ENTER 进入调整”);

void tmain()

tempin=30;

tempout=30;

temprun=30;

unsigned char key;

InitMenu();

while(1)

Run_Satus();

key=GetKey();

if(key==VK_ENTER)ShowMenu(&MainMenu);