为什么每次都只能接收8个字节,超过8个,他就先收8个,剩下的在下一次在接收比如说12个字节,就先收8个,再收四个,出发了两次oncomm事件
再比如说17个字节,就先收8个,再收8个,再收一个.大家分析一下 这与什么有关?另外不同的波特率下 比如说9600 和 52000下,仍然会出现只收8字节的情况。为什么?
再比如说17个字节,就先收8个,再收8个,再收一个.大家分析一下 这与什么有关?另外不同的波特率下 比如说9600 和 52000下,仍然会出现只收8字节的情况。为什么?
MSComm1.CommPort = 1
MSComm1.InBufferSize = 1024
MSComm1.OutBufferSize = 512
MSComm1.Settings = "19200,n,8,1"
MSComm1.InputMode = comInputModeBinary '二进制接收
MSComm1.InputLen = 0 '设置 InputLen 为 0 时,使用 Input 将使 MSComm 控件读取接收缓冲区中全部的内容
MSComm1.PortOpen = True
MSComm1.RThreshold = 1 '设置 Rthreshold 为 1,接收缓冲区收到每一个字符都会使 MSComm 控件产生 OnComm 事件
End SubPrivate Sub MsComm1_OnComm()
Select Case MSComm1.CommEvent
Case comEvReceive
ReDim ReceiveFrame(MSComm1.InBufferCount)
'Print MSComm1.InBufferCount
If MSComm1.InBufferCount = 17 Then '在使用 Input 前,用户可以选择检查 InBufferCount 属性来确定缓冲区中是否已有需要数目的字符。
ReceiveFrame() = MSComm1.Input 'Input属性:返回并删除接收缓冲区中的数据流
If (ReceiveFrame(0) = Asc("@")) And (ReceiveFrame(3) = Asc("R")) And (ReceiveFrame(4) = Asc("D")) And (ReceiveFrame(15) = Asc("*")) And (ReceiveFrame(16) = &HD) Then
Call Display_Data
End If
Else
MSComm1.InBufferCount = 0 'InBufferCount 是指调制解调器已接收,并在接收缓冲区等待被取走的字符数.可以把InBufferCount属性设置为0来清除接收缓冲区
Print "清空缓存"
End If
End Select
End Sub
单片机和PC机的VB的mSCOMM进行串口通信。
其中单片机为主机,VB为从。单片机每隔200ms发送17字节的帧给VB,VB接收到17字节后,若符合协议,VB发送10字节的帧给单片机。请问:(1)采用oncomm好呢,还是采用轮询方式好呢?
(2)若采用oncomm事件,令MSComm1.RThreshold = 1,那么 VB先收8个字节,再收8个字节,最后收1个字节,发生了三次oncomm事件。微软技术支持说是因为数据传输需要时间的缘故,见链接http://faq.csdn.net/read/215129.html 。
但是我发现把波特率更改了变大几倍之后,仍然是上面的“8字节现象”。不知道什么原因?注:我也觉得微软技术支持说得是对的。因为我用虚拟串口在同一台电脑上面模拟发送和接收,就不会出现“8字节现象”。现在我的做法是在oncomm程序里面的comEvReceive事件后面 加个延时,针对17个字节延时20毫秒,那么就可以完整接收17个字节了不知道大家针对这个问题 有什么自己的看法??
Dim m_buffer() As Byte
If hm_comm.InBufferCount <= 17 Then Exit Sub
m_buffer = hm_comm.Input '接收数据
然后判断m_buffer的大小进行处理。
如果你的单片机200ms发送一次数据,单片机的处理时间可能可能比较紧张,最好采用轮询方式
改为
If hm_comm.InBufferCount < 17 Then Exit Sub
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Sub Form_Load()
MSComm1.CommPort = 1
MSComm1.InBufferSize = 1024
MSComm1.OutBufferSize = 512
MSComm1.Settings = "19200,n,8,1"
MSComm1.InputMode = comInputModeBinary '二进制接收
MSComm1.InputLen = 0 '设置 InputLen 为 0 时,使用 Input 将使 MSComm 控件读取接收缓冲区中全部的内容
MSComm1.PortOpen = True
MSComm1.RThreshold = 1 '设置 Rthreshold 为 1,接收缓冲区收到每一个字符都会使 MSComm 控件产生 OnComm 事件
End Sub
Private Sub MsComm1_OnComm()
Dim ReceiveFrame() As Byte
Select Case MSComm1.CommEvent
Case comEvReceive
MSComm1.RThreshold = 0
Sleep 20
ReceiveFrame() = MSComm1.Input 'Input属性:返回并删除接收缓冲区中的数据流
If (ReceiveFrame(0) = Asc("@")) And (ReceiveFrame(3) = Asc("R")) And (ReceiveFrame(4) = Asc("D")) And (ReceiveFrame(15) = Asc("*")) And (ReceiveFrame(16) = &HD) Then
Call Display_Data
End If
MSComm1.RThreshold = 1
End Select
End Sub
你在程序中加入MSComm1.RThreshold = 0和MSComm1.RThreshold = 1是为了避免中断的嵌套,
这种做法是看起来有理论价值,但实际上似乎很有必要。我会好好考虑的。
你的通信是被动的,你要掌握好单片机发给你的数据的频率,使用了Input读取了串口缓冲区后,其实InBufferCount也就等于0了。给你一个代码参考一下吧,这个绝对正确:)
http://download.csdn.net/source/1262066
DoEvents
Loop
ReceiveFrame() = MSComm1.Input但接收到 17 个字节再触发 OnComm 事件更直接。如果想快,而且你确定你的代码所用的系统,包括硬件都是一致的,也可以 MSComm1.RThreshold = 10,你进入事件后,恰好收到 17 个。
至于 MSComm1.InBufferCount = 0,如果你确定下位机发送的就是 17 个字节,你也照单全收了,就多此一举。因为它已经是 0 了。
我们一般使用实际的物理串口,为调试COM口通信,电脑往往用串口扩展卡增加物理串口.
单片机会断电,那找个好的UPS电源来解决断电问题.
同样电脑也会断电,LZ的情况是要在非正常工况下如何来保证通信的正常.
各位回复时看下LZ的上贴.
电脑一个字节一个字节的收,你的状况没必要使用中断。用语句来计数。搞硬件,尽量采用简单的方法去处理才会可靠。
除非你初始化MSComm1控件时设置
MSComm1.RThreshold = 17
否则你只能在你的机器条件下如你所说的情况.
串口通信的基础是依据通信协议和数据帧约定做好算法,并依据此算法设计接收代码.
在次建议LZ,在有缺陷的代码上出问题,不找代码问题而去钻牛角尖,并听不进他人的意见,在此斗嘴.
下面给出一段经调试通过的符合LZ要求的代码:
Option Explicit
Dim strRecHex As StringPrivate Sub Form_Load()
MSComm1.CommPort = 1
MSComm1.InBufferSize = 1024
MSComm1.OutBufferSize = 512
MSComm1.Settings = "19200,n,8,1"
MSComm1.InputMode = comInputModeBinary '二进制接收
MSComm1.InputLen = 0 '设置 InputLen 为 0 时,使用 Input 将使 MSComm 控件读取接收缓冲区中全部的内容
MSComm1.PortOpen = True
MSComm1.RThreshold = 1 '设置 Rthreshold 为 1,接收缓冲区收到每一个字符都会使 MSComm 控件产生 OnComm 事件
End SubPrivate Sub MSComm1_OnComm()
Dim ReceiveFrame() As Byte
Dim i As Integer
Select Case MSComm1.CommEvent
Case comEvReceive
ReDim ReceiveFrame(MSComm1.InBufferCount)
Debug.Print MSComm1.InBufferCount
ReceiveFrame() = MSComm1.Input 'Input属性:返回并删除接收缓冲区中的数据流
For i = 0 To UBound(ReceiveFrame)
strRecHex = strRecHex & Right("0" & Hex(ReceiveFrame(i)), 2)
Next
'If (ReceiveFrame(0) = Asc("@")) And (ReceiveFrame(3) = Asc("R")) And (ReceiveFrame(4) = Asc("D")) And (ReceiveFrame(15) = Asc("*")) And (ReceiveFrame(16) = &HD) Then
If Mid(strRecHex, 1, 2) = "40" And Mid(strRecHex, 7, 4) = "5244" And Mid(strRecHex, 31, 4) = "2A0D" Then
Text1 = strRecHex
'Call Display_Data
strRecHex = ""
ElseIf Len(strRecHex) > 34 Then
strRecHex = ""
End If
End Select
End Sub
建议LZ,在有缺陷的代码上出问题时,应找代码问题而不要去钻牛角尖,也不要听不进他人的意见,在此斗嘴.
从我的感觉来说,感觉就是你的没有延迟,单片机发送数据的速率太快了,你的数据还没有处理完,就又有数据来了,所以,我个人的构思是:
1、一个一个字符的接受,触发OnComm事件
2、当触发了OnComm事件,马上把RThreshold设置为:0,这样可以避免再收到字符事触发OnComm事件,等待一小段时间,这个是必须的,等待一个完整的数据帧产过来,但具体等待多久,这个就得看实际情况了。
3、等待完毕后,就可以读缓冲区了。当然你需要对你读回来的数据进行处理判断。处理完毕后,将:RThreshold设置为:1,即可再次接收并触发事件了。关键点在:单片机上传数据的时间间隔和通信等待时间的匹配。以上是我的拙见。。呵呵
MSComm1.InputMode = comInputModeBinary '采用二进制接收
MSComm1.InBufferCount = 0 '清空接受缓冲区
MSComm1.OutBufferCount = 0 '清空传输缓冲区
MSComm1.InBufferSize = 100 '接收缓冲区大小
MSComm1.OutBufferSize = 100 '发送缓冲区大小
MSComm1.RThreshold = 1 '设置引发OnComm事件的字节长度
MSComm1.InputLen = 1 '设置Input从接收缓冲读取全部数据
MSComm1.PortOpen = True
Private Sub MSComm1_OnComm()
Sleep (500)
Select Case MSComm1.CommEvent
Case comEvReceive
Do While MSComm1.InBufferCount <> 0
indata = MSComm1.Input
If jieshouok Then
arrt(p) = indata(0)
p = p + 1
Else
If jieshouok = False And indata(0) <> 35 Then
Else
jieshouok = True
arrt(p) = indata(0)
p = p + 1
End If
End If
If indata(0) = 13 And jieshouok Then
'数据处理
p=0
end if
Loop
End Select
end sub
Private Sub MsComm1_OnComm()
Select Case MSComm1.CommEvent
Case comEvReceive
ReDim ReceiveFrame(MSComm1.InBufferCount)
Print "MSComm1.InBufferCount" & MSComm1.InBufferCount
If MSComm1.InBufferCount = 17 Then
MSComm1.InBufferCount = 0
End If
End Select
End Sub单片机每发送17个字符,你猜上面这段代码打印出什么了???太深奥了!!!
MSComm1.InBufferCount8
MSComm1.InBufferCount8
MSComm1.InBufferCount16
MSComm1.InBufferCount16
MSComm1.InBufferCount17
Private Sub MsComm1_OnComm()
Select Case MSComm1.CommEvent
Case comEvReceive
MSComm1.RThreshold = 0
Sleep (30)
ReDim ReceiveFrame(MSComm1.InBufferCount)
Print "MSComm1.InBufferCount" & MSComm1.InBufferCount End Select
End Sub