【问题标题】:Reading serial data of variable lengths and frequency读取可变长度和频率的串行数据
【发布时间】:2021-05-06 12:02:02
【问题描述】:

我正在尝试以不同的频率读取 2 个可变长度的串行数据缓冲区。

  1. 第一个缓冲区每 400 毫秒发送一次,缓冲区大小为 187。
  2. 每 500 毫秒发送第二个缓冲区,缓冲区大小为 216。

使用以下实现的代码,即使接收到的缓冲区长度是 187 或 216 字节,接收到的缓冲区大小也始终为 230 字节。

数据字节读取调用等待最多 230 个字节被接收,因此接收到的数据格式不符合预期的数据格式。

下面是实现的代码:

#define DEVICEPORT "/dev/ttyUSB4"
#define SLEEP_TIMEOUT 400
#define MAX_BUFF_SIZE 230

int main () {

    int ret = 0;
    struct termios options;

    int fd = open(DEVICEPORT, O_RDWR | O_NOCTTY | O_NDELAY );
    
    if(fd == -1)
        cout << "Error in opening the port" << endl;
    else
        cout << "port opened successfully" << endl;

    tcgetattr(fd, &options);

    cfmakeraw(&options);
    cfsetispeed(&options, B19200);
    cfsetospeed(&options, B19200);

    options.c_cflag |= PARENB;
    options.c_cflag |= PARODD;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS7;
    options.c_cflag &= ~CRTSCTS;
    options.c_cflag |= CREAD | CLOCAL;//enable receiver
    
    options.c_iflag &= ~(IXON | IXOFF | IXANY );
    options.c_iflag |= (INPCK | ISTRIP);

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

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

    tcflush(fd, TCIFLUSH);
    if((tcsetattr(fd,TCSANOW,&options)) != 0) /* Set the attributes to the termios structure*/
    {
        cout << "ERROR ! in Setting attributes" << endl;
    }
    else
    {   cout << "couldn't set options .. " << endl;
        tcflush(fd, TCIFLUSH);
    }

    ioctl(fd, TCFLSH, 2);

    char buff[MAX_BUFF_SIZE];

    while(true) {
        cout << "Reading the data : "<< endl;

        int n = read(fd, buff, sizeof(buff));

        if (n < 0) { 
            cout << "Error while reading .. " << endl;
        } else {
            cout << "Read data size :" << n << "\n" ;  
            for (size_t i = 0; i < n; i++ ) {
                cout << buff[i];
            } cout << endl;
        }
        
        std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIMEOUT));
    }
    return 0;
}

我应该设置什么串口设置来读取可变长度和频率的缓冲区?

【问题讨论】:

  • 是否有任何页眉或页脚来区分这两种数据?
  • 是的,有不同的标头来区分这两种数据。
  • 然后,先读取header,根据信息来判断剩下要读取的数据大小。
  • 你的意思是不同的间隔是吗?频率让我觉得你有一些脉宽解调的东西,因为频率与波特率和 bps = Hz 是一样的。
  • 你误用了"buffer"这个词;似乎您的意思是“消息”或“数据包”。配置真的是 7 位和原始模式的奇偶校验吗? “数据字节读取调用等待接收到最多 230 个字节...” -- 这只是您对实际发生的事情的误解,即您有非阻塞读取和睡眠。研究 read()man 页面。

标签: c++ linux serial-port embedded


【解决方案1】:

int n = read(fd, buff, sizeof(buff)); 替换为逐字节读取,至少在您读取协议标头和大小之前。也许类似于此伪代码的内容:

int n = read(fd, header, sizeof(header));
if(n != sizeof(header))
{ /* handle errors */ }

int expected_size = header.size;

n = read(fd, buff, expected_size)
if(n != expected_size)
{ /* handle errors */ }

/* now the first n bytes of buff contain the protocol */

你还应该在某个地方进行 CRC 检查,因为这么长的串行数据是不可信的。

【讨论】:

  • 此代码示例依赖于非规范的非阻塞 read() 系统调用来神奇地提供sizeof(header)expected_size 结果。不,来自串行终端的原始非阻塞 read() 不能那样工作。也不能保证读取将始终与消息保持一致。这不是健壮的代码。
猜你喜欢
  • 1970-01-01
  • 2011-10-12
  • 1970-01-01
  • 2018-04-09
  • 1970-01-01
  • 2013-02-25
  • 1970-01-01
  • 2018-09-20
  • 1970-01-01
相关资源
最近更新 更多