我这里有一个设备,该设备能够提供rs-485通讯,这个设备是用被动的模式实现rs-485通讯的.通讯协议我有.需要有一套软件对该设备(可能是255个)进行轮询,而后捕获各个数据反馈数据采集到以后需要存储到数据库中.轮询的算法写不出来,请大家看看我的代码,帮忙提提建议,谢谢! 我的想法是: 用定时器每5分钟轮询一次,每个周期需要从5台设备query数据. 
在一个轮询周期中,主机需要分别发一个命令给每个设备,收到设备回答后,方可继续query下一个设备. 依次查询,5台都查完之后, 等到下一个轮询周期到来.再分别发命令给5台设备. 我的困难是不知道如何实现上面的算法:  
我在OnTimer 里面发命令给设备,COM1口如果有数据,即触发MSCOMM控件的OnCommMscomm1事件.在这个事件处理函数中,如果数据包没结束,则先KillTimer(暂停定时器,即下一个命令不能发), 如数据包接收完整,则再次SetTimer. 可是我的代码只能应对一台设备, 5台设备怎么办呢? 在OnTimer函数中for循环好像不行吧. 
我要的是: 主机与一台设备对话时, 不能再发下一个命令, 直到收到当前设备回应. 收到后立马再与下一个设备通话, 5台全部通讯完, 停止等待下一个query周期的到来. 请大侠们帮忙,我的算法该如何实现呢,好急呀! 想两天了,还是没想出来. void CPanel::OnTimer(UINT nIDEvent) 

// TODO: Add your message handler code here and/or call default 
CString m_strCommand;   
m_strCommand = "{FA;FC; <Length> ¦64:PAC=1ABC;KDY=12A;KT0=13FB6;KYR=13FB6;RAD=1C2 ¦ <Crc> }"; 
Sleep(200); 
sendCommand(m_strCommand); if (m_bOutput!="") 

ParseData(); 
SaveToDataBase(); 

CDialog::OnTimer(nIDEvent); 

BEGIN_EVENTSINK_MAP(CPanel, CDialog) 
ON_EVENT(CPanel, IDC_MSCOMM1, 1, OnCommMscomm1, VTS_NONE) 
END_EVENTSINK_MAP() void CPanel::OnCommMscomm1() 
{     // TODO: Add your message handler code here 
    VARIANT variant_inp; 
    COleSafeArray safearray_inp; 
    LONG len,k; 
    BYTE rxdata[2048]; //设置BYTE数组 An 8-bit integerthat is not signed. 
    CString strtemp; 
// CString strtemp_roselu; 
static bool bEnd=false; 
if (bEnd == true) 

m_bOutput =""; 
bEnd=false; 

if(m_ctrlComm.get_CommEvent()==2) //事件值为2表示接收缓冲区内有字符 
    {             ////////以下你可以根据自己的通信协议加入处理代码 
if(bEnd==false) 
KillTimer(READER_EVENT_ID); variant_inp=m_ctrlComm.get_Input(); //读缓冲区 
        safearray_inp=variant_inp; //VARIANT型变量转换为ColeSafeArray型变量 
        len=safearray_inp.GetOneDimSize(); //得到有效数据长度 
        for(k=0;k <len;k++) 
            safearray_inp.GetElement(&k,rxdata+k);//转换为BYTE型数组 
        for(k=0;k <len;k++) //将数组转换为Cstring型变量 
        { 
            BYTE bt=*(char*)(rxdata+k); //字符型 
            strtemp.Format("%c",bt); //将字符送入临时变量strtemp存放 
            //m_strRXData+=strtemp; //加入接收编辑框对应字符串  
m_bOutput+=strtemp; //加入接收编辑框对应字符串 
if(strtemp=="}") 

bEnd=true; 
SetTimer(READER_EVENT_ID,READER_EVENT_TIME,NULL); 

        } 
    } 
m_info.SetWindowText(m_bOutput);     UpdateData(FALSE); //更新编辑框内容 }

解决方案 »

  1.   


    我觉得:
    1. 你可以在 OnTimer 中仅仅向第一个设备发查询请求,发出后置一个标志为真,这个标志当最后一个设备返回结果后置假,OnTimer 中判断这个标志为假后才开始下一轮查询。2. 在 OnCommMscomm1 事件中决定是否向下一个设备发出查询请求,即:当第一个设备发回查询结果,会触发 OnCommMscomm1 事件,在此事件中做相应处理,然后向第二个设备发送查询请求,当第二个设备返回查询结果,也会触发 OnCommMscomm1 事件,就可以继续向第三个设备发送查询请求,依次类推。不知我的想法是否有问题,请考虑。
      

  2.   


    不过还有一个问题,我这种方法是在每个设备都能返回查询结果的前提下实现的,即一环套一环,是否向下一个设备发送查询请求,取决于上一个设备是否返回了查询结果,如果有一个设备没有返回结果,整个过程就被阻塞住了,永远不会往下执行,所以实际实现的话,最好再加一个 Timer,用来判断是否长时间未收到 Comm 事件,如果长时间没有收到过数据,就自动向下一个设备发送请求。
      

  3.   

    周期性地向N个设备轮询已经试过, qing3962的算法可行的, 即在OnCommMscomm1 事件中判断如果收到当前设备的响应,继续在OnCommMscomm1 函数里发送命令给下一台设备.现在正在想如何实现-----"加一个 Timer,用来判断是否长时间未收到 Comm 事件,如果长时间没有收到过数据,就自动向下一个设备发送请求".
      

  4.   

    两个计时器:void CPanel::OnTimer(UINT nIDEvent)
    {
    // TODO: Add your message handler code here and/or call default
    //ndevice, m_strCommand要与ndevice关联,即ndevice决定向哪一台设备发送命令.
    //如果OnCommMscomm1()因轮询没响应而不被触发, 达到timeout, OnTimer则记录出错信息,并接着query下一台设备.
    CString m_strCommand, m_strDevice; 
    switch(nIDEvent) 

    case READER_EVENT_ID: 

    if (bContinueOnTimer == true)
    {
    //m_strCommand = "{FA;FC;<Length>|64:PAC=1ABC;KDY=12A;KT0=13FB6;KYR=13FB6;RAD=1C2|<Crc>}";
    m_strDevice.Format( "%x ",ndevice);  
    m_strDevice.MakeUpper(); 
    m_strCommand = "{FA;"+m_strDevice+";<Length>|64:PAC=1ABC;KDY=12A;KT0=13FB6;KYR=13FB6;RAD=1C2|<Crc>}";
    sendCommand(m_strCommand);
    Sleep(200);

    break; 
    case RE_SEND: 
    t2=GetTickCount();//获得从系统运行起的到现在的一个毫秒数.
    if ((t2-t1)> 3000000)
    {
    if (bContinueOnTimer == true)
    {
    Clog(3,"can not receive message from %d device\n",ndevice);
    ndevice++;
    m_strDevice.Format( "%x ",ndevice);  
    m_strDevice.MakeUpper(); 
    m_strCommand = "{FA;"+m_strDevice+";<Length>|64:PAC=1ABC;KDY=12A;KT0=13FB6;KYR=13FB6;RAD=1C2|<Crc>}";
    sendCommand(m_strCommand);
    Sleep(200);

    }
    break; 
    default: 
    break;  }//end swtich
    CDialog::OnTimer(nIDEvent);
    }
      

  5.   

    lz, bad idea & bad code.    -- by what_a_big