c - 将数字映射到 C 中的位位置

标签 c serial-communication bit-fields

我正在开发一个在 Atmel AT90CAN128 上运行的程序。连接到该 Controller 的有 40 个设备,每个设备都有一个状态(开/关)。因为我需要通过串行通信向 PC 报告每个设备的状态,所以我有 40 位,用于定义设备是打开还是关闭。此外,PC 可以打开或关闭任何此类设备。

因此,我的第一次尝试是创建以下结构:

typedef struct {
     unsigned char length;      //!< Data Length
     unsigned data_type;        //!< Data type
     unsigned char data[5];     //!< CAN data array 5 * 8 = 40 bits
} SERIAL_packet;

问题在于 PC 会发送一个 unsigned char address 告诉我设备打开/关闭,因此访问与该 address 编号对应的位原来是相当复杂...

所以我开始寻找选项,我偶然发现了 C99 _Bool 类型。我想,太好了,所以现在我只需创建一个 _Bool data[40] 并且我可以通过索引我的 data 来访问 address 位大批。事实证明,在 C(或 C++)中,内存映射需要一个完整的字节来对其进行寻址。因此,即使我声明了一个 _Bool,该 _Bool 的大小也将是 8 位,这是一个问题(它需要尽可能快,所以我发送的位越多它变得更慢,并且 PC 将 指定 40 位)并且通信效率不高。所以我开始研究位域,并尝试了以下方法:

typedef struct {
    unsigned char length;   //!< Data Length
    unsigned data_type;     //!< Data type
    arrayData data[40]; //!< Data array 5 bytes == 40 bits
} SERIAL_packet;

typedef struct {
    unsigned char aux : 1;
} arrayData;

我想知道,这是否会将 data[40] 映射到一个大小为 40 位(5 字节)的后续内存块?

如果没有,我是否缺少任何明显的解决方案?这似乎不是一件非常复杂的事情(如果设备少于 32 个,我可以使用 int 并通过位掩码访问会简单得多)。

最佳答案

假设您返回的地址在 0 - 39 范围内并且 char 有 8 位,您可以将 data 数组视为位数组:

| data[0]                       | data[1]                           ...
-----------------------------------------------------------------
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12| 13| 14| 15|
-----------------------------------------------------------------

设置位i:

packet.data[i/8] |= (1 << (i%8));

要清除位 i:

packet.data[i/8] &= (1 << (i%8)) ^ 0xff;

读取位i:

 int flag = (packet.data[i/8] & (1 << (i%8)) != 0;

关于c - 将数字映射到 C 中的位位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52742756/

相关文章:

c - 为什么这些构造使用前后递增的未定义行为?

比较两个结构文件(Linux 内核)

C++(以某种方式)将结构限制为父 union 大小

c - 我应该如何转换 14 位位域的字节序?

c - 如何转换一个数字的数字?

带有 switch/case 语句的 C 编译器指令?

java - 使用多个端口通过两对独立的 Arducam 和 arduino Uno 发送图像

serial-communication - CAN总线协议(protocol)实现

iOS 到 FTDI 芯片通信

c++ - 什么时候值得使用位域?