system: [SYSTEM]

user: 2. 测控系统模块化设计 2.1. 测控系统软件软件架构 测控系统的工作是以数据为基础的，其流程一般可划分为数据输入/输出、数据传递和数据处理三个阶段 [ 6 ] [ 7 ]。测控系统如果需要修改，通常是因为对这三个阶段的要求有所变化。一般来说，数据输入/输出的方式则取决于硬件系统，数据传递服从于数据输入/输出和数据处理的需要，而数据处理的过程取决于测控任务的内容。除了数据处理阶段决定了数据输入/输出所需要选通的通道外，这两部分互相影响并不大。因此，本文将测控系统的软件部分划分为如图1所示的三个层次。图1中： (1) 硬件控制层的主要作用就是对具体测控硬件进行抽象，向上层提供统一的用于获取或输出数据的函数接口及概要描述。在硬件环境变化时，只需动态卸载和加载与硬件相关的驱动模块即可保证系统正常运行，从而使系统具有较强的适应性。 (2) 核心服务层是整个系统的中心，也是唯一能独立运行的部分。它的主要任务是动态挂接各模块并控制这些它们之间的数据流，亦即控制传递数据的过程。它还要完成硬件调度和控制工作。 (3) 用户服务层的作用是进行数据处理，完成具体的测控任务。在测控任务改变时，只需要动态卸载和加载用户服务模块即可完成系统调整，从而使系统具有较强的灵活性。 图1. 测试系统结构划分 此时，只要预先规定统一的软件接口，用户服务层和硬件控制层中各模块的编写都比较简单。软件接口包含完备的标准函数和配套的数据结构。 标准函数的主要作用是使其他模块能够调用本模块的各项功能。采用模块间直接函数调用的形式使用目标模块功能，虽然在接口会较为复杂，但整个系统的执行效率能够得到保证。数据结构是数据传递的统一格式，常用的数据结构是作为数据缓冲区的循环队列 [ 8 ]。 硬件控制模块一般向上层提供开启/关闭硬件、获取硬件描述信息以及调用硬件功能的函数。例如，AD板卡的开始/停止连续采集、进行单次采集和获取采集数据。硬件控制模块一般由核心服务模块汇总所有用户服务模块的要求后再进行控制。 核心服务模块向上层资源请求函数，用于用户服务模块向其请求通道资源。用户服务模块向核心服务模块开放用于获取描述信息的函数。为了支持核心服务模块的数据流控制功能，有时各模块还要提供索取或传递数据缓冲区地址及缓冲区存储状态的函数。 2.2. 核心服务层设计 核心服务层是整个系统的中心，其主要功能是控制测控系统的数据流。由于数据的需求很可能会随系统结构而变化，为了保证数据按照需求流动此种系统就需要对数据流进行额外的控制，其执行效率可能会低于普通系统。为此，核心服务层在具体实现时就存在不同的内部设计，尤其是其中数据流控制的设计，在对系统可重构性提供支持的同时，还要考虑系统的执行效率。因此，核心服务层设计决定了整个测控系统动态重构的兼容与扩展能力，同时极大地影响着测控系统的执行效率。 (1) 模块载入设计 为了保证系统的动态可重构性，核心服务层必须能够动态加载、卸载模块 [ 9 ]。为此，挂接模块时首先采用LabWindows的函数LoadExternalModule动态读入含有该模块的库文件。 1) 若载入的是硬件控制模块，则系统分配一个用于存储硬件信息的结构体地址。使用函数GetExternalModuleAddr获得该模块中各标准函数的地址，写入结构体内的函数指针。然后调用标准函数获得所驱动的硬件设备的名称、各类型通道数，如有必要还可读入其他信息，如输入上下限等。这些信息同样存入结构体，供用户服务模块选择工作通道时参考。为保证系统运行正常，在载入过程中还应该调用标准函数查看驱动程序和对应的硬件是否匹配。 2) 若载入的是用户服务模块，则系统分配一个用于存储服务信息的结构体地址。使用GetExternalModuleAddr命令获得该模块中各标准函数的地址，写入结构体内的函数指针。然后将核心服务模块的标准函数地址发送给用户服务模块，并获得所该模块的各项信息。最后，在硬件提供的通道中为该模块分配工作通道。该过程可以由用户完成，也可以由系统自动分配。具体的通道占用情况在硬件控制模块对应的结构体中进行注册。 (2) 数据流控制设计 各用户模块对数据的需求很可能是不同的，为了保证挂接的模块能够正常工作，核心服务层必须能够按照用户服务层的需求来控制数据流和动态分配数据。数据流控制的方案依照数据分流模式的不同可以三种，如图2所示。这里以用户服务模块从某硬件设备连续获取数据为例，分别予以描述。 图2. 数据流控制模式示意图 1) 间接传递模式 图2中实线所示为间接传递式数据流控制。在这种模式下，硬件控制模块先从对应的硬件获取数据，然后填入核心服务层的数据缓冲区(通常采用循环队列形式)。核心服务层再按照各用户服务模块对数据通道的注册情况，将指定通道的数据填入它们的数据缓冲区。这种方式编程实现较为简单，但是由于数据要经过两次转存，时间和空间开销较大。 2) 直接传递模式 图2中虚线所示为直接传递式数据流控制。在这种模式下，核心服务模块不介入具体的数据传递过程，而仅仅在测控任务开始之前生成数据分配表，用以标明各通道数据应该流向哪些用户服务模块。硬件控制模块获得数据分配表和各用户服务模块的数据缓冲区地址后，测控任务才能开始。在测控任务进行中，硬件控制模块将用户服务模块指通道的数据直接填入它们的数据缓冲区，也就是在数据获取后立刻进行数据分配。这种方式下，硬件控制模块的编程实现略为复杂，但是时间和空间开销较小。 3) 缓存共用模式 图2中点划线所示为缓存共用式数据流控制。考虑有可能存在几个不同的用户服务模块同时需要某些通道的数据，那么向各用户服务模块分别传递这些相同的数据就会浪费时间和空间。在此模式下，硬件控制模块将数据填入核心服务层的数据缓冲区，并调用标准函数，更新用于标明缓冲区内数据个数的变量。用户服务模块直接对核心服务层缓冲区内所需的数据进行只读处理。这样数据指经过一次转存，也不存在重复转存的问题，因而时间和空间开销也较小。但是，对于任意用户服务模块，所需的数据很可能不是连续存储的，这就给数据处理工作带来额外的编程负担。 三种模式中，缓存共用模式与普通测控系统最为接近，效率也最高，一般建议使用此种模式。但如果挂接的用户服务模块数量较少，或多模块共用的通道很少，则直接传递式的效率与其相差无几。由于缓存共用模式下用户服务模块的编写相对复杂，所以如果同时挂接的用户服务模块较少，而它们又需要经常修改或编写，那么就可以选用直接传递模式。用户服务模块向硬件输出数据的模式与此类似。 (3) 其他主要细节的设计 1) 缓存共用模式下的缓冲区设计 动态可重构的测控系统中，数据缓冲区均以循环队列形式实现。在从硬件获取数据并处理的过程中，队列的尾指针记录于核心服务模块中。用户服务模块可通过函数接口查询这一指针。但是，由于各用户服务模块对缓冲区的读取情况不一，所以队列的头指针由各模块自己保存。 2) 硬件参数的设置 在前述设计中，所有硬件参数设置，如AD输入的上下限，都是固化在驱动程序中。除非修改程序，否则无法更改。如果要经常更改硬件参数，则考虑在测控系统之外建立一个硬件设置模块，通过简单地用户界面操作，更改硬件参数。但这样就需要软件接口提供额外的支持，硬件控制模块的编制难度相应加大。 3) 库文件生成设计 前文所述的模块化系统中，除核心服务模块是封装为可执行文件外，其余各模块都应封装为库文件——通常是动态链接库文件。如果采用LabWindows生成DLL文件，则可以直接加载对应的LIB文件。但如果是采用VC生成，则首先要保证所有函数均以C格式得到编译，而后使用LabWindows中的“Generate DLL Import Library”功能，以目标DLL文件及含有函数声明的头文件，生成LIB文件。利用该LIB文件可以动态加载库文件。