admin 管理员组

文章数量: 1086019


2024年3月13日发(作者:食肉菌预防)

30

卷 第

3

Vol.30 3

计 算 机 工 程

Computer Engineering

文献标识码:

A

2004

2

February 2004

中图分类号:

TP311 文章编号:

1000

3428(2004)03 0191

——

02

・开发研究与设计技术・

一种用

C51

实现的单片机系统菜单管理方案

黄声野

1

,陈秀华

2

,王东生

1

1. 100084

清华大学精密仪器系,北京;

2. 100084

北京汉王科技有限公司,北京)

摘 要:介绍的菜单管理方案灵活应用

C51

中的指针和结构体数据类型,使得菜单程序和主程序之间、各级菜单之间相对独立,实现了方便

地修改菜单的同时不会对主程序有任何影响。文中详细描述和举例说明了这种菜单管理方案,并说明了菜单修改的方法。

关键词:菜单;

C51

;指针变量

A Singlechip System Menu Management Realized with C51

HUANG Shengye

1

CHEN Xiuhua

2

WANG Dongsheng

1

(1. Dept. of PIM, Tsinghua University, Beijing100084

2. Beijing Hanwang Limit Co., Beijing 100084)

【Abstract】

The paper introduces a universal and practical method for menus manage . By using Pointer and structure of C51 langue, this novel menu

management successfully separates the menu program from the main program, and makes the submenus independent from each other. Details and

examples, as well as menu modify method are provided.

【Key words】

Menu; C51; Pointer variation

1

概述

采用单片机系统的仪器设备中经常采用菜单的方式进行

人机对话。在采用汇编语言单片机应用系统中

[1]

,用制表的

方法可以较好地编写菜单程序。但是汇编语言本身可读性和

移植性较差。单片机高级语言C51

[2]

不仅能够克服汇编语言

的这些缺点,在编写菜单程序时,还可以使用C语言

[3]

的各

种指针和数据结构灵活地实现菜单管理

[4,5]

。通常情况下,

菜单数据的全部或部分往往被直接写在主程序中,导致程序

错综复杂,难以进行多级菜单的维护和扩展。本文介绍的菜

单管理方案将菜单程序和主程序分开,而用指针变量将二者

联系起来,即使有很多级的菜单也能方便地修改或扩展。

M_Main

#define MainSum 2

项任务,那么“进入下级菜单”操作应运行执行程序来完成

某项具体的任务。基于这种理解,首先定义如下结构体数据

类型 struct menu,其成员是3个函数指针。

struct menu

{void ( * parent) ( ); void ( * brother ) ( ); void ( * child ) ( ); };

然后把每一级菜单定义成menu结构体的一个变量(简

称menu变量)。为便于区分和理解,约定menu变量以“M

_”开头。比如主菜单定义为:struct menu M_Main.

每一级菜单就是一个menu变量,它拥有3个指向菜单函

数的指针成员。菜单函数是实现菜单操作的子程序, 每个

menu变量都有3个菜单函数分别对应着前面所说的3种菜单

操作。比如M_Main 3菜单的个菜单操作函数为

void MainParent( );void MainBrother( );void MainChild( );

Sample Mode

#define SampleNum 1

M_Sample

#define SampleSum 2

Single

#define SingleNum 1

Void single();

Consective

#define ConsecutNum 2

Void consecut();

Channel

#define ChannelNum 2

M_Channel

#define ChannelSum 2

Channel1

#define Channel1Num 1

Void channel1();

Channel2

#define Channel2Num 2

Void channel2();

图1 树状菜单结构

函数名中的Main表示这是M_Main 下属的操作函数,

Parent, Brother, Child 表示3种不同的操作。这样的命名规则

有助于理解和记忆。

主程序中对菜单进行操作时,只需调用相应menu变量

的指针成员所指的菜单函数,至于菜单操作的具体实现,菜

单标题的显示等工作都由菜单函数来完成。

主程序中定义了指向结构体类型struct menu的全局指针

变量 * ptr_stru 和用于保存当前菜单项编号的全局字符型变

量 item_num. 主程序通过这两个全局变量进行菜单的有关操

作,实现了它和菜单程序之间的相对独立性。实际上item

_num也起到指针的作用,不同的是,ptr_stru指向一个结构

体变量,也就是指向某一级菜单,而item_num指向该级菜

单下的某一菜单项。要实现返回上级和进入下级菜单的操

作,就在菜单操作函数中让指针 ptr_stru指向上级或下级

menu变量;要在本级菜单的菜单项中滚动,就保持

*

ptr_stru

不变,而在操作函数中让item_num在本级的几个菜单项的

编号之间循环。在菜单初始化时令指针ptr_stru 指向主菜单

作者简介:黄声野(

1974

—),男,硕士生,主要研究方向:光学

工程;陈秀华,工程师;王东生,教授

收稿日期:

2003-01-27

E-mail:

huangsy02@

菜单的结构为形如图1的树状结构。菜单的操作有以下3

种:返回上级菜单,在本级菜单的菜单项中滚动,进入下级

菜单。如果当前处于主菜单,“返回上级菜单”操作将退出

菜单环境;如果当前处于最末一级,对它的确认就是执行某

191

M_Main, item_num = 1且,指向第一个菜单项。另外还把每

级菜单的菜单项总数、菜单项编号、菜单项标题都定义成

宏,以便菜单修改。

数 SampleParent( )中用以下语句实现返回上级的操作:

取上级菜单

ptr_stru = & M_Main; // M_Main

item_num = SampleNum;

//

子项

"Sample Mode"

编号为

SampleNum

//

显示标题等

2 C51

用描述一个菜单

要用C51程序来描述一个菜单,首先定义一个结构体类

型,然后为各级菜单定义结构体变量,并声明菜单操作函

数,最后对结构体变量进行初始化,让它们的指针成员指向

相应的操作函数。所有这些工作都放在一个头文件menu.h

里。请注意操作函数在menu.h中只进行声明,它们的定义放

在另一个文件menufunc.c中。

用图1所示的菜单为例。这个菜单的第一级是主菜单M

_Main,它有两个子项“Sample”和“Channel”,表示子项

数目的宏MainSum定义为2。

给两个子项的编号和标题也都分别在程序中定义了宏。

“Sample Mode”导出二级菜单M_Sample,“Channel” 导

出二级菜单M_Channel.

文件menu..h中用C51构成这个菜单,先定义结构体类

型 struct menu(如概述中所述),然后定义构造各级菜单M

_Main, M_Sample, M_Channel. 每一级子菜单的构成包括

menu变量,操作函数和表征属性的宏定义3个部分。构造M

_Main如下:

定义主菜单结构体变量

xdata struct menu M_Main ;// M_Main

#define MainSum 2 //

宏定义,主菜单中包含

2

个子项

#define SampleNum 1

宏定义,子项是主菜单中的第

1

个菜单项

// M_Sample

#define SampleLabel "Sample Mode" //

把标题定义成宏

#define ChannelNum 2

宏定义,子项是第

2

个菜单项

// M_Channel

#define ChannelLabel "Select Channel" //

把标题定义成宏

void MainParant(); void MainBrother(); void MainChild();

//

声明操作函数

SampleBrother( ) ptr_stru实现在本级菜单中滚动。不变

的情况下使item_num的值在本级菜单项总数范围内循环,

并显示菜单标题。下面是SampleBrother( ) 中的相关代码:

item_num = (item_num) % SampleSum + 1;

// item_num

在菜单项总数的范围内滚动

switch(item_num)

{ case SingleNum: WriteInstruction( CLD ); //

清屏

lcd ( SingleLabel); break; //

显示标题

case ConsecutNum: WriteInstruction( CLD ); //

清屏

lcd ( ConsectLabel ); break; //

显示标题

default: item_num = 0; }

进入下级菜单的操作函数SampleChild( ) 调用执行函数

后返回上级菜单。执行函数是负责完成系统指定的功能切

换、参数设置等任务的子程序。single() consecut() 和是执行

函数。实现操作的代码如下:

switch(item_num)

{ case SingleNum : single();

下的第一项是执行程序

// M_Sample single()

ptr_stru = &M_Main; //

返回上级菜单

指向相应子项

item_num = SampleNum; // "Sample Mode"

;break; //

显示子项标题等

case ConsecutNum : consecut();

下的第二项是执行程序

// M_Sample consecut

ptr_stru = &M_Main; //

执行完后退回到上级菜单

item_num = SampleNum; //

指向相应子项

; break;

情况下指向第一子项

default : item_num = 1; // default

}

最后定义菜单初始化函数menuini(),让各menu变量的

函数指针成员分别指向各自的菜单操作函数。比如初始化M

_Main:

M_ = MainParant;

的成员指向操作函数

// M_Main parent MainParent

M_r = MainBrother;

的成员指向操作函数

// M_Main brother MainBrother

M_ = MainChild;

的成员指向操作函数

// M_Main child MainChild

4

菜单修改方法

主程序中使用指针对菜单项进行操作,而不出现具体菜

单项结构体的变量名,修改菜单不会对主程序有任何影响。

修改菜单项标题的显示,只需修改菜单标题的宏定义即可。

增加菜单项,首先增添该菜单项的编号宏MenuNum,

并使该菜单项所属的那级菜单的子项总数宏MenuSum 1加,

然后在所属menu变量的执行函数MenuBrother( )中的switch

语句中添加指向新菜单项的语句,MenuChild( ) switch中的

语句中添加指向下级菜单或执行程序的的语句。最后,如果

新添菜单项导出的是新一级菜单,则在menu.h文件中加入新

菜单的相关定义和声明,并在menufunc.c 中定义操作函数;

如果添加的菜单导出的是执行函数,则直接在menufunc.c中

定义执行函数。

删除菜单项的步骤与添加菜单项的步骤类似: menu.在

h中删除该属于菜单项的宏定义,删除所有该菜单项的导出菜

单,删除menunin() menufunc.函数中的有关初始化语句。在

c中删除导出菜单的菜单操作函数和执行函数。

3

菜单操作的实现

在主程序中定义了一个指向menu变量的全局指针变量

* ptr_stru menu,这个指针所指向的变量就是当前菜单。使

用下面这句指令调用当前menu变量

M_Menu (Menu

指代菜

单名,如M_Main, M_Sample等)的指针成员*parent所指的操

作函数 MenuParent可以实现返回上级菜单的操作:

( * ptr_stru -> parent ) ( );

同理,下面这两句指令可以分别实现在本级菜单中滚动

和进入下级菜单:

( * ptr_stru -> brother ) ( );

( * ptr_stru -> child ) ( );

可见,实现菜单操作的具体步骤是在菜单操作函数中进

行的。所有这些函数的定义都放在文件menufunc.c 中。要返

回上级菜单时,先让结构体指针ptr_stru指向上级菜单的结

构体,并让item_num指向上级菜单中的某一项,最后显示

菜单项菜单标题。以M_Sample 的菜单操作为例,在操作函

5

结束语

可见,每个子菜单包括3个部分:menu结构体变量,操

作函数,表征属性的宏定义。menu的指针成员指向操作函

数,菜单函数中又需要用到宏定义。完整的菜单由多个子菜

(下转封三)

192

册代理、事务代理、交互代理3种代理来处理动态地理矢量

对象;(2) 代理的多线程性的多对象、多事务的支持。其结

构关系如图2所示。

GIS平台 用户

的动作是通过事务来完成的,系统的操作通过事务来完成,

可以有效地管理操作过程和状态,交互代理只是完成各个对

象间的联系,但具体对动态对象的操作还是交给事务代理来

完成,从某种程度上讲,事务代理是系统操作的核心,而交

互代理就相当于shell的功能。其结构如图3所示。

动态GIS的注册代理也是一种移动代理MA(Mobile

Agent)

[2]

,它的安全性是相当重要的,没有安全性,轻一

点可能动态图层对象不准确,大一点在应用中,那后果可能

事务代理 交互代理

动态图层处理

注册代理

是灾难性。

Mobile Agent MA的安全首先要求编程语言的安全,即

动态矢量对象

编写MA的程序代码即使在被错误编译的情况下也不能对主

机和其它代理产生威胁,它要求能对系统资源的存取进行严

图2 GIS动态结构中多代理关系

格的检查和限制。目前较多版本的Mobile Agent平台都是采

动态地理矢量对象首先通过自己的无线终端与动态图层

用TCL脚本和Java这两种语言开发的,比如IBM的Aglets平

处理层的注册代理进行通信,注册代理在收到该对象的注册

台是用Java开发的,美国Dartmouth大学的D'Agent移动代理

请求信号后,对该动态地理矢量对象进行注册;交互代理则

平台支持TCL、Java和Scheme多种语言

[3]

负责GIS对动态矢量对象操作和交互;而所有动态图层的注

MA的安全主要包括两个方面:

册处理和交互处理都是通过事务来进行,而这些事务是GIS

(1) MA保护主机。每个总是运行在一定的代理平台

对动态矢量对象的处理是通过事务代理来进行的。

(Agent Platform)下,每台主机可以运行一个或多个这样的平

交互操作事务

台。平台要接收来自不同地点的代理,这样平台就要承担保

护本机系统,包括文件系统、CPU、内存不受外来敌意代理

事务代理

GIS平台 

的破坏。我们称这方面的安全为主机的安全。

动态图层数据区

动态图层操作请求

(2) 保护代理。一般来说,每个代理都保存了自己执行

的任务的数据和中间结果,为了保护这些信息不被窃取,需

动态对象添加

事务代理池

交互代理

要处理与不可信代理、敌意主机的通信。我们称这方面的安

事务代理

全为MA的安全,一般采取移动代理中的安全认证和移动代

对象操作指令 注册事务

理中的安全通信两种方式解决。

事务代理

注册代理

动态图层

动态地理矢量对象实体

3

动态对象的安全性

4

总结

移动用户终端

图3 GIS动态中多代理关系

以一个动态矢量对象的生命周期来具体说明注册代理、

事务代理、交互代理在整个系统的作用和地位。动态矢量对

象生命是从地理对象通过无线终端向动态GIS代理层申请联

系开始的,动态GIS代理层的注册代理始终不断地扫描自己

的通信端口,它一旦接收到动态矢量对象的注册请求,则立

即启动注册程序,注册程序主要完成动态矢量对象的创建及

向相应动态图层添加动态对象,并负责动态地理对象的通信

及动态图层的维护。用户对动态对象的操作、指令执行及信

息反馈是通过交互代理来完成,当然,动态对象也会有联系

及协作,它们同样也通过交互代理来完成。对象交互的执行

动态GIS是针对某些特殊应用和特殊对象提出的一种体

系结构,这种体系结构在于探讨一种能方便解决GIS中部分

对象属性不确定性问题,特别是矢量不确定性,目前研究这

种不确定性还比较少。当然我们的体系结构还是研究性和探

讨性的,同时,我们也准备用这种体系结构做一个动态GIS

的模型系统,具体的实现我们以后再谈。

参考文献

1 Karak M J, Molenaar M, etc. Advances in GIS Research. Taylor&

Francis, 1998

张云勇移动及应用

. : , 2002

北京清华大学出版社

2 . Agent

3 Gray R S. Agent TCL: A Flexible and Secure Mobile-agent System

[R].

ftp:///TR/.

协作式多媒体系统的小型代理结构

.

信息科学

, 2002:1404 Simon.

※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※

(上接第192页)

单连接而成。每个子菜单只和它的上级或下级有联系,以保

证能够实现返回上级和进入下级,同时又和其它子菜单无

关,方便了菜单的修改和维护。主程序中涉及到菜单操作的

部分都使用结构体指针表示,从而保证了菜单修改时不会影

响主程序。实际应用证明这个菜单管理方案具有很强的实用

性和通用性。

参考文献

胡汉才单片机原理及其接口技术北京清华大学出版社,

1 . . : 1996

徐爱钧彭秀华单片机高级语言环境编程与应用

2 , . C51 Windows .

北京

: , 2001

电子工业出版社

谭浩强

C

程序设计

. : , 1997

北京清华大学出版社

3 .

朱恒军李雪梅齐跃斗通用菜单程序的

C

语言函数指针实现方

4 , , .

. , 2002, 18(1):60

齐齐哈尔大学学报

戴牡红通用菜单软件的设计与实现计算技术与自动化

5 . . , 1994,

13 (4):16


本文标签: 菜单 操作 代理 函数