news 2026/10/13 1:28:43

基于51单片机的红外遥控摇头小风扇设计与实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于51单片机的红外遥控摇头小风扇设计与实现

玩51单片机的朋友,很多都经历过这个阶段:课设选题或入门练手,总想做一个能拿得出手、逻辑不算复杂、成本又不高的东西。我前后做过不少小项目,这个红外摇头小风扇是性价比很高的一种——零件攒起来几十块钱,电路不算复杂,却把电源、驱动、红外协议解析、PWM调速、机械联动几层东西全串起来了。如果你正打算做类似的51课程设计或者给开发板配一个有趣的扩展项目,这篇内容应该能帮你少走不少弯路。

我尽量按照我实际动手时的顺序来讲:先聊整体方案怎么定,再讲硬件上每一块为什么这么接,然后重点拆红外解码和电机控制这两块软件逻辑,最后把试制过程中踩过的坑、调过的参数一次性整理出来。这样你照着做,基本能一次跑通。

1. 项目定位与整体方案选型

1.1 为什么拿51单片机做这种小玩意儿

先回答一个很多人纠结的问题:都什么年代了,还选51单片机?其实做这种桌面级小风扇,51不是“老古董”,反而是非常合适的平台。

首先,资源刚刚好。红外遥控解码需要一个外部中断输入引脚,PWM调速至少需要一个定时器,剩下的IO口控制电机方向、LED指示灯、按键扫描,STC89C52RC这种芯片一共32个IO口,完全够用,根本不需要外扩。其次,51的开发资料极多,即使你中断、定时器这些概念还不熟,网上随便搜都能找到现成框架。我用的是STC89C52RC,8KB Flash、256字节RAM,哪怕代码写得粗糙一点,编译出来也就几KB,完全不担心容量。

更重要的一点:51的机器周期固定,中断响应逻辑清晰,很适合理解红外解码这种对时序比较敏感的外设。用STM32做当然更“现代”,但很多细节被库函数遮住了,初学者反而学不到底层的东西。用51去解析NEC协议,你能亲眼看到“一条引导码到底是多少毫秒”,这种手感是高级库给不了的。

1.2 红外遥控、摇头功能,解决了什么问题

这个项目本质上是把一个普通USB风扇改造成“可远程操作、可自动送风”的桌面设备。红外的价值在于无线操作:不用起身按按钮,遥控器一按就能开关、调速、摇头。而且红外方案成本极低,一个遥控器加一个接收头总共几块钱,技术上也通用——学会解析NEC协议后,你完全可以把它用在做遥控灯、遥控窗帘甚至万能遥控器实验上。

摇头功能则是另一个维度:解决“直吹难受”的问题。普通小风扇固定角度吹久了人会觉得发闷,摇头之后空气流动范围变大,体感舒服很多。从工程角度看,摇头的机械实现也有很多方案可选:舵机、步进电机、减速电机加行程开关都可以,选择不同方案直接决定你代码的复杂度和最终体验,这部分后面我会详细对比。

1.3 整套系统拆开看,其实就三层活

你别被“基于51单片机”这种词吓到,把系统拆开就清楚了。

第一层是输入层:红外接收头负责接收遥控器信号,板上按键作为备用。第二层是控制层:51单片机解析红外指令,维护风扇的工作状态(开关、风速档位、是否摇头、是否定时)。第三层是执行层:主电机驱动风扇旋转,舵机或步进电机驱动摇头机构,LED指示灯反馈状态。

我画不出太多花里胡哨的框图,但你心里要有数:这项目就是一条单向链,按键/遥控器 → 主控 → 电机驱动,外加一个状态反馈。分层明确之后,调试时就能快速定位问题——遥控没反应查接收头和中断,电机不转查驱动和电源,摇头不动查舵机信号和机械结构。

2. 硬件电路设计:把每一块钱花明白

2.1 主控最小系统与晶振选择

STC89C52RC的最小系统很简单:电源、晶振、复位电路、下载电路。电源我用USB 5V直接进,板上用了一个自恢复保险丝,防止电机堵转过流把USB口搞挂。晶振选了11.0592MHz,其实红外解码对晶振精度要求不高,12MHz也一样能解,选11.0592主要是考虑到以后如果想串口通信,波特率可以做到极准——很多STC51板子默认就是这个晶振,兼容性最好。

这里有个细节:复位电路除了常见的10uF电容+10k电阻方案,我额外加了一个手动复位按键。实际调试中,程序卡死或状态不对时,按键复位比重新上电快得多,也别小看这个动作,它能帮你区分“程序逻辑跑飞了”还是“电源出问题导致重启”。

下载电路就直接用STC的串口下载方案,USB转TTL模块接RXD、TXD即可。注意STC下载需要“冷启动”——先点下载,再给板子上电,否则会一直等待握手。我刚开始用的时候经常卡在这一步,后来习惯之后觉得还好。

2.2 电机驱动与摇头机构,方案对比别踩坑

这是整个项目最值得花时间对比的部分。风扇主电机和摇头机构,驱动方式完全不同,我不能直接拿IO口去接电机,51单片机的IO口高电平驱动能力很弱,一个负载稍大的电机就能把单片机拉复位。

先看主电机方案。小风扇用的电机一般是空心杯电机或N20减速电机,正常工作电流几百毫安,堵转时可能到1A以上。我对比过几种驱动方式:

驱动方案能否PWM调速能否正反转成本适合场景
三极管+二极管可以不可以最低小功率电机、不反转
ULN2003达林顿管可以不可以很低步进电机或单方向电机
L9110S H桥可以可以低小功率直流电机、需要反转
DRV8833 H桥可以可以中电流较大且需要反转

这个项目里主电机不需要反转,很多教程用ULN2003,我也试过,完全没问题。但后来我换成L9110S,原因是它自带续流保护和逻辑电平转换,PWM控制更稳,而且以后如果做成遥控小车还能复用。L9110S的接线极其简单:VCC、GND、IA、IB,IA接单片机PWM输出,IB固定高电平或低电平即可控制方向。这里注意,IA接PWM时,IB接高电平,电机转速随占空比变化;如果IB也接PWM就是正反转控制,反过来接还能刹车。

再看摇头机构,这决定了整套系统的机械复杂度和软件难度。常见的就三种:

  1. 舵机方案(SG90)。成本低,9g舵机十来块钱,控制信号是20ms周期脉宽,转到哪个角度取决于高电平宽度。软件上用定时器生成1ms左右的脉宽就能控制角度。缺点是负载能力有限,如果你风扇扇叶很大,舵机带起来会吃力甚至发抖。解决办法是选扭矩更大的MG90S金属齿轮舵机。
  2. 步进电机方案(如28BYJ-48)。配合ULN2003驱动板,控制精确,带载能力强,可以精确转到任意角度。缺点是需要占用4个IO口,而且28BYJ-48是减速步进电机,转动速度慢,想要快速摇头会显得有点“憨”。
  3. 减速电机+行程开关。直流减速电机一直转,碰到左右两端的行程开关就反转,结构和控制最简单,但到位冲击大,而且行程开关比较容易坏。

我最终选了SG90舵机。一来代码量小,二来摇头速度可以程序控制,不至于像步进电机那样一顿一顿的。实际安装时我用扎带把舵机固定在底座上,舵机臂上拴一根连杆去推风扇头部左右摆动。注意风扇头部的转轴一定要顺滑,否则舵机堵转会抖得厉害。

在选驱动时,我还做了一次电流核算:风扇主电机额定电流约350mA,SG90舵机堵转电流在500mA左右。两个电机同时工作峰值电流接近1A,5V电源是从USB取的话,很多USB口限流500mA,这时候必须外接一个5V/2A电源。如果你非要用USB口供电,至少要在电机两端并联一个220uF电解电容和104瓷片电容来吸收瞬间电流,否则电机一转,单片机大概率直接复位。

2.3 红外接收电路与显示、按键接口

红外接收头我用的是HS0038B,输出端直接接单片机的外部中断0引脚(P3.2)。这里有个关键点:HS0038B的输出是集电极开路结构,需要加上拉电阻到VCC,我用的是10kΩ。它的电源端一定要加滤波电容,我并了10uF电解电容和0.1uF瓷片电容,因为红外接收对电源纹波非常敏感,供电抖动会直接导致解码乱码。

关于上拉电阻的取值,10k是常见值。如果你发现遥控距离变短,可以试着改小到4.7k,但注意太小会增大静态功耗,这个项目无所谓。

显示部分我用三个LED显示当前风速档位:1档亮一个,2档亮两个,3档亮三个。这里LED限流电阻用1k,5V供电算下来每个LED电流大概3mA左右,亮度足够了。你如果想做得好看一点,可以换成数码管或OLED屏,但我个人建议课程设计和入门项目先用LED,减少软件复杂度,把精力放在核心逻辑上。

板上按键我保留了三个:一个总电源开关,一个手动风速切换,一个手动摇头切换。千万别小看备用按键,后面调试红外解码的时候,没有按键只有遥控器会让你怀疑人生——你根本分不清是程序问题还是遥控器问题,有按键就能先排除输入链路。

3. 软件实现:红外解码和风扇状态机

3.1 NEC协议信号到底长什么样

很多人在这一步卡住,所以我把红外NEC协议讲得尽量通俗些。

红外遥控发射的数据,本质上是38kHz载波信号的有无组合。载波本身是“数字信号传输的搬运工”,真正有意义的是载波出现的时间长度。接收端HS0038B会把收到的38kHz载波解调成高低电平:有载波时输出低电平,没有载波时输出高电平。也就是说,你从单片机引脚读到的信号,跟遥控器发出的信号是反相后的结果。

NEC协议的一帧数据长这样:先是一个引导码,低电平9ms + 高电平4.5ms,相当于告诉接收端“注意,下面要发数据了”。然后是地址码8位 + 地址反码8位,接着是命令码8位 + 命令反码8位,总共32位数据。每一位数据的时间长度都是相同的间隔,用低电平0.56ms + 高电平时长区分逻辑0和逻辑1:高电平0.56ms是逻辑0,高电平1.68ms是逻辑1。在一次按键持续期间,遥控器还会间隔发送重复码,重复码是9ms低电平 + 2.25ms高电平。

我一开始看这个时序图也觉得头大,但写代码时发现核心就一句话:测量高电平的持续时间,超过1.12ms就判为1,否则判为0。引导码、数据位、重复码的区别只是时间阈值不同,用定时器就能搞定。

3.2 用中断加定时器,把解码吃透

解码软件我只用了两个硬件资源:外部中断0捕捉电平跳变,定时器0做时间测量。思路很简单:在P3.2引脚上检测到下降沿时,启动定时器0,同时开始计时;下一次中断时根据引脚当前电平判断是一个低电平结束还是高电平结束,把计时结果存下来,根据持续宽度判断是什么码元。

下面是我调试后保留的核心框架代码,你可以直接参考:

sbit IR_IN = P3^2; unsigned char ir_recv[4]; // 地址、地址反码、命令、命令反码 unsigned char ir_bit_cnt; unsigned char ir_cmd; bit ir_ok; // 一帧数据接收完成标志 bit ir_repeat; // 重复码标志 void Int0_Isr() interrupt 0 { static unsigned int time_cnt; unsigned int tmp; if (IR_IN == 0) { // 低电平开始,启动计时 TH0 = 0; TL0 = 0; TR0 = 1; } else { // 低电平结束,记录低电平宽度 tmp = (TH0 << 8) | TL0; TR0 = 0; // 根据低电平宽度判断引导码、数据位起始、重复码 if (tmp > 7000) // 约7.5ms以上,认为是引导码 { ir_bit_cnt = 0; } else if (tmp > 2500) // 重复码的低电平约9ms? 实际此处处理重复码 { ir_repeat = 1; } else { // 普通数据位,高电平宽度决定0还是1 // 高电平宽度判断要等下一次下降沿,这里先做位处理 } } }

其实更完整的做法是同时记录高低电平宽度,在低电平结束时判断前一个高电平宽度。我实际用的完整解码代码比上面长不少,因为要处理位移位、校验码、超时复位,但核心思想就是上面这套——中断记录时间,主循环或中断里组装字节。你需要注意的是,定时器0在每次低电平开始时清零、开始计时,这样每次测的都是“当前这一段的宽度”,逻辑非常清晰。

我还额外做了一个超时保护:如果定时器0溢出(也就是超过71ms没等到下降沿),就认为本次接收无效,清空所有状态。这个很有必要,因为遥控器松开时会有一段空闲高电平,不清空的话,残留状态可能影响下一帧数据的解析。

这里有个很容易踩的坑:HS0038B输出的低电平宽度和协议标称值不完全一致,不同接收头之间可能有10%左右的偏差。所以我判阈值时留了充足的余量——引导码低电平大概是9ms,我取大于7ms就算;1.68ms的高电平判1时,阈值取1.12ms左右。这样即使个别接收头差一点也能正常解码。

3.3 主电机PWM调速和摇头控制的程序调度

解码拿到命令码之后,剩下的软件就是一个典型的状态机。我定义了风扇状态变量fan_state,取值有OFF、SPEED_1、SPEED_2、SPEED_3。主循环里不停轮询ir_ok标志,一旦置位,就根据命令码查表执行对应动作。

PWM调速部分我用了定时器1产生软件PWM。方法很朴素:设定一个固定的周期,比如10ms,在定时器中断里累加计数,当计数值小于当前档位的阈值时,电机IO输出高电平,否则输出低电平。三档风速对应的占空比,我调成了30%、60%、90%,留出10%给全速档。你可能会问为什么不做100%,那是因为全速时风扇噪音大、电流大,而且和90%的体感差距很小,没必要。

舵机的控制我单独用了一个定时器或复用定时器1做分时处理。SG90舵机的控制周期是20ms,高电平0.5ms对应0度、2.5ms对应180度。我只让它左右各摆动45度,也就是从中心位置往两边各偏一点。这样舵机行程短、动作利索,也不会顶到风扇外壳。摇头的转速不要设得太快,我测试后觉得一个周期3秒左右最舒服——太快像抽搐,太慢没有“摇头”的感觉。

程序整体的调度原则就一句话:红外解码用中断,状态判断用主循环,PWM输出用定时器中断。三者的优先级从高到低是:定时器中断(PWM不能断) > 外部中断(红外解码) > 主循环(状态机)。这样设计的好处是,即使遥控信号在解码过程中到来,PWM输出依然稳定,不会出现风扇转速一抖一抖的情况。

这里必须提醒一个细节:如果你的PWM和红外解码共用定时器资源,一定要仔细分配优先级和时间片。我一开始图省事,把PWM和红外解码都放在同一个定时器中断里处理,结果低速档时舵机一抖,红外就解码失败。后来把红外解码独立到外部中断、PWM独立到定时器中断,问题才彻底解决。51只有一个定时器中断优先级可以设置成高优先级,所以尽量把不可间断的PWM放在高优先级,红外解码稍微延迟几微秒没关系。

4. 从原理图到实物:焊接、调试、填坑实录

4.1 组装顺序和电气布线的几个建议

拿到PCB或者洞洞板,别急着全焊完,分模块焊接和测试是最省时间的。我的顺序是:先焊最小系统(单片机+晶振+复位+下载口),烧一个LED闪烁程序,确认单片机活着;再焊红外接收头,写个串口打印IR解码值的测试程序,用串口助手看按键码值;接着焊电机驱动,用按键直接控制电机启停和PWM,确认驱动不发热、电机不抖;最后才把舵机接上,调摇头角度。

这个过程很笨,但每一步都能立刻暴露问题。我曾见过直接一鼓作气焊完全部,上电后风扇乱转、遥控失灵,结果排查了一下午才发现是下载口的一根线虚焊,白白浪费大量时间。

在模块连接上,有一点需要特别注意:电机电源和单片机电源最好在板子上分开走线,然后在电源入口处汇合。这样做叫“星形接地”,能有效防止电机大电流在地线上产生压降,从而干扰单片机的复位电路。如果你发现“风扇一转单片机就重启”,绝大多数情况就是电源走线问题,跟程序一点关系都没有。我在电机两端并联的电容组合是220uF电解电容+104瓷片电容,效果立竿见影。

另外一个细节:舵机信号线不要和电机电源线扎在一起走。舵机信号是1ms左右的脉宽信号,非常容易受到电机换向时的电磁干扰。如果PCB布线没办法分开,至少信号线要远离电机引线,或者给它套一个磁环。我亲眼见过舵机在风扇高速运转时自己乱摆,就是因为信号线跟电机线贴得太近了。

4.2 实测过程遇到的五个典型问题

我把整个调试过程中踩过的问题整理成了一个速查表,这些问题的出现频率极高,95%的此类小项目都会遇到其中至少两三个:

现象直接原因排查方向与解决办法
遥控距离不到1米,且角度很窄接收头上拉电阻不匹配、电源纹波大检查HS0038B电源端电容,上拉电阻改为4.7k~10k之间试验
风扇一转,单片机马上复位电机启动电流拉低电源电压电机两端并联220uF+104电容,改用独立5V/2A电源
红外解码偶尔出错解码期间PWM中断干扰把PWM和红外解码分到不同中断源,PWM优先级更高
舵机摇头到两端时发抖机械限位导致舵机堵转软件限制角度范围,机械上留出缓冲余量,检查连杆是否卡住
遥控器要按很重才有反应发射管驱动不足或发射管老化检查遥控器电池,用示波器测量发射管是否正常输出38kHz波形

还有一个非常隐蔽的问题:红外接收头怕强光。如果风扇放在窗边,阳光直射时遥控距离会明显变短,甚至完全失效。这是因为HS0038B内部的自动增益控制被环境光干扰,降低了接收灵敏度。解决办法是给接收头套一个黑色热缩管,只留出正前方的小窗口,减少侧面杂光进入。这一步很便宜,但效果明显。

程序方面的常见问题也有一个高发点:很多人解码程序里没做“重复码”处理,按键按久一点状态就切来切去。我专门在解码框架里加了一个repeat标志,如果检测到重复码,只更新风扇状态,不重复执行“按键功能”。这意味着按住遥控器电源键时,风扇不会反复开关,逻辑才符合直觉。

4.3 参数标定与最终效果记录

所有硬件都跑通之后,我花了一个下午做参数标定。首先是PWM档位的频率选择。电机PWM如果频率低于1kHz,会有明显的“滋滋”电噪声,这是绕组在电流断续时振动产生的;频率太高,51单片机软件PWM的精度又不够。我最终选了20Hz的周期?不对,20Hz太低,实际选了2kHz左右的PWM频率。用定时器1产生2kHz中断,每次中断里切换电平,占空比按档位设定。这个频率下电机的电磁噪声几乎听不见,转速也线性。

舵机摇头的角度参数也需要实测。我先把舵机脉宽从0.5ms到2.5ms逐步叠加,测量实际转角,发现SG90在1.5ms时基本在中位,0.8ms和2.2ms对应左右摆动边界。我在程序里把摇头角度限制在这两个脉宽之间,同时加了一个“软限位”:每次摇头到达边界后等待200ms再反转。这个等待时间很有用,能让舵机彻底停稳,避免惯性导致回程偏差。

最终测试结果:遥控距离在室内无遮挡条件下约8米,隔着玻璃窗测试也能到4米左右;风扇三档实测电流分别是180mA、260mA、420mA,加上舵机工作的峰值电流,用5V/2A电源完全没压力。整个系统代码量大致在600行左右,包含了一个完整的NEC解码器、三档PWM调速、舵机摇头逻辑和三键状态机。这个项目后来我还做了一个小扩展:利用STC89C52RC内部的EEPROM存储遥控器自学习键值,长按某个按键进入学习模式,任意NEC协议的遥控器都能用。如果你有兴趣,沿着这个方向扩展非常自然,逻辑上也不会增加太多难度。

最后说一点个人体会:这个项目最磨人的环节其实不是51单片机,而是电源和机械。代码上的问题基本一查中断和状态机就能解决,硬件上“电机一转就复位”“舵机一到边界就抖”这些坑,却能让人折腾一整晚。动手之前,给电源和机械结构多一点耐心,把基础打好,你就能在半小时内体会到红外遥控风扇“滴”一声跟着你的指令转起来的那种满足感。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 1:27:29

ESP32一键烧录包制作:数据边界与量产固件烧录全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/13 1:27:04

Maven Wrapper 实战:锁定构建版本,告别环境不一致

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/13 1:27:00

语音方案开发避坑指南:从需求到联调的绕远路经验总结

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/13 1:26:58

省选模拟Valleys题解:笛卡尔树与山谷统计实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/13 1:26:54

Java单词排序实战:从Scanner输入到Arrays.sort与手写快排

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/13 1:26:52

按位与路径构造题:贪心失效的本质与2×2黄金解法

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华