首页 > 解决方案 > 使用boost c++读取串口,我应该如何解码数据?

问题描述

我正在尝试创建一个从串行端口读取数据的简单应用程序。我有数据的结构,如下:

Byte Function   Format      Example Hex 
0    Header     ASCII Char  I       49  
1   Header      ASCII Char  W       57  
2   Header      ASCII Char  A       41  
3   Header      ASCII Char  P       50  
4   Header      ASCII Char  I       49  
5   Header      ASCII Char  x       78  
6   Version     uint8_t 1   1   
7   Pan         int32_t     0A  
8   Pan         int32_t     0B  
9   Pan         int32_t     0C  
10  Pan         int32_t 168496141   0D  
11  Tilt        int32_t     0A  
12  Tilt        int32_t     0B  
13  Tilt        int32_t     0C  
14  Tilt        int32_t 168496141   0D  
15  Roll        int32_t     0A  
16  Roll        int32_t     0B  
17  Roll        int32_t     0C  
18  Roll        int32_t 168496141   0D  
19  Jog A       int32_t     0A  
20  Jog A       int32_t     0B  
21  Jog A       int32_t     0C  
22  Jog A       int32_t 168496141   0D  
23  Jog B       int32_t     0A  
24  Jog B       int32_t     0B  
25  Jog B       int32_t     0C  
26  Jog B       int32_t 168496141   0D  
27  Focus       uint16_t            0A  
28  Focus       uint16_t    2571    0B  
29  Iris        uint16_t            0A  
30  Iris        uint16_t    2571    0B  
31  Zoom        uint16_t            0A  
32  Zoom        uint16_t    2571    0B  
33  To One      uint8_t (blip)  10  0A  
34  Reverse     uint8_t (blip)  10  0A  
35  Pause       uint8_t (blip)  10  0A  
36  Forward     uint8_t (blip)  10  0A  
37  Reserved                
38  Reserved                
39  Reserved                
40  Reserved                
41  Reserved                
42  Reserved                
43  Reserved                
44  Reserved                
45  Checksum    CheckSum8 Modulo 256            
46  Footer      ASCII Char  ;     3B    
47  Footer      ASCII Char  !     21    
48  Footer      ASCII Char  ;     3B    

数据为:UART:921600 Baud,8N2,Big-Endian

我正在像这样打开端口,并读取数据:

#include <iostream>
#include <boost/asio.hpp> 
using namespace std;
using namespace boost;


int main(int argc, char* argv[])
{
    asio::io_service io;
    asio::serial_port port(io);

    port.open("COM14");
    port.set_option(asio::serial_port_base::baud_rate(921600));

    char c;
    std::string rsp;
    
    while (c != ';')
    {
        asio::read(port, asio::buffer(&c, 1));
        rsp += c;
    }

    std::cout << rsp << std::endl;

    port.close();

    std::cin.get();
}

这给了我字符串:

IWVPx  :ã                               {;

显然我做错了,我认为是因为我将数据读取为char. 读取串口数据并将其转换为可读数据的正确方法是什么?

标签: c++boostserial-port

解决方案


您可以使用提供的结构来解析数据。您看到的空格很可能是由于二进制数据的 ASCII 解释。这是二进制数据的线索是作者指定了字节位置。这是我解析这些数据的方法。

首先,创建一个与您要解析的数据匹配的结构:

struct Data
{
    char header[5];
    uint8_t ver;
    int32_t pan;
    int32_t tilt;
    int32_t roll;
    int32_t joga;
    int32_t jogb;
    uint16_t focus;
    uint16_t iris;
    uint16_t zoom;
    uint8_t toOne;
    uint8_t reverse;
    uint8_t pause;
    uint8_t forward;
    uint8_t reserved[8];
    uint8_t checksum;
    char footer[3];
}__attribute__((packed));

接下来,读入所有数据。有很多仪器远远超出了描述如何实际解析这些数据的范围,所以我将把它排除在外。在这里,我指的是确保数据包正确对齐的方法,获取第二个分号,检查数据缓冲区的大小是否与预期结构的大小相同。其中一些只有在发出的数据包是自动发送而不是请求时才起作用。

填充缓冲区后,确保它与数据结构的大小相同,它很简单:

Data data;
memcpy( &data, buffer, sizeof(data) );

然后可以访问数据,就好像它是结构的一部分一样。请注意,此解决方案假定字节顺序在机器之间是一致的。如果不是,您可能必须执行一些字节反转。

最终结果可能如下所示:

int main(int argc, char* argv[])
{
    asio::io_service io;
    asio::serial_port port(io);

    port.open("COM14");
    port.set_option(asio::serial_port_base::baud_rate(921600));
        
    uint8_t obuf[256]; // arbitrary size, larger than largest expected buffer   

    // perform packet alignment here

    asio::read(port, asio::buffer(obuf, sizeof(Data)));

    Data d = {};
    memcpy( &d, obuf, sizeof(d) );

    // if your endianness is different than the data sent, fix it here.

    std::cin.get();
}

推荐阅读