我混淆的按位运算

A bitwise operation that im confused with

嗨,我正在研究 stm32f4。我需要读取 8 针并在将二进制转换为十进制后对值求和。例如8位的值是000000110,我的CardID一定是6。我用过这个,但可以有更好的方法:

CardID = (GPIOD->IDR & GPIO_Pin_8) + 
         (GPIOD->IDR & GPIO_Pin_9)*2 + 
         (GPIOD->IDR & GPIO_Pin_10)*4 + 
         (GPIOD->IDR & GPIO_Pin_11)*8 + 
         (GPIOD->IDR & GPIO_Pin_12)*16 + 
         (GPIOD->IDR & GPIO_Pin_13)*32 + 
         (GPIOD->IDR & GPIO_Pin_14)*64 + 
         (GPIOD->IDR & GPIO_Pin_15)*128;

提示:我知道GPIO_Pin_8,GPIO_Pin_9.....GPIO_Pin_15.

的值

我们可以对多个组合进行AND运算吗?

#define GPIO_Pin_8                 ((uint16_t)0x0100)  /* Pin 8 selected */
#define GPIO_Pin_9                 ((uint16_t)0x0200)  /* Pin 9 selected */
#define GPIO_Pin_10                ((uint16_t)0x0400)  /* Pin 10 selected */
#define GPIO_Pin_11                ((uint16_t)0x0800)  /* Pin 11 selected */
#define GPIO_Pin_12                ((uint16_t)0x1000)  /* Pin 12 selected */
#define GPIO_Pin_13                ((uint16_t)0x2000)  /* Pin 13 selected */
#define GPIO_Pin_14                ((uint16_t)0x4000)  /* Pin 14 selected */
#define GPIO_Pin_15                ((uint16_t)0x8000)  /* Pin 15 selected */

在我看来你只是想要这样的东西:

#define GPIO_PINS      ((uint16_t)0xFF00)
#define GPIO_OFFSET    (8)

// ...

CardID = (GPIOD->IDR & GPIO_PINS) >> GPIO_OFFSET;

只需获取完整的 GPIOD->IDR 然后调整它的移位和掩码以获得等于转换值的 16 位 int:

CardID = (GPIOD->IDR >> 8) & 0x00ff;

您的卡ID在GPIOD->IDR的高8位。

这可能是错误的:

  • 您不应该多次读取输入数据寄存器以获得相应的值。寄存器已定义 volatile,因此编译器无法优化访问。
  • 使用 & 进行掩码不会 return 01 (布尔结果),而是将位保留在原来的位置。乘法会将它们移动到位置 15..22,而大概它们应该移动到位 0..7.

由于这些是连续的位,正确的方法是:

// must be consecutive bits:
#define GPIO_CARD_ID_MASK  0xFF00U
#define GPIO_CARD_ID_SHIFT 8

CardID = (GPIOD->IDR & GPIO_CARD_ID_MASK) >> GPIO_CARD_ID_SHIFT;

这只读取寄存器一次,从而避免了竞争条件,并且 - 在这里可能更重要 - 节省了许多时钟周期。它还(几乎)通过使用正确命名的宏进行自我解释,因此更易于维护。

注意:对于给定的 architecture/MCU,掩码实际上不是必需的(这些是 uint16_t 的高 8 位),但样式很好。它记录了您正在使用的位。如果该字段恰好不是高位,无论如何你都会需要它,所以掩码使它更通用(它仍然需要连续的位,不连续的编号会使它变得不那么直接)。