Database 版 (精华区)
发信人: mengy (LEAR DLLS 命令时,将从内存中清除), 信区: Database
标 题: VFP 环 境 下 实 时 数 据 采 集 的 实 现
发信站: 哈工大紫丁香 (2000年12月13日09:19:22 星期三), 站内信件
VFP 环 境 下 实 时 数 据 采 集 的 实 现
东南大学热能所 周卫平
---- VFP 作 为 新 一 代 数 据 库 管 理 系 统, 在 数 据 的 存 取、 编 辑
、 显 示、 处 理 等 方 面 具 有 强 大 和 丰 富 的 工 具, 在 国 内 外 得
到 了 广 泛 应 用。 在 许 多 工 业 应 用 中, 往 往 要 对 现 场 模 拟
数 据 进 行A/D 转 换 且 实 时 处 理, 由 于VFP 不 能 对 端 口 进 行 直
接 访 问, 因 而 无 法 实 现 数 据 采 集。 幸 好VFP 提 供 了DDE 功 能。
DDE 是Windows 应 用 程 序 之 间 进 行 动 态 信 息 传 递 和 共 享 的 一
个 消 息 协 议, 利 用DDE 可 实 现Windows 的 服 务 程 序 和 客 户 程 序
的 相 互 独 立 运 行, 具 有 很 好 的 实 时 性。 在 实 践 中, 我 们 利
用 高 级 语 言BorLand C++ for Windows 实 现96 路A/D 数 据 采 集, 并 以
此 为 服 务 程 序; 在VFP 环 境 下 建 立 客 户 程 序, 将 服 务 程 序
传 递 过 来 的 数 据 及 时 进 行 运 算 处 理 后, 存 入 数 据 库, 并 作
为 各 种 表 单、 报 表、 曲 线 的 数 据 源。 该 方 法 在VB 或ACCESS
97 环 境 下 同 样 适 用, 只 要 将 客 户 程 序 稍 加 修 改 即 可。 下 面
就 如 何 实 现VFP 环 境 下 的 实 时 数 据 采 集 作 一 介 绍。
1. 建 立 数 据 采 集 服 务 程 序
---- 服 务 程 序 包 括 二 个 基 本 部 分: 其 一 是WinMain 入 口 函 数,
它 主 要 完 成 一 此 初 始 化 任 务, 建 立 一 个 名 为hwnd 的 原 始 数
据 显 示 窗 口, 服 务 程 序 名 为PFBCdas。 其 二 是 应 用 程 序 功 能
函 数MainWndProc。 下 面 是 程 序 清 单( 因 篇 幅 关 系, 在 此 省 去
WinMain 函 数)。
#define AD_Interval 1000 //采样周期为 1000ms
#define base 0x280 // A/D采样板基地址
/* base+k (k=1,2,…14)为A/D板各寄存器地址 */
#include < windows.h >
#include < dde.h >
#include < dos.h >
#include < io.h >
#include < stdlib.h >
#include < string.h >
#include < stdio.h >
#include < time.h >
#include < math.h >
int i, j, k , AD_Status, idTimer;
int AD_Data[8][16]; // A/D数据存储单元
int DdeAdviseStatus=0;
char buf[64], DDEbuf[2048]; //数据暂存缓冲器
char szAppName[]="PFBCdas"; //服务程序名
char szDdeTopic[]="AD001"; //主题名
char szDdeItem[]="DATA"; // 数据项名
long FAR PASCAL _export MainWndProc
(HWND, UINT, UINT, LONG) ;
long FAR PASCAL _export MainWndProc
(HWND hwnd, UINT message, UINT
wParam, LONG lParam)
//应用程序功能函数
{
ATOM aAppName,aTopic;
ATOM aItem;
GLOBALHANDLE hDdeData;
DDEDATA FAR *lpDdeData;
static HWND hwndClient;
switch (message)
{
case WM_CREATE:
idTimer=SetTimer(hwnd,NULL,AD_Interval,NULL); //打开定时器
outportb(base+11,0x10); //选择软件触发方式
outportb(base+9,1); //选择输入信号放大倍数为10
outportb(base+14,0);
outportb(base+13,0); //清A/D完成位
outportb(base+10,0); //选择通道0
return 0;
case WM_TIMER:
for(i=0;i< 6;i++)
for(j=0;j< 16;j++) //采样点为6*16=96个
{
outportb(base+13,j);
outportb(base+10,i);
outportb(base+12,0); //启动A/D转换
do AD_Status=inportb(base+5);
while ((AD_Status&0x10)==0x10);
//判转换是否结束?
AD_Data[i][j]=(inportb(base+5)&0x0f)*256+inportb(base+4);
/* 读A/D转换后的数字值 */
}
_strdate(buf); //取采样日期
strcpy(DDEbuf,buf);
strcat(DDEbuf,",");
_strtime(buf); //取采样时间
strcat(DDEbuf,buf);
strcat(DDEbuf,",");
for(i=0;i< 6;i++)
for(j=0;j< 16;j++)
{
char temp[32];
strcat(itoa(AD_Data[i][j],buf,10),",");
/*各采样数据之间以逗号分隔*/
strcat(DDEbuf,buf);
}
if(DdeAdviseStatus!=0) //如果建立了DDE服务
{
aItem = GlobalAddAtom (szDdeItem) ;
//添加DDE数据项为全局原子
hDdeData = GlobalAlloc (GHND | GMEM_DDESHARE,
sizeof (DDEDATA) + strlen (DDEbuf)) ;
/*给采样数据分配全局内存块*/
lpDdeData = (DDEDATA FAR *) GlobalLock (hDdeData) ;
lpDdeData- >fResponse = 0 ;
lpDdeData- >fRelease = 1 ;
lpDdeData- >fAckReq = 0 ;
lpDdeData- >cfFormat = CF_TEXT ; //采样数据为文本格式
lstrcpy ((LPSTR) lpDdeData- >Value,DDEbuf) ;
/*将采样数据从缓冲器放至DDE内存*/
GlobalUnlock (hDdeData) ;
if(!PostMessage(hwndClient,WM_DDE_DATA,hwnd,
MAKELONG(hDdeData,aItem))) //发送DDE数据
{
GlobalFree(hDdeData); //若发送失败,则释放资源
GlobalDeleteAtom(aItem);
}
}
return 0;
case WM_DDE_INITIATE: //DDE初始化
hwndClient=wParam;
hdc=GetDC(hwnd);
aAppName=GlobalAddAtom(szAppName);
aTopic=GlobalAddAtom(szDdeTopic);
if ((LOWORD (lParam) == NULL || LOWORD (lParam) == aAppName)
&& (HIWORD (lParam) == NULL || HIWORD (lParam) == aTopic))
{ // 发送服务程序名和主题名
SendMessage(hwndClient,WM_DDE_ACK,
hwnd,MAKELONG(aAppName,aTopic));
}
else
{
GlobalDeleteAtom (aAppName) ;
GlobalDeleteAtom (aTopic) ;
}
return 0 ;
case WM_DDE_TERMINATE: //关闭DDE服务
hwndClient=wParam;
PostMessage (hwndClient, WM_DDE_TERMINATE, hwnd, 0L) ;
return 0 ;
case WM_DDE_ADVISE: //建立DDE服务
DdeAdviseStatus=1; //已建立DDE服务标志
hwndClient=wParam;
aItem=HIWORD(lParam);
if(!PostMessage(hwndClient, WM_DDE_ACK, hwnd,
MAKELONG(0x8000,aItem))) //发送DDE应答
{
GlobalDeleteAtom(aItem);
}
return 0;
case WM_DESTROY: //程序失败处理
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
2. 建 立VFP 环 境 下 的 客 户 端 程 序
---- 首 先 建 立 和 服 务 程 序 之 间 的 通 道, 然 后 将 服 务 程 序 传
递 来 的 数 据 放 至 字 符 串DATA 内, 再 通 过 自 定 义 函 数recdata
将 采 样 数 据 存 入 数 据 库 中 待 用。 下 面 是 客 户 程 序 清 单。
PROCEDURE getdata
PUBLIC mchannel
mchannel = DDEInitiate('PFBCdas','AD001')
&&建立客户程序和服务程序间的通道
IF mchannel !=-1
=DDEadvise(mchannel,'DATA','recdata',2)
&&建立DDE热连接,数据项为DATA
ENDIF
RETURN
PROCEDURE recdata &&用户自定义函数
PARAMETERS channel,action,item,data,format,status
PRIVATE newdata
newdata=""
IF action='ADVISE' &&若连接成功
newdata=DATA &&将采样数据传递至newdata
do process with newdata &&调用数据处理程序
ELSE
IF action='TERMINATE'
= DDETerminate(mchannel) &&关闭通道
ENDIF
ENDIF
RETURN
PROCEDURE process
PARAMETER newdata
PRIVATE i,loc1,loc2
DIMENSION gdata(98)
* 从字符串 newdata中取采样值
gdata(97)=CTOD(left(newdata,8)) &&取日期值
gdata(98)=SUBSTR(newdata,10,8) &&取时间值
* 从字符串newdata的相邻逗号间取
采样值,并将采样值转化为毫伏值
FOR i=3 TO 98
loc1=ATC(",", newdata, (i-1))
loc2=ATC(",", newdata, (i))
gdata(i-2)=VAL(SUBSTR(newdata,
(loc1+1),(loc2-loc1)))*0.024414062
ENDFOR
IF USED("onedata")
SELECT onedata
ELSE
SELECT 0
USE onedata ALIAS onedata &&打开数据库onedata
ENDIF
APPEND FROM ARRAY gdata &&将数组
gdata中的转换数据添加到数据库中
RETURN
--
大海无边天做岸
山登绝顶我为风
※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: 202.118.227.121]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:2.498毫秒