协议格式:
详细计算磁场如下:
3字节数据的格式为有符号整型数,数据为补码格式,最高位为符号位。需要先将补码格式的数据转化为10进制的实际值,方法如下:
当数据小于时为正数,实际值为本身;
当数据大于等于时为负数,实际值为本身值减去;
例如:X通道数据为0x63FDC2 ,转化为十进制为6553026,小于8388607,所以它的实际值为它本身:6553026
又如:Y通道数据为0xDC54B2,转化为十进制为14439602,大于8388607,所以它的值为负数,实际值应为本身值减去;即:14439602 - = -2337614;
假设计算得到的数据实际值为data,最终磁场值为Mag,它们的关系为:
(单位:nT)
其中:Vref为参考电压,本设备参考电压为2.5V;
Kc为磁传感器的磁电系数Kc = 40nT/mV;
计算结果为负数时,说明磁场方向与参考方向相反。
#include <iostream>
#include <tuple>
#include <cstring>
#include <cstdint>
#include <memory>
#include <array>
// 定义单包内数据段个数
constexpr size_t data_one_package_num = 20;
struct data_receive_raw {
[[maybe_unused]] uint8_t _head[2]; // 000C头部标志
uint8_t _x_channel[3]; // x通道磁场数据
[[maybe_unused]] uint8_t _x_channel_count; // x通道计数
uint8_t _y_channel[3]; // y通道磁场数据
[[maybe_unused]] uint8_t _y_channel_count; // y通道计数
uint8_t _z_channel[3]; // z通道磁场数据
[[maybe_unused]] uint8_t _z_channel_count; // z通道计数
[[maybe_unused]] uint8_t _padding[6]; // CRC校验和,视作字节填充位
};
// 计算单包字节偏移量
constexpr size_t bytes_offset = sizeof(data_receive_raw);
// 编译期计算偏移量数组
constexpr std::array<size_t, data_one_package_num> calculate_offsets() {
std::array<size_t, data_one_package_num> offsets{};
for (size_t i = 0; i < data_one_package_num; ++i) {
offsets[i] = 6 + i * bytes_offset; // 6为包头丢弃部分
}
return offsets;
}
// 三通道磁场数据解算
std::tuple<double, double, double> cal_magnetic_nT(const data_receive_raw &raw_data) {
// 磁传感器磁电系数
constexpr static int Kc = 40;
// 参考电压
constexpr static float Vref = 2.5;
// 量化台阶
constexpr static int zoom = (1 << 23) - 1;
// 整数回绕值
constexpr static int odd = 1 << 24;
auto convert_channel = [](const uint8_t* channel) {
uint32_t data_raw = (channel[2] << 16) | (channel[1] << 8) | channel[0];
int data = static_cast<int>(data_raw);
data = (data >= zoom) ? data - odd : data;
return static_cast<double>(data) * (Vref / zoom) * 1000 * Kc;
};
double mag_x = convert_channel(raw_data._x_channel);
double mag_y = convert_channel(raw_data._y_channel);
double mag_z = convert_channel(raw_data._z_channel);
return std::make_tuple(mag_x, mag_y, mag_z);
}
int main() {
uint8_t data[] = {70, 77, 144, 1, 116, 54, 0, 12, 39, 31, 247, 88, 23,
71, 22, 89, 156, 250, 58, 90, 130, 0, 0, 84, 117, 54,
0, 12, 0, 35, 247, 88, 54, 73, 22, 89, 197, 251, 58,
90, 119, 0, 0, 84, 118, 54, 0, 12, 160, 35, 247, 88,
45, 71, 22, 89, 156, 255, 58, 90, 72, 255, 255, 84, 119,
54, 0, 12, 183, 32, 247, 88, 251, 68, 22, 89, 94, 254,
58, 90, 30, 0, 0, 84, 120, 54, 0, 12, 190, 33, 247,
88, 51, 70, 22, 89, 54, 251, 58, 90, 136, 0, 0, 84,
121, 54, 0, 12, 235, 37, 247, 88, 157, 72, 22, 89, 202,
252, 58, 90, 135, 0, 0, 84, 122, 54, 0, 12, 14, 38,
247, 88, 86, 72, 22, 89, 219, 255, 58, 90, 67, 255, 255,
84, 123, 54, 0, 12, 35, 35, 247, 88, 119, 70, 22, 89,
99, 254, 58, 90, 38, 0, 0, 84, 124, 54, 0, 12, 174,
36, 247, 88, 31, 70, 22, 89, 222, 250, 58, 90, 126, 0,
0, 84, 125, 54, 0, 12, 85, 32, 247, 88, 28, 70, 22,
89, 102, 253, 58, 90, 245, 0, 0, 84, 126, 54, 0, 12,
95, 33, 247, 88, 169, 73, 22, 89, 5, 253, 58, 90, 141,
0, 0, 84, 127, 54, 0, 12, 83, 36, 247, 88, 163, 73,
22, 89, 26, 1, 59, 90, 231, 254, 255, 84, 128, 54, 0,
12, 94, 35, 247, 88, 235, 69, 22, 89, 196, 1, 59, 90,
42, 0, 0, 84, 129, 54, 0, 12, 83, 32, 247, 88, 60,
70, 22, 89, 217, 253, 58, 90, 210, 0, 0, 84, 130, 54,
0, 12, 95, 34, 247, 88, 204, 72, 22, 89, 248, 253, 58,
90, 125, 0, 0, 84, 131, 54, 0, 12, 27, 37, 247, 88,
52, 73, 22, 89, 254, 0, 59, 90, 240, 254, 255, 84, 132,
54, 0, 12, 195, 35, 247, 88, 32, 71, 22, 89, 130, 0,
59, 90, 192, 255, 255, 84, 133, 54, 0, 12, 131, 32, 247,
88, 192, 70, 22, 89, 25, 253, 58, 90, 102, 1, 0, 84,
134, 54, 0, 12, 210, 33, 247, 88, 234, 72, 22, 89, 78,
253, 58, 90, 142, 0, 0, 84, 135, 54, 0, 12, 56, 36,
247, 88, 153, 73, 22, 89, 202, 0, 59, 90, 221, 254, 255,
84, 13, 10, 13, 10, 70, 71, 64, 0, 181, 98, 1, 2,
28, 0, 232, 140, 23, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 152, 189, 255, 255, 255, 255, 255, 255,
0, 102, 134, 223, 196, 79, 181, 98, 1, 33, 20, 0, 232,
140, 23, 0, 255, 255, 255, 255, 0, 132, 215, 23, 228, 7,
3, 22, 0, 25, 43, 240, 103, 242, 13, 10, 13, 10, 170,
169, 13, 10, 72, 83, 224, 1};
constexpr auto offsets = calculate_offsets();
auto one_package = std::make_unique<data_receive_raw[]>(data_one_package_num);
for (size_t i = 0; i < data_one_package_num; ++i) {
std::memcpy(&one_package[i], data + offsets[i], bytes_offset);
}
for (size_t i = 0; i < data_one_package_num; ++i) {
auto [x, y, z] = cal_magnetic_nT(one_package[i]);
std::cout << " X channel = " << x << " Y channel = " << y << " Z channel = " << z << std::endl;
}
return 0;
}