我可以将unit16_t转换为“uint12_t”吗?

问题描述 投票:0回答:2

我有一个问题,我需要将两个 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 位。

c++ casting integer can-bus
2个回答
1
投票

这通常可以通过使用足够大的 8 位倍数类型来解决。因此,在您的情况下,您将使用

uint16_t
并忽略前 4 位。

但是,如果您实际上需要一个由多个 12 位相邻块组成的位字段,则可以使用

uint8_t
数组来代替。示例(假设大端):

uint8_t can_data[8] =
{
    (data0 & 0xFF0) >> 4, 
    (data0 & 0x00F) << 4 | (data1 & 0xF00) >> 8, 
    (data1 & 0x0FF), 
    ...
};

即:

  • data0 位 11-4 进入第一个字节位 7-0
  • data0 位 3-0 到第二个字节位 7-4
  • data1 位 11-8 转换为第二个字节位 3-0
  • 数据 1 位 7-0 进入第三字节位 7-0

...等等。正如您所知,这是一种非常麻烦的格式。这是一种空间优化,但代价是可读性和性能。因此,除非万不得已,否则我们通常会避免使用这种格式。当我设计一个包含多个 12 位模拟值的紧凑型无线协议时,我实际上在现实世界中使用了非常相似的东西。 在 CAN 领域,值得注意的是 CANopen 决定将所有模拟值设为 16 位,尽管实际上并没有多少设备使用这种高分辨率。不过,它使他们免于像上面的位打包练习那样大惊小怪,因此这可能是对行业标准的正确呼吁。


0
投票
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 } };
}

© www.soinside.com 2019 - 2024. All rights reserved.