微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 基于嵌入式Linux的组态软件实时数据库的设计

基于嵌入式Linux的组态软件实时数据库的设计

时间:02-01 来源:3721RD 点击:

1 引言

实时数据库(real-time database, RTDB)作为组态软件设计与实现的核心内容解决了其所 应对的现代工业生产现场环境中生产数据与控制数据类型复杂多样,数据处理与事件调度时 间约束严格等难题[1]。目前,国内外已经有多种基于Windows 操作系统平台的实时数据库 产品在自动化过程控制领域中得到应用[2],随着Linux 操作系统的出现,这种开发平台单一 的局面有望得到改观。Linux 操作系统具有很多优秀的特性适于组态软件实时数据库系统的 开发,特别是其完善的进程线程管理,进程间通信机制与并发控制,可靠的内存管理系统[3], 更是为时间约束严格的实时数据库的开发提供了有力的支持。因此,本文结合Linux 系统实 时多任务方面的特性,采取能够满足数据实时响应要求的多级存储结构,研究并提出了一种 基于嵌入式Linux 系统平台并可应用于监控组态软件的实时数据库实现方案。

2 实时数据库存储结构的分析与设计

实时数据库是监控组态软件数据处理,事务调度,各应用程序间通信的中心。图1 即示 出了组态软件实时数据库的数据处理流程。


2.1 实时数据库的数据流分析

组态软件运行环境分为实时数据库管理系统(RTDBMS)和实时监控界面程序(real-time supervisory control interface, RTSCI)。实时数据库管理系统需要把工业现场中复杂多样的过 程和控制数据抽象为合理高效的数据结构,实时监控界面程序则利用实时过程数据为现场监 控人员提供一个反映实际生产过程的可视化图形界面,在实际运行中二者构成客户端/服务 器计算模式。RTDBMS 作为数据服务的提供者,需要满足RTSCI 种类多样的数据需求。

为了形象的描绘工业现场的实际生产过程,RTSCI 由多种图形对象构成,根据不同的数 据类型需求可分为实时显示,实时趋势,历史趋势,实时报警等。而应用于现代工业生产现 场环境的实时数据库还需要满足严格的数据存取与事件响应的定时限制。所以,传统的数据 库管理系统所采用的数据表示方法,存储模式已不能满足工控组态软件所要求的响应速度 [4]。为此,在设计实时数据库时,为了兼顾RTSCI 所要求的数据图形表现多样性与工业生产 环境时间约束的严格性,需要采用多种存储介质合理组合的多层级数据存储结构。

在工业生产过程中实时产生的过程量,是需要组态软件在每个采样周期中及时更新的动 态数据,为了保证实时数据库的及时响应,须将其存储在内存中;对于RTSCI 的某些数据 需求,如历史趋势显示,实时数据库应为之提供相比内存更大的存储空间,这类数据需求不 需要很高的响应速度,可将之命名为静态数据,其所服务的图形对象要求可按时间翻页浏览, 这类静态数据适于存储在文件系统中;而需要长期保存的生产过程量数据,即历史数据,它 们是今后进行生产效能分析的依据,这些数据可以保存在通用数据库中。这样,由内存数据 库,外存文件系统以及通用数据库的三级存储结构,便构成了既可满足实时数据定时限制又 兼顾数据需求多样性的可应用于监控组态软件的实时数据库的存储架构。

2.2 利用共享内存与命名管道技术实现实时数据库存储结构

Linux 提供了一组由AT&T System V.2 版本的UNIX 引入的进程间通信(Inter-Process CommunicatiON, IPC)机制,其中的共享内存技术允许两个不相关的进程访问同一段逻辑内 存,是在两个运行中的进程间传递数据的一种非常高效的数据访问机制[5],可为RTDBMS 与RTSCI 间的动态数据交互提供有力的支持。但共享内存技术本身并未提供任何同步机制, 因此还需要配合IPC 的信号量机制来保证二者间数据访问控制。Linux 提供的另一组在不相 关的进程间进行数据交互的函数是命名管道FIFO。它是将数据存储在文件系统中实现进程 间共享的一种通信方式。命名管道适用于数据存取响应时间要求相对宽松且数据交互总量较 大的应用场合。同时,FIFO 中实现数据读写的read 和write 调用的阻塞机制,还可以提供 进程间的同步控制。

由上述对其特点的分析,FIFO 技术是实现RTDBMS 与RTSCI 间静态数据交互较好的 选择。上图即示出了由共享内存,命名管道,ODBC 接口等多种进程间通信机制构建的实时 数据库存储结构。值得注意的是,为了实现实时数据库与通用数据库的双向数据交换,需要编写特定的通用数据库接口(ODBC 接口)例程。Linux 提供了一组丰富的接口函数用来访问 MySQL 数据库。通过对通用数据库MySQL 的数据连接进行组态,实时数据库便可按照预 先指定的采样周期,对规定时间区段内的历史数据与MySQL 数据库建立数据连接。

3 实时数据库系统的实现

3.1 数据模型的分析与构建

传统数据模型包括三个部分:一组数据对象及其结构,一组数据操作,关于数据对象与 操作的完整性约束[6]。而对于工业生产中所产生的实时数据,还必须约束于严格的定时限制。

在应用于工业现场控制的组态软件中不仅包括实时产生的过程量数据,还存在着描述系 统运行状况的系统数据,在利用采集到的过程量数据的基础上,经处理后提取出的计算数据, 以及涉及控制测量组态或从工控软件输出到输出装置上的数据等。由此,可将实时数据模型 抽象为:模拟量,开关量,字符串量三种数据类型。

3.2 数据类型的实现

上述用于构建实时数据过程量的三类数据模型,对应于具体的实现分别可用:浮点型, 布尔型,字符数组来表示。实时数据可由结构类型实现,以其中的实时数据类型字段来区分 不同的过程量类型。实时数据结构类型的实现如下。

/*枚举类型标记实时数据过程量类型 */
typedef enum {
double_t = 1,
bool_t
} pv_type_set;
/* 联合类型实现实时数据过程量值 */
typedef union {
double dPV;
bool swhPV;
} pv_data_set;
/* 实时数据的数据类型 */
#define name_LEN 20
#define DESC_LEN 50
typedef STruct {
char nAME[NAME_LEN + 1];//数据点名称
pv_type_set type;//数据点类型
char desc[DESC_LEN + 1];//数据点描述信息
pv_data_set pv;//数据点过程量值
char domain[3];//数据点所在域号
char eu[DESC_LEN + 1];//数据点工程单位描述
double euLow;//数据点工程单位下限
double euHigh;//数据点工程单位上限
double pvRaw;//现场测量裸数据
bool IsRanCon;//是否进行量程变换
double pvRawLow;//裸数据量程下限
double pvRawHigh;//裸数据量程上限
bool static;//静态数据历史数据存储至文件系统
int storecyc;//备份周期
bool IsAlarm;//是否报警
int AlarmPriority;//报警优先级
… …
} tag_node;

3.3 实时数据在数据库中的组织形式及相关数据结构

为了充分地利用 Linux 平台对实时多任务操作的支持,实时数据库的数据采集与处理等任务应以多进程的形式并发执行。而Linux 操作系统IPC 机制中的共享内存技术可以根据需 要离散地分配内存空间,从而可将所有数据点的共享内存地址构成索引并建表。在实际应用 中,经常会将若干在生产工艺上有关联的数据点划分为一个数据域,所以地址索引表为两级 结构:第一级为域表,其中的数据项存储特定数据域的地址;第二级为数据点表,数据项存 储某一数据域中的每个数据点的内存地址。域表与数据点表中存储的数据点所在的域号字段 与数据点号字段组合构成数据点ID。包括所有实时数据点的地址索引由一张域表与多张数 据点表构成。根据存储域表结构的内存地址,便可访问所有数据点的共享内存地址。下面给 出域表与数据点表用到的数据结构。

/* 描述域表数据项的数据结构 */
typedef struct {
char domIndex[3];//域号
tbTag_item *tbTag_ptr;//该域的数据点表地址
} tbDom_item;
/*描述数据点表数据项的数据结构*/
typedef struct {
char tagIndex[3];//数据点号
tag_node *tag_ptr;//指向数据点的指针
int shmid;//存储该数据点的共享内存标号
char name[NAME_LEN + 1];//数据点名称
} tbTag_item;
域表与数据点表的数据项内容与关系结构示意见图 3。


3.4 一组访问实时数据库的通用编程接口

作为投入现场运行的监控组态软件的核心部件,实时数据库需要为现场操作人员提供类 似传统数据库管理系统的实时数据查询与更新等功能。另外出于设备无关性的考虑,也需要 为监控组态软件的其他应用程序提供一组用来直接访问实时数据库的接口函数。这样,对于 其他工控设备与实时数据库进行数据交换的需求,只要利用这样一组接口函数开发不同的驱 动程序便可得到满足,从而增强了实时数据库系统的通用性与开放性。下面列出了一些较为 常用的数据访问接口函数。

int CreatTag();//创建数据点
char *GetNameByID(char *tagID);//通过数据点ID 取得数据点名
char *GetIDByName(char *tagName);//通过数据点名得到数据点ID
pv_type_set GetPVType(char *tagName);//通过数据点名得到数据点过程量值类型
int GetPVByName(char *tagName, pv_data_set *pv);//根据数据点名获取数据点过程量值
int SetPVByName(char *tagName, pv_data_set *pv);//根据数据点名写入数据点过程量值

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top