MSComm在适当时候引发控件的处理流程主要分为两步:
1)通过事件驱动处理连接端口通信 在收发一个字符或者生一个事件时,不管是产生一个事件还是错误(这取决于CommEvent的属性值),都会执行控件的事件程序OnComm()。我们需要预先将处理事件或者错误的逻辑代码输入在控件事件区。
2)检查CommEvent的属性值 通过检查CommEvent的值来判断是事件还是错误,并根据触发事件时CommEvent不同的值编写不同的分支来处理对应事件。对于处理串口收发数据,最常用的事件属性值有comEvSend(发送数据) 和 comEvReceive(接收数据)。
在早期,上位机和下位机之间经常使用的通信方式是RS-232的串行通信控制。直到今天,在USB通信普遍使用的方式下,PC端的应用软件依然是应用RS-232通信,保护了原有的软件开发投入。本次实验用的接口是较为常见USB接口,板子上采用了USB转串口芯片进行信号的转换。
上篇文章中讲到,VB6.0中MSComm控件的端口号仅限于1~16,并且大多数情况下用于插拔的USB都不是一个固定值,因此,我们首先需要获取PC机当前状态下可用于连接的串口端口号。
代码如下:
On Error Resume Next '打开端口出错时,程序不会中断 Dim I As Integer For I = 1 To 16 Step 1 '依次打开1~16的端口 MSComm1.CommPort = I MSComm1.PortOpen = True If Err.Number <> comPortInvalid Then Combo1.AddItem "COM" & I '获取能够正确打开的端口号 End If MSComm1.PortOpen = False Next Combo1.Text = Combo1.List(0) '将可用串口展示在在下拉菜单中效果如下图: 相关代码:
(1)On Error Resume Next 加上这句语句后,若当程序运行到某处出错时,不会中断,而是会存储出错信息到某处,然后继续执行后面的代码。在这里使用它的原因是,如果当时上位机并没有相应的串口设备注册,那么当我们企图打开一个串口时,会因错误中断而导致程序无法进行下去。加上这句话后,再结合MSComm1.PortOpen属性判断串口是否正确打开,以便于进行接下来的不同操作。
(2)Err.Number <> comPortInvalid 这句代码配合前面的On Error Resume Next使用。当发现打开串口出错时,继续执行后续代码,但这时已经将错误码存储于Err.Number之中,检查其是否和comPortInvalid相等,可判断该端口是否可用于串行通信。是,则将其加入下拉列表中。
在找到对应的可打开串口后,选择其中一个串口打开,这时候,也需要检查串口是否能够正确打开,如果出错,则对用户进行提示。针对打开按钮的单击操作如下:
On Error Resume Next ’打开出错时不中断 If MSComm1.PortOpen = False Then MSComm1.CommPort = Right(Combo1.Text, Len(Combo1.Text) - 3) MSComm1.PortOpen = True If Err.Number = comPortInvalid Then MsgBox "无法打开串口,请检查串口是否有效", vbOKOnly, "串口打开错误" Else Command1.Caption = "关闭" End IF Else MSComm1.PortOpen = False Command1.Caption = "打开" End If在上述代码中,如果不能 正确打开串口,会弹出消息框(MsgBox)报错,如下图:
在使用串口通信前,或者说打开串口前,应该对串口通信参数进行基础配置。这些配置参数可以在添加控件时的属性栏中进行编辑,也可以独自在代码中列出,如下:
MSComm1.Settings = "9600,o,8,2" '设置串口通信波特率 MSComm1.InBufferSize = 1024 '接收缓冲区大小 MSComm1.OutBufferSize = 512 '发送缓冲区大小 MSComm1.InputLen = 32 '每次从接收缓冲区中取出的字节数 MSComm1.InputMode = comInputModeBinary '设置为字节流传送 MSComm1.RThreshold = 9 '接收阈值,当接收字节数>=9时,触发接收事件 MSComm1.RTSEnable = True '接收功能使能 MSComm1.SThreshold = 0 '设置为0,不会触发comEvSend事件我们可以采用一个Text文本框进行接收数据的显示,将二进制字节数据转化为十六进制数据并以空格分隔显示在文本框当中。 1)对于文本框的设置 对于文本框,我们希望其可以将每一帧数据进行滚动显示,并且每次都显示最后一帧数据,于是进行如下设置:
Text28.MultiLine = True '允许多行显示 Text28.ScrollBars = 2 '垂直滚动显示 Text28.SelStart = Len(Text28.Text) '光标移到最后,每次显示最后一行2)进制转换代码
Public Function ReceiveToHex(bytInput() As Byte) As String Dim I As Integer Dim strData As String For I = 0 To UBound(bytInput) '遍历接收数组 If Len(Hex(bytInput(I))) = 1 Then '无效0填充 strData = strData & "0" & Hex(bytInput(I)) & " " Else strData = strData & Hex(bytInput(I)) & " " End If Next ReceiveToHex = strData & vbCrLf '末尾插入换行符 End Function效果图如图所示:
数据的发送使用了一个50ms的定时器,对发送数组进行内容填充更新,然后将该数组的值送入发送缓冲区。在定时器执行过程中有如下代码:
PackTranData '自定义数据填充更新函数 MSComm1.Output = bytOutput '将更新后的数组送入发送缓冲区**注:**由于数据发送缓冲区的数据填充过程并不是每次都从头开始存放数据,而是采用游标移动添加数据,所以每次数据帧在传送字节流的具体位置并不固定,比如:这次发送的数据是:
00 00 5A A5 06 00 00 00 00 00 00 00 00 00 00 00 00 00下一次的数据很可能是:
00 00 00 00 00 00 00 00 00 00 5A A5 06 00 00 00 00 00所以这时候,在下位机的接收端找到对应的数据帧十分重要,帧头和帧尾的重要性凸显。
