2014-04-17 122 views
1

从串口读取数据时出现问题。 问题是,对于从rs232端口读取的最后2个字节(CRC字节),读取等待,直到在timeval中设置的超时结束,然后返回。在rs485上,使用与读取相同的方法,读取返回正常。我在debbuging中看到的是,在rs485之后,在2个CRC字节后面有一个额外的字节,其值为FF。我找不到2.如何解决rs232串口的超时问题?

的另一个区别这里是代码的相关部分:

设置端口

bool Serial::setup(){ 


    if(!openPort()){ 
     return false; 
    } 

    tcgetattr(fdPort, &options); 

    cfsetispeed(&options, B115200); 
    cfsetospeed(&options, B115200); 

    options.c_cflag &= ~PARENB; 

    options.c_cflag &= ~CSTOPB; 
    options.c_cflag &= ~CSIZE; 
    options.c_cflag |= CS8; 

    options.c_cc[VMIN] = 0; 
    options.c_cc[VTIME] = 1; 

    options.c_oflag &= ~(OCRNL | ONLCR | ONLRET | 
         ONOCR | OFILL | OLCUC | OPOST); 

    options.c_iflag &= ~(IGNBRK | BRKINT | ICRNL | INLCR | 
         PARMRK | INPCK | ISTRIP | IXON) ; 

    options.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG); 

    if(tcsetattr(this->fdPort, TCSANOW, &options)){ 
     return false; 
    } 

    return true; 

} 

开埠

bool Serial::openPort(){ 
    this->fdPort = open(this->port, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); 

    if(fdPort == -1){ 
     return false; 
    } 
    else{ 
     //fcntl(fdPort, F_SETFL, 0); 
     //fcntl(fdPort, F_SETFL, FNDELAY); 
    } 

    int status = 0; 

    status |= TIOCM_RTS; 
    ioctl(this->fdPort, TIOCMSET, &status); 

    return true; 

} 

解释和读取数据的等待帧大块。

bool GlobalProtocol::WaitFrame(uint32_t timeOut) { 

    int32_t bytesRec = 0; 
    int32_t bytesToRec = 1; 
    int recPhase = GC_PHASE_START; 

    uint8_t *pData = m_RxBuff; 
    bool commSuccess = true; 

    m_LastError = boards::GCL_ERR_OK; 

    while (readData(pData, bytesToRec, &bytesRec, timeOut)) { 
     if (bytesRec) { 
      switch (recPhase) { 
      case GC_PHASE_START: 
       if (*pData != GC_START_FRAME_BYTE) { 
        continue; 
       } 
       recPhase++; 
       pData++; 
       break; 
      case GC_PHASE_DEST: 
       if (*pData != m_MasterAddr) { 
        commSuccess = false; 
        break; 
       } 
       recPhase++; 
       pData++; 
       break; 
      case GC_PHASE_SRC: 
       recPhase++; 
       pData++; 
       break; 
      case GC_PHASE_LEN_LO: 
       if (*pData < 2 || *pData > GC_MAX_COMM_DATA_LEN) { 
        commSuccess = false; 
        break; 
       } 
       recPhase++; 
       pData++; 
       break; 
      case GC_PHASE_LEN_HI: 
       if (*pData != 0) { 
        commSuccess = false; 
        break; 
       } 
       recPhase++; 
       pData++; 
       bytesToRec = m_RxBuff[GC_PHASE_LEN_LO]; 
       break; 
      case GC_PHASE_DATA: 
       if (bytesRec != bytesToRec) { 
        commSuccess = false; 
        break; 
       } 
       recPhase++; 
       pData += bytesRec; 
       bytesToRec = 2; 
       break; 
      case GC_PHASE_CRC_LO: 
       if (bytesRec != bytesToRec) { 
        commSuccess = false; 
        break; 
       } 
       if (CheckCRC(m_RxBuff, m_RxBuff[GC_PHASE_LEN_LO] + GC_PHASE_DATA + sizeof(uint16_t))) { 
        m_RecAddr = m_RxBuff[GC_PHASE_SRC]; 
        return true; 
       } 
       commSuccess = false; 
       break; 
      } 
      if (!commSuccess) break; 
     } 
     else break; 
    } 
    m_LastError = boards::GCL_ERR_ANSWERNOTREC; 

    return false; 
} 

并且读取完成。

bool Serial::readData(uint8_t *data, uint32_t length, int32_t *receivedDataBytes, int32_t timeoutVal){ 
    int32_t tempReceivedDataBytes = -1; 

    fd_set readFd; 
    FD_ZERO(&readFd); 
    FD_SET(fdPort, &readFd); 
    struct timeval timeout; 
    timeout.tv_sec = 0; 
    timeout.tv_usec = timeoutVal * 1000; 
    int test = 0; 
    uint32_t bytesAvail = 0; 

    QTime timer; 

    timer.start(); 

    if(fcntl(fdPort, F_GETFD) != -1){ 
     while(((test = select(this->fdPort + 1, &readFd, NULL, NULL, &timeout)) == 1) && (tempReceivedDataBytes == -1)){ 

      ioctl(fdPort, FIONREAD, &bytesAvail); 

      if(FD_ISSET(fdPort, &readFd) && bytesAvail >= length){ 
       tempReceivedDataBytes = read(fdPort, data, length); 
      } 

      if(timer.elapsed() > (timeoutVal + 5)){ //fail-safe 
       logger[debug_log] << "TIMEOUT" << endl; 
       break; 
      } 

     } 

     if(test == -1) 
      logger[debug_log]<< strerror(errno) << endl; 

     if(tempReceivedDataBytes < 0){ 
      return false; 
     } 
     if(tempReceivedDataBytes >= 0){ 
      *receivedDataBytes = tempReceivedDataBytes; 
      return true; 
     } 

    } 

    return false; 
} 

如果我将超时设置为100毫秒,然后它等待100毫秒来读取2个字节,如果我将其设置为10毫秒,然后它等待10毫秒来读取2个字节。

我尝试更改端口设置,但没有成功。

我一直在试图解决这个问题,但没有成功。

编辑: 我要补充一点ioctl(fdPort, FIONREAD, &bytesAvail);被设置bytesAvail为2,但read等待,直到超时阅读。

编辑2:

这里是一个日志,设置为25秒钟,这样你可以得到什么问题的想法超时:

04/17/2014 15:51:50:584,Main board start: 
04/17/2014 15:51:50:586,1 Received 1 Needed to receive 1 
04/17/2014 15:51:50:586,1 Received 1 Needed to receive 1 
04/17/2014 15:51:50:586,1 Received 1 Needed to receive 1 
04/17/2014 15:51:50:587,1 Received 1 Needed to receive 1 
04/17/2014 15:51:50:587,1 Received 1 Needed to receive 1 
04/17/2014 15:51:50:597,1 Received 110 Needed to receive 110 
04/17/2014 15:51:50:597,1 Received 2 Needed to receive 2 
04/17/2014 15:51:50:634,PID board start: 
04/17/2014 15:51:50:635,1 Received 1 Needed to receive 1 
04/17/2014 15:51:50:635,1 Received 1 Needed to receive 1 
04/17/2014 15:51:50:635,1 Received 1 Needed to receive 1 
04/17/2014 15:51:50:635,1 Received 1 Needed to receive 1 
04/17/2014 15:51:50:635,1 Received 1 Needed to receive 1 
04/17/2014 15:51:50:641,1 Received 70 Needed to receive 70 
04/17/2014 15:52:15:647,0 Received 2 Needed to receive 2 
04/17/2014 15:52:15:647,Set Leds board start: 
04/17/2014 15:52:15:649,1 Received 1 Needed to receive 1 
04/17/2014 15:52:15:649,1 Received 1 Needed to receive 1 
04/17/2014 15:52:15:652,1 Received 1 Needed to receive 1 
04/17/2014 15:52:15:652,1 Received 1 Needed to receive 1 
04/17/2014 15:52:15:652,1 Received 1 Needed to receive 1 
04/17/2014 15:52:15:652,1 Received 2 Needed to receive 2 
04/17/2014 15:52:15:652,1 Received 2 Needed to receive 2 
04/17/2014 15:52:15:652,Get state board start: 
04/17/2014 15:52:15:654,1 Received 1 Needed to receive 1 
04/17/2014 15:52:15:654,1 Received 1 Needed to receive 1 
04/17/2014 15:52:15:654,1 Received 1 Needed to receive 1 
04/17/2014 15:52:15:654,1 Received 1 Needed to receive 1 
04/17/2014 15:52:15:655,1 Received 1 Needed to receive 1 
04/17/2014 15:52:15:657,1 Received 30 Needed to receive 30 
04/17/2014 15:52:15:657,1 Received 2 Needed to receive 2 

的一个与问题是PID板(在rs232上),其他的在同一个rs485上。

这里是一个设置为大约30毫秒的超时(我不记得确切的值):

04/17/2014 15:08:08:045,Main board start: 
04/17/2014 15:08:08:046,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:046,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:046,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:047,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:047,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:056,1 Received 110 Needed to receive 110 
04/17/2014 15:08:08:056,1 Received 2 Needed to receive 2 
04/17/2014 15:08:08:078,PID board start: 
04/17/2014 15:08:08:079,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:079,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:079,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:079,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:079,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:094,1 Received 70 Needed to receive 70 
04/17/2014 15:08:08:120,0 Received 2 Needed to receive 2 
04/17/2014 15:08:08:120,Set Leds board start: 
04/17/2014 15:08:08:122,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:122,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:122,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:122,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:122,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:122,1 Received 2 Needed to receive 2 
04/17/2014 15:08:08:122,1 Received 2 Needed to receive 2 
04/17/2014 15:08:08:123,Get state board start: 
04/17/2014 15:08:08:124,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:124,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:124,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:125,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:125,1 Received 1 Needed to receive 1 
04/17/2014 15:08:08:128,1 Received 30 Needed to receive 30 
04/17/2014 15:08:08:128,1 Received 2 Needed to receive 2 

编辑:我仍然无法弄清楚什么是错的。如果我删除rs485上的额外字节,它是一样的。这里是另一个日志:

06/24/2014 12:57:01:923,Set Leds board start: 
06/24/2014 12:57:06:701,Select value 1 Received: 1 Needed: 1 Bytes available: 9 
06/24/2014 12:57:06:701,Select value 1 Received: 1 Needed: 1 Bytes available: 8 
06/24/2014 12:57:06:702,Select value 1 Received: 1 Needed: 1 Bytes available: 7 
06/24/2014 12:57:06:702,Select value 1 Received: 1 Needed: 1 Bytes available: 6 
06/24/2014 12:57:06:702,Select value 1 Received: 1 Needed: 1 Bytes available: 5 
06/24/2014 12:57:06:702,Select value 1 Received: 2 Needed: 2 Bytes available: 4 
06/24/2014 12:57:06:752,Select value 0 Received: 2 Needed: 2 Bytes available: 2 
06/24/2014 12:57:06:752,Get state board start: 
06/24/2014 12:57:06:754,Select value 1 Received: 1 Needed: 1 Bytes available: 4 
06/24/2014 12:57:06:754,Select value 1 Received: 1 Needed: 1 Bytes available: 3 
06/24/2014 12:57:06:754,Select value 1 Received: 1 Needed: 1 Bytes available: 2 
06/24/2014 12:57:06:754,Select value 1 Received: 1 Needed: 1 Bytes available: 1 
06/24/2014 12:57:06:755,Select value 1 Received: 1 Needed: 1 Bytes available: 10 
06/24/2014 12:57:06:758,Select value 1 Received: 30 Needed: 30 Bytes available: 30 
06/24/2014 12:57:06:808,Select value 0 Received: 2 Needed: 2 Bytes available: 2 
06/24/2014 12:57:06:886,Main board start: 
06/24/2014 12:57:06:888,Select value 1 Received: 1 Needed: 1 Bytes available: 3 
06/24/2014 12:57:06:888,Select value 1 Received: 1 Needed: 1 Bytes available: 2 
06/24/2014 12:57:06:889,Select value 1 Received: 1 Needed: 1 Bytes available: 1 
06/24/2014 12:57:06:890,Select value 1 Received: 1 Needed: 1 Bytes available: 23 
06/24/2014 12:57:06:890,Select value 1 Received: 1 Needed: 1 Bytes available: 22 
06/24/2014 12:57:06:898,Select value 1 Received: 110 Needed: 110 Bytes available: 113 
06/24/2014 12:57:06:898,Select value 1 Received: 2 Needed: 2 Bytes available: 3 

正如你可以看到当可用的字节数是字节数等于读等待在读取功能,直到超时,然后返回。

+0

您可以使用硬件RTS/CTS,但这意味着您的连接器将不得不进行配置。或者,您可以使用XON XOFF来停止和启动数据。 – cup

+0

问题不在于数据不存在,问题是即使数据在那里,read也会等待,直到超时才能读取它。 –

回答

1

我设法解决它。这是一个简单的修复。

我曾与while((tempReceivedDataBytes == -1) && ((test = select(this->fdPort + 1, &readFd, NULL, NULL, &timeout)) == 1)) 更换while(((test = select(this->fdPort + 1, &readFd, NULL, NULL, &timeout)) == 1) && (tempReceivedDataBytes == -1))

如果串行缓冲区为空,它将在select中等待,直到超时,即使它读取了某些内容。如果港口有人正在检查时间的第二部分并退出。

+0

嗨,亚历克斯,我正面临类似的问题,我试图搜索,并遇到你的线程。我使用不同的硬件和软件(Altera Nios II中的C代码将数据发送到串行端口,Matlab实时访问串行端口和绘图)(在我读取您的线程之前将我的线程发布到此处http://stackoverflow.com/问题/ 29122503/serial-port-timeout-10-seconds-but-getting-less-samples-than-expected-desired),能否请你在一般算法中告诉我你做了什么来解决这个问题,以便我能做到在我的平台的必要编码?请提前谢谢你 – user2563812

2

您使用的是什么硬件?真正的串行端口或USB适配器?一些FTDI USB转串口适配器被配置,所以他们通过USB批量发送字节。这加快了端口完全加载时的传输速度,但它们的行为与您在处理少量字节时的行为相似。

+0

在我的电脑上我有一个USB适配器,但在我正在制作应用程序的设备上,我有一个真正的串行端口,问题是一样的。 –

+0

我不会认为由此引发的延迟真的会在超时的数量级,而不是1-2毫秒...... – glglgl

+0

根据我的经验,这是> 10毫秒,但你说得对,100毫秒可能是对于这样的延迟太多了。 –

0

设置VMIN的非零值,以便只要至少有已经接收到许多字符,就可以满足读取。

这将意味着:

  • 如果没有数据被缓冲,通话将等待超时的一些数据

  • 如果至少VMIN字符被缓冲,来电会立即返回,不用等待超时。

+0

我试着用'VMIN'设置为1并设置为0,问题是一样的。 –