c++ - 使用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
. 读取串口数据并将其转换为可读数据的正确方法是什么?
解决方案
您可以使用提供的结构来解析数据。您看到的空格很可能是由于二进制数据的 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();
}
推荐阅读
- python - 如何删除 Python distutils 共享库(动态模块)
- javascript - jsGrid 未显示在 Vue-cli 脚手架应用程序中
- vue.js - 使用 createElement 和 render 函数从 .blade.php 文件将道具传递给 vue 实例
- python - 查找另一列中给定范围的列中的最大值
- python - Python中将非常大的数字转换为无穷大的问题
- javascript - 获取从 textarea 内的文本或输入文本中选择的字符数
- postgresql - 对多列进行续集检查约束
- react-native - 我想使用进度条在本机反应中上传数据
- arrays - VBA 将 1 列数组更改为一维数组
- firebird - 更新行时是否更新游标变量?