简介:这份资源是面向电子信息、自动化及相关专业学生与初学者的单片机红外遥控系统设计完整报告,以doc文档形式呈现,适合课程设计、毕业设计参考或自学数字系统设计时使用。压缩包内共1个doc文件,约18.27MB,内容涵盖电路原理图与配套程序,并系统梳理了数字集成电路的发展脉络、ASIC技术对可编程逻辑器件的推动、单片机在电子系统设计中的局限,以及CPLD/FPGA芯片在灵活性与可升级性上的优势。报告以红外遥控系统设计为核心,结合VHDL硬件描述语言与EDA技术,给出从系统原理分析、方案比较到主控芯片选型的完整思路,并涉及温度传感器、A/D转换与显示报警等外围电路。目前已有459人学习,适合需要一份结构完整、理论结合实践的红外遥控设计参考文档的读者。
1. 从一份“完整报告”说起:红外遥控系统到底要交付什么
很多人第一次做单片机红外遥控系统设计,卡住的地方不是写不出解码程序,而是不知道一份能交差的“完整报告”应该包含哪些东西。标题里写的是“含电路原理图和程序”,这意味着交付物至少有三块:一张能看懂的接收端原理图、一套能跑通的发射与接收代码、一份把两者串起来的说明。红外遥控的本质是 38kHz 载波上的脉冲位置调制,接收头负责把载波滤掉、还原出基带波形,单片机要做的就是把高低电平的持续时间翻译成 0 和 1。
这套东西适合谁?课程设计、毕业设计、电子竞赛入门,以及想把家里老遥控器接进自己板子的工程师。它不复杂,但坑很集中:载波频率偏了收不到,定时器分频算错解出来全是乱码,电源纹波大导致接收头误触发。下面按“先立原理、再搭电路、再写程序、最后调参排错”的顺序,把这份报告该有的内容讲清楚。
2. 红外遥控的调制原理与接收头选型
2.1 NEC 协议为什么是课程设计的默认选择
红外遥控协议里最常见的三种是 NEC、RC5、Sony SIRC。NEC 之所以成为单片机课程设计的默认选项,是因为它的时序规整、一位数据用固定时长表示,解码时只需要测脉宽,不需要复杂的载波同步。NEC 一帧的结构是:9ms 引导高电平 + 4.5ms 引导低电平 + 8 位地址 + 8 位地址反码 + 8 位命令 + 8 位命令反码 + 560us 结束位。
用“高电平持续时间”区分位值:560us 高电平代表逻辑 0,1.69ms 高电平代表逻辑 1。地址和命令都发反码,是为了让接收端做校验,收到反码不匹配就丢弃这一帧。这个设计在噪声环境下很实用,写程序时一定要用上,别只解命令字节。
载波是 38kHz,占空比通常 1/3。发射端用定时器输出 PWM 驱动红外 LED,接收端用一体化接收头(如常见的 1838 系列)把载波解调掉,输出端直接给出基带波形。注意接收头输出是反相的:收到载波时输出低电平,空闲时输出高电平。这一点在写解码逻辑时如果搞反,整个时序判断都会错。
2.2 接收头与发射管的电路参数怎么定
接收头选型看三个参数:载波中心频率、接收距离、输出极性。1838 系列中心频率 37.9kHz,和 38kHz 载波匹配,接收角度约 45 度,输出低有效。发射管选 940nm 红外 LED,正向压降约 1.2V,典型工作电流 20mA 到 100mA 脉冲。
发射驱动电路常见两种:直接用单片机 IO 灌电流,或者用三极管扩流。IO 直驱时电流被限制在 20mA 以内,距离只有一两米;要拉距离就用 NPN 三极管(如 S8050)做开关,基极串 1k 电阻,集电极串限流电阻。限流电阻按(VCC - Vf - Vce) / If算,5V 供电、Vf 取 1.2V、Vce 取 0.3V、If 取 100mA,得到约 35 欧,实际取 33 欧。
| 元件 | 型号示例 | 关键参数 | 作用 |
|---|---|---|---|
| 接收头 | 1838B | 37.9kHz,低有效 | 解调载波,输出基带 |
| 发射管 | IR333 | 940nm,Vf 1.2V | 发射红外光 |
| 驱动三极管 | S8050 | Ic 最大 700mA | 扩流,拉距离 |
| 限流电阻 | 33Ω | 1/4W | 限制发射管电流 |
| 去耦电容 | 100nF + 10uF | 靠近接收头 | 抑制电源纹波 |
接收头供电脚一定要并 100nF 陶瓷电容加 10uF 电解电容,位置尽量贴近接收头。红外接收头对电源噪声极其敏感,很多“时好时坏”的问题都是电源纹波造成的。
2.3 用定时器捕获还是外部中断加延时
解码方案有两种主流做法。第一种是外部中断加定时器计时:接收头输出接外部中断脚,下降沿触发,进中断后读定时器计数值,算出上一次到这一次的间隔。第二种是用输入捕获功能,硬件自动记录边沿时刻。
51 单片机没有输入捕获,只能用外部中断加定时器。STM32 有输入捕获,推荐用捕获,CPU 占用低、精度高。下面给一段 51 上常见的做法,定时器 0 设为 1T 模式、不自动重载,每次中断读 TH0/TL0 后清零,用来测脉宽。
// 51 单片机红外解码核心:外部中断 + 定时器0 测脉宽 #include <reg52.h> sbit IR_IN = P3^2; // 接收头输出接 INT0 unsigned char ir_data[4]; // 地址、地址反码、命令、命令反码 unsigned char bit_cnt = 0; unsigned int time_cnt = 0; void Timer0_Init(void) { TMOD &= 0xF0; TMOD |= 0x01; // 定时器0,模式1,16位 TH0 = 0; TL0 = 0; TR0 = 1; // 启动计时 } void INT0_Init(void) { IT0 = 1; // 下降沿触发 EX0 = 1; EA = 1; } // 外部中断:每次下降沿读走计数值,换算成微秒 void INT0_ISR(void) interrupt 0 { unsigned int t; t = (TH0 << 8) | TL0; TH0 = 0; TL0 = 0; time_cnt = t; // 保存本次脉宽,主循环里判断 }这段代码只做了“测脉宽”这一件事,把解码逻辑放到主循环里,是为了避免在中断里做太多判断导致丢边沿。IT0 = 1设下降沿触发,因为接收头空闲是高、收到载波变低,下降沿正好对应一个位的起始。定时器模式 1 是 16 位不重载,最大计到 65535,12MHz 晶振下 1 个机器周期 1us,够测 65ms,覆盖 9ms 引导码绰绰有余。
3. 电路原理图:从接收前端到单片机最小系统
3.1 接收前端电路怎么画才不误触发
接收前端就三根线:VCC、GND、OUT。但画原理图时要注意 OUT 脚的上拉。1838 输出是开集电极结构,内部已经有上拉,但长走线时建议外部再并一个 10k 上拉到 VCC,提高抗干扰。OUT 到单片机中断脚的走线尽量短,远离晶振和电源开关节点。
电源部分,接收头单独走一条 5V 到它的线,中间串一个磁珠或 10 欧电阻,再并 100nF 和 10uF。这个 RC 加磁珠的组合能把单片机数字开关噪声挡在接收头外面。很多同学原理图画得没问题,一上电就乱码,八成是这里省了。
3.2 单片机最小系统与下载电路
51 最小系统包含:晶振电路(12MHz 或 11.0592MHz 晶振 + 两个 30pF 瓷片电容)、复位电路(10uF 电解 + 10k 电阻,高电平复位)、电源去耦(每个 VCC 脚并 100nF)。晶振选 11.0592MHz 是为了串口波特率整除,纯红外解码用 12MHz 也行,计时更整。
下载电路看芯片。STC 系列用串口下载,需要 USB 转 TTL 模块,TXD 接单片机 RXD、RXD 接单片机 TXD,下载时先点下载再上电。STC 单片机支持在线编程,配合官方工具就能烧录,不需要专用编程器。如果用的是需要专用烧录器的型号,按对应工具接线即可。
# STC 串口下载典型流程(以官方下载工具为例) # 1. 选择芯片型号和串口号 # 2. 打开目标 .hex 文件 # 3. 点击“下载/编程”,然后给单片机上电 # 4. 等待握手成功,烧录完成下载失败最常见的原因是串口被占用、TXD/RXD 接反、或者没在点击下载后再上电。STC 的握手是在上电瞬间完成的,顺序错了就连不上。
3.3 发射端电路与按键矩阵
发射端如果只是复现遥控器,用一个红外 LED 加驱动三极管就够。如果要自己发码,加一个按键接 IO,按下时调发射函数。发射函数用定时器产生 38kHz 方波,按 NEC 时序控制通断。
// 发射端:定时器产生 38kHz 载波,按 NEC 时序发送 void SendNEC(unsigned char addr, unsigned char cmd) { SendByte(addr); // 地址 SendByte(~addr); // 地址反码 SendByte(cmd); // 命令 SendByte(~cmd); // 命令反码 // 结束位:560us 载波后拉低 } void SendByte(unsigned char dat) { unsigned char i; for (i = 0; i < 8; i++) { if (dat & 0x01) { SendCarrier(560); // 逻辑1:560us 载波 DelayUs(1690); // 再等 1690us 低电平 } else { SendCarrier(560); // 逻辑0:560us 载波 DelayUs(560); // 再等 560us 低电平 } dat >>= 1; } }SendCarrier里用定时器翻转 IO 产生 38kHz,周期约 26us,高电平 8.7us、低电平 17.3us,接近 1/3 占空比。DelayUs的精度直接决定对方能不能解对,用定时器做延时比空循环可靠。
4. 解码程序:状态机写法与常见乱码排查
4.1 用状态机替代延时判断
新手常写的解码是“等 9ms 低电平、等 4.5ms 高电平、然后循环读 32 位”,这种阻塞式写法一旦时序有偏差就全乱。更稳的是状态机:主循环里不断读time_cnt,根据当前状态和脉宽决定下一步。
// 状态机解码:在主循环里调用,非阻塞 #define STATE_IDLE 0 #define STATE_LEAD 1 #define STATE_DATA 2 unsigned char state = STATE_IDLE; unsigned char bit_idx = 0; void IR_Decode(void) { if (time_cnt == 0) return; // 没有新边沿 switch (state) { case STATE_IDLE: if (time_cnt > 8000 && time_cnt < 10000) { // 9ms 引导 state = STATE_LEAD; } break; case STATE_LEAD: if (time_cnt > 4000 && time_cnt < 5000) { // 4.5ms state = STATE_DATA; bit_idx = 0; } else { state = STATE_IDLE; } break; case STATE_DATA: if (time_cnt > 400 && time_cnt < 800) { // 逻辑0 ir_data[bit_idx / 8] &= ~(1 << (bit_idx % 8)); bit_idx++; } else if (time_cnt > 1400 && time_cnt < 1900) { // 逻辑1 ir_data[bit_idx / 8] |= (1 << (bit_idx % 8)); bit_idx++; } else { state = STATE_IDLE; // 时序异常,复位 } if (bit_idx >= 32) { // 校验反码 if ((ir_data[1] == (unsigned char)~ir_data[0]) && (ir_data[3] == (unsigned char)~ir_data[2])) { // 解码成功,ir_data[2] 就是命令 } state = STATE_IDLE; } break; } time_cnt = 0; // 清标志,等下一个边沿 }状态机的好处是任何一步超时都能回到 IDLE,不会卡死。time_cnt由中断更新,主循环只读不写,避免竞争。判断阈值取的是理论值上下浮动 20% 左右,比如 560us 取 400 到 800,1.69ms 取 1400 到 1900。
4.2 阈值、晶振与中断优先级的参数表
| 参数 | 理论值 | 建议判断区间 | 说明 |
|---|---|---|---|
| 引导高电平 | 9ms | 8.0–10.0ms | 低于 8ms 判为噪声 |
| 引导低电平 | 4.5ms | 4.0–5.0ms | 配合引导高一起判 |
| 逻辑0高电平 | 560us | 400–800us | 太窄是毛刺 |
| 逻辑1高电平 | 1.69ms | 1.4–1.9ms | 太宽是干扰 |
| 载波频率 | 38kHz | 37–39kHz | 偏了接收头不响应 |
晶振频率影响计时精度。12MHz 下定时器 1us 一个计数,11.0592MHz 下约 1.085us,算阈值时要把这个系数带进去,否则 9ms 会判成 8.3ms 左右,落在区间边缘。中断优先级上,红外中断要高于串口等非实时任务,否则边沿会被延迟响应。
4.3 收到乱码时先查这四处
第一查电源。用示波器看接收头 VCC 脚,如果有几十毫伏的纹波,先加电容。第二查载波。发射端用示波器看红外 LED 两端,确认是 38kHz 方波而不是直流。第三查极性。接收头输出空闲是高,如果程序按低有效写,全错。第四查晶振。用频率计或示波器确认实际频率,晶振起振不良会导致计时整体偏移。
提示:调试时先把接收头输出直接接示波器,手动按遥控器,看波形是否符合 NEC 时序。波形对了再查程序,能省一半时间。
5. 进阶:把红外遥控接进实际控制场景
5.1 红外遥控电机控制与报警器的联动
红外解码出来的是一个命令字节,真正有用的是拿它去控制别的模块。比如做红外遥控电机控制,命令 0x18 对应正转、0x52 对应反转、0x08 对应停止,解码成功后置一个标志位,主循环根据标志位驱动 H 桥。H 桥驱动电路原理图里,四个 MOS 管或三极管组成桥臂,注意上下桥臂不能同时导通,程序里要留死区。
做红外遥控报警器则是反过来:解码到特定命令后拉高蜂鸣器 IO。蜂鸣器电路原理图里,有源蜂鸣器直接 IO 驱动加三极管扩流,无源蜂鸣器需要 PWM 给频率。命令匹配用switch比一串if清晰,也方便扩展。
// 命令分发:解码成功后调用 void IR_Command(unsigned char cmd) { switch (cmd) { case 0x18: Motor_Forward(); break; case 0x52: Motor_Backward(); break; case 0x08: Motor_Stop(); break; case 0x5A: Buzzer_On(); break; // 报警 default: break; } }5.2 用重复码做长按与连发
NEC 协议里,按住按键不放时,遥控器不会重复发完整帧,而是发重复码:9ms 引导 + 2.25ms + 560us 结束位。识别重复码就能实现长按连发,比如按住音量键连续加减。判断方法是引导码之后的高电平只有 2.25ms 左右,而不是 4.5ms。
在状态机里加一个STATE_REPEAT,引导高电平之后如果测到 2.0–2.5ms,就认为是重复码,直接沿用上一次的命令,不更新ir_data。这样长按调电机速度、长按调亮度都能做。
5.3 验证解码正确率的两个土办法
第一个办法是串口打印。每解出一帧就把地址、命令、反码校验结果通过串口发出来,按十次遥控器看十次结果是否一致。串口波特率设 9600,用 USB 转 TTL 接电脑看。第二个办法是计数。定义一个全局变量,每成功解一帧加一,用数码管显示,按二十次看计数是不是二十。如果少于二十,说明有丢帧,回去查中断响应时间和电源。
注意:串口打印本身会占用时间,如果波特率太低、打印太长,可能影响下一次解码。调试时可以先只打印命令字节,确认没问题再打印完整帧。
把这两步做完,一份“含电路原理图和程序”的单片机红外遥控系统设计报告就有了可复现的骨架:原理图能解释每个元件为什么在那,程序能说清每个阈值怎么来的,调试记录能证明它真的跑通了。
本文还有配套的精品资源,点击获取