解决蓝桥杯嵌入式中lcd与led引脚冲突的问题

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),让你彻底明白每一段的作用:

先明确基础规则(关键前提)

表格

位段对应引脚用途操作规则
0x00FFPC0~PC7LCD 数据口任何时候不能修改,必须保留原始值
0xFF00PC8~PC15LED 控制口仅操作这部分,控制 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 个关键点)

  1. 永远锁定 LCD 引脚:所有操作都以 (GPIOC->ODR & 0x00FF) 开头,确保 PC0~PC7 不被修改,从根源避免和 LCD 冲突;
  2. 精准操作 LED 引脚
    • 点亮:先全灭 LED(0xFF00),再单独置低目标引脚(~led_pin);
    • 熄灭:仅置高目标引脚(| led_pin),保留其他 LED 状态。

这两行代码的优势是一行搞定所有逻辑,既高效(寄存器操作),又绝对安全(不碰 LCD 引脚),且仅修改 led_show 函数即可,完全符合你 “只动 LED 代码” 的需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值