读取 uart 十六进制值会忽略某些字节/字符

Posted

技术标签:

【中文标题】读取 uart 十六进制值会忽略某些字节/字符【英文标题】:Reading uart hex values ignores certain bytes/characters 【发布时间】:2020-04-06 12:21:07 【问题描述】:

我是 C/C++ 新手,我正在尝试使用 HEX 值通过 uart 进行通信。

设备端口:/dev/ttyS2。波特率:38400

我正在使用 redis 订阅消息。为了进行测试,我使用“Termite”,一个 RS232 终端来模拟。

我找到了一些非常有用的指南,问题是当我尝试阅读消息时,一些字节/字符会弄乱它。

这是我的连接代码:

    this->fd = open(device,O_RDWR | O_NOCTTY);

    /*---------- Setting the Attributes of the serial port using termios structure --------- */
    tcgetattr(this->fd, &SerialPortSettings);   /* Get the current attributes of the Serial port */

    /* Setting the Baud rate */
    cfsetispeed(&SerialPortSettings,B38400); /* Set Read  Speed as 38400 */
    cfsetospeed(&SerialPortSettings,B38400); /* Set Write Speed as 38400 */

    /* 8N1 Mode */
    SerialPortSettings.c_cflag &= ~PARENB;   /* Disables the Parity Enable bit(PARENB),So No Parity   */
    SerialPortSettings.c_cflag &= ~CSTOPB;   /* CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit */
    SerialPortSettings.c_cflag &= ~CSIZE;    /* Clears the mask for setting the data size             */
    SerialPortSettings.c_cflag |=  CS8;      /* Set the data bits = 8                                 */

    SerialPortSettings.c_cflag &= ~CRTSCTS;       /* No Hardware flow Control                         */
    SerialPortSettings.c_cflag |= CREAD | CLOCAL; /* Enable receiver,Ignore Modem Control lines       */

    SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY);          /* Disable XON/XOFF flow control both i/p and o/p */
    SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);  /* Non Cannonical mode                            */

    SerialPortSettings.c_oflag &= ~OPOST; /*No Output Processing*/
    SerialPortSettings.c_oflag = 0;

    /* Setting Time outs */
    SerialPortSettings.c_cc[VMIN] = 1;  /* Read at least X characters */
    SerialPortSettings.c_cc[VTIME] = 0; /* Wait indefinetly */

    tcflush(this->fd, TCIFLUSH);

    if((tcsetattr(this->fd,TCSANOW,&SerialPortSettings)) != 0)  /* Set the attributes to the termios structure*/
        printf("\n  ERROR ! in Setting attributes");
    
    else 
        tcsetattr(fd, TCSANOW, &SerialPortSettings);
        printf("\n  BaudRate = 38400 \n  StopBits = 1 \n  Parity   = none\n\n");
    

这是阅读的代码:

        char read_buffer[32];
        int bytes_read;

        while(true) 
            bytes_read = read(serialport.fd, &read_buffer, sizeof(read_buffer)); /* Read the data */

            printf("bytes read: %d", bytes_read);

            if (bytes_read < 0) 
                printf("Error reading: %s", strerror(errno));
            
            else if (bytes_read > 0) 
                //read_buffer[bytes_read] = '\0';

                printf("\n");
                printf("HEX:");
                for (int i=0; i<bytes_read; i++)    /*printing only the received characters*/
                    printf(" %02x",read_buffer[i]);
                
                printf("\n");
                printf("+----------------------------------+\n");


                /*#if defined(MODULE_REDIS) || defined(MODULE_ALL)
                    //redis.publish("channel:uart:ack", read_buffer);
                    redis.publish("channel:uart:ack", vectorUint8toHex(read_data).c_str());
                #endif*/
            

            std::this_thread::sleep_for(std::chrono::milliseconds(1));
        

当我发送消息 0x2401010203040506070809af23 时,它只显示 8 个字节。 (字节 0x030x04 与消息混淆)

OUTPUT:

bytes read: 0bytes read: 8
HEX: 05 06 07 08 09 af 23 0a
+----------------------------------+

但是当我发送 0x2401010200000506070809af23 时,它工作正常

OUTPUT:

bytes read: 14
HEX: 24 01 01 02 00 00 05 06 07 08 09 af 23 0a
+----------------------------------+

我做错了什么?还有一件事情。使用 Termite 必须打开“附加 LF”设置,否则我无法阅读消息,但会在我的消息中添加“0a”,这与串口的配置?

【问题讨论】:

这里清除的一些 tty 标志是从错误的变量中清除的。 ICANON 和其他几个是 c_lflag 中的标志,而不是 c_iflag。逐一检查所有这些标志,并验证它们是否应用于正确的变量。 bytes 0x03 and 0x04 是“ASCII 文本结束”和“ASCII 传输结束”。大概您的串行端口标志之一不会禁用对这些字符的解释。 是的,我就是这么想的,当我查阅ascii表时,我认为它现在可以工作了,我只是添加了“SerialPortSettings.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG); "现在可以了。我的错,还没有读过标志。它解决了这两个问题。谢谢 这能回答你的问题吗? Binary serial port read missing bytes in c 是的,我没有找到。不过我已经解决了,谢谢。 【参考方案1】:

好的,所以问题是二进制中的一些字节是 0x03 和 0x04,它们位于 ASCII“文本结束”和“传输结束”中。并且在配置中缺少这一行:

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

感谢cmets,我搜索了一些缺失的配置,找到了。

对于我当时没有找到的问题,还有另一篇帖子: Binary serial port read missing bytes in c

【讨论】:

以上是关于读取 uart 十六进制值会忽略某些字节/字符的主要内容,如果未能解决你的问题,请参考以下文章

打印存储为字符串的十六进制值会产生意外的输出

如何在 C++ 中读取由空格分隔的十六进制字节数据

在 Python 中将整数转换为 2 字节的十六进制值

如何根据十六进制值测试字节?

有没有办法使用 Java 流将十六进制字符串转换为字节?

如何从 BluetoothChat 的输入/输出流中读取/写入原始十六进制字节?