嵌入式系统编程中位掩码与位操作正确使用指南
-
位掩码宏定义:
使用位掩码宏:通常,硬件抽象层(HAL)或标准外设库会提供位掩码宏,这些宏定义了寄存器中每个位的掩码。使用这些宏可以避免直接使用位位置数字,使代码更易读和维护。
使用宏定义来创建一个位掩码,该掩码用于操作寄存器的特定位。例如,如果我们想操作一个32位寄存器中的第2位:#define ENABLE_MASK (1UL<< 2) // 1UL表示无符号长整型,保证位移操作不会引入符号位
-
检查特定位是否设置:
位与操作(AND):使用&操作符来检查特定位的状态。例如,if ((reg & MASK) != 0) 可以检查reg中的特定位是否被设置。
使用位与操作(AND)来检查寄存器中的特定位是否被设置:if ((ControlRegister & ENABLE_MASK) != 0) { // ENABLE位被设置了 }
分析:ENABLE_MASK的第2位为1,其他为0,ControlRegister和ENABLE_MASK做与操作,根据与0为0,与1为原始值,可知结果为:ControlRegister(被掩码的)第二位(掩码第2位为1)保留,其他为0.
-
设置特定位:
位或操作(OR):使用|操作符来设置特定位。例如,reg |= MASK 将设置reg中的特定位。
使用位或操作(OR)来设置寄存器中的特定位:ControlRegister |= ENABLE_MASK; // 设置ENABLE位
分析:ENABLE_MASK的第2位为1,其他为0,ControlRegister和ENABLE_MASK做或操作,根据或1为1,与0为原始值,可知结果为:ControlRegister(被掩码的)第二位(第二位值为1)变为1,其他位保留。
-
清除特定位:
位清零操作(AND NOT):使用&操作符与位掩码的补码来清除特定位。例如,reg &= ~MASK 将清除reg中的特定位。
使用位与操作和掩码的补码来清除寄存器中的特定位:ControlRegister &= ~ENABLE_MASK; // 清除ENABLE位
分析:
~ENABLE_MASK
的第2位为0
,其他为1,ControlRegister和~ENABLE_MASK做或操作,根据或0为0,与1为原始值,可知结果为:ControlRegister(被掩码的)第二位(第二位值为0)清0,其他位不变。 -
切换特定位的状态:
位异或操作(XOR):使用^操作符来切换特定位的状态。例如,reg ^= MASK 将在reg中的特定位上切换状态。
使用位异或操作(XOR)来切换寄存器中特定位的状态:ControlRegister ^= ENABLE_MASK; // 切换ENABLE位
分析:
ENABLE_MASK
的第2位为1
,其他位为0,ControlRegister和ENABLE_MASK做异或操作,根据异或1取反,与0为原始值,可知结果为:ControlRegister(被掩码的)第二位(第二位值为1)取反,其他位不变。 -
位字段提取:
如果需要从寄存器中提取一个字段,可以使用位掩码和右移操作。例如,(field & MASK) >> SHIFT 可以从field中提取特定的位字段。
如果需要从寄存器中提取一个字段,可以使用位与操作和位移操作。例如,提取一个8位宽的字段:#define VALUE_MASK (0xFF << 16) // 1111111100000000 #define VALUE_SHIFT 16 uint8_t value = (ControlRegister & VALUE_MASK) >> VALUE_SHIFT;
-
位左移和右移:
位左移和右移:使用<<和>>操作符来移动位字段。例如,value << SHIFT 将value中的位向左移动SHIFT位。
使用位移操作来移动位字段。例如,将一个值左移3位:uint32_t data = 0x1; // 00000001 data <<= 3; // 00000100
如果需要将
data
右移3位:data >>= 3; // 00000001
-
避免硬编码位位置:
使用宏定义来避免硬编码位位置,提高代码的可读性和可维护性:#define SET_MODE(FunctionSelect, mode) (FunctionSelect = (mode) ? MODE_MASK : 0)
使用这个宏来设置模式:
SET_MODE(FunctionSelect, 1); // 设置MODE位
-
位域结构使用:
使用C语言的位域来定义寄存器结构,直观地访问和修改特定位:
typedef struct {
uint32_t reserved : 16; // 保留16位
uint32_t MODE : 1; // 模式位
uint32_t ENABLE : 1; // 使能位
uint32_t reserved2 : 14; // 另外保留14位
} ControlRegisterType;
ControlRegisterType ControlRegister;
ControlRegister.ENABLE = 1; // 设置ENABLE位
这些示例和描述展示了如何在嵌入式系统编程中使用位掩码和位操作来访问和修改寄存器的特定位。遵循这些示例和最佳实践可以帮助你编写更清晰、更有效的嵌入式代码。
总结:
& 遇0为0 遇1为原始
| 遇1为1 遇0为原始
^ 遇1为1取反 遇0为原始
mask的mask位为1,其他位为0
a&mask | 保留mask位,其他位置0 | 筛选器,指定位通过,其他位清零 :提取指定位 |
---|---|---|
a & ~mask | mask位置0,其他为保留 | 通道反向筛选器:指定位无法通过被清0,其他位通过:请除指定位 |
a | mask | mask位置1,其他为保留 | 画家指定位画1:指定位置1 |
a | ~mask | mask位保留,其他为置1 | |
a ^ mask | 取反mask位,其他为保留 | 指定位取反 |
a ^ ~mask | mask位保留,其他为取反 |
作者:物语系列