☰
51单片机红外遥控小车实战:红外解码与电机驱动全解析
2026/10/15 18:25:59 网站建设 项目流程

简介:51单片机红外遥控小车是一份完整的嵌入式入门实践工程,适合单片机学习者与科创爱好者动手复现。项目以8051为核心,结合红外接收头、电机驱动电路与马达,实现前进、后退、左转、右转的遥控控制,覆盖红外协议解析、PWM信号处理、中断服务程序编写及H桥驱动等关键知识点。压缩包共17个文件,大小仅40KB,内含main.c源码、STARTUP.A51启动文件、pro.uvproj工程文件及hex烧录文件等,结构精简清晰,便于直接打开学习或烧录验证。已有1106人浏览学习。借助该工程,读者可以掌握从硬件接线到软件解码的完整流程,理解NEC等红外编码规则,并学会如何用C语言控制电机驱动模块,为后续智能小车、机器人项目奠定扎实基础。

1. 51单片机红外遥控小车:先把最难的红外解码啃下来

做51单片机红外遥控小车,电机驱动是最不用操心的部分,L298N加四个IO口,方向逻辑翻来覆去就那几个组合。真正卡住进度的是红外解码:遥控器明明有反应,接收头也装好了,单片机解出来的键码却总是不一致,或者按下没反应。我第一次做这类项目时,代码逻辑和IO接线都没问题,最后查出来是定时器的计数单位没算对,白白折腾了一晚。这篇文章就按我做这个项目的完整路径来讲:红外接收、解码、电机驱动、整机联调,一步一步说清楚。新手能照着搭,做过的也能对照检查自己的细节。文中提到几个高频踩坑点,都是我反复折腾出来的经验。

2. 红外遥控小车的硬件选型与接线:从接收头到L298N的引脚分配

2.1 一体化接收头的选型与三个引脚坑

先确认协议。市面上消费级遥控器绝大多数是NEC协议,载波38kHz,所以接收端选一体化红外接收头就行,常见器件型号HS0038这类都可以。一体化接收头内置了光电二极管、AGC放大和带通滤波,输出的是TTL电平,不需要额外解调电路。你要做的只是把它输出的高低电平当成数字信号,用单片机去测量电平变化的时间间隔,从间隔里还原出按键码。

选型时有三件事容易翻车。第一是引脚顺序,HS0038这类接收头常见引脚定义是OUT、GND、VCC,但不同封装或兼容型号可能是VCC、GND、OUT的排列,买回来先对照丝印确认,接反了轻则不工作,重则烧器件。第二是输出级是集电极开路结构,内部没有上拉电阻,裸器件接单片机时,OUT和VCC之间要加一个10k上拉电阻;网购平台上的成品接收模块一般已焊好上拉,用模块就省这一步。第三是供电电压,按5V设计没问题,但有些兼容型号上限只有5.5V,别直接接到电机驱动板的板载稳压输出上,原因放到后面的电源部分讲。

接收头输出引脚接P3.2,这是外部中断0的输入脚。为什么一定要用中断口而不是普通IO轮询?因为NEC协议的一个码元周期在微秒级,轮询方式很难稳定捕获到下降沿,中断方式可以保证每次信号变化都被记录。大家常问“遥控器按下没反应是不是接收头坏了”,其实多数情况是接错引脚或没共地。想确认手里的遥控器到底是不是NEC协议,最简单的办法是逻辑分析仪看波形;没有仪器就先搭好解码代码,按一个键看能否稳定解出键码。如果串口打出来全是FF FF FF这类固定值,大概率是RC5、RC6之类的相位编码遥控器,直接换一个消费级NEC遥控器最省事。

2.2 L298N 驱动板的接线与共地原则

电机驱动用L298N模块是常见做法,它内部是双H桥,能同时驱动左右两个直流电机,板上还有一路逻辑电源稳压输出,接线相对简单。核心引脚分三组:逻辑输入IN1到IN4、使能端ENA和ENB、电机输出OUT1到OUT4。单片机的P1.0到P1.3分别接IN1到IN4,P1.4接ENA,P1.5接ENB。方向控制和调速是分开的:IN1、IN2组合决定电机A的转向,ENA上的PWM决定转速。

单片机引脚模块引脚说明
P3.2接收头 OUT红外信号输入,INT0下降沿触发
P1.0L298N IN1左电机方向控制 A
P1.1L298N IN2左电机方向控制 B
P1.2L298N IN3右电机方向控制 A
P1.3L298N IN4右电机方向控制 B
P1.4L298N ENA左电机 PWM 使能
P1.5L298N ENB右电机 PWM 使能
GND接收头 GND、L298N GND全部共地

接线里最容易出错的是共地。单片机的GND、接收头的GND、L298N的逻辑地必须连通,否则接收头输出的高电平相对单片机的地是悬浮的,单片机读到的电平全是乱的,解码自然失败。我见过有人把三个地分开接,折腾一下午没解出键码,把共地线连上立刻就好。电机选型方面,最常见的TT减速电机(工作电压3到6V)就够用,电池选6V的镍氢电池组或7.4V锂电池组。L298N本身有约2V压降,7.4V输入时电机两端大约5V多,对TT马达来说偏热但能接受;如果电机额定电压只有3V,建议选6V电池。

2.3 电源方案:为什么我的第一辆小车会复位重启

电源是整个小车最容易出隐患的地方。常见错误做法是:电机由电池直接供电,单片机由L298N板载5V稳压输出供电,接收头再从单片机5V取电。听起来合理,实际跑起来会出现一个经典现象:电机一转,单片机就复位,小车像抽筋一样一顿一顿。

原因是电机启动瞬间电流是正常运行的数倍,电池电压被瞬间拉低,L298N板载稳压器输入电压低于所需压差,输出5V跟着掉,单片机供电低于4.5V就复位。另外电机电刷产生的尖峰噪声会通过电源线传导到接收头,干扰红外信号。解决思路是尽量分开供电:电机用电池直接供电,单片机用独立的降压模块供电,三者的地仍然连在一起。如果板子上只有一路电源,那就把电池电压选高一点,比如7.4V锂电池组,保证L298N输入压降后还有足够余量输出稳定的5V。

接收头供电可以再加一道保险:在接收头VCC和GND之间并一个100uF电解电容加一个104陶瓷电容,或者串一个100Ω电阻再接5V。这个做法很土但非常有效,能滤掉大部分电机带来的电源纹波。这个坑放在硬件阶段讲,是因为后面软件调得再好,电源不稳都白搭。遇到“电机一转遥控就失灵”“小车突然复位”“接收头时好时坏”,先查供电,再查代码。

3. 51单片机红外解码代码:外部中断加定时器的最小可抄实现

3.1 NEC协议波形与接收头的反相输出

NEC协议一次完整帧是32位:8位地址码、8位地址反码、8位键码、8位键码反码,低位在前。发数据前先发引导码:9ms的38kHz载波脉冲,接着4.5ms空闲。Data 0是560us载波加560us空闲,总长1120us;Data 1是560us载波加1690us空闲,总长2250us。重复码是9ms载波加2.25ms空闲,按住按键不放时,每隔110ms发一次重复码。

接收头输出的是反相逻辑:空闲时输出高电平,收到38kHz载波时输出低电平。所以在接收头输出脚上看到的波形,低电平段就是载波段,高电平段是空闲段。NEC每个码元都由一个560us的低电平开头,然后接不同长度的高电平,因此下降沿正好是每个码元的起始边界。利用这个特征,在下降沿触发的外部中断里测量两次下降沿之间的时间间隔,就能区分出引导码、数据0、数据1还是重复码。

这个思路的核心是不直接读电平宽度,而是测码元周期。因为每个码元都是低段加高段组成,两次下降沿间隔就是完整码元长度,数值上区分度很明显:引导码约13500us,数据0约1120us,数据1约2250us,重复码约11250us。阈值留出足够余量,误判率就很低。

3.2 定时器0加外部中断0的解码代码

我用的是定时器0工作在模式1,16位自由计数,不自动重装。外部中断0配置为下降沿触发。每次进入中断,读定时器当前值,算出与上一次下降沿的间隔,然后把定时器清零重新计时。这样时间测量和码元判断完全解耦。

提示:12MHz晶振下定时器不加预分频,每个机器周期计一次数,也就是每微秒计一个数,读TH0和TL0拼出来的就是微秒数。

#include <reg52.h> sbit IR_IN = P3^2; // 接收头输出接P3.2,外部中断0输入 volatile uint32_t ir_code = 0; // 完整32位NEC帧 volatile bit ir_ready = 0; // 解码完成标志,主循环轮询 static uint8_t bit_count = 0; // 当前帧已收到的位数 /* 外部中断0服务函数:下降沿触发 */ void int0_isr(void) interrupt 0 { uint16_t duration; // 两次下降沿间隔,单位us uint8_t th = TH0; uint8_t tl = TL0; TH0 = 0; // 定时器清零,从0重新计时 TL0 = 0; duration = (th << 8) | tl; if (duration > 10000) { /* 间隔大于10ms:引导码或重复码,重新开始一帧 */ bit_count = 0; ir_code = 0; } else if (duration > 2000) { /* 间隔约2250us:数据1 */ ir_code = (ir_code << 1) | 1; bit_count++; } else { /* 间隔约1120us:数据0,也顺带过滤窄脉冲干扰 */ ir_code <<= 1; bit_count++; } if (bit_count >= 32) { ir_ready = 1; // 收满32位,交给主循环处理 bit_count = 0; } } /* 定时器0初始化:模式1,16位自由计数 */ void timer0_init(void) { TMOD &= 0xF0; // 只清低4位,保留定时器1的模式设置 TMOD |= 0x01; // 定时器0设为模式1 TH0 = 0; TL0 = 0; ET0 = 1; TR0 = 1; } /* 外部中断0初始化:下降沿触发 */ void ext0_init(void) { IT0 = 1; // INT0下降沿触发 EX0 = 1; EA = 1; }

几个参数说明。duration单位是微秒,12MHz晶振下直接读TH0、TL0拼成16位即可。如果换了11.0592MHz晶振,计数频率变成0.9216MHz,读出来的值单位变成约1.085us,判断阈值也要按比例换算,最省事的做法是继续用12MHz晶振。数据0和数据1的阈值放在2000us,数据0是1120us,数据1是2250us,中间有一倍以上的空档,不会误判。10000us的引导码阈值同理,只有真正的引导码和重复码会超过。

中断服务函数里只做时间和位移操作,不打印、不判断按键、不调用任何外部函数。中断处理时间过长会让下一次下降沿触发被延迟,间隔测量失真,这是解码丢码最常见的原因。严格做法是先读TH0再读TL0再读一次TH0比对,不一致就重读一遍,防止计数进位瞬间读到错值;代码里为了清晰没写这个重读逻辑,实际工程建议加上。这个解码方案能解出完整32位帧,但校验码检查放在主循环做,因为中断越短越好,按键处理和电机控制这类非实时任务放到主循环更合理。

3.3 键码映射:先实测键码再写功能

NEC帧的位序是低位先发,收到的ir_code里最低位是帧的第一个数据位。地址码占bit0到bit7,地址反码占bit8到bit15,键码占bit16到bit23,键码反码占bit24到bit31。在“累计32位后一次读出”的架构下,不需要关心发送顺序,只需要知道键码从bit16开始,这个结论是确定的。

我的习惯是先写一段临时代码,把ir_ready触发时收到的ir_code用十六进制发到串口,按一次按键记录一次值,连续按三次取值一致的就是这条按键的稳定码。以下是手头遥控器的实测值,不同遥控器可能不同,但格式可以参考:

按键完整帧(十六进制)键码(bit16~23)
CH-0x00FF45BA0x45
CH+0x00FF46B90x46
左0x00FF44BB0x44
右0x00FF43BC0x43
暂停0x00FF40BF0x40

校验逻辑:地址码和地址反码取反后应相等,键码和键码反码同理。主循环里判断ir_ready后取键码并做反码校验,通过才执行按键动作:

void main(void) { timer0_init(); ext0_init(); while (1) { if (ir_ready) { ir_ready = 0; /* 键码取bit16~23 */ uint8_t key = (ir_code >> 16) & 0xFF; /* 校验:键码与键码反码按位异或应为0xFF */ if ((key ^ (ir_code >> 24)) == 0xFF) { key_action(key); } } } }

反码校验这一步很多人会省掉,但加上之后抗干扰能力明显提升。如果某次按键受噪声影响解错了某一位,键码和反码的校验关系大概率对不上,这次数据直接丢弃,不会让小车乱跑。

4. 电机驱动与运动控制:L298N四线制和PWM调速的工程细节

4.1 方向控制真值表与转弯方式

L298N的每个H桥由两个逻辑输入控制,逻辑关系简单:IN1=1、IN2=0,电机A正转;反过来反转;两个都为0是自由停止;两个都为1是刹车,小车场景一般不用。左右电机组合出来的运动方式如下:

IN1IN2IN3IN4运动状态
1010前进
0101后退
0110原地左转
1001原地右转
0000停止

原地转的方式是左右轮反向转,适合场地小的遥控场景。还有一种弧线转弯是只转一侧轮子,另一侧停止,转弯半径更大。我做这辆小车用的原地转,因为遥控操作的核心诉求是想停就停、想转就转,原地转对空间要求最低,操作手感最直接。原地转时左右电机都通电,电流是前进的两倍,电池电压跌落会比前进时更明显,所以转向占空比我一般比前进低10个百分点。

这里有一个容易忽略的点:真值表只管方向,不管速度。如果方向组合正确但ENA一直为高,电机会直接全速转,上电瞬间容易冲出去。所以程序启动第一件事就是把所有IN全部拉低,再对ENA输出PWM。方向组合和PWM是两回事,不要混在一起理解。

4.2 用定时器1中断模拟PWM调速

51单片机没有硬件PWM外设,最通用的做法是用定时器1中断模拟。我选择10ms一个PWM周期,也就是100Hz,在这个频率下直流减速电机的转速抖动可以接受,电流声也不明显。定时器初值按100us中断一次计算,12MHz晶振下重装值为65536减100,也就是0xFF9C。中断里累加一个计数器,用比较方式输出:

sbit ENA = P1^4; sbit ENB = P1^5; volatile uint8_t pwm_left = 0; /* 左轮占空比 0~100 */ volatile uint8_t pwm_right = 0; /* 右轮占空比 0~100 */ volatile uint8_t pwm_cnt = 0; /* 100us中断累积计数 */ /* 定时器1初始化:模式1,12MHz下每100us中断一次 */ void timer1_init(void) { TMOD &= 0x0F; /* 只清高4位,保留定时器0的设置 */ TMOD |= 0x10; /* 定时器1设为模式1 */ TH1 = 0xFF; TL1 = 0x9C; /* 重装值65536-100=0xFF9C */ ET1 = 1; TR1 = 1; } /* 定时器1中断服务函数:每100us一次 */ void timer1_isr(void) interrupt 3 { TH1 = 0xFF; TL1 = 0x9C; pwm_cnt++; if (pwm_cnt >= 100) { pwm_cnt = 0; /* 100次累加,构成一个PWM周期 */ } ENA = (pwm_cnt < pwm_left) ? 1 : 0; ENB = (pwm_cnt < pwm_right) ? 1 : 0; }

pwm_left的值在0到100之间,pwm_cnt从0加到99。占空比50就是把前50个100us设为高电平,后50个设为低电平。这个比较式输出的好处是占空比修改即时生效,不需要重新配置定时器。转速初值我一般设60,也就是60%占空比,TT马达在这个占空比下扭矩足够,电量消耗也慢。如果发现小车不动,先把占空比调到80再试,排除是电机扭矩不够还是驱动没接对。定时器1和定时器0的TMOD赋值互不影响,代码里用了与操作和或操作分开设置,这是51单片机初始化里很容易写错的地方。

4.3 主循环整合:遥控、转向、停止的状态流转

把解码和驱动拼到一起,按键功能映射按应用需求分成两种方式。一种是单帧执行,每按一次按键执行一个动作并保持,适合前进、后退这类需要持续保持的指令;另一种是长按连续动作,松开就停,需要额外处理NEC协议的重复码。先实现单帧执行版:按下前进键,小车一直前进,直到按下停止键。这在遥控小车里很常见,逻辑也最简单。

void key_action(uint8_t key) { switch (key) { case 0x45: /* CH-:前进 */ motor_forward(60); break; case 0x46: /* CH+:后退 */ motor_backward(50); break; case 0x44: /* 左:原地左转 */ motor_left(50); break; case 0x43: /* 右:原地右转 */ motor_right(50); break; case 0x40: /* 暂停:停止 */ motor_stop(); break; default: break; } } void motor_forward(uint8_t speed) { IN1 = 1; IN2 = 0; IN3 = 1; IN4 = 0; pwm_left = speed; pwm_right = speed; } void motor_left(uint8_t speed) { IN1 = 0; IN2 = 1; /* 左轮后退 */ IN3 = 1; IN4 = 0; /* 右轮前进 */ pwm_left = speed; pwm_right = speed; } void motor_stop(void) { IN1 = 0; IN2 = 0; IN3 = 0; IN4 = 0; pwm_left = 0; pwm_right = 0; }

左右电机的制造误差会导致实际转速有偏差,原地左转和原地右转的转速可能不一样。如果左转明显比右转快,可以单独把某一侧的占空比调低5到10个百分点,这是最粗糙也最有效的校准方式。校准系数放到后面避坑章节详细说。主循环里除了检测ir_ready,还可以加一个按键超时逻辑:比如3秒没收到任何有效帧就自动停车,防止小车失控后一直往前跑,这个功能在窄小场地里很实用。

5. 红外遥控小车常见问题排查:五条高频踩坑记录

5.1 解码乱码,同一个按键每次键码都不一样

现象:按下同一个按键,串口打印出来的ir_code每次都不同,或者干脆打印不出来。

原因排查:先确认晶振频率。12MHz下定时器0的计数单位是1us,换成11.0592MHz后计数单位变成约1.085us,如果阈值没换算,数据1的2250us读出来约2442,还在数据1范围内,不容易误判;但数据0的1120us读出来约1215,离2000的阈值仍然很远,也不会误判。所以晶振不是主要原因。真正常见的两个问题:接收头供电纹波太大导致波形畸变,以及中断服务函数里处理了太多事情,导致下一次下降沿到来时中断还没返回,间隔测量被拉长。我把串口打印临时放到中断里调试时,解码成功率直接掉了一半,这个坑印象很深。

解决:中断服务函数里只做计时和移位,不打印、不判断按键、不调用任何函数;接收头供电加滤波电容。我在接收头VCC和GND之间并了一个100uF电解电容加一个104陶瓷电容,乱码问题直接消失,比调代码阈值更有效。如果还是乱码,用万用表量接收头VCC电压,电机空转时电压波动超过0.3V就说明供电隔离没做好。

5.2 上电瞬间小车猛冲一下然后才停住

现象:一上电,小车明显蹿出去一小段然后停下,之后按键操作又正常。

原因:单片机复位期间IO口输出高电平,L298N的IN1到IN4在悬空状态下被内部电路置成不确定的组合,如果刚好是前进组合并且ENA为高,电机就得电转了。ENA使能端在复位期间同样受IO状态影响,所以上电瞬间的电机动作几乎是每次都能复现,不是偶发现象。

解决:在main函数最开始、任何初始化之前调用motor_stop()把所有IN拉低,同时把ENA和ENB也拉低。硬件上更保险的做法是在ENA和ENB对地各加一个10k下拉电阻,保证复位期间使能端一直为低。我两个方法都用了,之后再没出现过上电猛冲。注意motor_stop()里要同时把pwm_left和pwm_right清零,否则PWM中断一旦开启,即使IN全是低电平,使能端也可能被占空比拉高。

5.3 电机一转遥控就失灵,这锅真要电源背

现象:待机时遥控正常,按前进键电机一启动,红外遥控就没反应;或者电机转起来之后键码错误率明显上升。

原因:电机启动瞬间电流是正常运行的数倍,电池电压瞬间跌落。接收头和单片机共用同一路5V时,跌落直接传导到接收头电源上;接收头内部AGC电路对供电电压敏感,电压波动会让输出波形畸变。另一种常见干扰是电机电刷噪声通过地线耦合到接收头,让解码阈值被打乱。

解决:把接收头和单片机的供电从电机电源中独立出来。我用的是一个单独的降压模块给单片机供电,电池直接给L298N的VS供电;如果只能共用L298N板载5V,那就在电机两端并联104陶瓷电容,并把电机线双绞后远离接收头。这两条都做不到的话,至少保证共地只在一个点连接,避免地环路把电机噪声带进接收头。这个现象是典型的“软件调不出结果就怀疑电源,电源处理好软件就好了”。

5.4 左右转向不对称,转着转着就偏

现象:按左转,小车明显比右转转得快,或者直线前进时走不了直线,总往一边偏。

原因:两个电机的出厂转速本来就有差异,加上左右轮与地面摩擦不同、电池电压在两侧分配不均,都会导致两侧转速不一致。遥控小车在开环控制下这是必然现象,不算故障。但转向不对称会直接影响操控手感,让人误以为解码或驱动逻辑有问题。

解决:先实测两侧轮子的空载转速差,然后固定两个校准系数。做法是在程序里定义left_k和right_k两个常量,占空比赋值时乘上校准系数再取整。我实测发现左轮比右轮快约8%,于是pwm_left = speed,pwm_right = speed * 108 / 100。校准系数最好在50%和80%两个占空比下各测一次,因为直流电机在不同占空比下转速线性度略有差异,取平均值更稳。

5.5 按键松开小车继续跑,或长按抖动停不下来

现象:按一下前进键,小车一直前进,再按停止才停,这是单帧执行逻辑,本身没问题。但换成长按模式后,按住前进键小车抖动,或者按键松开小车还在跑。

原因:NEC长按时发的是重复码,重复码只有引导码加2.25ms空闲,没有数据部分。如果代码把重复码也当成新帧处理,ir_code会被清空并重新累积,结果就是按下前进键后,小车动一下停一下的抖动。如果代码要求必须收到完整32位才动作,重复码会被直接忽略,长按不会产生连续动作,松开按键时也没有新的帧到来,小车自然保持上一个状态继续跑。

解决:按应用需求二选一。要单帧锁定式控制,就在解码代码里把重复码丢弃,只有完整帧才置ir_ready,当前代码已经是这个行为;要长按连续动作,就在解码里增加一个repeat标志,主循环检测到重复码时保持当前动作不变,同时设一个定时器,重复码中断超过200ms就停车。我习惯用单帧锁定式控制,逻辑简单误触少,适合遥控小车这种手动操作场景。

6. 进阶:串口调参与状态机重构,让小车更可靠

6.1 用串口把解码值打印出来再映射按键

前面的键码表是实测来的,实测方法就是串口打印。51的串口1在12MHz晶振下建议用2400bps,波特率计算公式是晶振频率除以12再除以32再除以(256减TH1),TH1取0xF3时实际波特率约2403bps,误差0.15%,可以稳定通信。9600bps在12MHz晶振下误差偏大,串口助手会看到乱码,这是很多人调试时误以为串口坏了的原因。

SCON = 0x50; /* 串口模式1,8位UART,允许接收 */ TMOD &= 0x0F; /* 不动定时器0的模式 */ TMOD |= 0x20; /* 定时器1设为模式2,8位自动重装 */ TH1 = 0xF3; TL1 = 0xF3; /* 2400bps @ 12MHz */ TR1 = 1;

然后在ir_ready置位后,把ir_code按十六进制通过串口发出。串口端看到同一个按键三次返回同一个值,说明解码链路稳定,可以放心写按键映射。如果三次返回都不一样,先别急着调按键逻辑,回头查电源和中断处理时间。串口调试这个习惯我一直留着,后面加超声波避障模块、调试PID参数时,串口都是最直接的观察窗口。

6.2 用状态机重构解码中断,抗干扰更强

当前解码是纯时序轮询,逻辑简单但不够稳。改进做法是把解码过程拆成状态机:空闲态、引导态、数据态。空闲态遇到长间隔进入引导态,引导态确认后进入数据态,每个数据位根据间隔判定0还是1。状态机的好处是能够明确区分引导码和重复码,也能在收到半帧噪声时自动回到空闲态,不会把半帧脏数据当成有效帧。中断服务函数体积会变大,但每个分支的逻辑更清晰,调试时也更容易定位问题。

typedef enum { IR_IDLE, IR_GUIDE, IR_DATA } ir_state_t;

这个重构不是必须的,当前方案稳定就不动。我自己是在加了超声波避障之后才做的重构,因为主循环变长之后,原来的中断解码丢帧率开始上升,状态机方式对主循环延时的容忍度明显更高。做完状态机重构后,同时把主循环里所有耗时操作都控制在2ms以内,解码就再没掉过帧。

把小车从“能跑”变成“好用”,我最深的体会是:红外解码的稳定性不是靠代码逻辑堆出来的,而是靠供电、接地、中断精简这三件事。硬件底子打好了,软件只是时间问题。做这类51单片机红外遥控小车项目,先让电源和共地过关,再让解码稳定,最后才是按键映射和花哨功能,这个顺序反过来就是反复返工。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询