MSComm1.CommPort = 1
    MSComm1.Settings = "9600,N,8,1"
    MSComm1.RThreshold = 17
    MSComm1.InputLen = 0
    MSComm1.SThreshold = 1
    MSComm1.InputMode = comInputModeBinary
    If MSComm1.PortOpen = False Then MSComm1.PortOpen = True   
   如上代码,我写在Form_Load()中。MSComm1.RThreshold被我写死了。与一个设备或者同类型设备通信时没有问题。
  但是我现在要添加其他的设备,还包括与单片机通信,这样,返回的数据长度就有可能不一样(都使用modbus协议)。
  请问,当与多个设备通信,返回的数据长度不同,在MSComm1_OnComm()中如何判断接收呢?

解决方案 »

  1.   

    那就设置:
    MSComm1.RThreshold = 1
    在OnComm事件的接收代码中按各自数据帧的约定进行判断,如字节长度,帧头帧尾判断.
      

  2.   

    zdingyun说得对,
    不能的长度,需要你自己定义一个协议
      

  3.   


    您的意思是不是先判断第一个地址号,然后再读操作号,再根据第三个BYTE的数据长度的值,读取数据长度+2的BYTE的数据,然后将这些数据看成一帧,然后再进行处理?如果多台外设同时发送数据给上位机程序,怎么做才能不让这些数据相互参杂,从而保证数据的正确性呢。软件延时是否能达到这个作用呢?
      

  4.   

    应该是你先发送一个命令,再接收反馈数据吧?
    在发送命令前,根据预期的反馈数据长度动态设置 RThreshold。
      

  5.   

    http://download.csdn.net/source/1262066给你一个串口通信的源代码,对你肯定有用
      

  6.   

    1.我喜欢一个字符一个字符的接受
    2.如果需要xon、xoff,采用单字符接受直接用语句去判断11 和 13.
    不要采用mscomm自带的西欧你、xoff功能。停的慢容易产生override.
    3.一般的数据采集,没有必要用中断
    4.尽量采用简单的方法去解决复杂的问题
    5.自控---简单就意味这可靠
    6.如果采用字符长度进行接受,如果采集对象中途关机。关机的干扰也会采进来。
      

  7.   

    请问一下,在一个机房中(60,70平米左右),连接在485线上的设备,从发送查询帧到接受到数据,大概需要多少的延迟?如果延迟不大的话,用TIMER一次发送一个查询帧得了,留给充分的时间接收数据
      

  8.   

    LZ:你的现场通信连接线长度不会超过200M,导线本身的延迟可忽略不计.
    这里的延迟主要考虑3方面:
    1)轮询数据帧字节数和波特率,如果波特率是9600,每秒理论可传输960字节,也就是说每字节至少需要1MS,如果发送10字节数据帧,则为10MS
    2)发送和接收的串口将位电平信号硬件处理的时间,一般远在MS数量级下.
    3)下位机接收和返回数据的时间.
    采用TIMER计时器设置100-200MS周期是较为恰当的.
      

  9.   


    波特率是4800,查询是8字节,返回的最多为17字节,这样的话TIMER设置100-200MS应该也可以。再将MSComm1.RThreshold = 1 一次接收完。理论上应该没问题了。下次需要到机房试试。
      

  10.   

    协议固定,数据长度不固定 !我现在想到的方法是 inputlen = 1
     MSComm1.RThreshold = 1
      

  11.   


    这个标志字节是什么呢?是地址码吗? 还是帧的开始和结束标志?OnComm()接收到的数据中没看到开始和结束标志啊
      

  12.   

    gddennis 我的回复你没有看到么??我问过你:你说的 帧长度不一样 指的是什么??? 是说情况一:单片机某个单片机A ,有时候发送7个字节的帧,有时候发送5个字节的帧,有时候发送9个字节的帧,有时候....................。还是说情况2:单片机A只发9个字节的帧, 单片机B只发送8个字节的帧 ??
    我告诉你吧  可能是  大概是:假设是情况2:那要简单点,首先要说的是 要用oncomm事件,那么会出现接收超过8字节会多次进入oncomm程序的情况,要想进入一次oncomm就全部接受帧的所有字节,就要加延时,在Case comEvReceive后面 加延时,延时多长时间呢,比如说一个帧20个字节,那么你就延时30毫秒,应该没有问题。如果有问题,就加大延时时间。然后再判断接收的帧的长度IF (接收到单片机A的9个帧) then
         ReceiveFrame() = MSComm1.Input '接收的帧转移到数组里面
          判断接收的帧是否符合你的协议
    ELSE IF (接收到单片机B的8个帧) then
        ReceiveFrame() = MSComm1.Input '接收的帧转移到数组里面
          判断接收的帧是否符合你的协议
    ELSE 
         MSComm1.InBufferCount = 0'清空缓存好情况2到此结束。现在说情况1
    情况1就麻烦了,我也没有试过
         还是不说了
    ============================================9楼说的很好,一个字节一个字节的接收 对于处理不定长的情况很好 
    我现在想到的方法是 inputlen = 1 
    MSComm1.RThreshold = 1  不知道能不能实现一个字节一个字节的接收。
    那就需要定时器,如果设定时间内没有接收到数据 就认为本帧传输完毕。以后有时间 要试一试==========================================
    一般来说 发送数据采用轮询  接收数据采用中断
      

  13.   

    动态设置 RThreshold的值就好了
      

  14.   

    给你个例子学习:'定义一个数据缓冲池,这里用Collection对象作缓冲池,你也可以用数组或其他东西
    Dim coldata As CollectionPrivate Sub Form_Load()
        '初始化数据缓冲池
        Set coldata = New Collection    '初始化并打开串口
        MSComm1.CommPort = 1
        MSComm1.Settings = "9600, n, 8, 1"
        MSComm1.RThreshold = 1     '设置为每收到一个字节数据触发一次Oncomm事件
        MSComm1.InputMode = comInputModeBinary
        MSComm1.PortOpen = True
    End SubPrivate Sub MSComm1_OnComm()
    Dim yy As Long
    Select Case MSComm1.CommEvent
    Case comEvReceive
        Dim xx() As Byte
        xx = MSComm1.Input
        For yy = 0 To UBound(xx) - 1    '把串口接收到的所有数据都先保存到数据缓冲池暂时不去处理,因为无法保证数据已经接收完整
            coldata.Add xx(yy)
        Next yy
    End Select
    End Sub'用Timer控件循环对接收到的数据进行处理,如果你会用多线程的话可以另开一个线程来单独处理
    Private Sub Timer1_Timer()
        Dim xx As Long
        For xx = 1 To coldata.Count     '遍历所有串口收到的数据
            '代码略,按照通讯协议对串口收到的数据进行分析和处理
            '处理完成及时把已处理的数据从缓冲池中移除
        Next xx
    End Sub