3-1 独立按键控制LED状态(SDCC + Notepad++ + STC-ISP/普中ISP)

问题分析

上节实现了按下按键LED亮,松开按键LED 灭,这节需要实现的是第一次按下按键LED会亮,第二次按下按键LED会灭,如此循环。

像要实现这个功能,可以先读取灯的值,当按键按下后,如果是高电平就设置为低电平,如果是低电平就设置为高电平,即进行取反。

按键抖动

通过上述思路会有一个问题,独立键盘的按键按下和松开时会有波动,如果不消除抖动,直接对LED进行取反,那么就会一直亮灭。如下图,按下和松开的时候会有10ms左右的抖动,如果在20s后即抖动之后再进行取反,则跟预期效果一致。

txt 复制代码
理想情况(无抖动):
高 ─────┐         ┌─────
        │         │
低      └─────────┘

实际情况(有抖动):
高 ──┐ ┌┐ ┌───┐   ┌─┐ ┌─────
     │ ││ │   │   │ │ │
低   └─┘└─┘   └───┘ └─┘
     ↑         ↑
   按下抖动   松开抖动

完整代码

sdcc -mmcs51 --model-small --iram-size 256 --xram-size 0 --code-size 8192 .\key_led_32.c

c 复制代码
#include <mcs51/8051.h>

void DelayXms(unsigned int xms)
{
    unsigned char i, j;
    if(xms == 0) return;
    do {
        i = 2;
        j = 239;
        do {
            while (--j);
        } while (--i);
    } while (--xms);
}

void main(void)
{
    while(1)
    {
        if(P3_1 == 0)           // 按键按下
        {
            DelayXms(20);       // 消抖
            while(P3_1 == 0);   // 等待松手
            DelayXms(20);       // 消抖
            P2_0 = !P2_0;       // 按下为高电平灯灭,第一次按下灯亮,第二次灯灭。
        }
    }
}

直接~P2_0没有效果

为什么 ~ 在 SDCC 里"失灵"了?

关键在于 "整数提升"(Integer Promotion) 和 "截断"(Truncation) 这两个标准 C 的行为:

  • 取值:当 P2_0 的值是 1(高电平)时,参与运算前会被提升为 int 类型的 0x0001。
  • 取反:~0x0001 得到 0xFFFE。
  • 截断:因为 P2_0 只能存 0 或 1,0xFFFE 被截断后,非零值变成了 1(真值)。

最终结果就是 1 取反还是 1,P2_0 永远被置为高电平,你自然看不到它翻转。所以 SDCC 会警告你,但不报错,因为从 C 标准看这个行为是"合法"的。

正确的做法是用 ! 或 ^= 1

在 SDCC 中操作 51 单片机的位变量,应该使用逻辑非 ! 或异或 ^=,它们不会触发整数提升,能精确地翻转位状态。

操作符 代码示例 效果
逻辑非 ! P2_0 = !P2_0; 推荐,清晰直观,翻转电平
异或赋值 ^= P2_0 ^= 1; 同样有效,更接近底层翻转的意图
按位取反 ~ P2_0 = ~P2_0; 避免使用,会导致引脚被强制置高

效果展示

相关推荐
xunyan62342 小时前
3-3 独立按键控制LED显示二进制(SDCC + Notepad++ + STC-ISP/普中ISP)
接口隔离原则
一木 之林20 小时前
微信小程序开发全攻略·文章版|01 入门与环境搭建
人工智能·学习·计算机视觉·微信小程序·notepad++
xunyan623421 小时前
51 单片机LED流水灯(SDCC + Notepad++ + STC-ISP/普中ISP)
单片机·嵌入式硬件·接口隔离原则
雪雪爱冲浪2 天前
2026 年网络爬虫领域的Puppeteer vs. Playwright
爬虫·网络协议·测试工具·接口隔离原则
DolitD5 天前
3D应用多实例并发中的GPU隔离技术路径分析
容器·gru·接口隔离原则
xunyan62345 天前
51 单片机LED闪烁(SDCC + Notepad++ + STC-ISP/普中ISP)
单片机·notepad++·接口隔离原则
运维行者_6 天前
PHP性能监控怎么做?从响应时间到慢函数的6个关键指标
运维·服务器·开发语言·网络·支持向量机·php·接口隔离原则
雪雪爱冲浪6 天前
ISP代理与住宅代理选型对比:从原理到实战
服务器·网络·网络协议·tcp/ip·接口隔离原则
liangshanbo12157 天前
前端面试题:微信小程序怎么优化性能?
前端·微信小程序·notepad++