高手帮忙!关于MSCOMM接收问题!急啊!

VIV777 2007-04-11 01:46:06
我用VB写了一个关于MODBUS的协议
可是在接收时产生了问题
我用的是MSComm1_OnComm事件接受的,代码如下:
Dim nowstring As Variant
Dim i As Integer
Select Case MSComm1.CommEvent
Case comEvReceive '接收事件
'接收缓冲区收到Rthreshold个字符时触发
If MSComm1.InBufferCount Then
nowstring = MSComm1.Input
For i = LBound(nowstring) To UBound(nowstring)
InString = InString & CStr(Hex(Val(nowstring(i)))) & " "
Next i
nowstring = ""
end if
比如我发送的数据是 01 04 00 00 00 10 F1 C6
接收的数据应该为01 04 20 04 B2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B1 1B
可是有时这个数据接收过来是正确的,有时只接受到01 04 20 04 B2 00 00 00
怎样才能正确接收啊?
我设置的MSCOMM的属性为
MSComm1.Settings = "19200,8,N,1"
MSComm1.CommPort =1
MSComm1.SThreshold = 1
MSComm1.RThreshold = 1
MSComm1.InputLen = 0
MSComm1.PortOpen=true
MSComm1.InputMode = comInputModeBinary

请各位大侠帮忙啊!在下不胜感激!
...全文
1462 点赞 收藏 20
写回复
20 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
wumingyuan001001 2007-04-16
在VB6.0中使用datagrid
怎么样双击表头进行双向排序
在网上找了一些例子不使用
不知道怎么写
有那位兄弟有这方面的事例
不是在(。NET)
回复
newnazi 2007-04-14
使用TIMER控件效率是很底的.
1 检查你的初始化 是否正确, 波特率设置的不要太高建议使用9600,可能232的晶震不能提供这么高的频率
2 MSComm1.RThreshold 值根据需要设置可以设置的大一些.
3 用"串口调试助手"调试
4 如果你是要与单片机(C51 128 )通信应该使用 双字节的16进制编码.
回复
Gutta 2007-04-12
串口通讯一般都是单双工的,所以发送以后返回的数据具体是什么内容应该是明确的.

个人推荐使用timer,一般设置为100ms就可以了,因为在9600bps速率下,100ms的间隔可以等待大概100bytes的数据,而一般通讯而言,对于单独一次的通讯应该不可能返回超过100bytes的数据吧?

在发送的时候设置一个fgSEND,以便在下一个timer事件中直接进行判断这次返回的数据是什么数据,还有使用了timer的话,一定要设置RThreshold = 0,这样能保证把接受缓冲区的数据全部收到程序的Buffer() as Byte字节数组中进行处理.

还有,用VB写一般通讯程序,如果使用ONCOMM事件来进行不断通讯的处理的话,程序的其他操作就会比较卡,所以可以考虑用后台ActiveX EXE组件来实现,在前台只要处理一下返回的数据就可以了,然后其他前台的操作也不受通讯的影响,比较不错.

我们公司当前的监控管理软件系统就是这么做的.

个人观点,请大家多多批评.
回复
VIV777 2007-04-12
呵呵,谢谢啊,问题已经解决!
现在就结贴!
回复
littlestone08 2007-04-12
呵,感觉楼上的方法虽然能解决问题,却都是治标不治本的方法.

这个问题根本就不是一个BUG,而是使用方法的问题.
如果用TIME等去查询,就失去了使用事件的意义,而且如果上位机工作压力过大的话,很有可以失掉数据,用TIME延时的时间也不好控制,太大了不好,太小了还是会丢数据.

实际的根源在于:当你响应ON_COMM时,这时候,很有可能控件已经再接收到了新的数据,此时的数据数目已经不再是你刚进入事件处理程序时取得的数据长度了,所以,删除数据时的依据不能以刚刚进入程序时取得的数据长度为准.就说这么多了,希望对大家有点帮助.
回复
yl01152005 2007-04-12
这问题我碰到过,是mscomm控件本身的问题,尤其在不间断发出请求时尤其明显,必须加延迟或者加大传输率,这是我的解决方法
回复
zdingyun 2007-04-11
所以建议使用TIMER控件来控制轮询数据。我2007-04-11 15:20:53 及2007-04-11 15:58:17的答贴代码可供你参考,祝好运.使用TIMER控件来控制轮询数据实质就是延迟空出间隔来处理MSComm1_OnComm事件的接收.
回复
VIV777 2007-04-11
是单工的,我都测试了一下
比如01 04 00 00 00 02 71 CB
01 04 00 00 00 06 70 08
01 04 00 00 00 0A 70 0D
01 04 00 00 00 0E 71 CE
01 04 00 01 00 02 20 0B
01 04 00 01 00 06 21 C8
01 04 00 01 00 0A 21 CD
01 04 00 01 00 0E 20 0E
01 04 00 02 00 02 D0 0B
01 04 00 02 00 06 D1 C8
01 04 00 02 00 0A D1 CD
01 04 00 02 00 0E D0 0E
。。。。。。。
01 04 00 0D 00 02 E0 08
01 04 00 0E 00 02 10 08
这些接收时必须要设短点才能接收到正确的结果,否则错误
回复
zdingyun 2007-04-11
查下你下位机是用RS232还是RS485。RS232是双工,RS485是单工。
回复
VIV777 2007-04-11
发送数据 01 04 00 00 00 0A 70 0D
应该接收到01 04 14 04 B2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7B 67

可是为什么不设断点的时候就接收错误,只有设了断点以后逐步调试才能接收到正确的数据,这是为什么?
回复
guyehanxinlei 2007-04-11
帮顶
回复
zdingyun 2007-04-11
那你应使用TIMER控件来控制轮询数据。
Private Sub Timer1_Timer()
Dim i As Integer
Static j As Byte
Dim bytData(1) As Byte
j = j + 1
For i = 0 To 1
bytData(i) = &H0 + j
Next
If j >= 4 Then
j = j - 4
End If
Call SendData(bytData) '发送
End Sub
在窗体初始化设置
Timer1.Interval = 100 '数字可调,最小55,TIMER控件每秒系统提供18次变化
回复
VIV777 2007-04-11
谢谢了
回复
programart_life 2007-04-11
需要延时是因为第一端口通讯需要时间,第二下位机响应更需要时间。如果是非双工模式,这个时间更明显。
回复
zdingyun 2007-04-11
将MSComm1.Settings = "19200,n,8,1"中19200改9600试试。
发送命令时间间隔调大些。
RS232串口连接距离不宜过长,可能有干扰。在接收代码中增加判断代码。
建议返回数据固定字节长,可补足字节长。不回接收出错,字节长尽可能为8的倍数。
回复
VIV777 2007-04-11
to zdingyun()
我接受的数据不是固定的,这得看我发送的数据是多少
比如我发送的数据是
01 04 00 00 00 10 f1 c6
那么我的数据长度就是10,即16位
而此时我接受的数据就是16*2=32位
另外的数据是地址、功能和校验码
如果我发送的数据是,这里就是37位
01 04 00 00 00 07 B1 C8
那么数据长度就是07 ,即14位
接收的数据就为28位
如果再加上其他的数据总共是33位

发送和接收的数据都是十六进制
现在这个问题我已经解决了
加入了延时,可是我还是不明白为什么加入延时才可以呢?
回复
zdingyun 2007-04-11
Private Sub Form_Load()
MSComm1.CommPort = 1 'COM端口
MSComm1.Settings = "19200,n,8,1"
MSComm1.InputMode = comInputModeBinary '采用二进制传输
MSComm1.InBufferCount = 0 '清空接受缓冲区
MSComm1.OutBufferCount = 0 '清空传输缓冲区
'MSComm1.SThreshold = 1 '如果传输缓冲区完全空时产生MSComm事件
MSComm1.RThreshold = 1 '产生MSComm事件
MSComm1.PortOpen = True
Text3 = "" '打开端口
End Sub

Private Sub MSComm1_OnComm()
On Error Resume Next
Dim BytReceived() As Byte
Dim strBuff As String
Dim strData As String
Dim i As Integer
Dim x As Integer
Select Case MSComm1.CommEvent
Case 2
MSComm1.InputLen = 0
strBuff = MSComm1.Input
BytReceived() = strBuff
For i = 0 To UBound(BytReceived)
If Len(Hex(BytReceived(i))) = 1 Then
strData = strData & "0" & Hex(BytReceived(i))
Else
strData = strData & Hex(BytReceived(i))
End If
Next
Text3 = Text3 + strData
If Left(strData, 2) = "00" And Len(strData) = 8 Then '接收4字节
Text1(0).Text = Left(strData, 8)
Call DataClear
ElseIf Left(strData, 2) = "01" And Len(strData) = 74 Then '接收37字节
Text1(1).Text = Left(strData, 74)
Call DataClear
End If
End Select
End Sub

Public Sub DataClear()
MSComm1.OutBufferCount = 0 '清空发送缓冲区
MSComm1.InBufferCount = 0
Text3 = ""
End Sub
回复
VIV777 2007-04-11
to zdingyun()
接收数据的长度是不固定的
回复
CathySun118 2007-04-11
Setting the SThreshold property to 0 (the default) disables the OnComm event for data transmission events. Setting the SThreshold property to 1 causes the Comm control to generate the OnComm event when the transmit buffer is completely empty.

If the number of characters in the transmit buffer is less than value, the CommEvent property is set to comEvSend, and the OnComm event is generated. The comEvSend event is fired only once, when the number of characters crosses the SThreshold property. For example, if SThreshold equals five, the comEvSend event occurs only when the number of characters drops from five to four in the output queue. If there are never more than SThreshold characters in the output queue, the event is never fired.
回复
zdingyun 2007-04-11
设置MSComm1.RThreshold = 37
回复
相关推荐
发帖
VB基础类
创建于2007-09-28

7489

社区成员

VB 基础类
申请成为版主
帖子事件
创建了帖子
2007-04-11 01:46
社区公告
暂无公告