当上位机(电脑软件)与下位机(单片机)通讯时,上位机总不能将下位机发送的数据(十六进制)全部接受,每次通讯数据量在10万以下,vb的 mscoom控件的InBufferSize属性的最大值为32767,大于此值可能会溢出,但奇怪的是当小于此值时也会丢,请问丢哪里了,期待赐教!!!
以下是电脑软件程序的部分代码:Private Sub Comm_OnComm()
   Dim IntR  as integer
   Static Resv As Variant '接收数据
   Static DataC As Long '串口数据字节数
   Static CTestData() As Byte'用于存放接受的字符
   Static FactCount As Long '累计实际接收的数据
   static TestFlag  Boolean'实验结束标志
   TestFlag = false
   Comm.RThreshold = 0 
   FactCount = 0
   DataC = Comm.InBufferCount: Resv = Comm.Input  
   ReDim CTestData(100000)
   For IntR = 0 To DataC - 1
          CTestData(IntR) = Resv(IntR)
          FactCount = FactCount + 1
   Next IntR
   
   Static CurrTime As Long '等待时间
   CurrTime = GetTickCount
   '一直接受数据,直到接受完成为止 
   do                        
           If Comm.InBufferCount >= 1000 Or Abs(GetTickCount - CurrTime) >= 100 Then
                CurrTime = GetTickCount 
                DataC = Comm.InBufferCount: Resv = Comm.Input
                For IntR = 0 To DataC - 1
                     CTestData(FactCount) = Resv(IntR)
                     FactCount = FactCount + 1                    
                     DoEvents
                     Next IntR
                End If
                DoEvents
            Endif
            Do While  Comm.InBufferCount = 0 '无数据则测试结束
              debug.print "实验结束"
              TestFlag = ture
              Exit Do
           Loop
           if TestFlag  then Exit do
        
Exit Sub

解决方案 »

  1.   

    嘿嘿 的确是发重了
    对于通信质量要求高或者数据量偏大的应用,不建议用 Comm_OnComm()
    建议:
    用双Timer实现。一个管收数据,一个管发数据。建立自己的缓冲区,不间断的接收所有的数据,知道发送端发送完毕。
      

  2.   

    留一个邮箱,给你发我的基于Comm_OnComm()
    的测试源码。
    双Timer的涉及公司版权,恕不能相赠
      

  3.   

    试一试这个,看看有没有丢失信息的情况,如果没有,依照这个代码写自己的程序即可。
    http://download.csdn.net/source/1262066
      

  4.   

    我的信箱是[email protected]
    双Timer会好些吗?我尽量试试,谢谢
      

  5.   

    具体点?那就给你看一段简单的单片机串口通讯时的处理过程吧void COM_Event () interrupt 4 
    {   
    unsigned char dat = 0;
    unsigned char NXorData = 0;
    if(RI == 1){
    //接收数据 SBUF 为单片机的接收发送缓冲寄存器
    dat = SBUF;
    RI = 0;
    // 这里分析你收到的信息,同事可做出反应
    switch(CApproach){
    case 0: // 数据包头
    if(dat==0xB2){
     CApproach = 1;
    }
    break;
    case 1: // 机号
    if(dat==MyNumber){
     CApproach = 2;
    }else{
     CApproach = 0;
    }
    break;
    case 2: // 命令
    if(dat>=1&&dat<=7){
     CCommand = dat;
     CApproach = 3;
    }else{
     CApproach = 0;
    }
    break;
    case 3: // 命令参数
    switch(CApproach){
    case 1: // 探测设备命令,无参数
    CXorCount = dat;
    CApproach = 255;
    break;
    case 2: // 开启通讯监视,无参数
    CXorCount = dat;
    CApproach = 255;
    break;
    case 3: // 关闭通讯监视,无参数
    CXorCount = dat;
    CApproach = 255;
    break;
    default:
    CApproach = 0;
    break;
    }
    break;
    case 255: // 接收包尾
    if(dat==0xB3){
    switch(CCommand){
    case 1: // 探测设备命令需要进行异或校验
    NXorData = 0xB2;
    NXorData = NXorData^MyNumber;
    NXorData = NXorData ^ CCommand;
    if(NXorData==CXorCount){
    SendBufToPort("LTC-20100409A",13);
    }else{
    CApproach = 0;
    }
    break;
    case 2: // 开启通讯监视命令需要进行异或校验
    NXorData = 0xB2;
    NXorData = NXorData^MyNumber;
    NXorData = NXorData ^ CCommand;
    if(NXorData==CXorCount){
    AddMinute = 0;
    AddSecond = 0;
    AddMillisecond = 0;
    AddMicrosecond = 0;
    Approach = 1; SendBufToPort("Open stakeout.",14);
    }else{
    CApproach = 0;
    }
    break;
    case 3: // 关闭通讯监视命令需要进行异或校验
    NXorData = 0xB2;
    NXorData = NXorData^MyNumber;
    NXorData = NXorData ^ CCommand;
    if(NXorData==CXorCount){
    Approach = 0;
    AddMinute = 0;
    AddSecond = 0;
    AddMillisecond = 0;
    AddMicrosecond = 0;
    SendBufToPort("Close stakeout.",14);
    }else{
    CApproach = 0;
    }
    break;
    default:
    CApproach = 0;
    break;
    }
    }else{
    CApproach = 0;
    }
    break;
    }
    }else{
    TI = 0;
    }}
      

  6.   

    再给你看一段PC处理串口通讯的过程,VC代码,该程序的完整过程可以在我的资源里找到//============================================================================================================
    //                                          关 键 部 分 代 码
    //============================================================================================================
    void CDemoDlg::OnOK() 
    {
    BOOL OpenState;
    DWORD NowTickCount;
    DWORD SaveTickCount;
    char * SendText;
    // 这里很关键,因为 Send 是通过 GlobalSize 来取得指针大小的,所以需要这样分配控件大小
    SendText = (char *)GlobalAlloc(GMEM_ZEROINIT, 4); ReturnValue = 0; //设置默认返回为失败
    Approach = 0; //设置接收步骤参数 COMM1.EventRead = OnComm; //设置处理函数
    COMM1.ObjClassAddress = (DWORD)this; //设置类地址,确保在OnComm过程中可以调用本类中的一些过程或变量
    COMM1.Port = 1; //设置端口
    COMM1.BaudRate = CBR_57600; //设置波特率
    COMM1.ByteSize = 8; //设置数据位
    COMM1.Parity = 0; //设置校检
    COMM1.StopBits = 1; //设置停止位
    OpenState = COMM1.Open(); //打开串口,这时候便开始了 OnComm 事件的侦听
    if(OpenState==TRUE){
    sprintf(SendText,"AT\r\n"); //设置要发送的文本内容(当然也可以发送字节流)
    COMM1.Send((BYTE*)SendText); //发送文本到串口 //=========== 以下做超时处理 ===========
    //超时处理总共有两个全局变量控制
    //ExecOver 和 ReturnValue
    ExecOver = FALSE;
    SaveTickCount = GetTickCount();
    while(ExecOver==FALSE){
    Sleep(5);
    NowTickCount = GetTickCount();
    if(NowTickCount-SaveTickCount>=1000){
    //超过1秒钟还未正常返回结果就自动退出循环
    ReturnValue = 0;
    ExecOver=TRUE;
    }
    }
    COMM1.Close();
    }
    if(ReturnValue==1){
    MessageBox("串口1接入的设备支持AT命令。","执行结果",64);
    }else{
    MessageBox("没有检测到串口1接入支持AT命令的设备。","执行结果",64);
    }
    }void CDemoDlg::OnComm(DWORD pClassAddress, BYTE *ReadBuffers, DWORD ReadCount)
    {
    // pClassAddress 类地址,由用户自行设置 ObjClassAddress 而来
    // ReadBuffers 从串口缓冲区读到的数据指针
    // ReadCount 从川口缓冲区读到的数据大小
    //=============== 还原类的方法,以下是范例 ===============
    //CDemoDlg * DlgObj;
    //DlgObj = (CDemoDlg *)pClassAddress;
    //DlgObj->COMM1.Send((BYTE *)"AAA");
    //========================================================
    // 下面做个简单的信息识别处理 // 还原类事例对象,因为要用到类中的变量
    CDemoDlg * DlgObj;
    DlgObj = (CDemoDlg *)pClassAddress; DWORD i;
    if(ReadCount>0){
    for(i=0;i<ReadCount;i++){
    switch(DlgObj->Approach){
    case 0:
    if((BYTE)ReadBuffers[i]==0x0D||(BYTE)ReadBuffers[i]==0x0A){ //有可能先发换行符号
    DlgObj->Approach = 1;
    }else if((BYTE)ReadBuffers[i]==0x4F||(BYTE)ReadBuffers[i]==0x62){ //有可能直接发 OK 信息
    DlgObj->Approach = 2;
    }
    break;
    case 1:
    if((BYTE)ReadBuffers[i]==0x4F||(BYTE)ReadBuffers[i]==0x6F){
    DlgObj->Approach = 2;
    }else if((BYTE)ReadBuffers[i]==0x0D||(BYTE)ReadBuffers[i]==0x0A){
    DlgObj->Approach = 1;
    }else{
    DlgObj->Approach = 0;
    }
    break;
    case 2:
    if((BYTE)ReadBuffers[i]==0x4B||(BYTE)ReadBuffers[i]==0x6B){
    DlgObj->Approach = 3;
    }else{
    DlgObj->Approach = 0;
    }
    break;
    case 3:
    if((BYTE)ReadBuffers[i]==0x0D||(BYTE)ReadBuffers[i]==0x0A){
    DlgObj->ReturnValue = 1;
    DlgObj->ExecOver = TRUE;
    }
    DlgObj->Approach = 0;
    break;
    }

    }
    }
    }
      

  7.   

    找了一下,这里还有一段VB的过程Private Sub MSComm1_OnComm()
       Dim TempBytes() As Byte, TempBytesCount As Long
       Dim X As Long, nowxor As Long, RetEventStr As String
       On Error Resume Next
       '通过 CommEvent 属性判断是发生什么事件
       If MSComm1.CommEvent = comEvReceive Then
          JJ = JJ + 1
          ReadBytes = MSComm1.Input      ReadCount = UBound(ReadBytes)
          'ReDim ReadBytes(ReadCount)
          'CopyMemory ReadBytes(0), TempBytes(0), ReadCount + 1      For X = 0 To ReadCount
             Select Case Approach
             Case 201: '判断是否是结束符号
                      If ReadBytes(X) = &HB3 Then
                         '开始运算数据是否正确
                         Select Case NowCommand
                         Case &HFF:  '机器型号命令
                                     nowxor = &HB2
                                     nowxor = nowxor Xor m_ENumber
                                     nowxor = nowxor Xor NowCommand
                                     nowxor = nowxor Xor Parameter1
                                     For Y = 0 To Parameter1 - 1
                                        nowxor = nowxor Xor ReadByteArray(Y)
                                     Next Y
                                     If xorvalue = nowxor Then
                                        ReturnString = StrConv(ReadByteArray, vbUnicode)
                                     Else
                                        ReturnString = ""
                                     End If
                                     Timer1.Enabled = False
                                     WaitTime = 0
                         End Select
                      End If
                      Approach = 0               '完成处理,将步骤设置为初始阶段
             
             Case 200: '接收异或校检码准备对数据的完整性和正确性进行核对
                      xorvalue = ReadBytes(X)       '将异或校检码存入公共变量中,等就收到包尾信息后再进行处理
                      Approach = 201                '因为异或校检码属于不定值,所以无法判断是否正确,直接进入下一步等下一步进行判断
             
             
             Case 8:  '机器型号返回信息
                      ReadByteArray(ReadByteCount) = ReadBytes(X)
                      ReadByteCount = ReadByteCount + 1
                      If ReadByteCount >= Parameter1 Then
                         Approach = 200          '去接收异或校检码准备和对数据的正确性
                      End If         Case 6:  '机器型号返回信息
                      ReturnString = ""
                      Parameter1 = ReadBytes(X)     '接收返回字符串数量
                      ReadByteCount = 0
                      ReDim ReadByteArray(Parameter1 - 1)
                      Approach = 8                  '无法验证数据的正确性,将接收步骤调整为下一步
                      
             Case 2:  '识别命令,若数据不在可识别的命令数值范围内,作弃包处理
                      Select Case ReadBytes(X)
                      Case &HFF:  '机器型号命令
                                  NowCommand = &HFF
                                  Approach = 6      '数据符合要求,将接收步骤调整为下一步
                      Case Else
                         Approach = 0   '数据不符合接收步骤和相关的规定,放弃该数据(弃包处理)
                      End Select
                      
             Case 1:  '识别机号,判断数据是否应该发送到本机的,若不是就不必继续处理了
                      If m_ENumber = 0 Then
                         '初始化时没有机号标准,所以直接读取信息成为机号
                         m_ENumber = ReadBytes(X)
                         Approach = 2   '数据符合要求,将接收步骤调整为下一步
                      Else
                         If ReadBytes(X) = m_ENumber Then
                            Approach = 2   '数据符合要求,将接收步骤调整为下一步
                         Else
                            Approach = 0   '数据不符合接收步骤和相关的规定,放弃该数据(弃包处理)
                         End If
                      End If
                      
             Case 0:  '根据步骤,等待包头的出现,若不是包头数据就继续等待包头
                      If ReadBytes(X) = &HB2 Then
                         Approach = 1   '数据符合要求,将接收步骤调整为下一步
                      End If
                      
             End Select
          Next X
       End If
       Exit Sub
    错误处理:
       Approach = 0
    End Sub
      

  8.   

    VB的多线程要编译P代码才好用,而且调试最好是编译EXE后运行看看,直接调试弄不好会有问题的。
    VB做多线程本来就很多要注意的地方,个人感觉VC在这方面要简单和稳定很多。
      

  9.   

    其实你可以参考一下我资源里的一个串口通讯的VC代码,用起来也很简单的。
    http://download.csdn.net/source/2690778