简介:基于 C51 单片机的电动智能小车毕业设计文档,面向电子信息、自动化等专业学生及相关单片机开发者,可作为课程设计、毕业设计或课外实践的直接参考资料。资源以 80C51 单片机为控制核心,围绕自动避障、自动寻迹、寻光、快慢速行驶与自动停车等功能,系统讲解直流电机 PWM 调速、超声波传感器与光电检测器应用、新型显示芯片驱动,以及时钟复位、前向/后向通道等硬件电路设计方法。文档覆盖方案设计与论证、硬件设计、软件主程序及子程序设计、测试数据与结果分析,还融入软件抗干扰和看门狗技术,并附有程序清单与硬件原理图。压缩包为 1 个 doc 文档,大小 5.42MB,结构完整、层次清晰,已有 448 人学习浏览,适合需要快速理解系统框架、复现电路与代码并在此基础上进行功能扩展的读者。
1. 80C51智能电动小车的设计目标与系统构成
一辆玩具电动车底盘改造的智能小车,能完成的事情比多数课设要求的更多:超声波传感器探测正前方障碍,红外光电对管识别地面黑线与光线方向,光电码盘测速测距,数码管实时显示时间、里程和速度,PWM脉宽调速控制快慢行驶和定位停车。这个毕业设计的核心难点不是让车跑起来,而是把8位单片机有限的I/O资源、中断系统和外部检测电路做成一个合理分配的整体——80C51只有128字节片内RAM、2个16位定时器和4个并行口,所有功能都必须在这套资源里装下。这套设计适合正在做课设或毕设、手里有一套散件却不知道从哪里开始搭电路和写程序的人,也适合想把传感器选型和调速链路一次理清的人。
2. 传感器检测通道:超声波避障、红外寻迹与光电码盘测速的实现
2.1 障碍物检测:40kHz超声波收发链路
超声波测距的基本关系是距离=声速乘往返时间再除以2,工程实现的关键在接收信号的放大和判决。T/R-40-12是常见的收发分体式超声波传感器,中心频率40kHz,发送器由80C51输出的40kHz方波驱动,接收器把回波转换成毫伏级电压信号,先经LM318做两级放大,再送到带锁相环的音频解码芯片LM567。输入信号大于25mV时,LM567输出端从高电平跳变为低电平,这个电平变化直接作为80C51的查询输入。
// 40kHz超声波发送脉冲生成(定时器0方式2,8位自动重装) void ultrasonic_send(void) { unsigned char i; TH0 = 0xF4; // 12MHz晶振下定时12us,约41.7kHz TL0 = 0xF4; TF0 = 0; TR0 = 1; // 启动定时器,方式2自动重装 P1_0 = 0; for (i = 0; i < 16; i++) // 16次翻转,输出8个完整方波 { while (!TF0); // 等待定时器溢出 TF0 = 0; P1_0 = ~P1_0; // 翻转输出,形成半周期 } TR0 = 0; // 停止定时器 }初值0xF4对应256减12,在12MHz晶振、12分频模式下机器周期为1us,每12us翻转一次引脚,输出方波频率约为41.7kHz。这个频率相对40kHz有约4%的偏差,在T/R-40-12的带宽范围内可以正常起振和接收。如果想要更接近40kHz,可以改用11.0592MHz晶振并重新计算初值,或者把定时长度调整为13us,输出约38.5kHz。完整发送一次需要16乘12us约192us,这个阻塞时间对周期几十毫秒的避障检测来说可以接受。
提示:设计文档里写"中心频率为40Hz"属于笔误,压电晶片的实际中心频率是40kHz,驱动脉冲序列必须按40kHz生成,否则灵敏度会大幅下降。
超声波的接收侧没有软件代码,主要靠硬件判决。LM567是锁相环音频解码器,它的中心频率由外接电阻电容决定,调试时要把中心频率调到和发射频率一致。接收信号经LM318两级放大后送入LM567,信号幅度大于25mV时输出低电平。用示波器看LM567第8脚,在障碍物接近时能看到电平被拉低,拉低的持续时间对应超声波往返时间。这个时间信号如果送给定时器1做输入捕获,可以算出精确距离;如果只是做避障判断,直接查询电平跳变就够用。
2.2 寻迹检测:反射式红外光电传感器的地面线识别
寻迹检测采用反射接收原理。红外发光二极管持续发射红外光,红外光敏三极管接收地面反射回来的光线。白纸表面反射率高,接收管导通,输出高电平;黑色线条吸收红外光,接收管截止,输出低电平。这一高一低直接反映小车是否压到黑线。原始信号直接接单片机也能工作,但地面反光不均匀、环境光干扰叠加会产生毛刺,所以传感器输出到80C51之间串了LM393电压比较器和74LS14施密特触发器两级处理,比较器提供明确阈值,施密特触发器提供回差,保证电平切换干净。
// 寻迹信号读取:P3.4接收左传感器,P3.5接收右传感器 unsigned char track_read(void) { unsigned char status = 0; if (!P3_4) status |= 0x01; // 左侧压黑线,输出低电平 if (!P3_5) status |= 0x02; // 右侧压黑线,输出低电平 switch (status) { case 0x00: return 0; // 两侧都未压线,直行 case 0x01: return 1; // 左侧压线,向右修正 case 0x02: return 2; // 右侧压线,向左修正 case 0x03: return 3; // 两侧都压线,到达起终点 } return 0; }这段代码把压线定义为低电平有效,和原文"经过黑线时传感器输出低电平"一致。P3.4和P3.5需要配置为输入模式。返回的状态值被主循环用来做转向决策,case 3同时意味着小车到了起终点黑线,程序转入停车记录里程。LM393是开漏输出,上拉电阻通常选4.7kΩ到10kΩ,阈值由反相输入端的电位器分压设定。调试时把小车推到黑线上,调节电位器到刚好翻转,再推回白纸确认输出恢复,阈值就定住了,不要只在一个位置调完就认为完成。
2.3 测速与里程:红外光电码盘的双通道计数
测距的核心部件是测距轮、遮光盘和槽型光电耦合器。遮光盘安装在车轮轴上,圆周开一个缺口,缺口转过凹槽型光电耦合器的瞬间,红外发射管的光线穿过缺口照到接收管,产生一个脉冲。测距轮每转一圈输出一个脉冲,车轮周长0.1米的话,每个脉冲对应0.1米行程。可逆计数需要两个槽型光电耦合器并列放置,遮光盘先后通过两个凹槽产生两个相位差90度的脉冲,根据到达先后判断正转还是反转,正转时A相先到,反转时B相先到,这就是工程里常见的正交编码计数思路。
// 只把A相接INT0中断,B相接P3.3判断方向 void ext0_isr(void) interrupt 0 { if (P3_3) distance++; // A相中断时B相为高,正转 else distance--; // A相中断时B相为低,反转 }INT0中断按A相每个脉冲触发一次,B相只作为方向参考,避免了两个通道都进中断造成的重复计数。distance是unsigned int类型,最大可计数65535个脉冲,对应约6.5公里,课设场景够用。如果行程更长,需要改成unsigned long并在主循环里定期保存。遮光盘和槽型光电耦合器应当封装在不透光的盒子里,外部光线一旦干扰接收管,脉冲波形会出现毛刺,直接影响里程精度。
表:码盘脉冲与行车参数换算(车轮周长0.1米)
| 参数 | 计算方式 | 示例 |
|---|---|---|
| 里程 | 脉冲数乘单脉冲行程 | 1000脉冲等于100米 |
| 速度 | 单位时间脉冲数乘单脉冲行程 | 10脉冲每秒等于1米每秒 |
| 行驶时间 | 定时器中断累计 | 定时器1计数 |
| 方向 | A相与B相脉冲先后 | A先到为正转 |
2.4 光线跟踪:光敏三极管的方向检测
光线跟踪用两个光敏三极管,分别放在车头左右两侧。有光照时三极管c-e间阻值下降,检测电路输出高电平;无光照时阻值升高,输出低电平。左右两个传感器组合决定转向电机动作:左侧受光则左转,右侧受光则右转,两侧同时受光则直行。信号同样经过LM393加74LS14两级处理,因为光敏三极管输出是模拟量,环境光缓慢变化会让输出处于临界区,直接接I/O口会反复跳变,加入比较器和施密特触发器后就稳定多了。
表:左右光敏管状态与转向逻辑
| 左侧光敏管 | 右侧光敏管 | 转向控制 |
|---|---|---|
| 1 | 0 | 向左转 |
| 0 | 1 | 向右转 |
| 1 | 1 | 直行 |
| 0 | 0 | 保持上一状态 |
检测通道的四个功能到这里就分开了。实际系统里它们不是各自独立工作,而是主循环里按优先级读取:寻迹状态决定是否到站,超声波状态决定是否要避障,码盘脉冲保证里程累计,光敏管只在追光模式里启用。把这四个信号在单片机侧汇总,就进入下一层的执行机构控制——PWM调速。
3. 双极式H型PWM调速:从方案对比到驱动代码
3.1 调速方案对比
直流调速有三条常规路线:串电阻调速、可控整流V-M系统、脉宽调制PWM。串电阻调速在电机回路串入功率电阻,用电阻值调节电机端电压,结构最简单,但能量全部消耗在电阻上,效率低,换档时转矩冲击大。V-M系统用晶闸管整流替代旋转变流机组,能够平滑调速,但晶闸管的单向导电性让电流不能反向,可逆运行需要额外配置桥臂,低速时功率因数低还产生谐波。PWM让功率管工作在开关状态,开关频率高,电枢电流靠电机电感滤波就能获得很小的脉动,低速平稳、调速范围宽、效率高。对这个项目来说,PWM是唯一能同时满足调速范围、效率和可逆控制三个条件的方案。
表:三种直流调速方案的对比
| 方案 | 效率 | 调速范围 | 可逆性 | 系统复杂度 |
|---|---|---|---|---|
| 串电阻 | 低 | 窄 | 不支持 | 低 |
| V-M系统 | 中 | 中 | 需扩展桥臂 | 高 |
| PWM | 高 | 宽 | 自然支持 | 中 |
3.2 双极式H型变换器的工作原理
双极式H型变换器由4个三极管和4个续流二极管组成桥式电路,电机接在桥路对角线上。VT1和VT4是一组,基极驱动电压相同;VT2和VT3是另一组,驱动电压与第一组反相。两组管子交替导通,电机电枢两端电压极性周期性反转,这就是"双极式"名称的出处。占空比大于50%时正组导通时间更长,平均电压为正,电机正转;小于50%时平均电压为负,电机反转;等于50%时平均电压为零,但电机两端仍然交替承受正负电压,产生微振电流,能消除静摩擦死区,让启动更干脆。
双极式变换器最大的优点是电流连续。不管占空比多小,续流二极管总在关断期间维持电枢电流,低速运行不会有电流断续引起的转速抖动,这也是它能做到很宽调速范围的原因。缺点也有,四个管子始终处于高频开关状态,开关损耗比单极式大,但在这个小功率玩具车平台上是完全可接受的。
3.3 单片机生成PWM信号的实现
用80C51生成PWM有两种做法,一种是定时器中断翻转引脚,另一种是外接专用PWM芯片。对课设级双电机控制,定时器中断足够,只是中断频率要规划好。PWM频率高则电流脉动小,但中断负担重;频率低则开关损耗小,但电流脉动变大,电机噪音明显。我一般会把PWM频率取在100Hz到1kHz之间,下面代码用100us定时加100次计数,合成10ms周期100Hz的PWM。
// 定时器1中断生成PWM,P1.1输出,周期10ms,占空比由speed变量控制 void timer1_isr(void) interrupt 3 { static unsigned char cnt = 0; TH1 = 0xFF; // 65536-100=65436,即0xFF9C TL1 = 0x9C; // 12MHz晶振下定时100us cnt++; if (cnt < speed) // speed范围0到100,即占空比数值 PWM_OUT = 1; else PWM_OUT = 0; if (cnt >= 100) cnt = 0; // 100次计数构成一个PWM周期 } void motor_speed(unsigned char percent) { if (percent > 100) percent = 100; speed = percent; // 修改占空比目标值,中断里自动生效 }定时器1每100us进入一次中断,cnt从0递增到99,当cnt小于speed时输出高电平,否则输出低电平,cnt到100清零重来。speed是一个全局变量,数值就是占空比百分比,motor_speed函数只改这个变量,PWM波形自动跟随,不需要停掉定时器。初值计算依据:12MHz晶振除以12分频得1MHz机器周期,100us就是100个机器周期,初值65536减100等于65436,十六进制0xFF9C。如果把晶振换成11.0592MHz,这个值要重新算。
提示:PWM频率不能无脑提高。三极管和续流二极管的开关损耗与频率成正比,频率过高时管子发烫,反而抵消PWM的效率优势。调试时先固定频率只看占空比,确认车速符合预期后再去优化频率设置。
3.4 占空比与变速策略
原文提到"进入减速区时由单片机控制进行PWM变频调速",这里的"变频"实际含义是改变占空比序列,不是改变PWM频率本身。快速行驶和慢速行驶对应两组占空比设定,停车场合则用反接制动。反接制动的做法是让占空比瞬时跳到低于50%,平均电压反向,电机快速停转。
// 速度模式控制 void speed_control(unsigned char mode) { switch (mode) { case MODE_FAST: motor_speed(80); break; // 快速巡航 case MODE_SLOW: motor_speed(40); break; // 减速区行驶 case MODE_BRAKE: motor_speed(5); break; // 反接制动停车 default: break; } }停车占空比设成5而不是0,是因为完全断电后电机处于自由滑行状态,停车位置很难控制。保留5%占空比让电枢平均电压微反向,相当于给电机一个倒拖力,停车更精准。这个值跟底盘重量、地面摩擦、电池电量都有关系,需要现场实测。电池电压下降后同样占空比对应车速会变低,所以里程和速度显示要基于码盘脉冲而不是占空比换算。
4. 显示电路与软件架构:数码管驱动、中断分配与看门狗
4.1 两片4位八段数码管的双重显示策略
显示部分用两片4位八段数码管gem4561ae。8位数码管按功能拆成两组:小车停放时一片显示年月,另一片显示时分;行驶时一片显示时间,另一片显示行驶距离。这样免去了切换按键,也不会在行驶中因为切换显示内容而丢失数据。动态扫描是八段数码管的标配驱动方式,段选线和位选线分开,逐位轮流点亮,靠人眼视觉暂留形成同时亮的效果。P0口做段选输出必须外接上拉电阻,P2口部分引脚做位选。
// 动态扫描显示:P0输出段码,P2低4位输出位选 void display_scan(void) { unsigned char i; unsigned char code seg_table[] = { 0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07, // 共阴段码0-7 0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71 // 共阴段码8-F }; for (i = 0; i < 4; i++) { P0 = seg_table[disp_buf[i]]; // 取当前位段码 P2 = (P2 & 0xF0) | (1 << i); // 选中第i位数码管 delay_ms(1); // 点亮保持1ms } }段码表按共阴数码管排列,0x3F对应数字0。P2低4位做位选,高4位保留给其他功能,所以写P2时先与0xF0保持高位不变。扫描周期是4ms,刷新率250Hz,肉眼看不到闪烁,亮度也均匀。如果显示数据在行驶中变化,更新disp_buf和扫描无冲突,扫描只读缓冲区,主循环只管写缓冲区。
4.2 主程序运行框架
主程序是初始化加主循环的经典结构。上电先完成时钟、定时器、外部中断和显示缓冲区初始化,然后进入循环,轮询传感器状态、更新速度输出和显示内容。没有操作系统,任务通过中断和主循环两层配合。
void main(void) { system_init(); // 时钟、I/O、定时器、中断初始化 while (1) { unsigned char s = track_read(); // 读寻迹传感器状态 if (s == 3) stop_and_log(); // 压到终点黑线,停车并记录数据 if (ultrasonic_check()) handle_obstacle(); // 检测到障碍则避障 update_display_data(); // 更新显示缓冲区数据 delay_ms(10); // 主循环节拍10ms } }主循环是顺序查询所有输入、按优先级处理的骨架。寻迹优先级高于避障,因为压到终点黑线表示到站,必须立即停车;超声波避障在中途行驶时生效。每轮循环固定延时10ms,让轮询节拍稳定,避免传感器读取频率忽快忽慢。中断部分负责码盘计数、PWM生成和显示扫描,主循环不碰这三个硬件模块,从结构上减少竞争。
4.3 避障子程序与决策逻辑
避障逻辑本身不复杂,超声波检测正前方,左右红外光电传感器判断障碍偏向,障碍在哪侧就往另一侧转向。但超声波传感器的探测周期受声速限制,40kHz脉冲在空气中往返0.5米约需1.5ms,发送加等待至少要3ms,所以避障判断不能追求太快,要给超声波留完整的发送接收窗口。
表:避障决策矩阵
| 超声波检测 | 左侧红外 | 右侧红外 | 执行动作 |
|---|---|---|---|
| 有障碍 | 有障碍 | 无障碍 | 向右转 |
| 有障碍 | 无障碍 | 有障碍 | 向左转 |
| 有障碍 | 无障碍 | 无障碍 | 减速直行 |
| 无障碍 | 任意 | 任意 | 保持当前速度 |
这个矩阵没有覆盖两侧都有障碍的情况,实际遇到时我一般处理成原地掉头或倒车后退,课设场景里很少出现。判断结果直接调用speed_control切换速度模式,转向电机的动作由转向继电器或H桥的另一组输出控制。
4.4 软件抗干扰与看门狗
运行环境里的干扰主要来自电机换向火花和PWM开关噪声。电机是感性负载,PWM切换瞬间产生很大的电流变化率,通过电源线和地线窜入单片机复位电路,轻则程序跑飞,重则直接复位。硬件上在电机两端并联续流二极管和RC吸收网络,软件上采用指令冗余、软件陷阱和看门狗三重手段。指令冗余是在关键跳转和返回指令前插入NOP,软件陷阱在未用程序区填充跳转指令,看门狗最后兜底。
// 定时器2作看门狗,正常运行时周期性喂狗 void watchdog_feed(void) { TL2 = 0x00; // 清零低字节 TH2 = 0x00; // 清零高字节,防止溢出复位 } void timer2_isr(void) interrupt 5 { while (1); // 溢出复位前的死循环,等硬件复位 }喂狗必须在主循环每个周期执行一次,一旦主循环卡住,定时器2超时溢出就触发复位。喂狗指令不能放在中断服务程序里,否则主循环跑飞、中断还在执行时看门狗永远被喂饱,就失去了监视作用。如果后续要扩展成串口升级架构,这套硬件平台可以直接复用,把RXD和TXD预留出来,引导程序放低地址区、应用程序放高地址区,串口接收固件后写入Flash即可,不过课设阶段先把传感器和PWM两条主线调稳更实际。
5. 调试与验证:传感器标定、车速映射与故障定位
5.1 传感器阈值标定
红外寻迹传感器的灵敏度不是固定值。地面红外反射率跟纸张颜色、表面粗糙度、环境光强都有关系,必须现场标定。标准步骤是:小车停白纸上,万用表测比较器输出,调电位器到输出稳定高电平;推到黑线上方,确认输出翻转为低电平。两个位置反复切换几次,找到同时满足条件的电位器位置后紧固。超声波部分用硬纸板放在20cm、50cm、1m处,示波器看LM567输出,确认都能稳定输出低电平脉冲。近处检测不到通常是发送过强导致接收饱和,需要减小发送幅度;远处检测不到则检查LM318放大倍数。
5.2 PWM占空比与车速映射
占空比和车速不是线性关系。电机端电压是占空比的线性函数,但转速还受反电动势和负载影响。调试时用秒表计时,让小车在10米直道上分别以固定占空比行驶,记录平均速度,形成一张对照表。拿到表之后,程序里的速度控制就从"写占空比"变成"写目标车速",查表得到占空比,逻辑清晰得多。
表:某样车实测占空比与车速对照
| 占空比 | 实测车速(米每秒) | 适用场景 |
|---|---|---|
| 30% | 0.4 | 慢速寻迹 |
| 50% | 0.8 | 巡航 |
| 70% | 1.3 | 快速行驶 |
| 90% | 1.6 | 追光 |
5.3 里程计数与停车精度验证
码盘计数误差主要来自遮光盘缺口宽度偏差和高速旋转时的中断丢脉冲。验证方法是让小车在已知长度直道上行驶,对比累计里程与实际距离。10米直道如果计数在98到102个脉冲之间波动,属于合理误差;普遍偏少优先查中断服务程序执行时间,把非必要指令删掉;脉冲数时多时少不稳定,检查遮光盘是否偏心、缺口每次都能完整通过凹槽。停车重复性用同一启动点和停车条件跑10次,偏差在正负5厘米内可接受,超出就要重新调反接制动占空比和制动延时,这两个参数跟地面摩擦和电池电压关联很大。
// 码盘脉冲数转里程显示 float pulses_to_meter(unsigned int pulses) { return (float)pulses * 0.1f; // 每个脉冲对应0.1米 }5.4 高频信号测量与常见故障排查
调试中最容易同时出现的两个症状是数码管闪烁和电机转速不稳,它们往往是同一个原因:电源线上叠加了PWM开关噪声。排查顺序固定为:先用示波器看单片机VCC引脚纹波,再检查电机电源和逻辑电源是否共地,最后确认续流二极管是否反接。测量PWM波形时探头地线就近接单片机GND,不要接电机电源地,否则地线回路上叠加的开关噪声会淹没真实波形。另一个高频坑是P0口上拉电阻取值:过大数码管亮度不足,过小P0口灌电流过大,常见做法是4.7kΩ或10kΩ的八联排阻,段电流由限流电阻单独决定。
本文还有配套的精品资源,点击获取