嵌入式基础-修改寄存器的位操作方法
·
总体目标
在嵌入式开发中,寄存器是 32/16/8 位宽的整数,我们经常需要:
- 只清零某几个连续位(其他位不变)
- 对这几个位写入新值(其他位不变)
- 对单个位取反(其他位不变)
这三个操作是 位操作(bit manipulation) 的核心技巧,广泛用于驱动开发、硬件配置等。
把变量的某几个连续位清零
场景假设
-
变量
a是 8 位(为便于演示) -
把每 2 位 分成一组:
bit7 bit6 | bit5 bit4 | bit3 bit2 | bit1 bit0 组3 | 组2 | 组1 | 组0 -
目标:清零第1组(bit3、bit2)
核心公式
a &= ~(mask);
mask是 要清零的那些位为 1,其他位为 0 的掩码~mask就是 要清零的位为 0,其他位为 1- 与
a按位与 → 要清零的位变成 0,其他位保留原值
构造 mask:(3 << 2*组号)
| 符号 | 含义 |
|---|---|
3 |
二进制 11b,表示组内 2 位全为 1 |
2 |
每组位数 = 2 |
组号 |
从 0 开始计数 |
示例:清零第1组(组号=1)
mask = 3 << (2 * 1); // 3 << 2
计算过程:
3 = 00000011 b
<<2 = 00001100 b → bit3、bit2 为 1
所以:
~(3 << 2*1) = ~00001100 b = 11110011 b
完整操作
a &= ~(3 << 2*1);
举例验证
a = 10011111 b // 原始值
a = 1001 1111
~mask = 1111 0011
& 运算后 a = 1001 0011
bit3、bit2 被清零,其他位不变!
通用公式总结
// 清零第 n 组(每组 k 位)
a &= ~(( (1<<k) - 1 ) << (k * n));
等价写法(更清晰):
#define CLR_BITS(a, n, k) ((a) &= ~(((1<<(k))-1) << ((k)*(n))))
n:组号(从 0 开始)k:每组位数(1<<k)-1:生成 k 个 1(如 k=2 → 3)
其他例子
| 目标 | 代码 |
|---|---|
| 清零第2组(bit5、bit4) | a &= ~(3 << 2*2); |
| 清零第0组(bit1、bit0) | a &= ~(3 << 0); |
| 每组4位,清零第1组(bit7~bit4) | a &= ~((15) << 4*1); |
对变量的某几位进行赋值
前提
已经 清零了目标位,现在可以安全写入新值。
方法:按位或 |= + 移位
a |= (value << (k * n));
value:要写入的值(不超过 k 位)k * n:目标组的起始位偏移
示例:设置第2组为 01b
// 假设 a 已经清零了 bit5、bit4
a |= (1 << (2*2)); // 1 << 4
计算:
1 << 4 = 00010000 b
所以 bit4 置 1,bit5 仍为 0 → 写入 01b
完整前后对比
a = 1000 0011 b
// 清零第2组
a &= ~(3 << 4); // a = 1000 0011 → 1000 0011 (bit5,4=00)
// 写入 01
a |= (1 << 4); // a = 1001 0011
成功!只改了 bit5、bit4
通用赋值宏
#define SET_BITS(a, n, k, val) \
do { \
(a) &= ~(((1<<(k))-1) << ((k)*(n))); \
(a) |= (((val) & ((1<<(k))-1)) << ((k)*(n))); \
} while(0)
用法:
SET_BITS(a, 2, 2, 1); // 第2组写 01b
SET_BITS(a, 1, 2, 3); // 第1组写 11b
对变量的某位取反
目标
将 某一位 翻转(0→1,1→0),其他位不变
方法:异或 ^= 1<<pos
a ^= (1 << pos);
原理:异或是 相同为0,相异为1
| 原位 | 1<<pos | 结果 |
|---|---|---|
| 0 | 1 | 1 |
| 1 | 1 | 0 |
示例:翻转 bit6
a = 1001 0011 b
a ^= (1 << 6); // 1<<6 = 01000000 b
a = 1001 0011
mask = 0100 0000
^ 结果 = 1101 0011
bit6 从 0 → 1,其他位不变
通用取反宏
#define FLIP_BIT(a, pos) ((a) ^= (1 << (pos)))
总结表格
| 操作 | 代码模板 | 说明 |
|---|---|---|
| 清零连续 k 位(第 n 组) | a &= ~(((1<<k)-1) << (k*n)); |
构造掩码后取反 |
| 设置连续 k 位为 val | a |= (val << (k*n)); |
需先清零 |
| 取反第 pos 位 | a ^= (1 << pos); |
异或翻转 |
实际应用场景
// 配置 UART 波特率寄存器
UART_BAUD = (UART_BAUD & ~0xFF) | 0x68; // 设置低8位
// 使能 GPIO 输出
GPIO_CRH &= ~(0xF << 4); // 清零 pin10 模式位
GPIO_CRH |= (0x3 << 4); // 设置为输出
// 翻转 LED
LED_PIN ^= (1 << 5);
推荐练习
- 写一个函数:
void set_bits(uint32_t *reg, int start, int len, uint32_t val) - 实现
toggle_bit(uint8_t *reg, int pos) - 用宏封装上述操作
更多推荐



所有评论(0)