
简介《基于单片机的停车场计数系统设计》是一份面向单片机课程设计、毕业设计及电子竞赛参赛者的完整设计文档围绕STC89C52单片机实现停车场车辆计数、进出控制与报警。系统方案涵盖红外对射式传感器检测、液晶显示、继电器开关与按键设置并给出主程序、数据采集及显示模块的编程思路同时包含硬件调试和软件调试的完整过程。资源包体积仅1.34MB内含1个doc说明文档整体结构从摘要、方案对比、硬件设计、程序设计到系统测试、原理图与源程序附录一应俱全。已有103人学习。文档能够帮助读者系统梳理单片机控制电路与传感器信号处理的关键环节也可为后续扩展停车位引导、计时计费等功能提供设计基础。1. 基于单片机的停车场计数系统设计这份完整版设计文档解决什么问题基于单片机的停车场计数系统听起来像要接摄像头、做车牌识别实际拆开看核心逻辑非常简单入口和出口各装红外对管车辆遮挡使传感器电平翻转单片机收到信号执行加一或减一最后用数码管把场内车辆数显示出来。整套设计可以压缩成传感器检测、单片机处理、数码显示三块小型停车场几十个车位的统计绰绰有余。我照着这份完整版设计文档重新搭过一遍流程从元件选型、引脚接线到程序烧录都走通了也踩了若干坑。它适合正在赶课设、做毕设或者只想快速搭一个计数原型验证逻辑的人。2. 检测方案与选型为什么是双红外对管而不是地磁和超声波2.1 红外对管、地磁、超声波三种检测方案怎么选停车计数要解决的第一件事是「用什么感知车」。市面上常见三个方向红外对管、地磁感应线圈、超声波雷达。地磁感应要在路面开槽埋线圈检测车轮下方的金属物可靠性高但施工成本大后面想改检测位置等于重新开一次槽超声波靠发射声波和接收回波判断有无遮挡不需要破坏地面但传感器得挂在高处雨雪天表面结水会误报。红外对管最便宜一对模块十几块钱一个支架就能装核心思想是检测红外光路上有没有障碍物。维度红外对管地磁感应超声波检测对象实体遮挡金属车体反射面施工成本低支架固定即可高路面开槽埋线中需高位挂装安装调整随时挪位置改位置要重新破路调整相对容易典型误判阳光干扰、串光周边金属体干扰雨雪天气误报适用场景窄车道、出入口快速通道、正规道闸大范围车位探测为什么这套完整版设计坚持双红外对管关键在于小停车场车道窄、车速慢红外模块的响应机制完全覆盖得了。文档里的布局是入口、出口各一组对管一组管进、一组管出单片机轮流扫描电平翻转。如果你的车道宽超过两米或者车速高于10km/k红外方案就要谨慎因为车辆遮挡红外线的时间窗口太短程序来不及捕捉下降沿那种工况更适合地磁。另外还有一个很现实的原因小型停车场地面多数已硬化开槽埋线圈的成本超过几组红外对管好几倍对管方案不动地面。2.2 红外对管的工作电平与电位器调节市面常见的三线制红外对管模块供电和信号都很简单红线接5V绿线接地黄线是信号输出。输出逻辑有一段必须记牢无障碍时信号线输出高电平接近电源电压检测到障碍物时输出立刻翻转为低电平同时模块上指示灯点亮。程序后续所有判断都在等这个「高变低」的下降沿而不是持续低电平。模块背面的蓝色电位器用来调节检测距离逆时针调远、顺时针调近典型范围3到80cm。我调试时一般先把车停在传感器正前方调电位器直到指示灯稳定亮起然后把车往后退出半米确认指示灯熄灭这个状态误报概率最低。模块响应时间在几十毫秒级别对低速通过的小汽车足够但如果有人快速跑过电平翻转时间太短程序可能漏读这也是后面要在软件里做防抖和边缘检测的原因。安装位置同样影响可靠性。常见做法是把对管装在汽车保险杠高度离地约30到50cm。装太低SUV底盘高的车型会漏检装太高行人的大腿手臂可能误触发。装好后拿万用表量OUT对地电压手掌挡一下传感器电压从高跳低、指示灯亮说明硬件链路没问题再往下写程序才有意义。2.3 单片机选型STC89C52能扛住这个任务吗要判断够不够用先列需求处理两路开关量输入做加一减一计数驱动四位共阳数码管。这个任务没有浮点运算、没有并发、没有复杂协议所以STC89C52这类51内核单片机完全够用。32个IO引脚绰绰有余内置定时器用来做动态扫描和轮询周期8KB Flash存段码表加主程序还有富余5V供电也正好与传感器模块同源。从调试角度看51内核资料多、烧录简单出问题排查成本低。常见失误是一上来就换STM32甚至加RTOS把一个逻辑简单的计数任务复杂化。如果后续确定要加LCD屏、加RFID读卡、加掉电保存那提前换带硬件I2C的型号可以理解但纯停车计数场景STC89C52是做课设和样机最稳妥的选择。晶振我习惯选11.0592MHz这个频率配合定时器能精确分频出9600波特率给后面做串口调试留好路。3. 硬件接线与计数逻辑传感器、数码管和一进一出的状态机3.1 引脚分配表先照这个接线再谈代码整套硬件接线围绕三个外设红外传感器、数码管、单片机。入口传感器接P1.0出口传感器接P1.1数码管段码走P0口位选走P2.0到P2.3。这块接线比较直观先把分配表固定住后面写代码不用来回改引脚定义。信号引脚说明入口传感器OUTP1.0无车高电平有车低电平出口传感器OUTP1.1无车高电平有车低电平数码管段码a-g、dpP0.0-P0.7共阳数码管低电平点亮段位选个/十/百/千P2.0-P2.3低电平选中当前位传感器电源VCC 5V / GND与单片机共地接线里有两个细节容易翻车。第一STC89C52的P0口是开漏输出直接驱动共阳数码管段码会点不亮或亮度很低常见做法是在P0口加一排4.7k上拉电阻段码低电平才能正常拉亮。第二位选不要直接接IO口一位数码管工作电流大概20到40mA四位同时扫描峰值电流能到上百毫安单片机的灌电流能力扛不住。我一般会在位选端加PNP三极管低电平导通后给数码管公共端供电显示亮度也更稳。3.2 一进一出的计数逻辑边缘触发而不是电平判断计数逻辑的代码量不大但核心思路需要想清楚。程序里最重要的一件事是区分「人的动作」和「车的动作」不能一读到低电平就加一。一辆车在传感器前停留可能两三秒轮询周期要是10ms持续低电平会被读到几百次直接计数就会一辆车加两百多次。正确做法是只认下降沿也就是上一次读到高电平、这一次读到低电平的那一个瞬间这样一辆车只触发一次。unsigned int car_count 0; // 当前场内车辆数范围 0-9999 bit last_in 1; // 入口传感器上一次电平1无车 bit last_out 1; // 出口传感器上一次电平 void parking_count_poll(void) // 每10ms调用一次 { bit now_in P1_0; // 读入口红外模块输出 bit now_out P1_1; // 读出口红外模块输出 // 入口出现“高变低”且出口当前无车判定车辆进场 if (now_in 0 last_in 1 now_out 1) { if (car_count 9999) car_count; } // 出口出现“高变低”且入口当前无车判定车辆出场 if (now_out 0 last_out 1 now_in 1) { if (car_count 0) car_count--; } last_in now_in; // 记录本次电平供下次比较 last_out now_out; }这段代码的逻辑可以拆成三层。第一层是下降沿检测now_in 0 last_in 1表示此刻有车、上一刻无车只在这种状态跳变时计数。第二层是方向仲裁入口触发加一的同时要求出口无车出口触发减一的同时要求入口无车避免同一辆车同时压住两路传感器时被重复计算。第三层是上下限保护car_count限定在0到9999之间既防止倒减成负数也防止向上越界。轮询周期建议固定在10ms到20ms之间。红外模块响应时间在几十毫秒10ms的扫描间隔不会错过有效下降沿同时也能滤掉部分几十微秒级的噪声抖动。如果轮询周期小于1ms反而可能读到传感器输出翻转过程中的中间电压给逻辑制造麻烦。这块代码后面配串口调试时会非常有用能直接看到内部计数变量而不只是数码管上的最终结果。3.3 四位数码管动态扫描从变量到稳定数字的显示链路计数变量在单片机内部要让人眼看到就得通过数码管。四位共阳数码管和单片机之间只有两组线段码线和位选线。P0口送显示数字对应的段码P2口决定点亮哪一位。由于单片机不能同时点亮所有位只能用动态扫描方式让每位轮流亮几百微秒靠人眼视觉暂留看起来像同时点亮。unsigned char code duan[] {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; // 共阳数码管段码表下标0-9对应显示数字0-9 void display_num(unsigned int num) { unsigned char i; unsigned char pos; for (i 0; i 4; i) { // 1. 关闭所有位选消除上一轮残影 P2 0x0F; // 2. 按当前位取出数字 if (i 0) pos num % 10; // 个位 if (i 1) pos num / 10 % 10; // 十位 if (i 2) pos num / 100 % 10; // 百位 if (i 3) pos num / 1000; // 千位 // 3. 送段码到P0 P0 duan[pos]; // 4. 打开当前位低电平选中 P2 ~(1 i); // 5. 保持约1ms视觉暂留 delay_timer(1); } }代码里必须严格遵守「关位选、送段码、开位选」的先后顺序。如果先送段码再切换位选上一位的余晖会残留在当前位置上数字边缘出现拖影。P2 0x0F把所有位选引脚全部置高此时所有位都不亮起到消隐作用。P2 ~(1 i)是把第i位置低其余置高只点亮第i位。这里选择1ms的保持时长四个位下来一轮扫描约4ms刷新频率超过200Hz人眼看起来是常亮的。如果保持时间拉到10ms以上就能肉眼看到明显闪烁。取位运算这里也容易写错。num % 10拿到个位num / 10 % 10拿到十位num / 100 % 10拿百位num / 1000拿千位。四位数码管最大显示9999正好与car_count的上限对应。如果想扩展显示「剩余车位」改成remaining total - car_count再传入函数即可显示链路上不用做其他改动。4. 避坑记录五个高发问题与排查链路4.1 串光与阳光干扰数码管数字全天乱跳现象晴天正午系统每隔十几秒自己加一次数晚上一切正常。原因红外接收管对太阳光里的红外成分极其敏感模块的透镜会把太阳反射光当作有效信号接收另一类是两组对管安装时面对面A组发射管的光直射到B组接收管上形成串光误触发。解决先把程序暂停用万用表量传感器OUT引脚对地电压如果电压不稳定跳变可以确定问题在光路而不是程序。将发射管和接收管套上一段黑色热缩管或PVC管挡住非正前方的杂散光再把模块电位器往回调把检测距离缩短到30cm左右让传感器只对近距离遮挡敏感。处理后观察万用表电压稳定再恢复程序运行。4.2 一辆车压住两个传感器数字不升反降现象车从入口开进来显示屏计数没有加一反而从999变成998。原因入口和出口传感器装得太近间距小于一辆车长度。小轿车车身普遍超过3米如果两路传感器距离只有一两米车头触发入口传感器时车尾还留在出口范围两侧同时为低电平程序把这次事件判定成出口触发执行了减一。解决把两路传感器拉开到至少一个车身距离常见做法是不小于5米让一辆车在任何一个瞬间只可能压住一侧。如果场地实在窄只能改逻辑增加一个「方向锁存」状态入口先触发后一段时间内只处理入口不响应出口直到车辆完全离开。不过这种方案逻辑复杂度会上升优先还是拉开物理距离。4.3 数码管显示拖影和亮度不均刷新顺序错了现象数字边缘有残影某一位明显比其它位暗数字变化时重影更明显。原因动态扫描时先送了段码再切位选旧位选还没关闭新段码的内容已经出现在上一位上视觉上形成残影亮度不均则是位选三极管参数不一致或者某一位导通时电流过大造成电源跌落四位亮度被拉偏。解决软件上严格按「关位选、送段码、开位选」执行位选切换前先把当前段码全部置零。硬件上把四位驱动三极管选同型号同批次并在电源端加470µF电解电容吸收动态扫描时的瞬态电流。软件和硬件都处理到位后显示亮度会均匀得多。4.4 断电清零掉电之后车位数量丢失现象晚上停车场断电第二天早上开机计数显示0可场内明明还有几十辆车。原因STC89C52的RAM是易失性存储car_count变量运行时存在RAM里断电后就清零了。这不是硬件故障而是方案设计里没有考虑掉电保存。解决给系统加一块AT24C02走I2C接口每次计数变化后把car_count写入EEPROM如果换用带内部EEPROM的单片机型号用片内存储更省事。程序初始化时先读取EEPROM数值再赋给car_count断电恢复后数字自然续上。需要注意的坑是EEPROM有写入寿命不能每个轮询周期都写只在计数变化时写入即可。课设答辩阶段不做掉电保存可以接受但实际运营场景必须加。4.5 程序下载后不运行烧录的一个经典流程问题现象烧录软件提示下载成功但板子就是没反应数码管不亮传感器指示灯也不变。原因STC系列单片机是冷启动下载必须先点下载按钮再给单片机上电顺序反了会导致程序根本没写进去另外还有共地问题USB转TTL的地和单片机电源的地不是同一个通信握手失败。解决确认USB转TTL的GND和单片机GND接在同一根线上然后重复一遍标准流程打开烧录软件、选择串口、点下载、给开发板通电看到握手成功后再松手。如果还是刷不进去查晶振两脚对地电压是否起振复位电路是否处于正常工作电平。这三个检查点走完能定位九成以上的「下载成功但程序不跑」问题。5. 进阶验证把内部计数拉到电脑上看5.1 用串口回传数字把黑匣子打开数码管只能显示最终结果看不到入口出口的触发顺序也看不到程序内部到底有没有正确处理下降沿。给系统加一个最简单的串口回传就能把内部变量拉出来看。STC89C52的UART初始化代码并不复杂void uart_init(void) { SCON 0x50; // 串口模式18位UART允许接收 TMOD 0x20; // 定时器1作为波特率发生器 TH1 0xFD; // 11.0592MHz下对应9600波特率 TR1 1; // 启动定时器1 }然后在car_count变化时用一条发送语句把数值发出去SBUF car_count; // 发送当前计数变量 while (!TI); // 等待发送完成 TI 0; // 清除发送完成标志电脑端串口助手选9600波特率就能实时看到每次车辆触发带来的数字变化。哪次没加上、哪次减错了对着数码管和串口输出一对比问题立刻定位。这个习惯强烈建议保留它能把传感器干扰这类「玄学问题」变成可复现的工程判断。注意串口线需要共地调试时线不要扯太长半米以内基本稳定超过两米要考虑波特率降到4800。5.2 遮挡模拟测试方向仲裁的三组验证烧好程序后不要直接拉到现场先在实验台上用纸板或手掌做三组遮挡测试验证方向逻辑。第一组单独遮挡入口传感器数码管应加一单独遮挡出口传感器数码管应减一。这组证明基本计数链路没问题。第二组先遮挡入口再遮挡出口模拟一辆车完整驶过显示应经历加一、短暂保持、无变化反过来先遮挡出口再遮挡入口数字应经历减一、短暂保持、无变化。这组验证的是方向仲裁逻辑是否只在同侧触发时生效。第三组快速连续遮挡入口两次间隔小于100ms观察数字是否加二。红外模块响应时间在几十毫秒程序轮询周期10ms如果两次遮挡靠得太近二次触发会漏掉。这组测试能暴露轮询瓶颈也能验证传感器响应速度是否跟得上现场车速。三组测试都通过后再加一道「同时遮挡两个传感器」的测试确认两侧同时低电平时计数不发生漂移。这套流程走完逻辑层的信心就建立起来了。5.3 交付前最后一道自查冷启动完整流程我习惯在交付前把系统重新断电冷启动一次按固定顺序走自查链路上电后数码管应显示0用纸板模拟车辆入场数字加1模拟出场数字减1断电再上电观察是否有掉电保存逻辑的恢复动作。这四步能同时检查下载是否正常、计数逻辑是否完整、掉电保存是否生效。车辆方向判断、传感器安装距离、动态扫描消影这三个环节是这套基于单片机的停车场计数系统里最容易反复返工的地方。从那以后我每次做这类计数系统都强制自己完整走一遍这套测试流程再去现场部署。希望这份完整版设计文档的拆解和踩坑记录能帮你在复现路上少花几个晚上的调试时间。本文还有配套的精品资源点击获取