【叶帆开源区】-MSComm串口通信示例

叶帆
博客专家认证
业界专家认证
2004-09-19 12:27:32
做工控,做自动化离不开通信,串口通信是最常见的通信方式(232、485)。
现把我多年使用串口的经验整理出来供大家参考。

源码下载:http://blog.csdn.net/yefanqiu 【叶帆源码】- 串口通信示例

部分源码:--------------------
'*************************************************************************
'**模 块 名:frmMain
'**说 明:YFHome 版权所有2004 - 2005(C)
'**创 建 人:叶帆
'**日 期:2004-09-19
'**修 改 人:
'**日 期:
'**描 述:串口通信示例(CSDN 开源)
'** :-------------------------------------------------------
'** :示例说明
'** :
'** :该示例程序模拟PC机与一终端(下位机)串口通信,PC机先向下位机发送五个字节,下位机
'** :收到数据后也返回送五个字节的确认命令
'** :
'** : 字头 站号 副本 命令 副本
'** :帧 结 构:AC 01 01 0A 0A 正副本校验方式
'** :
'** :返 回 帧:AC 01 01 AA AA 响应命令,表示终端接收到数据
'** :-------------------------------------------------------
'**版 本:V1.0.0
'*************************************************************************
Option Explicit
Private Declare Function GetCurrentTime Lib "kernel32" Alias "GetTickCount" () As Long

'*************************************************************************
'**函 数 名:cmdSend_Click
'**输 入:无
'**输 出:无
'**功能描述:发送命令
'**全局变量:
'**调用模块:
'**作 者:叶帆
'**日 期:2004-09-19
'**修 改 人:
'**日 期:
'**版 本:V1.0.0
'*************************************************************************
Private Sub cmdSend_Click()
Dim bytData(10) As Byte
bytData(0) = &HA '数据
txtMsg.Text = SendData(1, bytData, 1) '发送命令
End Sub

'*************************************************************************
'**函 数 名:Form_Load
'**输 入:无
'**输 出:无
'**功能描述:串口初始化
'**全局变量:
'**调用模块:
'**作 者:叶帆
'**日 期:2004-09-19
'**修 改 人:
'**日 期:
'**版 本:V1.0.0
'*************************************************************************
Private Sub Form_Load()
OpenPort 1 '打开串口
End Sub

'*************************************************************************
'**函 数 名:OpenPort
'**输 入:PortNo(Integer) - 串口号 1,2,3...
'** :Optional InBufferSize(Integer = 1024) - 接收缓冲区 默认为1024个字节
'** :Optional OutBufferSize(Integer = 512) - 发送缓冲区 默认为512个字节
'**输 出:0 打开串口成功 1 打开串口失败
'**功能描述:打开串口
'**全局变量:
'**调用模块:
'**作 者:叶帆
'**日 期:2003年12月17日
'**修 改 人:
'**日 期:
'**版 本:V1.0
'*************************************************************************
Public Function OpenPort(PortNo As Integer, Optional InBufferSize As Integer = 1024, Optional OutBufferSize As Integer = 512) As Long
On Error GoTo ErrExit
MSComm1.CommPort = PortNo '采用COM端口
MSComm1.Settings = "9600,n,8,1"
MSComm1.InputMode = comInputModeBinary '采用二进制传输
MSComm1.NullDiscard = False 'NULL字符从端口传送到接受缓冲区
MSComm1.DTREnable = False 'DTR线无效
MSComm1.EOFEnable = False '不寻找EOF符
MSComm1.RTSEnable = False 'RTS线无效
MSComm1.InBufferCount = 0 '清空接受缓冲区
MSComm1.OutBufferCount = 0 '清空传输缓冲区
MSComm1.SThreshold = 1 '如果传输缓冲区完全空时产生MSComm事件
MSComm1.RThreshold = 0 '不产生MSComm事件
MSComm1.InBufferSize = InBufferSize '接收缓冲区 默认为1024个字节
MSComm1.OutBufferSize = OutBufferSize '发送缓冲区 默认为512个字节
MSComm1.PortOpen = True '打开端口
OpenPort = 0
Exit Function
ErrExit:
OpenPort = 1
End Function
'*************************************************************************
'**函 数 名:ClosePort
'**输 入:无
'**输 出:无
'**功能描述:关闭串口
'**全局变量:
'**调用模块:
'**作 者:叶帆
'**日 期:2003年12月15日
'**修 改 人:
'**日 期:
'**版 本:V1.0
'*************************************************************************
Public Sub ClosePort()
On Error GoTo ErrExit
MSComm1.PortOpen = False '关闭端口
Exit Sub
ErrExit:

End Sub

'*************************************************************************
'**函 数 名:SendData
'**输 入:bytAddr(Byte) - 设备地址(0~255)
'** :bytData()(byte) - 数据数组
'** :bytNum(byte) - 数据个数(1~256/数据类型的长度)
'**输 出:(Long) - 0 成功 1 -超时 2 - 接收的数据有误 3 - 其它未知错误
'**功能描述:发送数据
'**全局变量:
'**调用模块:
'**作 者:叶帆
'**日 期:2004年05月19日
'**修 改 人:
'**日 期:
'**版 本:V1.0
'*************************************************************************
Public Function SendData(bytAddr As Byte, bytData() As Byte, Optional bytNum As Byte = 1) As Long
On Error GoTo ErrExit

Dim bytSendArray() As Byte '发送数据缓冲区
Dim intGetDataLen As Integer '要接收的数据长度
Dim sngTimeSpace As Single '延时时间
Dim sngTime As Single
Dim bytReceiveArray() As Byte '接收的数据
Dim VarReceiveData As Variant '接收的变体数据

Dim i As Long

ReDim bytSendArray(0 To bytNum * 2 + 2) As Byte '发送数据缓冲区

bytSendArray(0) = &HAC '同步字头
bytSendArray(1) = bytAddr '下位机地址
bytSendArray(2) = bytAddr '副本

'数据
For i = 0 To bytNum * 2 - 1 Step 2
bytSendArray(i + 3) = bytData(i / 2)
bytSendArray(i + 4) = bytData(i / 2)
Next

'=====================================================================================
'信息发送
'=====================================================================================
MSComm1.InBufferCount = 0 '清空接收缓冲区
MSComm1.Output = bytSendArray '发送数据

Do
DoEvents
Loop Until MSComm1.OutBufferCount = 0 '等待,直到数据发送完毕

'=====================================================================================
'信息接收
'=====================================================================================

'设定要接收的数据长度
intGetDataLen = 5

'超时时间计算:字节数×每个字节的传输时间×10 9600为波特率 请根据实际设定
sngTimeSpace = intGetDataLen * (11000# / 9600#) * 10#

sngTime = GetCurrentTime() '

Do While True '数据接收

DoEvents
If MSComm1.InBufferCount >= intGetDataLen Then Exit Do

'超时处理
If Abs(GetCurrentTime() - sngTime) > sngTimeSpace Then '超时
SendData = 1
Exit Function
End If

Loop

VarReceiveData = MSComm1.Input
bytReceiveArray = VarReceiveData

'返回帧校验
SendData = 2 '先赋值接收的数据错误
If bytReceiveArray(0) = &HAC Then '字头
'帧数据是否正确(正副本校验)
If bytReceiveArray(1) = bytReceiveArray(2) And bytReceiveArray(3) = bytReceiveArray(4) Then
'站号,命令判断
If bytReceiveArray(1) = bytSendArray(1) And bytReceiveArray(3) = &HAA Then
SendData = 0 '命令正确
End If
End If
End If

Exit Function

ErrExit:
SendData = 3
End Function
...全文
1787 71 打赏 收藏 转发到动态 举报
写回复
用AI写文章
71 条回复
切换为时间正序
请发表友善的回复…
发表回复
busy2005 2005-08-25
  • 打赏
  • 举报
回复
楼主能不能去看看我刚才发的问题 帮我解决一下? 也是串口方面的问题.
刚学vb ,太多不懂!
andy_join 2005-08-23
  • 打赏
  • 举报
回复
非常感谢bilujun!
andy_join 2005-08-22
  • 打赏
  • 举报
回复
在发送数据的时候,如何把一段字符转化为十六进制!
“2134568aa7987897879aa” 转化为
dim senddata() as byte
??
.
.
.
.
.就是不知道怎么写了?请教叶兄如何处理!
riwan61170 2005-08-22
  • 打赏
  • 举报
回复
学习中,帮顶
bilujun 2005-08-22
  • 打赏
  • 举报
回复
to andy_join(剑)

'字符串转换成字节数组
'num:要转换的字符串
'isLowByteFirst:是否低位字节在前
Public Function StringToByteArray(num As String) As Byte()
Dim i As Long
Dim strMod As Long
Dim arr() As Byte
'判断输入参数
If num = "" Then
Exit Function
End If
'得到字节数组长度
strMod = Len(num) Mod 2
If strMod > 0 Then
num = "0" & num
End If

arrLen = Len(num) / 2
ReDim arr(arrLen - 1)
'转换成字节数组
For i = 0 To arrLen - 1
arr(i) = VAL("&H" & Mid(num, 2 * i + 1, 2))
Next i
StringToByteArray = arr
End Function
blp 2005-08-22
  • 打赏
  • 举报
回复
为什么不能连续发超过3次?
bilujun 2005-08-22
  • 打赏
  • 举报
回复
下面我也给出一个接收的函数.供大家参考使用。
'函数功能说明 :从串口接收一个完整的返回帧,注意byteInterval越大,效率就越低。
'byteInterval :字节间隔时间(根据波特率来计算.windows2000下mscomm是8个字节一起接收的,
' 取值如下大致如下)
' bps = 1200 byteInterval=120
' bps = 2400 byteInterval=60
' bps = 4800 byteInterval=30
' bps = 9600 byteInterval=15
'timeOut :超时时间
Public Function RecvData(Optional byteInterval As long = 15,Optional timeOut as Long = 1000) As Byte()
Dim TmpFrame() as Byte
Dim RecvFrame() As Byte
Dim StartTime as Long
Dim LastBufferCount AS Long
Dim i As Long

'清空缓冲区
TmpFrame = MSComm.input

startTime = GetTickCount()
'超时判断
Do
Sleep 10
If GetTickCount - startTime > timeOut Then
Exit Function
End If
If MSComm.InBufferCount > 0 Then
lastBufferCount = MSComm.InBufferCount
Exit Do
End If
Loop
'接收数据
Do
Sleep byteInterval
If LastBufferCount = MSComm.InBufferCount Then
Exit Do
Else
LastBufferCount = MSComm.InBufferCount
End If
Loop
RecvData = MSComm.Input
End Function
bilujun 2005-08-22
  • 打赏
  • 举报
回复
我还是非常喜欢搂住的编程风格,不采用事件驱动方式接收数据是为了模块化更加清晰.性能的损失应该说可以接受的。
不过我觉得接收数据部分还可以改进一下,以达到对不定长帧的接收。我是这样处理的,判断字符间隔时间内没有接收到数据,则认为一帧接收结束。
bilujun 2005-08-22
  • 打赏
  • 举报
回复
搂住,好像InBufferCount是无法清空缓冲区的,或许这是一个BUG。清空缓冲区还是用 MSCOMM.input = ""。

henryjee 2005-08-22
  • 打赏
  • 举报
回复
mk
yinweihong 2005-08-22
  • 打赏
  • 举报
回复
啪,留个脚印
gzhoney 2005-06-26
  • 打赏
  • 举报
回复
好东东
rongdong_zhu 2005-06-13
  • 打赏
  • 举报
回复
lihai
南山明月 2005-06-13
  • 打赏
  • 举报
回复
先收藏
acev 2005-06-13
  • 打赏
  • 举报
回复
学习一下。
一年前做过通信的程序,现在忘光了~~
wxrwan 2005-06-13
  • 打赏
  • 举报
回复
好东西
红三天 2005-06-07
  • 打赏
  • 举报
回复
不上很明白GetCurrentTime()有什么作用,这段代码虽然不错,但是我个人觉得还是事件驱动的方法比较好点。原因很简单,这段代码在兼容性上存在不足,接收数据的时候会遇到不可预知的错误,例如接收缓冲区无数据,导致接收时超时!
关于大家所说的USB通信,我知道有个CP2101的芯片,只要用了这个芯片,在上位机上装好CP2101的驱动,那么,电脑上就有一个虚拟的com口了,一般是COM3,然后对这个虚拟COM口操作,就可以了。连接时,还是用的USB。
kcm8233 2005-05-17
  • 打赏
  • 举报
回复
把端口改一下。mscomm1.CommPort = 2或3
试试
叶帆 2005-05-17
  • 打赏
  • 举报
回复
usb通信,我也在探索,多么希望,有谁封装成控件,就想mscomm一样使用,该多好
叶帆 2005-05-17
  • 打赏
  • 举报
回复
端口已经被别的程序打开,或者是你程序打开了,但是没有关闭(比如调试时,直接单击终止按钮)

一般,我把通信的内容封装的到控件里,也算个单元线程吧。这样就不至于影响宿主程序。
此外,我喜欢一进一出的编程风格,用事件方式,不可否认执行效率比较高(但mscomm控件实际也是封装的API,在封装的时候,也是有循环等待的,只不过用专门的API函数,执行效率较高),但程序在执行多种命令时,编码相对复杂。
各有所长吧
加载更多回复(51)

7,763

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧