红外遥控直流电机 PWM 调速实验------调试全过程总结
工程路径 :
C:\Users\54200\Desktop\51MCU\17 红外遥控电机转速目标现象 :复现教学视频(BV1Mb411e7re P38)中"遥控器控制直流电机转速"的效果
最终状态 :✅ 已实现------空调遥控器单键(VOL-)循环调速:0停→1低速→2中速→3全速→0停
调试时间 :2026-08-30
参考教程:普中 51 单片机开发板配套教程(Bilibili BV1Mb411e7re P38)
目录
- 一、问题背景与目标
- 二、初始代码分析与方案设计
- [2.1 原程序结构](#2.1 原程序结构)
- [2.2 红外遥控方案设计](#2.2 红外遥控方案设计)
- [三、第一轮调试:NEC 红外解码实现](#三、第一轮调试:NEC 红外解码实现)
- [3.1 解码架构](#3.1 解码架构)
- [3.2 关键技术点](#3.2 关键技术点)
- [3.3 初版按键映射](#3.3 初版按键映射)
- [四、第二轮调试:VOL+ 循环升档与键值对调](#四、第二轮调试:VOL+ 循环升档与键值对调)
- 五、第三轮调试:"转几秒停止"之谜
- [5.1 现象与初步推断](#5.1 现象与初步推断)
- [5.2 程序侧逐字节排查](#5.2 程序侧逐字节排查)
- [5.3 发现外部干扰因素](#5.3 发现外部干扰因素)
- [5.4 防呆措施:上电指纹 + 唯一文件名](#5.4 防呆措施:上电指纹 + 唯一文件名)
- 六、第四轮调试:真相大白------空调遥控器连发双键值
- [6.1 指纹实验的关键结论](#6.1 指纹实验的关键结论)
- [6.2 怪现象的完整解释](#6.2 怪现象的完整解释)
- [6.3 v4 单键循环方案](#6.3 v4 单键循环方案)
- 七、最终程序结构与操作说明
- 八、调试经验与要点提炼
一、问题背景与目标
「17 红外遥控电机转速」工程初始为上一课的独立按键调速 版本。目标是改为教学视频 P38 中的红外遥控调速效果:上电电机停止,用遥控器按键逐步调节直流电机转速,数码管同步显示档位。
二、初始代码分析与方案设计
2.1 原程序结构
原 main.c 基于定时器 T0 产生 PWM(100us 中断,周期 10ms,即 100Hz)驱动直流电机(P1.0,经驱动电路接 J47 端子),K1 按键消抖循环切换四档占空比(0/30/70/100),数码管(P0 段选 + 74HC138 位选 LSA/LSB/LSC)显示档位。缺的只是红外接收部分。
2.2 红外遥控方案设计
采用 NEC 红外协议解码:
| 硬件资源 | 用途 |
|---|---|
| INT0 外部中断(P3.2,下降沿触发) | 红外接收头 OUT 引脚,引导码下降沿进入解码 |
| T0 定时器(100us 中断) | 复用为脉宽测量时基 + PWM 产生 |
| 数码管第 1 位 | 显示当前档位 0~3 |
三、第一轮调试:NEC 红外解码实现
3.1 解码架构
在 INT0 中断服务函数中按 NEC 协议逐位解码:9ms 引导码低电平 → 4.5ms 高电平 → 32 位数据(地址码、地址反码、数据码、数据反码),并做键值反码校验防误码。
3.2 关键技术点
- 脉宽测量不用软件延时 :解码期间 PWM 中断照常运行,软件延时函数会被打断导致测量失真。改为复用 T0 中断中每 100us 累加一次的时基计数器
g_ir_time(u8 类型,8 位读取天然原子,避免读撕裂)。 - 中断优先级 :T0 设高优先级(
PT0=1),保证 60 余毫秒的解码过程中 PWM 输出不中断,电机不顿挫。 - '0'/'1' 判决:数据位高电平约 560us 判 '0',约 1.68ms 判 '1'(以 100us 计数次数为阈值)。
3.3 初版按键映射
按普中配套遥控器键值表:数字键 0~3 直接设档,VOL+ 升档、VOL- 降档。编译 0 错误 0 警告(20:06)。
四、第二轮调试:VOL+ 循环升档与键值对调
用户需求 :希望 VOL+ 为增、VOL- 为减,且最高档后再按能回到 0(循环)。用户实测反馈"按 VOL- 反而增档",据此判断该批次遥控器 VOL+/VOL- 键值与常见表相反,对调两键映射,并实现 VOL+ 循环回 0、VOL- 降到底为止(20:12 编译)。
五、第三轮调试:"转几秒停止"之谜
5.1 现象与初步推断
用户反馈烧录后"上电自己转几秒停止、完全无遥控反应"------与最原始"转 5 秒停止"老程序行为一致,初步怀疑烧录了旧固件。
5.2 程序侧逐字节排查
对 template.hex 做了逐字节解析验证:
- ✅ 主函数开头
CLR P1.0(上电电机必停),程序无任何"自转"路径 - ✅
SETB IT0/EX0/PT0红外中断配置齐全 - ✅ 六个键值比较指令均在------注意 C51 将
switch编译为减法树 ,键值 0x16/0x18/0x5E 以差值形式出现,直接按原始字节搜索搜不到是虚惊一场(重要教训) - ✅ 与用户在 Keil GUI 中自行编译的 hex 完全一致(cmp 校验)
5.3 发现外部干扰因素
- 51MCU 目录下存在 11 个同名
template.hex,极易选错 - STC-ISP 不会自动刷新已加载文件,重编译后必须重新"打开程序文件"
- 用户曾于 20:21 在 Keil 图形界面自行打开工程编译(
template.uvgui.54200文件为证)
5.4 防呆措施:上电指纹 + 唯一文件名
- 程序上电先在数码管显示 H 约 1 秒(旧程序无此动作),一眼分辨固件新旧
- hex 另存为唯一文件名
红外遥控电机_v3指纹H.hex(1756 字节,code=566)
六、第四轮调试:真相大白------空调遥控器连发双键值
6.1 指纹实验的关键结论
用户烧录 v3 后看到了 H 指纹 ,证明烧录链路完全正常!但电机仍"转几秒停止"。由此锁定真正的根因:用户使用的是空调遥控器,而非普中配套遥控器。
6.2 怪现象的完整解释
空调遥控器按一次键会连发多帧数据 ,程序先后解码出 0x15 和 0x07 两个键值:
| 版本 | 0x15 的映射 | 0x07 的映射 | 净效果(按一次键) |
|---|---|---|---|
| v1("好用"版) | 升档 | 降档(从 0 减不动,无效) | 净加一档,但封顶不能停 |
| v3("转几秒停止") | 降档 | 升档 | 先加后减互相抵消,电机一顿一顿回到 0 |
6.3 v4 单键循环方案
既然遥控器实际就这两个键值,干脆统一映射为同一个动作:
- 0x15 与 0x07 均触发"升一档,最高档后回 0":0停→1低速→2中速→3全速→0停,循环
- 其余键值忽略(保留 0x16=停止作为保险)
- 新增 200ms 按键锁存 (
g_lock_ms,由 T0 中断 1ms 分频递减):一次按键产生的连发重复帧直接丢弃,杜绝一次连跳几档 - 上电指纹改为 P(区分 v3 的 H)
v4 编译 0 错误 0 警告(code=559,20:45),文件名 红外遥控电机_v4_单键循环.hex。实测成功:单键 VOL- 即可完成"逐步增速 + 循环回停"全部操作。
七、最终程序结构与操作说明
main.c(v4 单键循环版)
├── PWM 生成:T0 100us 中断,100Hz,占空比查表 speed_table[4]={0,30,70,100}
├── 红外解码:INT0(P3.2)+ T0 时基测脉宽,NEC 协议 + 反码校验
├── 按键锁存:200ms 内重复帧丢弃(T0 中断 1ms 分频递减)
├── 档位控制:收到 0x15/0x07 → g_speed_level++(>3 回 0)
├── 数码管:上电显示 P 1 秒 → 显示档位 0~3
└── 上电防御:DC_Motor=0,初始占空比 0%
| 空调遥控器操作 | 电机 | 数码管 |
|---|---|---|
| 上电 | 停止(先显示 P 一秒) | 0 |
| 按一次 | 低速 30% | 1 |
| 按两次 | 中速 70% | 2 |
| 按三次 | 全速 100% | 3 |
| 按四次 | 停止 | 0 |





八、调试经验与要点提炼
- 硬件资源复用:一个定时器可同时承担 PWM 产生与红外脉宽测量时基,关键在于中断优先级设计(PT0=1)
- 中断环境忌软件延时 :脉宽测量应基于定时器时基计数,而非
delay()函数;多字节共享变量需考虑原子性(u8 单字节读取天然原子) - switch 的编译器优化:C51 将 switch 编译为减法树,立即数以差值形式出现在机器码中------反汇编搜索常量时要留意,勿因搜不到而误判
- 固件版本管理 :多个工程同名 hex 是大坑;重编译后 STC-ISP 不会自动刷新;唯一文件名 + 上电指纹是低成本高可靠的防呆组合
- 现象指纹法:为不同版本固件设计不同的上电显示(H/P),一次实验即可区分"程序问题"还是"烧录问题"
- 非配套遥控器的协议差异:空调遥控器连发多帧、单键多码值,适配时应按实测键值映射,并对重复帧做时间窗锁存
- 逐步排除法:本轮调试依次排除了"代码缺失→烧录错误→编译产物过期→遥控器协议差异",每轮一个假设、一个验证手段,最终定位根因