VC实现串行通信的动态链接库(DLL)

本文以实例方式介绍了用VC++编写DLL实现串行通信的方法,并给出了用其它语言调用该DLL的范例。

虽然关于串口编程的资料很多,但由于工程上需求多种多样,需要根据不同的条件对串口进行灵活控制,在实际应用中,常用的方法有:

(1)用汇编或标准通讯函数,往指定端口直接读写数据;

(2)利用Visual Studio提供的MSComm控件;

(3)使用Windows提供的API函数。

本文用API。

用VC++ 编写动态链接有以下四种类型:

Win32 DLL、

MFC常规DLL(动态链接MFC)、

MFC常规DLL(静态链接MFC)、

MFC扩展DLL

本程序的编写为Win32 DLL。实现串口编程的关键词:DCB(Device Control Block), GetCommState函数,SetCommState函数

串口通信一般需按以下四步进行:

(1) 打开串口。串口是独占性资源。

(2)配置串口。利用GetCommState函数获取串口当前配置,根据需要更改DCB 结构中的参数,然后用SetCommState函数设置串口通讯参数。

(3)数据传送。在串口上进行数据发送接收,并根据需要进行校验,触发一些事件等等。这个串口通讯DLL的目的就是收发数据。

(4)关闭串口。

CALLBACK函数:“CALLBACK函数是由应用程序定义而由操作系统调用的函数”。在我们编写DLL时,就是由应用程序定义而由此DLL执行的函数,这一机制在被调用者(DLL)和调用者(应用程序)之间进行信息传递是非常有用的。这一特性,让初学者较难理解,但是它却是编写串行通信程序者的福音,正是由于使用这一特性,才可很方便地在动态链接库中实现MSComm控件中的OnComm 事件,并且可根据需要进行灵活控制。

以下就编写了dll:

1、New,并选择Win32 Dynamic-Link Library项,创建一个工程。

2、往工程中添加头文件,根据需要,我们在头文件中定义此DLL提供给外部调用的五个输出函数,其定义方法如下:

//com.h
#ifndef _COM_DLL_H
#define _COM_DLL_H
#ifdef MyComDll
#else
#define MyComDll extern "C" __declspec(dllimport)
#endif
MyComDll int FAR PASCAL ComOpen(int port);
MyComDll int FAR PASCAL ComClose();
MyComDll int FAR PASCAL SetCallback(void (CALLBACK* fun)(int port));
MyComDll int FAR PASCAL GetComData(LPBYTE buf);
MyComDll BOOL FAR PASCAL SendDataToCom(LPBYTE Cmd,int CmdLen);
#endif

DLL的源代码模块需要包含该头文件,若要编写调用该动态链接库函数的C/C++应用程序,也需要包含此头文件。另外,你会发现,MyComDll中包含了extern "C"链接指示符,这是因为在用C++编写动态链接库时,通常在经C++编译器编译后,其函数名称会改变,如ComOpen编译后,展现给调用者的名字是:_ComOpen@8之类,这样应用程序在调用时,链接程序就会抱怨找不到指定的函数。加上extern“C”后,就告诉编译器不要改变变量名或函数名。__declspec(dllimport)是告诉编译器,应用程序将从这个DLL 模块引入这些函数,_declspec(dllexport) 是告诉编译器这些函数是从产生的DLL模块输出给别的应用程序调用。

3、往工程中添加C/C++源代码模块

在C++源代码模块中,首先应包含如下头文件,及定义相关变量:

#include <windows.h>
#define MyComDll extern "C" __declspec(dllexport)
#include "com.h"  

然后就定义本动态链接库的五个输出函数:

(1)ComOpen(int port)

此函数用来打开指定的串行通讯口,其参数port即为通讯口号。打开端口后,通过API函数GetCommState得到该端口的配置;根据实际需要,更改其波特率、数据位、停止位等,以及设置触发信号事件的字符(即设置BCB的EvtChar字段);然后通过调用SetCommState设置端口。

串口打开成功后,创建一个线程ComThreader,在ComThreader中,循环监控串行口是否收到有效数据,若收到则触发回调函数。

(2)GetComData (LPBYTE buf)

此函数是将串口接收缓冲区中的数据放到指针变量buf中。

(3)SendDataToCom(LPBYTE Cmd,int CmdLen)

此函数是将指定长度的数据发送到串行口中。其长度由于变量CmdLen指定,发送的数据即为变量Cmd中的内容。发送数据时,需要将线程ComThreader暂时挂起,以避免与接收数据的线程冲突,产生紊乱。

(4)ComClose()

此函数将打开的串行口关闭,无参数。通过事件触发以及WaitForSingleObject 、WaitForMultipleObjects函数,中断线程,关闭创建的各种事件、文件,释放相应资源,因为采用了多线程技术,因此需要特别注意主线程和子线程的相互同步。

(5)SetCallBack(int controlport,void (CALLBACK *outfunc)(int controlport))

此函数的功能是设置回调函数,controlport为指定的端口,outfunc是外部应用程序传过来的函数指针,其主要目的是将应用程序的函数指针传给DLL中的一个指针函数,DLL在特定的时刻(本程序是当串行端口接收到有效数据时)通过内部的指针函数,调用外部的应用程序,从而实现“回调”功能。

//com.cpp
void (CALLBACK* infunc) (int port);
int FAR PASCAL SetCallBack(int controlport, void (CALLBACK*
outfunc)(int controlport))
{
if(outfunc!=NULL)
infunc=outfunc;
return 1;
}  

4、往工程中添加模块定义文件

模块定义文件(module-definition)文件是以.def为扩展名的文本文件,为了能被其他开发工具如Visual Basic、Delphi等使用,创建的DLL文件必须要有模块定义文件,否则在应用程序调用ComOpen时会出现“Can’t find DLL entry point ComOpen in Comdll.dll”的错误提示。Exports节和extern“C”的作用一样,告诉编译器不要改变输出的函数名。

LIBRARY COMDLL
DESCRIPTION ’COM Communication Demo’
EXPORTS
ComOpen @ 1
ComClose @ 2
SendDataToCom @ 3
SetCallBack @ 4
GetComData @ 5  

四、动态链接库函数的VB 调用示范

1、VB测试程序

以下程序示范了在VB中如何调用由VC++编写的动态链接库中的函数。因为动态链接库中使用了回调函数,在VB代码中必须将回调函数放到标准的.BAS模块中,不可放在窗体模块中,也不能将其附加到类模块中。CALLBACK函数只是触发同一工程中一个窗体上的定时器控件,对串口数据进行采集,其定义如下:

Sub CallBackFunc(ByVal port As Long) Form1.Timer1.Interval = 1
Form1.Timer1.Enabled = True
End Sub

在标准的.BAS模块中,还需定义该DLL函数的调用方式,具体如下:

Option Explicit
Public Declare Function ComOpen Lib "Comdll.dll" (ByVal
port As Long) As Long
Public Declare Function ComClose Lib "Comdll.dll" () As
Long
Public Declare Function SendDataToCom Lib "Comdll.dll"
(ByRef Cmd As Byte, ByVal CmdLen As Long) As Long
Public Declare Function SetCallBack Lib "Comdll.dll" (ByVal
port As Long, ByVal func As Long) As Long
Public Declare Function GetComData Lib "Comdll.dll" (ByRef
buf As Byte) As Long  

在窗体程序中,当打开串口时,调用DLL的SetCallBack函数设置回调函数,调用方式如下:

SetCallBack (comport, AddressOf CallBackFunc);

关键字AddressOf是将CallBackFunc的函数地址传递给DLL中的指针函数void (CALLBACK* infunc) (int port)。

2、调试方法

串行通讯的调试相对来说是比较麻烦,在实践中,可以在同一台具有两个串行通讯口的机器上进行调试,只需要将两个串口的RXD和TXD交叉连接,并将5脚对等连接,就可以进行调试了;当然,也可用一个串口进行调试,只需将同一串口的2、3连接。

在调试过程中,需提醒读者注意的一点是:动态链接库与执行文件应在同一目录下,否则出现找不到动态链接库的问题;由于Windows操作系统本身的原因,在对动态链接库的第一次使用时,须将其拷贝至系统安装目录的system32子目录中才能避免上述问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值