往串口写控制命令,被控制的硬件都做动作了;而我这儿屏幕上显示的还是上一个控制命令的回应,随后过了一会儿才出现这次命令的回应,而且随后的测试的回应变得越来越慢(而硬件动作也没有延迟),可能是哪方面的原因?!
程序开始运行的时候没那么慢,做了一些测试以后才出现上述现象。

解决方案 »

  1.   

    用Windows自带的超级终端看看是否是硬件返回信息的延迟?
    建议在上一个命令未返回前不要发下一个测试命令!
      

  2.   

    以下是我的通信程序,有问题吗?void CMainFrame::OnTimer(UINT nIDEvent) 
    {  
    DWORD readnum=Communication();
    if(readnum==0)            
    {
        iLinkCount++;      
    if(iLinkCount==50)
    {
      KillTimer(timeID);
      UINT ooo=this->MessageBox("RS232 ERROR","´íÎó",MB_RETRYCANCEL|MB_ICONSTOP);
      if(ooo==IDRETRY)
      timeID=SetTimer(3,100,NULL);
     
     iLinkCount=0;
     
    }

    return;
    }    iLinkCount=0;
    byte mCheck=0;
    for(int i=0;i<=m_Count;i++)
    {
     mCheck+=inbuff[i];
    }
    if(mCheck!=0xFF)                 
    return;
    m_Count=inbuff[0];
    UpdateWindow();
    switch(m_Count)
    {
    case 0x01: LinkResult();break;    
    case 0x2e: LPUCheck();break;      
    case 0x3e: LPUCheck();break;      
    case 0xE1: wait();break;          
    case 0x13: {SelfCheck();break;
             case 0x46: MFDWrongCheck();break; 
    case 0x52: RoundKey();break;     
    case 0x61: VideoFold();break;     
    case 0x71: MFDFixCheck();break;   
    case 0xf2: Wrong();break;         
    default:   return;
    }
        
    CFrameWnd::OnTimer(nIDEvent);
    }
    int CMainFrame::Communication()
    {
    for(int i=0;i<15;i++)
    inbuff[i]=0;             DWORD nBytesRead,nBytesWrite;
    p_outbuff=&outbuff[0];
    if(!WriteFile(handle,p_outbuff,3,&nBytesWrite,NULL))
    {
    nBytesWrite=0;
    return 0;
    }
    if(nBytesWrite!=3)
     return 0;

    p_inbuff=&inbuff[0];
    if(!ReadFile(handle,p_inbuff,1,&nBytesRead,NULL))
    {
    nBytesRead=0;
    return 0;
    }

    if(nBytesRead==0)
    return 0;
    m_Count=inbuff[0];
    m_Count&=0x0F;
    p_inbuff++;
    if(!m_Count)
    return true; if(!ReadFile(handle,p_inbuff,m_Count,&nBytesRead,NULL))
    {
    nBytesRead=0;
    return 0;
    }
    if(nBytesRead!=m_Count)
    {
       return 0;
    } //PurgeComm(handle,PURGE_RXCLEAR);
    return true;
    }
      

  3.   

    通讯命令是在一些快捷按钮中添加的,很简单,即:
    outbuffer[0]=A0;
    outbuffer[0]=00;
    outbuffer[0]=E4;
    其他命令也是类似结构!
      

  4.   

    还有一个奇怪的问题,我在一些按钮处理程序中加了个对话框;即:
    CXinxiDlg xinxi;
    if(xinxin.DoModal==1)
    {
     outbuffer[0]=A0;
     outbuffer[0]=00;
     outbuffer[0]=E4;}
    对话框用于输入一些测试信息,以前没加的时候不会变慢;加了以后就出现上述回送显示延迟的现象。
    还有,我曾加过一个用于退出的按钮,即往串口发通信联络命令;然后在每进行完一项测试项目后我按这个按钮,然后再进入其他测试项目,发现速度也不会出现明显变慢(至少察觉不出来);我就奇怪了,一样的命令格式,我先进入通信状态再进入其他测试项目跟直接进入有什么区别?!不都是要覆盖outbuffer[]吗?
      

  5.   

    请检查WriteFile和ReadFile的返回值,可能是有问题。
      

  6.   

    我做过很多通信类的程序,看看我现在写的代码,对你有帮助的/*
    * 函数介绍:规约处理函数
    * 输入参数:无
    * 输出参数:无
    * 返回值  :TRUE-〉成功,FALSE-〉失败
    */BOOL CModbusEPM420::ProtocolProc()
    {
    unsigned char TXBuf[BUFSZ];
    const int DELAYTIME = 100;
    unsigned short nCrc;
    unsigned int i,nDataCount; TXBuf[0] = m_nSlaveID;
    TXBuf[1] = 0x03;
    TXBuf[2] = 0x00;
    TXBuf[3] = 0x00;
    TXBuf[4] = 0x00;
    TXBuf[5] = 0x10;

    nCrc = MB_Crc(TXBuf,6);
    TXBuf[6] = nCrc & 0xff;
    TXBuf[7] = (nCrc >> 8) & 0xff; m_pTermSrvPort->TX (TXBuf,8);
    Sleep(DELAYTIME);
    m_pTermSrvPort->RX (); nDataCount = TXBuf[4]*256+TXBuf[5];
    if (m_pTermSrvPort->m_nRXCount == (int)(nDataCount*2+5) )
    {
    nCrc = MB_Crc(m_pTermSrvPort->m_szRXBuf,nDataCount*2+3);
    if (m_pTermSrvPort->m_szRXBuf[nDataCount*2+3] == (nCrc & 0xff) &&
    m_pTermSrvPort->m_szRXBuf[nDataCount*2+4] == ((nCrc >> 8) & 0xff) )
    {
    //TRACE("update EPM420 m_fAI[0] - m_fAI[15]\n");
    for (i=0;i<nDataCount;i++) //0-15
    {
    ASSERT (i < RTU_AI_MAX && i < m_nAICount);
    m_fAI[i] = (float)(m_pTermSrvPort->m_szRXBuf[3+2*i]*256 + m_pTermSrvPort->m_szRXBuf[4+2*i]);
    }
    }
    else
    {
    TRACE("EPM420 Crc error\n");
    }
    } TXBuf[0] = m_nSlaveID;
    TXBuf[1] = 0x03;
    TXBuf[2] = 0x00;
    TXBuf[3] = 0x40;
    TXBuf[4] = 0x00;
    TXBuf[5] = 0x08;

    nCrc = MB_Crc(TXBuf,6);
    TXBuf[6] = nCrc & 0xff;
    TXBuf[7] = (nCrc >> 8) & 0xff; m_pTermSrvPort->TX (TXBuf,8);
    Sleep(DELAYTIME);
    m_pTermSrvPort->RX (); nDataCount = TXBuf[4]*256+TXBuf[5];
    if (m_pTermSrvPort->m_nRXCount == (int)(nDataCount*2+5) )
    {
    nCrc = MB_Crc(m_pTermSrvPort->m_szRXBuf,nDataCount*2+3);
    if (m_pTermSrvPort->m_szRXBuf[nDataCount*2+3] == (nCrc & 0xff) &&
    m_pTermSrvPort->m_szRXBuf[nDataCount*2+4] == ((nCrc >> 8) & 0xff) )
    {
    //TRACE("update EPM420 m_fAI[16] - m_fAI[19]\n");
    for (i=0;i<nDataCount/2;i++) //16-19
    {
    ASSERT (i+16 < RTU_AI_MAX && i+16 < m_nAICount);
    m_fAI[i+16] = (float)(
    m_pTermSrvPort->m_szRXBuf[3+4*i]*256 + 
    m_pTermSrvPort->m_szRXBuf[4+4*i] +
    m_pTermSrvPort->m_szRXBuf[5+4*i]*256*256*256 +
    m_pTermSrvPort->m_szRXBuf[5+4*i]*256*256
    );
    }
    }
    else
    {
    TRACE("EPM420 Crc error\n");
    }
    }

    TXBuf[0] = m_nSlaveID;
    TXBuf[1] = 0x03;
    TXBuf[2] = 0x02;
    TXBuf[3] = 0x80;
    TXBuf[4] = 0x00;
    TXBuf[5] = 0x11;

    nCrc = MB_Crc(TXBuf,6);
    TXBuf[6] = nCrc & 0xff;
    TXBuf[7] = (nCrc >> 8) & 0xff; m_pTermSrvPort->TX (TXBuf,8);
    Sleep(DELAYTIME);
    m_pTermSrvPort->RX ();

    nDataCount = TXBuf[4]*256+TXBuf[5];
    if (m_pTermSrvPort->m_nRXCount == (int)(nDataCount*2+5) )
    {
    nCrc = MB_Crc(m_pTermSrvPort->m_szRXBuf,nDataCount*2+3);
    if (m_pTermSrvPort->m_szRXBuf[nDataCount*2+3] == (nCrc & 0xff) &&
    m_pTermSrvPort->m_szRXBuf[nDataCount*2+4] == ((nCrc >> 8) & 0xff) )
    {
    //TRACE("EPM420 update m_fAI[20] - m_fAI[36]\n");
    for (i=0;i<nDataCount;i++) //20-36
    {
    ASSERT (i+20 < RTU_AI_MAX && i+20 < m_nAICount);
    m_fAI[i+20] = (float)(m_pTermSrvPort->m_szRXBuf[3+2*i]*256 + m_pTermSrvPort->m_szRXBuf[4+2*i]);
    }
    }
    else
    {
    TRACE("EPM420 Crc error\n");
    }
    } TRACE ("RTU m_szName = %10s,m_nRTUID = %d, m_szProtocol=%15s, ChannelName = %10s\n",
    m_szName,m_nRTUID,m_szProtocol,m_pTermSrvPort->m_szName );
    return TRUE;
    }
      

  7.   

    denis95    上面的 是 Modbus   协议吗
    你作的是电力系统相关的监控吧
      

  8.   

    对于向串行通信这样含有后台处理的程序,推荐你使用线程来做,楼主用Timer我不赞成,试想一下这样一种情况,你的timer里面的代码如果没执行完(可能在等待),但是又一个timer事件来了,你的程序怎么办?下位机怎么办?好好把握你的程序中发送和接收数据的节奏吧
      

  9.   

    对,开一个辅助监视线程来做。不要用timer.http://images.163.com/images/it/books/vc/chap12/chap12_4.htm
      

  10.   

    我做过串口通信程序,你开辅助线程监视串口。⑴.在中MainFrm.cpp定义全局变量HANDLE    hCom; // 准备打开的串口的句柄HANDLE    hCommWatchThread ;//辅助线程的全局函数⑵.打开串口,设置串口hCom =CreateFile( "COM2", GENERIC_READ | GENERIC_WRITE, // 允许读写         0,          // 此项必须为0         NULL,         // no security attrs         OPEN_EXISTING,    //设置产生方式         FILE_FLAG_OVERLAPPED, // 我们准备使用异步通信         NULL );请大家注意,我们使用了FILE_FLAG_OVERLAPPED结构。这正是使用API实现非阻塞通信的关键所在。ASSERT(hCom!=INVALID_HANDLE_VALUE); //检测打开串口操作是否成功SetCommMask(hCom, EV_RXCHAR|EV_TXEMPTY );//设置事件驱动的类型SetupComm( hCom, 1024,512) ; //设置输入、输出缓冲区的大小PurgeComm( hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR           | PURGE_RXCLEAR ); //清干净输入、输出缓冲区
      

  11.   

    COMMTIMEOUTS CommTimeOuts ; //定义超时结构,并填写该结构   …………SetCommTimeouts( hCom, &CommTimeOuts ) ;//设置读写操作所允许的超时DCB    dcb ; // 定义数据控制块结构GetCommState(hCom, &dcb ) ; //读串口原来的参数设置dcb.BaudRate =9600; dcb.ByteSize =8; dcb.Parity = NOPARITY;dcb.StopBits = ONESTOPBIT ;dcb.fBinary = TRUE ;dcb.fParity = FALSE;SetCommState(hCom, &dcb ) ; //串口参数配置上述的COMMTIMEOUTS结构和DCB都很重要,实际工作中需要仔细选择参数。⑶启动一个辅助线程,用于串口事件的处理。Windows提供了两种线程,辅助线程和用户界面线程。区别在于:辅助线程没有窗口,所以它没有自己的消息循环。但是辅助线程很容易编程,通常也很有用。在次,我们使用辅助线程。主要用它来监视串口状态,看有无数据到达、通信有无错误;而主线程则可专心进行数据处理、提供友好的用户界面等重要的工作。hCommWatchThread=     CreateThread( (LPSECURITY_ATTRIBUTES) NULL, //安全属性         0,//初始化线程栈的大小,缺省为与主线程大小相同         (LPTHREAD_START_ROUTINE)CommWatchProc, //线程的全局函数         GetSafeHwnd(), //此处传入了主框架的句柄         0, &dwThreadID );  ASSERT(hCommWatchThread!=NULL);⑷为辅助线程写一个全局函数,主要完成数据接收的工作。请注意OVERLAPPED结构的使用,以及怎样实现了非阻塞通信。UINT CommWatchProc(HWND hSendWnd){  DWORD dwEvtMask=0 ;  SetCommMask( hCom, EV_RXCHAR|EV_TXEMPTY );//有哪些串口事件需要监视?  WaitCommEvent( hCom, &dwEvtMask, os );// 等待串口通信事件的发生  检测返回的dwEvtMask,知道发生了什么串口事件:  if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR){ // 缓冲区中有数据到达  COMSTAT ComStat ; DWORD dwLength;  ClearCommError(hCom, &dwErrorFlags, &ComStat ) ;  dwLength = ComStat.cbInQue ; //输入缓冲区有多少数据?  if (dwLength > 0) {BOOL fReadStat ;    fReadStat = ReadFile( hCom, lpBuffer,dwLength, &dwBytesRead,            &READ_OS( npTTYInfo ) ); //读数据注:我们在CreareFile()时使用了FILE_FLAG_OVERLAPPED,现在ReadFile()也必须使用
      

  12.   

    LPOVERLAPPED结构.否则,函数会不正确地报告读操作已完成了.    使用LPOVERLAPPED结构, ReadFile()立即返回,不必等待读操作完成,实现非阻塞    通信.此时, ReadFile()返回FALSE, GetLastError()返回ERROR_IO_PENDING.if (!fReadStat){   if (GetLastError() == ERROR_IO_PENDING){     while(!GetOverlappedResult(hCom,       &READ_OS( npTTYInfo ), & dwBytesRead, TRUE )){       dwError = GetLastError();       if(dwError == ERROR_IO_INCOMPLETE) continue;             //缓冲区数据没有读完,继续       …… ……         ::PostMessage((HWND)hSendWnd,WM_NOTIFYPROCESS,0,0);//通知主线程,串口收到数据  }  所谓的非阻塞通信,也即异步通信。是指在进行需要花费大量时间的数据读写操作(不仅仅是指串行通信操作)时,一旦调用ReadFile()、WriteFile(), 就能立即返回,而让实际的读写操作在后台运行;相反,如使用阻塞通信,则必须在读或写操作全部完成后才能返回。由于操作可能需要任意长的时间才能完成,于是问题就出现了。非常阻塞操作还允许读、写操作能同时进行(即重叠操作?),在实际工作中非常有用。要使用非阻塞通信,首先在CreateFile()时必须使用FILE_FLAG_OVERLAPPED;然后在 ReadFile()时lpOverlapped参数一定不能为NULL,接着检查函数调用的返回值,调用GetLastError(),看是否返回ERROR_IO_PENDING。如是,最后调用GetOverlappedResult()返回重叠操作(overlapped operation)的结果;WriteFile()的使用类似。⑸.在主线程中发送下行命令。BOOL  fWriteStat ; char szBuffer[count];       …………//准备好发送的数据,放在szBuffer[]中fWriteStat = WriteFile(hCom, szBuffer, dwBytesToWrite,           &dwBytesWritten, &WRITE_OS( npTTYInfo ) ); //写数据注:我们在CreareFile()时使用了FILE_FLAG_OVERLAPPED,现在WriteFile()也必须使用   LPOVERLAPPED结构.否则,函数会不正确地报告写操作已完成了.   使用LPOVERLAPPED结构,WriteFile()立即返回,不必等待写操作完成,实现非阻塞 通信.此时, WriteFile()返回FALSE, GetLastError()返回ERROR_IO_PENDING.int err=GetLastError();if (!fWriteStat) {   if(GetLastError() == ERROR_IO_PENDING){    while(!GetOverlappedResult(hCom, &WRITE_OS( npTTYInfo ),           &dwBytesWritten, TRUE )) {      dwError = GetLastError();      if(dwError == ERROR_IO_INCOMPLETE){           // normal result if not finished        dwBytesSent += dwBytesWritten; continue; }    综上,我们使用了多线程技术,在辅助线程中监视串口,有数据到达时依靠事件驱动,读入数据并向主线程报告(发送数据在主线程中,相对说来,下行命令的数据总是少得多);并且,WaitCommEvent()、ReadFile()、WriteFile()都使用了非阻塞通信技术,依靠重叠(overlapped)读写操作,让串口读写操作在后台运行。
      

  13.   

    是不是对话框的问题?!我用的是模式对话框!结果我试着点了程序的“关于”对话框后关闭,结果也发现
    显示变慢的问题!!!程序主框架采用的是视图/文档结构。我对话框是用DoModal()显示的,应该没什么
    问题吧。如下所示(其中一项测试的窗体):
    void CMainFrame::OnSimage() 
    {
         CSimage m_image;
    m_image.DoModal();
    }
    }
      

  14.   

    绝对不是对话框本身的问题,是你处理数据的问题,
    我主要是不在现场,不然也许可以帮你忙,
    给你个多线程的简单例子,
    //#include "StdAfx.h"
    #include "Testdes.h" //上面二个是和其他CPP文件相同的几个必要的头文件,在这里我的工整叫Testdes
    #include "CommCtrl.h" //不用说了吧
    #include "TestdesDlg.h" //对话框头文件UINT SetData(LPVOID pParam)
    {
    CTestdesDlg *dlg1 = (CTestdesDlg*)pParam;
    CString str;
    str.Format("你的数据");
    dlg1->SetDlgItemText(IDC_EDIT3,str); //在对话框中的IDC_EDIT3显示"你的数据" return 1;
    }//"CommCtrl.h"
    //函数声明
    UINT SetData(LPVOID pParam);
      

  15.   

    我的E-mail :[email protected]
    你最好找个近点的高手,我得走了,实在不好意思了。