论伊瑟尔的隐含的读者:串口通讯及其在VB平台下的实现

来源:百度文库 编辑:偶看新闻 时间:2024/04/25 11:55:37
串口通讯及其在VB平台下的实现0推荐

  随着计算机系统的普及与外围设备技术的发展,计算机与外围设备之间的通讯就显得越来越
重要了。由于串行通信是在一根传输线上一位一位的传送信息,所用的传输线少,并且可以借助
现成的电话网进行信息传送,因此,特别适合于远距离传输。对于那些与计算机相距不远的人-
机交换设备和串行存储的外部设备如终端、打印机、逻辑分析仪、磁盘等,采用串行方式交换数
据也很普遍。在实时控制和管理方面,采用多台微机处理机组成分级分布控制系统中,各CPU之
间的通信一般都是串行方式。所以串行接口是微机应用系统常用的接口,而相应的应用程序也成
为今年来研究的热点。本文旨在阐述一般的穿口通讯的原理及其程序设计,希望借此能够抛砖引
玉,为更深入的研究打下一定的基础。
 
一、串行通讯的基本原理
  所谓"串行通信"是指外设和计算机间使用一根数据信号线,数据在一根数据信号线上按位进
行传输,每一位数据都占据一个固定的时间长度。这种通信方式使用的数据线少,在远距离通信
中可以节约通信成本,当然,其传输速度比并行传输慢。相比之下,由于高速率的要求,处于计
算机内部的CPU与串口之间的通讯仍然采用并行的通讯方式,所以串行口的本质就是实现CPU与外
围数据设备的数据格式转换(或者称为串并转换器),即当数据从外围设备输入计算机时,数据
格式由位(bit)转化为字节数据;反之,当计算机发送下行数据到外围设备时,串口又将字节数
据转化为位数据。

二、串口通讯的程序设计原理
  前面介绍了串行通讯的基本原理,那么如何在程序设计中实现它呢?事实上,这个过程并不
复杂,一般有两种实现途径:其一就是使用MSCOMM控件,此控件提供很多方便操作的属性和方法,
利用它们可以很方便地实现你的目的;另外一种途径就是使用Windows API,微软为开发者提供了
很多相关的串行操作的编程接口,使用这些接口,可以很完成更为强大的功能。限于篇幅以及本
文的宗旨,这里着重介绍第一种方法,第二种方法实际思路与第一种方法一样,不同的是它利用
API函数代替了控件。
  无论使用哪一种途径,其基本的操作步骤大致一样的:首先初始化串口,比如端口号,波特
率等属性,然后打开端口,通过接受缓冲区读上行数据,通过发送缓冲区来写下行数据。最后通
过事件驱动来反映数据的到达与发送过程,另外在通讯过程中的错误的产生也可以通过CommEvent
属性来管理。

三、VB平台下的实现

  使用MSCOMM控件主要是通过事件来处理串行口的交互,即当数据到达时,控件的OnComm的事
件就会来捕获或处理这些通讯事件。而OnComm事件也可以用来捕获和处理通讯错误。在实际应用
中,一个MSCOMM控件就对应一个串行口,所以如果要处理多个串行口的话,必须有相应数量的控
件与之对应。下面介绍一下此控件的主要属性:
    CommPort  ------  设置或者返回串行端口号, 如设成1(默认值),表示对Com1进行操作。
  Settings  ------  用来设置和返回波特率,奇偶校验,数据位和结束位
                      对串口通讯的相关参数。包括串口通讯的比特率,奇偶校验,
                      数据位长度、停止位等。其默认值 是“9600,N,8,1”,表示串口比特率
                      是9600bit/s,不作奇偶校验,8位数据位,1个停止位。
  PortOpen  ------  设置或者返回通讯端口的状态,也可以打开和关闭一个端口;
                      值为True时打开串口,值为False时关闭串口。
  Input     ------  从接受缓冲区里获取或删除数据;
                      从输入寄存器读取数据,返回值为从串口读取的数据内容,同时输
                      入寄存器将被清空。
                      该属性设计时无效,运行时只读
  Output   -------  发送缓冲区里写数据; 发送数据到输出寄存器。
                      该属性设计时无效,运行时只读
    InBufferCount:    设置输入寄存器所存储的字符数,当将其值设为0时,则输入寄存器将被清空。
                       设置或返回接收缓冲区中等待计算机接收的字符数。
    InputMode:        设置从输入寄存器中读取数据的形式。若值为0,则表示以文本形式读取;
                      值为1,则表示以 二进制形式读取。
    Inputlen:        设置或返回一次从接收缓冲区中读取字节数。
    InBufferSize:    设置或返回接收缓冲区的大小,缺省值为1024字节
    OutBufferCount:  设置输出寄存器所存储的字符数,当将其值设为0时,则输出寄存器将被清空。
    OutBufferSize:   设置或返回发送缓冲区的大小,缺省值为512字节
    RThreshold:      设置在MSComm控件设置CommEvent属性为comEvReceive并产生OnComm事件之前
                      要接受的字符数
                      该属性为一阀值。当接收缓冲区中字符数达到该值时,MSComm控件设置Commevent
                      属性为ComEvReceive,并产生OnComm事件。用户可在OnComm事件处理程序中进行
                      相应处理。若Rthreshold属性设置为0,则不产生OnComm事件。例如用户希望接收
                      缓冲区中达到一个字符就接收一个字符,可将Rthreshold设置为1。这样接收缓冲
                      区中接收到一个字符,就产生一次OnComm事件。
    Sthreshold:      该属性亦为一阀值。当发送缓冲区中字符数小于该值时,MSComm控件设置Commevent
                      属性为ComEvSend,并产生OnComm事件。若Sthreshold属性设置为0,则不产生
                      OnComm事件。要特别注意的是仅当发送缓冲区中字符数小于该值的瞬间才产生
                      OnComm事件,其后就不再产生OnComm事件。例如Sthreshold设置为3,仅当发送缓冲
                      区中字符数从3降为2时,MSComm控件设置Commevent属性为ComEvSend,同时产生
                      OnComm事件,如发送缓冲区中字符始终为2,则不会再产生OnComm事件。这就避免了
                      发送缓冲区中数据未发送完就反复发生OnComm事件。
    CommEvent属性:   返回最近的通讯事件或错误。通过对它具体属性值的查询,我们就可以获得
                      通讯事件和通 讯错误的完整信息。当其值是comEvReceive时表示接收到数据。
                      这是一个非常重要的属性。该属性设计时无效,运行时只读。一旦串口发生通信事件
                      或产生错误,依据产生的事件和错误,MSComm控件为CommEvent属性赋不同的代码,
                      同时产生OnComm事件。用户程序就可在OnComm事件处理程序中针对不同的代码,进行
                      相应的处理。

    除了公共事件之外,MSComm只有一个OnComm事件。当CommEvent属性值变化时将发生OnComm事件,
    指示发生 一个通讯事件或错误。当我们设置Rtheshold属性值为0时,将使得捕获comEvReceive
    事件无效。CommEvent属性里面包含了通讯事件或者产生的错误的编号。
 
CommEvent属性的代码、常数及含义参见表1及表2。
表1 CommEvent通信事件
 代码 常数  含义
 1 ComEvReceive 接受到Rthreshold个字符。该事件将持续产生,直到用Input属性从
                         接受缓冲区中读取并删除字符。
 2 ComEvSend 发送缓冲区中数据少于Sthreshold个,说明串口已经发送了一些数据,
                         程序可以用Output属性继续发送数据。
 3 ComEvCTS Clear To Send信号线状态发生变化。
 4 ComEvDSR Data Set Ready信号线状态从1变到0。
 5 ComEvCD  Carrier Detect信号线状态发生变化。
 6 ComEvRing 检测到振铃信号。  
 7 ComEvEOF 接受到文件结束符。

表2 CommEvent通信错误
 代码 常数  含义
 1001 ComEvntBreak 接受到一个中断信号。
 1002 ComEvntCTSTO Clear To Send信号超时。
 1003 ComEvntDSRTO Data Set Ready信号超时。
 1004 ComEvnt 帧错误。
 1006 ComEvntOverrun 串口超速。
 1007 ComEvntCDTO 载波检测超时。
 1008 ComEvntRxOver 接受缓冲区溢出,缓冲区中已没有空间。
 1009 ComEvntRxParity 奇偶校验错。
 1010 ComEvntTxFull 发送缓冲区溢出,缓冲区中已没有空间。
 1011 ComEvntDCB 检索串口的设备控制块时发生错误。
 
    写一个串口通信程序首先要放一个控件进去,然后在Form_Load()的时候,通常是在load的时
    候定义好mscomm的各种属性,比如速率,数据位,停止位等等.然后打开某个端口,再想办法
    触发OnComm事件,然后对缓冲区的内容收或者发。然后对收到的数据加工处理。或者处理好
    数据发出去。就这么简单,的确简单。如果想让程序变得聪明点,出了问题知道问题在哪里,
    那一定要好好利用CommEvent属性
 
    为了能够更加清楚的说明上述问题,下面给出一个例程,
    例程要实现的功能很简单,就是在一个过程里给一个特定的串行口发送数据,然后在另外一个
    过程里实时检测此串行口以便一旦此串行口的发送缓冲区有数据就显示消息,如果发送空数据
    就会显示"无数据的字样"。
  主要核心代码如下:

Private Sub Command1_Click()
If Text1.Text = "" Then
List1.AddItem "发送缓冲区无数据"
Exit Sub
End If
MSComm1.Output = Text1.Text
End Sub
Private Sub Command2_Click()
Unload Me
End Sub

'主要进行串口的初始化
Private Sub Form_Load()
'选择com1
MSComm1.CommPort = 1
'设置波特率为9.6kpbs,没有奇偶校验,8位数据位,1位结束位
MSComm1.Settings = "9600,N,8,1"
'读取全部的输入缓冲区
MSComm1.InputLen = 0
'端口打开
MSComm1.PortOpen = True
MSComm1.RThreshold = 10
MSComm1.SThreshold = 10
'以下就可以进行数据的发送了
End Sub
'所有的通讯事件都可以激发MSComm1控件的OnComm事件
Private Sub MSComm1_OnComm()
Select Case MSComm1.CommEvent
Case comEvReceive
'此处的代码可以进行当串口的接受缓冲区里有RThreshold个字符的处理
Case comEvSend
'此处的代码可以进行当串口的发送缓冲区里有SThreshold个字符的处理
List1.AddItem "发送缓冲区有数据"
End Select
End Sub
 
四、小结
  虽然上面的例程实现的功能简单,但是从文中的分析不难看出,通过控件MSCOMM的input 和
output属性可以很方便的接受和发送串口缓冲区的数据。当然要编制比较完善的通讯应用程序,
还需要进行更深入的研究,比如通过使用"握手"的机制来增强通讯的安全性和稳定性,另外通过
数据的重复的发送达到收发数据的准确性等等。这些方面希望读者在实际开发中多实践,以便能
够满足实际的需要。 
 

串口通讯编程实例 二
    在完成了对MSComm控件的简要介绍之后,笔者就以实际程序为例,介绍一下串口通讯的具体
实现方法。

1、PC机间的串口通讯
  (1)、实现方法:
 
   A、新建一个窗体,在上面放两个Text控件、两个CommandButton控件和两个Label控件(如图1.bmp所示)。
具体见下表:

控件类型           名称            Caption属性          作用
-------------------------------------------------------------------------------
Text                Text1            -------          输入所要发送的信息
Text                Text2            -------          显示接收到的信息
CommandButton       Command1         发  送             ---------           
CommandButton       Command2         退  出             ---------
Label               Label1         发送的数据             提示
Label               Label2         接收的数据             提示

   B、在控件工具箱中的空白处点击鼠标右键,在弹出的菜单中选择“部件”,在弹出的窗口中的控
   件列表中 找到“Microsoft Comm Control”,将其选中,在点击“应用”、“关闭”,在控件工具栏
   中就会出现一个电 话的小图标。
  
   C、用串口线将两台电脑连接起来。您可以使用Com1对Com1的对应连接,也可以使用Com1和Com2
   的交叉连接。本程序使用的是Com1对Com1的连接。
  
   D、输入以下代码:
Private Sub Command1_Click()
'...发送数据
MSComm1.OutBufferCount = 0 '...清空输出寄存器
MSComm1.Output = Text1.Text '...发送数据
End Sub

Private Sub Command2_Click()
'...退出
Unload Me
End Sub

Private Sub Form_Load()
'...初始化
MSComm1.CommPort = 1 '...使用Com1口
MSComm1.Settings = "9600,n,8,1" '...设置通讯参数
MSComm1.PortOpen = True '...打开串口
End Sub

Private Sub Mscomm1_Oncomm()
'...通讯事件发生
Select Case MSComm1.CommEvent
Case comEvReceive '...有接受事件发生
Text2.Text = MSComm1.Input '...接受显示数据
MSComm1.InBufferCount = 0 '...清空输入寄存器
End Select
End Sub

2、PC机与单片机之间的通讯
   PC机与单片机之间的通讯被广泛的用于工业、医疗测控等领域之中。在应用中,我们通常
   将单片机作为“感 受器”和“效应器”,负责数据采集、响应计算机发出的指令对电路进行
   控制,有时也进行一些简单的运算, 最后再将执行数据反馈给计算机处理。本程序将实
   现在PC机上输入一个0-255之间的整数,将此数据发送到单片 机,单片机接收到数据后,
   将数据在显示管上显示,再将此数除以2,将得数返回给PC机。(运行效果如图 3.BMP所
   示)其实现方法如下:
  
    A、同PC机间通讯的实现方法A-B。

    B、连接电脑和单片机。注意!由于PC机端的RS232电平与单片机端TTL的并不不匹配,
       故应注意电平转换。

    C、在VB中输入以下代码:

Private Sub Mscomm1_Oncomm()
'...通讯事件发生
Dim indata As Variant
Dim bte(0) As Byte
Select Case MSComm1.CommEvent
Case comEvReceive '...有接受事件发生
indata = MSComm1.Input
'...注意!要通过MSComm控件发送或接收二进制数据必须用Variant类型的变量对二进
'...制Byte类型的变量进行转换!
bte(0) = AscB(indata)
Text2.Text = bte(0)
MSComm1.InBufferCount = 0 '...清空输入寄存器
End Select
End Sub

Private Sub Command1_Click()
'...发送数据
Dim Num As Integer
Dim outbte(0) As Byte
Num = Val(Text1.Text)
outbte(0) = CByte(Num)
MSComm1.OutBufferCount = 0 '...清空输出寄存器
MSComm1.Output = outbte(0) '...发送数据
End Sub

Private Sub Command2_Click()
'...退出
Unload Me
End Sub

Private Sub Form_Load()
'...初始化
MSComm1.CommPort = 1 '...使用Com1口
MSComm1.Settings = "9600,n,8,1" '...设置通讯参数
MSComm1.PortOpen = True '...打开串口
End Sub

   D、单片机工作方式置于1,比特率设为9600bit/s。在单片机上,我们只得使用汇编语言编写,
   并且调用中 断实现对串口数据的收发工作。
   源代码如下:
PUSH PSW        ;将程序状态字压入堆栈
PUSH ACC        ;将累加器压入堆栈
CLR EA          ;关闭系统中断         
CLR RI          ;清除中断标志位
MOV A,SBUF      ;从接收寄存器中读取数据
MOV 70H,A       ;分解数据百、十、个位并显示
MOV B,#100     
DIV AB
MOV 52H,A       ;分解百位,送入存储器52H
MOV A,B
MOV B,#10
DIV AB
MOV 51H,A       ;分解十位,送入存储器51H
MOV 50H,B       ;分解个位,送入存储器50H
MOV A,70H
MOV B,#2  
DIV AB          ;将接受的数据除以2
MOV SBUF,A      ;将得数发送到输出寄存器
ACALL DL1       ;延时保证数据完整发送
ACALL DL1
CLR RI          ;清除中断标志位
SETB EA         ;打开系统中断
POP ACC         ;累加器出栈
POP PSW         ;程序状态字出栈
RETI            ;中断程序返回

3、编程环境
     以上程序在Windows 2000 Professional,Visual Basic 6.0企业版,AT89C52型单片机下调试通过。
总结
    从以上程序可以看出,在VB中利用MSComm控件,可以快速开发出串口通讯程序,从而大大提高编程效率。

参看范例
Private Sub Command1_Click()
'... 发生数据
MSComm1.OutBufferCount = 0 '... 清零输出寄存器
MSComm1.Output = Text1.Text '... 发送数据

End Sub

Private Sub Command2_Click()
'... 退出
Unload Me

End Sub

Private Sub Command3_Click()
MSComm1.PortOpen = False '... 关串口
End Sub

Private Sub Form_Load()
'... 初始化串口
MSComm1.CommPort = 1 '... 设置串口编号
MSComm1.Settings = "9600,n,8,1" '...设置通讯参数
MSComm1.InBufferSize = 40 '设置缓冲区接收数据为40字节, 默认1024
MSComm1.InputLen = 1 '...一次从接收缓冲区读取字节为1, 默认为 0,读取全部内容
MSComm1.RThreshold = 1 '... 接收一个字节就产生oncommm事件
MSComm1.PortOpen = True '... 打开串口

End Sub

Private Sub MSComm1_OnComm()
'... 通讯事件发生
Select Case MSComm1.CommEvent
Case comEvReceive '... 有接受事件
Text2.Text = Text2.Text & MSComm1.Input '... 接收显示数据
MSComm1.InBufferCount = 0 '... 清空输入寄存器
End Select

End Sub