
简介这份毕业设计论文面向电子信息、自动化等专业学生及单片机初学者围绕基于MSC-51系列ATSC51单片机与8255A可编程并行I/O接口芯片的交通灯控制系统展开解决传统固定配时信号灯难以适应动态车流的问题。压缩包内为1个doc文档约257KB完整收录论文正文涵盖交通灯发展沿革、8051内部结构与引脚说明、硬件原理图与接口电路分析、初始化与状态切换等源程序代码以及系统测试与结论。论文实现了红绿灯循环点亮、倒计时剩5秒黄灯闪烁警示、闯红灯报警和绿灯时段车流量检测显示等功能软硬件结合、层次清晰。目前已有1011人学习可作为毕业设计选题范本、课程设计参考或单片机控制类项目的入门实践材料帮助读者理解从需求分析、方案设计到编程调试的完整流程。1. 从一次答辩被问懵说起这套交通灯方案到底解决什么答辩现场最容易被问倒的不是代码写没写出来而是“你这个东西和市面上几十块的定时器有什么区别”。很多同学做单片机交通灯最后交上去的就是一个固定 60 秒红灯、80 秒绿灯的循环导师一句“车流量变化了怎么办”就答不上来。这套基于 MCS-51 系列单片机AT89S51/8031 一类加 8255A 可编程并行接口芯片的交通灯控制器核心价值恰恰在于它不是一个死循环定时器红绿灯时长可通过 P1 口现场设定绿灯期间能检测车流量并数码管显示倒计时剩 5 秒黄灯闪烁车辆闯红灯还能触发蜂鸣报警。它适合正在做单片机课程设计、毕业设计的学生也适合需要一份可交付的十字路口信号控制原型的从业者把“能跑”和“能讲清楚为什么这么设计”两件事一起解决。2. 需求与方案论证十字路口两干道四相位怎么定2.1 从路口实际通行矛盾倒推功能清单先把场景钉死东西、南北两条干道交叉各有一组红黄绿三色灯行人随对应方向绿灯通行。原料里给了一个很关键的假设——东西道车流量大于南北道所以东西绿灯 80 秒、南北绿灯 60 秒中间各插 5 秒黄灯作为公共停车缓冲。这个不对称配时就是整个方案的需求起点而不是随便拍脑袋定 60/60。由此倒推出的功能清单有四条硬需求第一红、绿、黄三色按固定相位顺序循环黄灯在切换前闪烁警示第二红绿灯初始时长可由键盘现场修改不能烧死在程序里第三绿灯时段要能统计通过车辆数并用双位数码管显示为后续动态配时留接口第四红灯期间若检测到车辆越线闯红灯蜂鸣器报警约 3 秒后恢复。这四条对应了原料摘要里“实用性强、操作简单、扩展功能强”的定位也是答辩时能展开讲的技术点。2.2 为什么选 8051 8255A 而不是纯单片机口这是方案论证里必须讲清楚的一步也是很多设计文档最薄弱的地方。8051 本身有 P0、P1、P2、P3 四组 8 位 I/O但 P0 要分时复用做地址/数据总线P2 出高 8 位地址P3 又承担中断、串口、定时器外部输入等第二功能真正能干净借用的只剩 P1。而本系统要同时驱动两路红黄绿共 6 个灯、两组双位数码管段选加位选、开关键盘输入、车流量检测输入、蜂鸣器端口数量明显不够。扩展有两条路借用外部 RAM 地址空间做 I/O或者用专用接口芯片。前者省成本但地址译码和时序要自己兜调试时容易和存储器访问打架后者用 8255AA 口出信号灯、C 口出数码管段码、B 口做位选和辅助输出控制字一次写清楚端口职责分明。我一般会跟学生讲课程设计阶段可读性和可调试性比省一片芯片重要8255A 的代价是多几根连线和一次初始化换来的是“哪个口干什么”一眼能说清。原料里 74LS373 用来锁存 P0 送出的低 8 位地址MAX692 看门狗负责程序跑飞复位7805 提供 5V 稳压这套器件组合是那个年代教学板的经典配置今天用仿真或打样都还能复现。2.3 相位与时序表把配时写成可查的表方案论证的落点是时序表。按原料表 2 的逻辑一个完整循环是东西红灯 60 秒南北绿灯→ 黄灯闪 5 秒 → 东西绿灯 80 秒南北红灯→ 黄灯闪 5 秒 → 回到起点。注意黄灯是两干道公共停车时间两个方向此时都该停所以黄灯阶段信号灯输出要同时点亮两侧黄灯。阶段东西方向南北方向时长说明1红灯绿灯60s南北车流通行东西行人可过2黄灯闪黄灯闪5s公共缓冲全向停车3绿灯红灯80s东西车流大配时更长4黄灯闪黄灯闪5s公共缓冲回到阶段 1这张表就是软件状态机的骨架后面所有代码都是围绕它展开。把表先定下来硬件接线和程序分支才有依据答辩时被问“为什么黄灯 5 秒”也能答它是切换缓冲取值要大于车辆制动反应时间教学场景取 5 秒便于观察。3. 硬件总体设计从总框图到 8255A 端口分配3.1 系统总框图与信号流向硬件按“单片机核心 并行扩展 驱动输出 人机输入”四块组织。8051 通过 P0 口分时向 8255A 送数据和控制字74LS373 锁存低 8 位地址完成片选与端口选择8255A 的 PA 口经驱动后接 6 只交通灯PC 口输出七段段码、PB 口输出位选驱动两组共阴数码管P1 口接开关键盘用于设定红绿初始时间P2.0 接车流量检测开关P3.0 控制工作/设置状态并驱动蜂鸣器报警MAX692 看门狗监控程序运行7805 给整板供 5V。信号流向一句话概括输入走 P1/P2/P3输出全压到 8255A 三个口上单片机只负责算时间和写控制字。这样划分的好处是输出侧完全由 8255A 承担单片机端口压力小程序里对灯的操作用一条MOVX写外部地址就能完成逻辑干净。3.2 8255A 控制字与端口地址译码8255A 用方式 0基本输入/输出就够了因为信号灯和数码管都是单向输出键盘和检测开关是单向输入不需要选通和中断握手。控制字按原料表 1 的格式D71 标志有效D6D500 选 A 口方式 0D40 令 A 口输出D30 令 C 口高 4 位输出D20 选 B 口方式 0D10 令 B 口输出D00 令 C 口低 4 位输出合起来就是0x80。端口地址用 P0.7 做片选P0.1、P0.0 选口P0.70 时片选有效00H为 PA、01H为 PB、02H为 PC、03H为控制口。原料里写的是 P0.71 时片选有效、地址写成 0003H 一类实际接线以片选逻辑为准写代码时把基址和偏移对齐即可。下面这段初始化是整板能出灯的前提// 8255A 初始化方式0PA/PB/PC 全部输出 // 端口基址按片选译码确定此处以 0x0000 为例 #define P8255_A 0x0000 #define P8255_B 0x0001 #define P8255_C 0x0002 #define P8255_CTL 0x0003 void init_8255(void) { unsigned char ctrl 0x80; // D71, 方式0, 三口全输出 XBYTE[P8255_CTL] ctrl; // 写控制寄存器 XBYTE[P8255_A] 0xFF; // 上电先全灭共阳低电平点亮 XBYTE[P8255_B] 0xFF; XBYTE[P8255_C] 0xFF; }XBYTE是 Keil C51 里访问外部数据空间的宏等价于原料汇编里的MOVX DPTR,A。控制字0x80的含义要能背下来最高位是方式标志低六位逐位对应三个口的高低半字节方向。初始化后先写全 1 灭灯避免上电瞬间乱亮。3.3 信号灯与数码管的驱动细节信号灯接 PA 口发光二极管共阳接法端口输出低电平对应灯亮。按相位表阶段 1 东西红、南北绿PA 输出要同时拉低对应位阶段 3 反过来。原料里给的0xDD、0xEB、0xD4、0xE2就是这些组合的十六进制编码实际接线顺序不同编码要重算不能照抄。数码管用共阴接法PC 口出段码、PB 口出位选。段码表按dp g f e d c b a排列0 到 9 对应3FH、06H、5BH、4FH、66H、6DH、7DH、07H、7FH、6FH。双位数码管要动态扫描先送十位段码、开十位位选、延时 1 到 2 毫秒再送个位段码、开个位位选、延时循环刷新。扫描频率太低会闪太高亮度不够1 毫秒左右是教学板上比较稳的取值。提示共阳灯和共阴数码管的电平逻辑相反接线前先把“低电平点亮”还是“高电平点亮”确认一遍这是后面调试阶段最常见的返工点。4. 软件设计定时、状态机与车流量检测怎么落地4.1 1 秒基准定时器 50ms 加软件计数8051 在 12MHz 晶振下机器周期 1 微秒方式 1 的 16 位定时器最大定时 65.536 毫秒直接定 1 秒做不到。原料给的思路是定时器 T0 定 50 毫秒主程序里设一个初值 20 的软件计数器中断里减到 0 就是 1 秒。初值计算TC 65536 - 50000 15536 0x3CB0所以TH00x3C、TL00xB0。// T0 方式150ms 中断一次20 次凑 1 秒 volatile unsigned char tick_50ms 20; volatile unsigned char flag_1s 0; void timer0_isr(void) interrupt 1 { TH0 0x3C; // 重装 50ms 初值 TL0 0xB0; if (--tick_50ms 0) { tick_50ms 20; flag_1s 1; // 置 1 秒标志主循环消费 } display_scan(); // 借中断顺带刷新数码管 }这里有个设计取舍数码管扫描放在定时中断里保证刷新节奏稳定主循环只处理秒级逻辑。中断服务要短所以display_scan()里只做段码送出和位选切换不做除法运算。flag_1s用标志位而不是在中断里直接跑状态机是为了避免中断嵌套和长耗时操作。4.2 相位状态机四个状态加倒计时变量把第 2 章的时序表翻译成状态机四个状态循环S_EW_RED东西红、南北绿60 秒、S_YELLOW1双黄闪 5 秒、S_EW_GREEN东西绿、南北红80 秒、S_YELLOW2双黄闪 5 秒。每个状态维护一个倒计时变量countdown每秒减 1减到 0 切下一状态并重装时长。typedef enum { S_EW_RED, S_YELLOW1, S_EW_GREEN, S_YELLOW2 } phase_t; phase_t phase S_EW_RED; unsigned char countdown 60; unsigned char t_red 60, t_green 80; // 可由键盘修改 void traffic_fsm(void) { if (!flag_1s) return; flag_1s 0; if (countdown 0) countdown--; if (countdown 0) { switch (phase) { case S_EW_RED: phase S_YELLOW1; countdown 5; break; case S_YELLOW1: phase S_EW_GREEN; countdown t_green; break; case S_EW_GREEN: phase S_YELLOW2; countdown 5; break; case S_YELLOW2: phase S_EW_RED; countdown t_red; break; } } output_lights(phase); // 按状态写 PA 口 output_countdown(countdown); // 倒计时送数码管 }状态机的好处是加相位、改配时只动switch分支和时长变量不用在汇编里到处跳转。原料的汇编用N00/N1/N2/N3标号实现同样的循环C 语言版本更利于答辩时讲清楚“状态迁移条件是什么”。4.3 黄灯闪烁与闯红灯报警的时序处理黄灯闪烁不是简单常亮而是亮 0.5 秒、灭 0.5 秒持续 5 秒。实现上在黄灯状态里用一个 0.5 秒计数器翻转输出位5 秒内翻转 10 次。原料用CJNE R4,#7DH,$这类空循环凑 0.5 秒C 版本可以复用 50 毫秒中断计数每 10 次翻转一次时序更准。闯红灯报警逻辑红灯相位期间若检测到越线信号P2.0 或独立检测输入为有效电平拉低蜂鸣器控制位 P3.0同时启动 3 秒报警计时计时到就恢复。这里要注意报警不能打断正常倒计时所以报警计时和相位倒计时用两个独立变量互不覆盖。原料里B0/B01段就是这个思路判断倒计时是否归零再决定是否继续报警避免绿灯切换后还在响。4.4 车流量检测与键盘设定初值车流量检测放在绿灯相位每检测到一个有效脉冲计数器加 1超过 99 回绕双位数码管只能显示两位并把当前值送数码管显示直到下一次绿灯重新计数。检测用边沿触发比电平触发可靠否则开关按住不放会一直累加。键盘设定初值走 P1 口P3.1 为 0 进入设置态读 P1 低 7 位作为时长值P1.7 区分设红灯还是绿灯设完写回t_red或t_green并刷新显示。这里有个细节键盘是机械按键必须做 10 到 20 毫秒软件消抖否则一次按下会被读成多次时长直接跳变。原料的汇编里用LCALL DELAY做延时消抖C 版本同样保留这个习惯。5. 避坑与排查调试阶段最容易翻车的五个点5.1 灯全亮或全灭先查共阳共阴和驱动现象上电后 6 只灯同时亮或同时不亮改程序也没反应。原因多半是发光二极管接法判断错共阳接法要低电平点亮程序里却按高电平写或者 PA 口直接驱动电流不够灯偏暗甚至不亮。解决先用万用表量 PA 口对应位在“该亮”时是不是低电平再确认每路是否加了限流电阻或驱动三极管原料用 74LS07 做驱动就是干这个的。这一步不确认后面所有时序调试都是白费。5.2 数码管显示乱码或重影现象倒计时数字缺段、两位数字叠在一起、或者亮度忽明忽暗。原因通常是段码表和实际接线顺序对不上或者动态扫描没有消隐——换位选前没先关段码上一位的残影留到了下一位。解决先静态点亮一位验证段码表再开动态扫描扫描函数里按“关段码→换位选→送新段码→延时”的顺序写延时控制在 1 到 2 毫秒。原料段码表是按dp g f e d c b a排的接线换了顺序就要重算不能直接抄。5.3 倒计时不准越走越偏现象跑十分钟后倒计时和手机秒表差出好几秒。原因一般是中断里做了耗时操作比如在中断里做除法转十进制、长延时导致 50 毫秒中断被拉长或者重装初值时漏了TH0/TL0的补偿。解决中断里只置标志、做最短的扫描进制转换和状态判断放主循环重装初值用“当前值加 50 毫秒”而不是固定写死减少累积误差。教学场景对精度要求不高但偏差大到肉眼可见就说明中断设计有问题。5.4 8255A 写不进去灯和数码管都没反应现象初始化代码跑了但 PA 口电平不变。原因常见于片选地址算错、XBYTE基址和实际译码不符或者控制字写成了输入方向。解决用示波器或逻辑笔看写控制口时 CS、WR、A0、A1 的时序确认片选有效把控制字0x80单独写一个小测试程序验证再检查 74LS373 的 LE 和 OE 接法锁存没打开时地址根本送不到 8255A。这类问题属于“黑匣子”式故障分段隔离比盯着代码猜快得多。5.5 闯红灯报警误触发或一直响现象没车闯红灯也报警或者报警响起来停不下来。原因通常是检测输入没有消抖电平抖动被当成多次触发或者报警计时变量和倒计时变量共用切换相位时把报警计时清零逻辑写乱了。解决检测输入加 RC 滤波或软件确认连续多次采样有效报警计时独立成一个变量只在报警触发时装载 3 秒倒计时归零只影响相位不影响报警复位。血泪经验是报警和正常时序一定要解耦否则一个边界条件就能让蜂鸣器响一整晚。6. 验收与答辩怎么证明这套交通灯真的能交付验收分三层按顺序走别跳。第一层是静态检查断电用万用表测电源对地无短路5V 稳压输出正常8255A 控制字写入后 PA/PB/PC 三口电平可控这一步过了才敢上电。第二层是功能逐项验收对着第 2 章的需求清单打勾建议做成下面这张表答辩时直接展示。验收项操作合格判据相位循环上电观察一个完整周期红60s→黄闪5s→绿80s→黄闪5s顺序正确黄灯闪烁秒表卡黄灯段亮灭各约0.5s总时长约5s倒计时显示对照秒表每秒减1两位数字无缺段无重影键盘设时进入设置态改红灯为30s下一周期红灯段变为30s车流量检测绿灯期按检测开关若干次数码管计数递增下次绿灯重新计数闯红灯报警红灯期触发检测输入蜂鸣器响约3s后自动恢复不干扰倒计时第三层是边界与异常验收把红灯设成 5 秒、绿灯设成 5 秒看会不会和黄灯逻辑打架按住检测开关不放看计数会不会失控拔掉看门狗看复位后能否回到初始相位。这些边界条件答辩时主动讲出来比被问倒强。答辩陈述有个我常用的节奏先用一句话说清“这不是固定配时是可通过键盘改时长、能检测车流量、能报警的控制器”再拿时序表讲相位设计接着用状态机代码讲软件结构最后主动说一个自己踩过的坑比如数码管重影怎么解决的。导师最想听的是你的设计决策依据而不是把论文目录念一遍。被问到“为什么不用更高级的芯片”时答“教学场景下 8051 加 8255A 的端口扩展路径清晰、成本低、可调试性好动态配时和检测接口已经留出换平台只需改驱动层”这个回答既守住方案又留了扩展余地。从那以后我每次带这类单片机设计都强制先画时序表再动烙铁先验证 8255A 三口电平再写业务逻辑验收表不填满不算完成。这套顺序看着笨但能省掉大量返工。希望帮到你。本文还有配套的精品资源点击获取