为什么每次都只能接收8个字节,超过8个,他就先收8个,剩下的在下一次在接收比如说12个字节,就先收8个,再收四个,出发了两次oncomm事件
再比如说17个字节,就先收8个,再收8个,再收一个.大家分析一下 这与什么有关?另外不同的波特率下 比如说9600 和 52000下,仍然会出现只收8字节的情况。为什么?

解决方案 »

  1.   

    回复2楼 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 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
      

  2.   

    具体情况 我再次描述如下:
    单片机和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个字节了不知道大家针对这个问题  有什么自己的看法?? 
      

  3.   

    http://www.gkong.com/gkong_bbs/dispbbs.asp?ID=36135
      

  4.   

    不要固定设置接收8个字符,设置一个非固定长度的数组作为接收缓冲区:
        Dim m_buffer() As Byte
        If hm_comm.InBufferCount <= 17 Then Exit Sub
        m_buffer = hm_comm.Input  '接收数据
    然后判断m_buffer的大小进行处理。
    如果你的单片机200ms发送一次数据,单片机的处理时间可能可能比较紧张,最好采用轮询方式
      

  5.   

    If hm_comm.InBufferCount <= 17 Then Exit Sub 
    改为
    If hm_comm.InBufferCount < 17 Then Exit Sub 
      

  6.   

    Option Explicit
    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
      

  7.   

    Veron_04 ,8楼!!你的这个程序是有问题的!!问题很大!!!你把我的 原先程序中的MSComm1.InBufferCount = 0 '删除了  ,这是不对的。接收到不完整的帧,那么接收到下一帧 也不会符合 “If (ReceiveFrame(0) = Asc("@")) And (ReceiveFrame(3) = Asc("R")) And (ReceiveFrame ”这个协议的。
    你在程序中加入MSComm1.RThreshold = 0和MSComm1.RThreshold = 1是为了避免中断的嵌套,
    这种做法是看起来有理论价值,但实际上似乎很有必要。我会好好考虑的。
      

  8.   

    看看你的单片机发送端是否有问题,发送数据的时候是不是两个数据之间间隔时间太长,如果太长就会触发两次ONCOMM事件。
      

  9.   


    你的通信是被动的,你要掌握好单片机发给你的数据的频率,使用了Input读取了串口缓冲区后,其实InBufferCount也就等于0了。给你一个代码参考一下吧,这个绝对正确:)
    http://download.csdn.net/source/1262066
      

  10.   

    MSComm1.RThreshold = 17既然确定下位机发送 17 个字节,为什么不一次完整接收。你收到 8 个字节,是因为第一个字节触发事件,到你完成接收,缓冲区恰好收到 8 个。当然你也可以采取延时等待的方法, Do Until MSComm1.InBufferCount >= 17
        DoEvents
    Loop 
    ReceiveFrame() = MSComm1.Input但接收到 17 个字节再触发 OnComm 事件更直接。如果想快,而且你确定你的代码所用的系统,包括硬件都是一致的,也可以 MSComm1.RThreshold = 10,你进入事件后,恰好收到 17 个。
      

  11.   


    至于 MSComm1.InBufferCount = 0,如果你确定下位机发送的就是 17 个字节,你也照单全收了,就多此一举。因为它已经是 0 了。
      

  12.   

    各位有所不知,LZ的串口是虚拟的,它涉及建立虚拟串口的驱动.
    我们一般使用实际的物理串口,为调试COM口通信,电脑往往用串口扩展卡增加物理串口.
      

  13.   

    楼上各位 请搞清 !@!正如12楼所说 VB是被动接受的  所以说 单片机是上位机   VB是下位机 。不要以为电脑总是下位机。
      

  14.   

    那就解决干扰问题.
    单片机会断电,那找个好的UPS电源来解决断电问题.
    同样电脑也会断电,LZ的情况是要在非正常工况下如何来保证通信的正常.
      

  15.   

    [url=http://www.vbgood.com/viewthread.php?tid=86156&extra=&page=1url]
    各位回复时看下LZ的上贴.
      

  16.   

    MSComm1.InputLen = 1
    电脑一个字节一个字节的收,你的状况没必要使用中断。用语句来计数。搞硬件,尽量采用简单的方法去处理才会可靠。
      

  17.   

    仔细看了LZ在3楼的代码,靠你的代码是无法完成正确接收来自下(上)位机的17字节数据的.
    除非你初始化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
      

  18.   

    更正LS回复的一句话,应该为:
    建议LZ,在有缺陷的代码上出问题时,应找代码问题而不要去钻牛角尖,也不要听不进他人的意见,在此斗嘴.
      

  19.   


    从我的感觉来说,感觉就是你的没有延迟,单片机发送数据的速率太快了,你的数据还没有处理完,就又有数据来了,所以,我个人的构思是:
    1、一个一个字符的接受,触发OnComm事件
    2、当触发了OnComm事件,马上把RThreshold设置为:0,这样可以避免再收到字符事触发OnComm事件,等待一小段时间,这个是必须的,等待一个完整的数据帧产过来,但具体等待多久,这个就得看实际情况了。
    3、等待完毕后,就可以读缓冲区了。当然你需要对你读回来的数据进行处理判断。处理完毕后,将:RThreshold设置为:1,即可再次接收并触发事件了。关键点在:单片机上传数据的时间间隔和通信等待时间的匹配。以上是我的拙见。。呵呵
      

  20.   

    我要接收有头和尾的数据,头是35 尾是“H0D”,为什么我把sleep去了就不可以了 ,且加sleep 后,有些数据有时候可以受到,有时候不可以,大家帮忙呀
        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
      

  21.   

    应该是延迟等待的问题,就是那个Sleep的问题
      

  22.   

    楼上, 这个MSCOMM玄机太多了
    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个字符,你猜上面这段代码打印出什么了???太深奥了!!!
      

  23.   

    竟然打印出
    MSComm1.InBufferCount8
    MSComm1.InBufferCount8
    MSComm1.InBufferCount16
    MSComm1.InBufferCount16
    MSComm1.InBufferCount17
      

  24.   

    还有 看看这段代码打印出什么来了???
    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