c
运行
void led_show(uint8_t led, uint8_t mode)
{
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET); // 开锁存器
if(mode) // 点亮指定LED:先全灭,再单独置低
{
// 一行代码实现:PC8~PC15全高(灭) + 指定引脚置低(亮)
GPIOC->ODR = (GPIOC->ODR & 0x00FF) | 0xFF00 & ~(GPIO_PIN_8 << (led-1));
}
else // 熄灭指定LED:仅把指定引脚置高
{
GPIOC->ODR = (GPIOC->ODR & 0x00FF) | (GPIOC->ODR & 0xFF00) | (GPIO_PIN_8 << (led-1));
}
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); // 关锁存器
}
我会把这两行核心代码拆成最易懂的步骤,结合二进制位运算原理和你的硬件场景(PC0~PC7 给 LCD、PC8~PC15 给 LED),让你彻底明白每一段的作用:
先明确基础规则(关键前提)
表格
| 位段 | 对应引脚 | 用途 | 操作规则 |
|---|---|---|---|
0x00FF | PC0~PC7 | LCD 数据口 | 任何时候不能修改,必须保留原始值 |
0xFF00 | PC8~PC15 | LED 控制口 | 仅操作这部分,控制 LED 亮灭 |
GPIOC->ODR是 16 位寄存器,二进制格式:[PC15~PC8] [PC7~PC0]- LED 亮 = 对应引脚低电平(0),LED 灭 = 对应引脚高电平(1)
第一行代码:点亮指定 LED(先全灭,再单独亮)
c
运行
GPIOC->ODR = (GPIOC->ODR & 0x00FF) | 0xFF00 & ~(GPIO_PIN_8 << (led-1));
拆解成 3 个核心步骤(以 LED2 为例,led=2):
步骤 1:GPIOC->ODR & 0x00FF → 锁定 LCD 引脚(PC0~PC7)
- 作用:提取并保留 PC0~PC7 的原始电平,完全不碰 LCD 数据口;
- 举例:假设当前 PC0~PC7 电平是
0101 0101(0x55),这部分结果就是0x0055; - 二进制示意:
plaintext
原始 GPIOC->ODR:[PC15~PC8: 1010 1010] [PC7~PC0: 0101 0101] & 0x00FF(二进制:0000 0000 1111 1111) = 结果:0000 0000 0101 0101(仅保留 PC0~PC7)
步骤 2:0xFF00 & ~(GPIO_PIN_8 << (led-1)) → 控制 LED 引脚(PC8~PC15)
- 先算
GPIO_PIN_8 << (led-1):LED2 对应GPIO_PIN_8 << 1 = 0x0200(二进制:0000 0010 0000 0000); - 再算
~0x0200:按位取反,结果是0xFDFF(二进制:1111 1101 1111 1111); - 最后算
0xFF00 & 0xFDFF:仅保留 PC8~PC15 部分,结果是0xFD00(二进制:1111 1101 0000 0000); - 含义:PC8~PC15 全部置 1(所有 LED 灭),仅 PC9(LED2)置 0(亮)。
步骤 3:| 合并两部分 → 最终赋值给 GPIOC->ODR
- 合并:
0x0055(LCD 部分) | 0xFD00(LED 部分) = 0xFD55; - 二进制结果:
1111 1101 0101 0101; - 效果:PC0~PC7 保持原样(LCD 正常),PC8~PC15 仅 PC9 为 0(LED2 亮),其余为 1(其他 LED 灭)。
第二行代码:熄灭指定 LED(仅灭目标,其他不变)
c
运行
GPIOC->ODR = (GPIOC->ODR & 0x00FF) | (GPIOC->ODR & 0xFF00) | (GPIO_PIN_8 << (led-1));
同样拆解 3 步(仍以 LED2 为例):
步骤 1:GPIOC->ODR & 0x00FF → 还是锁定 LCD 引脚
- 和第一行完全一样,保留 PC0~PC7 的原始电平(比如
0x0055)。
步骤 2:GPIOC->ODR & 0xFF00 → 保留现有 LED 状态
- 作用:提取当前 PC8~PC15 的电平(比如当前是
0xFD00,即 LED2 亮、其他灭); - 避免 “一熄灭就全灭”,只改目标 LED,其他 LED 保持原有状态。
步骤 3:| (GPIO_PIN_8 << (led-1)) → 仅把指定 LED 置 1(灭)
- LED2 对应
0x0200,和步骤 2 的0xFD00做|运算:0xFD00 | 0x0200 = 0xFF00; - 合并所有部分:
0x0055 | 0xFF00 = 0xFF55; - 二进制结果:
1111 1111 0101 0101; - 效果:PC0~PC7 不变(LCD 正常),PC9(LED2)置 1(灭),其他 LED 引脚保持原样。
核心总结(2 个关键点)
- 永远锁定 LCD 引脚:所有操作都以
(GPIOC->ODR & 0x00FF)开头,确保 PC0~PC7 不被修改,从根源避免和 LCD 冲突; - 精准操作 LED 引脚:
- 点亮:先全灭 LED(
0xFF00),再单独置低目标引脚(~led_pin); - 熄灭:仅置高目标引脚(
| led_pin),保留其他 LED 状态。
- 点亮:先全灭 LED(
这两行代码的优势是一行搞定所有逻辑,既高效(寄存器操作),又绝对安全(不碰 LCD 引脚),且仅修改 led_show 函数即可,完全符合你 “只动 LED 代码” 的需求。
4442

被折叠的 条评论
为什么被折叠?



