我有一个问题,我需要将两个 uint16_t 数字压缩到 2 字节空间中。 我知道我丢失了信息,但高于 12 位的数字与我无关。 前 12 位为一个数,后 12 位为秒数。 CAN 消息需要输出。 有谁知道如何用 C++ 解决这个问题吗?
这是我的第一次尝试,但它产生了预期的两个字节大小的数字。
byte OUT[2];
union OUT_byte {
byte bufferOUT[2];
uint16_t OUT_array_int;
} OUTb;
OUTb.OUT_array_int = (double)(round(INPUT)); // casting from an double originaly
for (int i = 0; i < sizeof(OUTb.bufferOUT); i++) {
OUT[i] = OUTb.bufferOUT[i];
}
这给了我两个字节一个包含我的信息的数组。 现在我需要两个数字压缩为 3 字节中的 12 位。
这通常可以通过使用足够大的 8 位倍数类型来解决。因此,在您的情况下,您将使用
uint16_t
并忽略前 4 位。
但是,如果您实际上需要一个由多个 12 位相邻块组成的位字段,则可以使用
uint8_t
数组来代替。示例(假设大端):
uint8_t can_data[8] =
{
(data0 & 0xFF0) >> 4,
(data0 & 0x00F) << 4 | (data1 & 0xF00) >> 8,
(data1 & 0x0FF),
...
};
即:
...等等。正如您所知,这是一种非常麻烦的格式。这是一种空间优化,但代价是可读性和性能。因此,除非万不得已,否则我们通常会避免使用这种格式。当我设计一个包含多个 12 位模拟值的紧凑型无线协议时,我实际上在现实世界中使用了非常相似的东西。 在 CAN 领域,值得注意的是 CANopen 决定将所有模拟值设为 16 位,尽管实际上并没有多少设备使用这种高分辨率。不过,它使他们免于像上面的位打包练习那样大惊小怪,因此这可能是对行业标准的正确呼吁。
std::uint16_t
值打包为 24 位数据。
struct input
{
std::uint16_t a, b;
}
struct output
{
std::uint8_t array[3];
}
output pack2into3(input vals)
{
// Assume bit 0 is the most significant bit
int first = (vals.a >> 4) & 0xFF; // Shift down 4 and mask in the lowest 8 bits of a (bit 4-12).
int second_high = vals.a & 0x0F; // Mask in the lowest 4 bits of a (bit 12-16).
int second low = (vals.b >> 8) & 0x0F; // Shift down 8 and mask the lowest 4 bits of b (bit 4-8).
int second = (second_high << 4) | second_low; // Or together the bits from a and b which makes up the second octet.
int third = vals.b & 0xFF; // Mask in the lowest 8 bits of b (bit 8-16).
return { { first, second, third } };
}