小弟通过电脑的232串口读取外部激光测距传感器的测量值,程序是根据龚建伟老师的串口调试助手写的。激光发射的函数通过OnTimer函数触发,每5s发射一次。我想从激光返回的CString类型的字符串获取测量的值,并转化成double类型的数据,下面是我的程序。
void SCOMM::OnComm()//10.23mhf 读串口数据
{    //char *str,*str1;
    COleSafeArray safearray_inp;
    VARIANT variant_inp;
    LONG len,k;
    BYTE rxdata[2048]; 
    CString strtemp;
    CString strry1;
    CString strry;
    if(m_comm.get_CommEvent()==2)
    {
        variant_inp=m_comm.get_Input();
         //将str的指针指向数据缓冲区
        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=5;k<len;k++)             //将数组转换为Cstring型变量(我自己写的,从字符串中获取数据位)
{
   BYTE bt=*(char*)(rxdata+k);      //字符型
   strry.Format("%c",bt); //将字符送入临时变量strtemp存放  
            strry1+=strry;    //加入接收编辑框对应字符串  
}
         rs_l_err=_tstof(strry1);//转化成double类型
         laser_l_err=rs_l_err;
         for(k=0;k<len;k++)             //将数组转换为Cstring型变量
{
   BYTE bt=*(char*)(rxdata+k);      //字符型
   strtemp.Format("%c",bt); //将字符送入临时变量strtemp
            m_strRXData+=strtemp;    //加入接收编辑框对应字符串    
}
     } UpdateData(FALSE);           //更新编辑框内容
}单步调试的时候,激光每次返回的字符串是“128‘$’,6‘_’,130,48‘0’,46 ‘0’,49‘1’,57‘8’,152”,单步调试的时候可以读取正确的测量值0.19800000000001。但在正常运行的时候,激光每5s发射一次,这时候返回的值就不对。哪位大侠帮忙解答一下

解决方案 »

  1.   

    BYTE rxdata[2048];
    数组使用前要初始化memset(rxdata,0,2048);
    后面for(k=0;k<len;k++) //将数组转换为Cstring型变量
     {
    BYTE bt=*(char*)(rxdata+k); //字符型
    strtemp.Format("%c",bt); //将字符送入临时变量strtemp
       m_strRXData+=strtemp; //加入接收编辑框对应字符串   
    }
     这些完全多余
      

  2.   

    后面的是用来显示的,这一块没什么问题,主要是下面的有问题
    for(k=5;k<len;k++) //将数组转换为Cstring型变量(我自己写的,从字符串中获取数据位)
    {
    BYTE bt=*(char*)(rxdata+k); //字符型
    strry.Format("%c",bt); //将字符送入临时变量strtemp存放   
      strry1+=strry; //加入接收编辑框对应字符串   
    }
      rs_l_err=_tstof(strry1);//转化成double类型
      laser_l_err=rs_l_err;
      

  3.   

    m_ctrComm.SetRThreshold();//你设的多少
    m_ctrComm.SetInputLen(0);//你设的0对吧,也就是缓冲区有多少你要多少但是一般串口的波特率设置为9600也就是10ms一个字节,你设置5ms发一次,这意味着什么?
    先通过波特率和字节数算好你发的时间和接收的时间5ms太短
      

  4.   

    SetTimer(156,5000,NULL);我是通过这个函数来触发OnTimer发送,是每5s发一次
      

  5.   

    void SCOMM::OnComm()//10.23mhf 读串口数据
    {    COleSafeArray safearray_inp;
        VARIANT variant_inp;
        LONG len,k;
        BYTE rxdata[2048]; //设置BYTE数组 An 8-bit integerthat is not signed.
        CString strtemp;
        CString strry1;
        CString strry;
        CString strry2;
        CString strry3;
        double rs_l_err1,rs_l_err2;
        if(m_comm.get_CommEvent()==2)
       {
            variant_inp=m_comm.get_Input();//将str的指针指向数据缓冲区
             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=5;k<len;k++)             //将数组转换为Cstring型变量
    {
       BYTE bt2=*(char*)(rxdata+k);      //字符型
        strry3.Format("%c",bt2); //将字符送入临时变量strtemp存放  
                 strry2+=strry3;    //加入接收编辑框对应字符串  
    }
       rs_l_err2=_tstof(strry2);//转化成double类型
       Sleep(500);
       for(k=0;k<len;k++)             //将数组转换为Cstring型变量
    {
       BYTE bt1=*(char*)(rxdata+k);      //字符型
        strry.Format("%c",bt1); //将字符送入临时变量strtemp存放  
                 strry1+=strry;    //加入接收编辑框对应字符串  
    }
            rs_l_err1=_tstof(strry1);//转化成double类型
             rs_l_err=rs_l_err1/1000;
            if(rs_l_err>0.00005)
     {
                laser_l_err=rs_l_err;
    }
             Sleep(600);
    for(k=0;k<len;k++)             //将数组转换为Cstring型变量
    {
    BYTE bt=*(char*)(rxdata+k);      //字符型
    strtemp.Format("%c",bt); //将字符送入临时变量strtemp存放
    m_strRXData+=strtemp;    //加入接收编辑框对应字符串    
    }
    }
    UpdateData(FALSE);           //更新编辑框内容
    }void SCOMM::OnBnClickedOpenport()//10.23mhf 读串口数据
    {
    // TODO: 在此添加控件通知处理程序代码
                      m_Port=1;
    m_comm.put_CommPort(m_Port);//设置串口
    m_comm.put_InputMode(1);//设置数据读取格式为二进制
    m_comm.put_Settings(_T("9600,n,8,1"));//传输参数,波特率9600,无校验,8个数据位,1个停止位
    m_comm.put_RThreshold(1);//缓冲区内有一个字符就可以接收
    m_comm.put_InBufferSize(4086);//接收缓冲区的大小2字节
    m_comm.put_OutBufferSize(4086);//发送缓冲区大小2字节
    m_comm.put_InBufferCount(0);//清空接收缓冲区
    if(!m_comm.get_PortOpen())
    {
    m_comm.put_PortOpen(true);//打开串口
    GetDlgItem(ID_OPENPORT)->EnableWindow(FALSE);
                            GetDlgItem(ID_CLOSEPORT)->EnableWindow(TRUE);
    Is_open=true;
    }
    else
    MessageBox(_T("串行口已经打开!"),_T("提示"));}void SCOMM::OnBnClickedCloseport()
    {
    // TODO: 在此添加控件通知处理程序代码
        if(m_comm.get_PortOpen())
    {
    m_comm.put_PortOpen(false);//关闭串口
    GetDlgItem(ID_OPENPORT)->EnableWindow(TRUE);
    GetDlgItem(ID_CLOSEPORT)->EnableWindow(FALSE);
    Is_open=false;
    KillTimer(1);
    }
    }void SCOMM::OnBnClickedOne()//单步测量
    {
    // TODO: 在此添加控件通知处理程序代码
       UpdateData(TRUE); //读取编辑框内容
    if(m_ctrlHexSend.GetCheck())
    {
    m_strSend="80060278";
    CByteArray hexdata;
    int len=String2Hex(m_strSend,hexdata);  //此处返回的len可以用于计算发送了多少个十六进制数
    m_comm.put_Output(COleVariant(hexdata));  //发送十六进制数据
    }
    else 
    m_comm.put_Output(COleVariant(m_strSend));//发送ASCII字符数据

    }int SCOMM::String2Hex(CString str, CByteArray &senddata)
    {
        int hexdata,lowhexdata;
    int hexdatalen=0;
    int len=str.GetLength();
    senddata.SetSize(len/2);
    for(int i=0;i<len;)
    {
    char lstr,hstr=str[i];
    if(hstr==' ')
    {
    i++;
    continue;
    }
    i++;
    if(i>=len)
    break;
    lstr=str[i];
    hexdata=ConvertHexChar(hstr);
    lowhexdata=ConvertHexChar(lstr);
    if((hexdata==16)||(lowhexdata==16))
    break;
    else 
    hexdata=hexdata*16+lowhexdata;
    i++;
    senddata[hexdatalen]=(char)hexdata;
    hexdatalen++;
    }
    senddata.SetSize(hexdatalen);
    return hexdatalen;
    }char SCOMM::ConvertHexChar(char ch)
    {
        if((ch>='0')&&(ch<='9'))
    return ch-0x30;
    else if((ch>='A')&&(ch<='F'))
    return ch-'A'+10;
    else if((ch>='a')&&(ch<='f'))
    return ch-'a'+10;
    else 
    return (-1);
    return 0;
    }void SCOMM::OnBnClickedCon()
    {
    // TODO: 在此添加控件通知处理程序代码
    UpdateData(TRUE); //读取编辑框内容
    if(m_ctrlHexSend.GetCheck())
    {
    m_strSend="80060377";
    CByteArray hexdata;
    int len=String2Hex(m_strSend,hexdata);  //此处返回的len可以用于计算发送了多少个十六进制数
    m_comm.put_Output(COleVariant(hexdata));  //发送十六进制数据
    }
    else 
    m_comm.put_Output(COleVariant(m_strSend));//发送ASCII字符数据
    }void SCOMM::OnBnClickedStop()
    {
    // TODO: 在此添加控件通知处理程序代码
             UpdateData(TRUE); //读取编辑框内容
    if(m_ctrlHexSend.GetCheck())
    {
    m_strSend="8004027A";
    CByteArray hexdata;
    int len=String2Hex(m_strSend,hexdata);  //此处返回的len可以用于计算发送了多少个十六进制数
    m_comm.put_Output(COleVariant(hexdata));  //发送十六进制数据
    }
    else 
    m_comm.put_Output(COleVariant(m_strSend));//发送ASCII字符数据
    }void SCOMM::OnCheckAutosend()
    {
    // TODO: 在此添加控件通知处理程序代码
    m_bAutoSend=!m_bAutoSend;
    if(m_bAutoSend)
    {
    SetTimer(156,3000,NULL);
    }
    else
    {
    KillTimer(156);
    }
    }void SCOMM::OnTimer(UINT_PTR nIDEvent)
    {
    // TODO: 在此添加消息处理程序代码和/或调用默认值
         UpdateData();
    if(nIDEvent==156)
    {
           OnBnClickedOne();
    }
        UpdateData(0);
    CDialog::OnTimer(nIDEvent);
    }
    不好意思有点长,我现在是rs_l_err1变量获取转化的double测量值,现在是可以获取最后两位的值
      

  6.   

    // modbus协议中每帧数据都有地址码。
      

  7.   

    m_comm.get_CommEvent()==3 这是为什么了,原因以及修改的方法,我在这谢谢了 ,高人们,救命