VB串口通信详解

VB串口通信详解
VB串口通信详解

VB串口通信

目前,Visual Basic (简称VB)已成为WINDOWS 系统开发的主要语言,以其高效、简单易学及功能强大的特点越来越为广大程序设计人员及用户所青睐。VB 支持面向对象的程序设计,具有结构化的事件驱动编程模式并可以使用无限扩增的控件。在VB 应用程序可以方便地调用WINDOWS API函数,使得编程效率提高,应用功能增强。

利用VB 提供的这些功能,我们可以有三种方法完成串口通信。一种是用VB 提供的具有强大功能的通信控件;另一种方法是调用WINDOWS API 函数,使用WINDOWS 提供的通信函数编写移植性强的应用程序;第三是利用文件的输入/ 输出完成,该方法简便易行,但有一定的局限性。

一、利用通信控件(MSCOMM)完成串口通信

VB 提供了通信控件MSCOMM,文件名为MSCOMM. VBX。该控件可设置串行通信的数据发送和接收,对串口状态及串行通信的信息格式和协议进行设置。在通信过程中可以触发OnComm事件,在该事件过程进行数据检验处理及检错,还可以通过编程访问CommEvent 属性来了解通信的情况,进行收发数据的处理。每个通信控件对应一个串口,如果要访问多个通信口,则要设计多个通信控件。

1、通信控件的事件及基本属性

(1)事件

OnComm:通信控件只提供了一个事件,该事件的触发可以对串口的通信事件及错误进行处理。通过对CommEvent 属性的判断可知当前的通信错误和事件,分别对每个CommEvent 值进行编程就完成了对各个错误和事件的处理。如:CommEvent = MSCOMM—EV—SEND 表示发送事件。这些信息可从VB 提供的常量文件CONSTANT. TXT中查出。

(2)属性

CommPort :设置通信控件与哪个串口相连接,设置并返回通信口号。

Setting :设置通信的信息格式,为字符型。顺序为:波特率、校验、数据位、停止位。PortOpen :布尔型、开关通信口。

InputLen :从接收缓冲区读取字符个数。

Input ,Output :读取接收缓冲区或写入发送缓冲区字符。

以上五种属性对串口完成基本的设置和操作,下面的三种属性是描述如何利用VB 提供的事件驱动机制来实现通信。

CommEvent :返回通信过程中产生的错误信息及事件,了解通信状况。

SThreshold :设置并返回不触发OnComm事件时发送缓冲区被允许的最少字符数。当缓冲区的字符少于设置的值时,则触发OnComm事件,并把CommEvent 设为MSCOMMM—EV—SEND。当SThreshold = 0 则禁止发送触发OnComm 事件,当SThreshold = 1 则发送缓冲区为空时就触发OnComm事件。利用这一属性,就可完成发送数据后的一系列操作。如:对刚发送的数据进行处理,当串口是和MODEM通信时,发送完数据后可进行拆除线路联接、挂机等操作。

RThreshold :设置并返回不触发OnComm事件时接收缓冲区被允许的最多字符数。当缓冲区的字符多于设置的值时,则触发OnComm 事件,并把CommEvent 设为MSCOMM—EV —RECEIVE,当RThreshold = 0 则禁止接收触发OnComm 事件,当RThreshold = 1 则接收缓冲区有一个或更多字符时就触发OnComm事件。利用这一属性,就可完成对串口接收数据的处理。

2、利用通信控件的实例

Sub Form1 —load ()

form1. show

′设置COM1

comm1. commport = 1

comm1. Setting = " 9600 ,o ,8 ,1" ′波特率:9600 奇校验,8位数据,1 位停止位comm1. Inputlen = 0 ′读取接收缓冲区的所有字符

comm1. OutBufferSize = 512 ′设置发送缓冲区为512 字节

comm1. InBufferSize = 512 ′设置接收缓冲区为512 字节

comm1. SThreshold = 0 ′禁止发送事件

comm1. RThreshold = 1 ′每一个字符到接收缓冲区都触发接收事件

′设置COM2

comm2. commport = 2

comm2. Setting = "2400 ,e ,8 ,1" ′波特率:2400 偶验,8 位数据,1 位停止位comm2. Inputlen = 0 ′读取接收缓冲区的所有字符

comm2. OutBufferSize = 512 ′设置发送缓冲区为512 字节

comm2. InBufferSize = 512 ′设置接收缓冲区为512 字节

comm2. SThreshold = 1 ′发送缓冲区空触发发送事件

comm2. RThreshold = 0 ′禁止接收事件

′打开COM1 ,COM2

comm1. Portopen = True

comm2. Portopen = True

Timer1. interval = 5000

End Sub

Sub Comm1 —OnComm()

Dim Inbuff as string

Dim i as integer ,n as integer ,t as integer

Select Case Comm1. CommEven

case MSCOMM—EV—RECEIVE

Inbuff = Comm1. Input

n = len (Inbuff)

For i = 1 to n

t = Asc (Mid (Inbuff ,i ,1))or &HFF

print f

Next i

End Select

End Sub

Sub Comm2 —OnComm()

Select Case Comm2. CommEvent

Case MSCOMM—EV—SEND

Print time

End Select

End Sub

Sub Timer1—Timer ()

Comm2. output = Second (Now)

End sub

二、通过调用API 函数实现通信

以上说明了用VB 提供的控件实现通信的方法,只要理解了VB 控件的机制就很容易完成对串口的操作,但可移植

性差。但VB 可以很容易调用API 函数实现通信。

1、VB 对API 的调用

VB 使用动态链接库DLL(Dynamic Link Libraries)的能力,大大扩展了其功能。WINDOWS 本身提供了API 函数包括三大动态链接库:KERNEL 库、GDI 库、USER 库,通过VB 用户可以直接调用这些库中的函数。调用之前,必须首先在VB 中声明。该声明可为模块级或窗体级,当作为模块级声明时,其作用域为所有FORM和MODULE,而作为窗体级声明时其作用域为该声明所在的FORM。

VB 调用DLL 的格式:

Declare Sub 过程名Lib″库名″[Alias″别名″] ([ByVal 参数As 类型])

Declare Function 函数名Lib″库名″[Alias″别名″] ([ByVal参数As 类型])As 类型在声明中:DECLARE 表示声明DLL 中的函数,当声明是不具有返回值的过程时用SUB 关键字,而如果调用的函数具

有返回值,则必须用FUNCTION 关键字将其声明为函数并在声明语句的最后用AS 指明函数返回值的类型。LIB 关键字表示当前声明的过程或函数是库名所指定的库中函数而非VB 本身的函数。库名,就是对应动态链接库的名称,其中通信函数在USER 库中。ByVal 关键字将原参数数据类型一一对应到VB 类型中。

WINDOWS 的HELP 文件WINSDK. HLP 中包含了完整的WINDOWS API 函数信息,可用该文件查看联机函数、数据结

构及错误信息。

2、API 提供的通信函数

为了方便说明,我们将有关通信的函数及相关的数据结构放在全局模块中,文件名为COMM.BAS(见API 编程函数

实例)。以下是这些函数的基本介绍:

(1)OpenComm(IpComName As String ,wInQueue As Inte-ger ,wOutQueue As Integer)IpComName :设备名,以“COMn”的形式来说明,n 为设备号;wInQueue 、wOutQueue :分别以字节为单位说明发送、接收缓冲区的大小。该函数调用成功返回打开的设备号,否则返回一负数代表错误信息码。

(2)SetCommState (IpDCB As DCB)

IpDCB :是DCB 结构存放设备所希望的通信设置(DCB 结构如COMM.BAS 中所示),其中DCB 的ID 成员必须标识该

设备。如果函数调用成功返回0 ;否则,返回值小于0。

(3)ReadComm(nCid As Integer ,IpBuf As String ,nSize As Integer)

WriteComm(nCid As Integer ,IpBuf As String ,nSize As In-teger)

这是用来对通信设备进行读写的函数,nCid :说明要读写的通信设备号,IpBuf :为读写缓冲区,nSize :为要读写的字节数。如果读写成功,返回读写的字节数,否则是小于0 的值,并且其绝对值为读写的字节数。

(4)Closecomm(nCid As Integer)

该函数关闭nCid 所指定的通信设备,并且释放分配给设备的发送,接收缓冲存储器,调用成功返回0 ;否则,返回值小于0。

(5)BuildCommDCB(IpDef As String ,IpDCB As DCB)

lpDef :为一字符串指定设备控制信息,此字符串具有MS-DOS 中MODE 命令所使用的

参数形式。IpDCB :为一DCB数据结构。该函数将IpDef 字符串转换成串行设备控制块(DCB)代码。

(6)GetCommError (nCid As Integer ,IpStat As COMSTA T)

该函数检取nCid 指定的设备最近的错误值和当前状态,IpStat :是COMSTAT结构,具体形式如COMM.BAS 中所定义的。返回值为COMM.BAS 中带CE- 的常量的某种组合。3. 用API 函数编程实例

这个例子是一仿真发送机,将从键盘输入的字符发送给COM端口。在FORM中加一按钮COMMAND1 来关闭通信口。

Type DCB

Id As String 3 1

BaudRate As Integer

ByteSize As String 3 1

Parity As String 3 1

StopBits As String 3 1

RlsTimeout As Integer

CtsTimeout As Integer

DsrTimeout As Integer

Bits1 As String 3 1

Bits2 As String 3 1

XonChar As String 3 1

XoffChar As String 3 1

XonLim As Integer

XoffLim As Integer

PeChar As String 3 1

EofChar As String 3 1

EvtChar As String 3 1

TxDelay As Integer

End Type

Type COMSTAT

Bits As String 3 1

cbInQue As Integer

cbOutQue As Integer

End Type

Declare Function OpenComm Lib ″User″(ByVal IpComName As

String ,ByVal wInQueue As Integer ,ByVal wOutQueue As Integer)As Integer

Declare Function SetCommState Lib ″User″(IpDCB As DCB)

As Integer

Declare Function ReadComm Lib ″User″(ByVal nCid As Integer ,ByVal IpBuf As String ,ByVal nSize As Integer)As Integer

Declare Function WriteComm Lib ″User″(ByVal nCid As Integer ,ByVal IpBuf As String ,ByVal nSize As Integer)As Integer

Declare Function Closecomm Lib ″User″(ByVal nCid As Integer)As Integer

Declare Function BuildCommDCB Lib ″User″(ByVal IpDef As

String ,IpDCB As DCB)As Integer

Declare Function GetCommError Lib ″User″(ByVal nCid As

Integer ,IpStat As COMSTA T)As Integer

Global IpDCB As DCB

Global nCid As Integer

Sub Form1 —load ()

Dim comset As String

comset =“COM2"

nCid = OpenComm(comset ,512 ,512)′打开COM2 设置接收,发送缓冲区为512 字节

If nCid < 0 Then ′处理错误

MsgBox“不能打开COM:" + Str (nCid)+“Error Num2

ber :" + Str (nCid),16

end

end if

Command1. Caption =“关闭通信口" ′设置串口DCB 设备控制块

comset =“COM2 :9600 ,n ,8 ,1"

If (BuildCommDCB(comset ,LpDCB))Then

MsgBox“不能建立COMM DCB" ,16

end

end if

LpDCB. Id = Chr (nCid)

If (SetCommState (LpDCB))Then ′设置串口状态

MsgBox"不能设置串口状态" ,16

end

endif

End Sub

Sub Form1-keyPress (keyAscii As Integer)

Dim nsend As integer ,x As integer

Dim Lpstate As COMSTAT ′通信状态块

Static inbuff as string

inbuff = imbuff + Chr (KeyAscii)

x = GetCommError (ncid ,Lpstate)′读取当前串口错误或状态

if lpstate. cbOutQue < 512 Then ′送缓冲区有空间否?

Nsend = WriteComm(nCid ,inbuff ,Len (inbuff))′发送inbuff

if Nsend < = 0 then Nsend = - Nsend ′忽略错误

inbuff = Mid (inbuff ,Nsend + 1)′清除已发送的字符

end if

end if

End Sub

Sub Command1-Click()

Dim Nclose As integer

Nclose = CloseComm(nCid)

If Nclose < 0 Then

MsgBox“不能关闭COMM口:" + Str (nCid),16

end

else

ncid = 0

end if

Cmmand1. Caption =“通信已关闭”

End Sub

三、用文件输入/ 输出技术完成通信

用VB 提供的以上两种方法已足以应付各种串行通信的问题。另外还可以用文件输入/ 输出的方法完成简单的通信应用程序,如拨号。它用我们非常熟悉的BASIC 输入/ 输出指令,如:OPEN、CLOSE、GET、PUT(PRINT、WRITE)、ERR 来完成打开、关闭、读、写和检错通信口的功能。由于以上指令常在BASIC 中使用,所以不在本文中详细介绍。仅举一小例子来说一个为拨号操作,一个为挂机操作,程序很简单。

Sub Form1 —load ()

Dim Telnum As Sting

Command1. Caption = " "

Command2. Caption = " "

End Sub

Sub Command1 —Click()

Open“COM2" For Output As # 1

print # 1 ,Telnum

End Sub

Sub Command2 —Click()

Telnum=“A TH"

Print # 1 ,Telnum

Close # 1

End Sub

这个小例子仅用了PRINT来发送数据,该命令自动在字符串后加了回车符。其他指令如PUT、WRITE 亦可完成。但是注意变量TELNUM的格式,要在最后命令字符串后加回车符。WINDOWS 使用DOS 操作完成文件处理,所以将通信端口当成文件来操作,就仅使用了DOS 系统。这种方法十分简便。但是,使用文件输入/ 输出就使得通信不可靠,进来的字符可能遗漏,尤其是在2400b/s 以上的速率传输数据时。原因是这种方法仍基于DOS 操作,使通信无法高速传输或在WINDOWS 这样的多任务环境下使用。

经过长期的实践,笔者认为以上三种通信方法各有利弊。如果在以低速传输且不十分复杂的情况下,那么可选用第三种方法。而当在系统复杂传输速率高的情况下,则要选择前两种。第一种学习起来快,而且程序为事件驱动程序模块化;使用第二种方法要对WINDOWS API 函数有深入了解,对熟悉WINDOWS API 函数的程序设计人员来说,无疑是个好方法,而且程序可移植性强

相关主题
相关文档
最新文档