我混淆的按位运算
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 0
或 1
(布尔结果),而是将位保留在原来的位置。乘法会将它们移动到位置 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 位),但样式很好。它记录了您正在使用的位。如果该字段恰好不是高位,无论如何你都会需要它,所以掩码使它更通用(它仍然需要连续的位,不连续的编号会使它变得不那么直接)。
嗨,我正在研究 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
,因此编译器无法优化访问。 - 使用
&
进行掩码不会 return0
或1
(布尔结果),而是将位保留在原来的位置。乘法会将它们移动到位置 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 位),但样式很好。它记录了您正在使用的位。如果该字段恰好不是高位,无论如何你都会需要它,所以掩码使它更通用(它仍然需要连续的位,不连续的编号会使它变得不那么直接)。