☰
基于8051与8255的交通灯控制系统:从毕业设计到工程实践
2026/11/2 4:11:15 网站建设 项目流程

简介:这份毕业设计论文面向电子信息、自动化等专业的学生与单片机初学者,围绕基于MSC-51系列ATSC51单片机与8255A可编程并行I/O接口芯片的交通灯控制系统展开,解决传统固定配时信号灯难以适应动态车流的问题。压缩包内为1个doc文档,约257KB,完整收录了从交通灯发展历史、单片机内部结构剖析,到硬件原理图与接口电路说明、软件源程序(初始化、时间设定、状态切换等)以及系统测试结果的全流程内容。论文重点实现了依据车流量经P1口设置红绿灯燃亮时间、倒计时剩5秒黄灯闪烁警示、闯红灯报警与绿灯时段车流量检测显示等功能,兼具实用性与可扩展性。目前已有1011人学习,可作为毕业设计写作范本,也为智能交通控制方向的软硬件联调提供可参考的设计思路与代码框架。

1. 从一份 27 页的毕业设计说起:这套单片机交通灯到底能跑出什么

十字路口那套红绿黄循环,看着简单,真让你用一块 8051 加一片 8255 从零搭出来,坑比想象中多。这份毕业设计论文给的不是 PPT 概念稿,而是一套能落地的完整方案:MCS-51 系列单片机做核心,8255A 扩展 I/O,PA 口驱动红黄绿六盏灯,PC 口接两位共阴数码管做倒计时,P1 口拨码设定红绿灯时长,P3.0 兼做启动与闯红灯报警输出,P2.0 检测车流量按键。东西道车流大给 60 秒红灯、80 秒绿灯,南北道对称错开,黄灯统一 5 秒闪烁过渡。它适合谁?电子、自动化、嵌入式方向的在校生拿来做课设或毕设底稿,也适合刚接触 8051 想找一个“有输入、有输出、有中断、有状态机”的完整小项目练手的开发者。论文里连定时器初值、8255 控制字、数码管段码表都写全了,照着接线和烧录,实验室里能亮起来。

2. 硬件架构拆解:8031、8255A 与 74LS373 怎么分工

这套系统的硬件不是随便堆料,每个芯片都有明确职责。先把总线关系理清楚,后面看代码才不会懵。

2.1 最小系统与总线扩展

8031 本身没有内部 ROM,必须外扩程序存储器,所以 P0 口分时复用做低 8 位地址和数据,P2 口出高 8 位地址,ALE 信号配合 74LS373 锁存低地址。论文里 74LS373 的 LE 接 ALE,OE 接地,1D-8D 接 P0.0-P0.7,1Q-8Q 出 A0-A7,这是 8051 外扩存储器的标准套路。晶振取 11.0592MHz 或 6MHz 都行,论文软件延时部分按 6MHz 算机器周期 2μs,如果你手头是 11.0592MHz 的板子,延时子程序的循环次数要按比例改,否则倒计时会明显偏快,这是第一个容易翻车的地方。

复位电路用 10μF 电容加 10k 电阻做上电复位,再并一个按键做手动复位。EA 引脚对 8031 必须接地,强制从外部 ROM 取指;如果你换成了内部有 Flash 的型号(比如常见的 89 系列),EA 接高电平即可,但论文的地址译码逻辑是按外部扩展写的,换芯片时片选要重新核对。

2.2 8255A 的端口分配与控制字

8255A 在这里承担了“把 8051 有限的 I/O 撑开”的角色。片选 CS 接 P0.7,地址译码后四个端口地址落在 0000H(PA)、0001H(PB)、0002H(PC)、0003H(控制口)。初始化控制字 80H 的含义拆开看:D7=1 方式选择有效,D6D5=00 表示 A 口方式 0,D4=0 表示 A 口输出,D3=0 表示 C 口高 4 位输出,D2=0 表示 B 口方式 0,D1=0 表示 B 口输出,D0=0 表示 C 口低 4 位输出。也就是三个口全做基本输出,正好对应灯组和数码管。

; 8255 初始化:三个端口全部方式0输出 MOV DPTR, #0003H ; 指向 8255 控制寄存器 MOV A, #80H ; D7=1方式字有效, A/B/C全部输出, 方式0 MOVX @DPTR, A ; 写入控制字

这段代码是整个系统能出灯的前提,控制字写错,PA 口可能变成输入,灯永远不亮。写完控制字后,往 0000H 写数据就是控制 PA 口八根线,往 0002H 写就是控制 PC 口。论文里 PA 口低六位对应东西红黄绿和南北红黄绿,PC 口接数码管段选,PB 口做位选,具体接线以原理图为准,但地址映射是固定的。

2.3 灯组驱动与数码管显示

发光二极管采用共阳极接法,PA 口输出低电平对应灯亮,所以论文里出现 0DDH、0EBH 这类值——把要亮的位清零、其余置一。比如 0DDH 二进制 1101 1101,低六位里对应东西红灯和南北绿灯的位是 0,其余是 1。数码管是共阴极,段码表 3FH、06H、5BH、4FH、66H、6DH、7DH、07H、7FH 对应 0 到 8,PC 口送段码、PB 口送位选,两位轮流点亮靠人眼视觉暂留。这里有个细节:论文用 PC0-PC6 接 a-g、PC7 接小数点并接地,PB0/PB1 做两位位选,写位选值时 0F7H 和 0FBH 分别选中十位和个位,低电平有效。

提示:共阳灯组和共阴数码管的电平逻辑是相反的,接线前一定拿万用表确认模块类型,接反了不是不亮就是全亮,排查起来很费时间。

3. 软件状态机:定时器、倒计时与闯红灯报警怎么串起来

硬件搭好只是骨架,真正让灯按 60-5-80-5 循环跑起来的是软件里的状态机和定时中断。论文的汇编代码结构清晰,但直接抄要注意几个隐含约定。

3.1 1 秒时基的构造

8051 的定时器在方式 1 下最大定时 65.536ms(12MHz 晶振),1 秒必须靠“定时器中断 + 软件计数”拼出来。论文的做法是 T0 定 50ms,中断里对一个软件计数器累加,满 20 次就是 1 秒。初值计算:TC = 65536 - 50000 = 15536 = 3CB0H,所以 TH0 装 3CH、TL0 装 B0H。中断服务里先重装初值,再判断计数。

; T0 中断服务:50ms 一次,累计 20 次为 1 秒 T0_INT: MOV TL0, #0B0H ; 重装低字节 MOV TH0, #3CH ; 重装高字节 INC R5 ; 50ms 计数器 CJNE R5, #20, T01 ; 未满 20 次跳去刷新显示 MOV R5, #00H ; 满 1 秒清零 DEC R3 ; 倒计时减一 DEC R2 ; 报警计时减一 T01: ACALL DISP ; 每次中断都刷新数码管 RETI

R3 存当前相位剩余秒数,R2 存报警剩余秒数。注意论文里 T0 初值在中断里重装而不是用自动重装方式 2,因为方式 2 只有 8 位、最大 256μs,撑不到 50ms。如果你把晶振换成 11.0592MHz,50ms 对应计数值约 46080,初值变成 4C00H 附近,必须重算,否则一秒会变成约 0.92 秒,跑一晚上红绿灯整体偏移肉眼可见。

3.2 相位切换与黄灯闪烁

主循环按“东西红/南北绿 → 黄闪 → 东西绿/南北红 → 黄闪”四相位推进。每个相位开始时把该相位时长装入 R3,然后循环等待 R3 减到 0。黄灯闪烁不是简单亮 5 秒,而是亮 0.5 秒灭 0.5 秒重复 5 次,论文用 R4 做 0.5 秒的粗延时(CJNE R4,#7DH 空转),这个延时是软件死等,期间不响应显示刷新,所以黄灯阶段数码管会短暂停显,属于这套方案的已知取舍。

; 黄灯闪烁:亮0.5s灭0.5s,共5次 N1: MOV R3, #05H MOV DPTR, #0000H MOV A, #0D4H ; 东西南北黄灯亮 MOVX @DPTR, A N11: MOV R4, #00H N12: CJNE R4, #7DH, $ ; 软件延时约0.5s N13: MOV A, #0DDH ; 黄灯灭,恢复红/绿 MOVX @DPTR, A N14: MOV R4, #00H CJNE R4, #7DH, $ CJNE R3, #00H, N1 ; 闪5次退出

这段代码的可移植性一般,因为 0.5 秒靠指令周期硬凑,换晶振就失准。二次开发时我一般会把它改成用 T0 的 50ms 计数来驱动闪烁节拍,把“亮灭切换”放进中断里做状态翻转,主循环只负责相位推进,这样时序和显示都不打架。

3.3 闯红灯报警与车流量检测

报警逻辑挂在 P3.0:正常时 P3.0 为高,检测到闯红灯(论文用外部中断 1 或按键模拟)后拉低 P3.0 驱动蜂鸣器,同时 R2 装 3,每秒减一,减到 0 恢复。车流量检测在绿灯相位查询 P2.0,每按一次 R7 加一,满 100 归零,并通过数码管显示。这里论文的写法是“绿灯倒计时期间检测”,意味着检测窗口只在绿灯亮时打开,符合实际路口地感线圈的布设逻辑。

; 闯红灯报警:拉低P3.0鸣响,持续3秒 B0: MOV R2, #03H B01: MOV A, R3 JZ N1 ; 倒计时结束不再报警 CLR P3.0 ; 蜂鸣器响 CJNE R2, #00H, B01 SJMP N02

R2 在 T0 中断里递减,所以 3 秒是准的。但要注意 P3.0 同时被主程序用作“启动/设置”标志位,论文里用 SETB P3.0 表示进入运行态,报警时又 CLR P3.0,两个语义复用一个引脚,读代码时容易看晕。二次开发建议把报警输出挪到 8255 的空闲位(比如 PB 口高位),P3.0 只做模式切换,职责分离后调试轻松很多。

4. 上手实操:从接线到烧录的完整路径

论文给的是原理和代码,真到实验室还得落到具体动作。这一章按“先静态后动态、先显示后逻辑”的顺序走,能少走弯路。

4.1 硬件搭建顺序

第一步先把 8031 最小系统跑通:晶振、复位、EA 接地,用编程器烧一个只让某个 IO 翻转的测试程序,示波器或 LED 确认时钟和复位正常。第二步接 74LS373 和外部 ROM,确认能取指运行。第三步接 8255A,CS 接 P0.7,WR/RD 接 8051 对应引脚,A0/A1 接 P0.0/P0.1,先写控制字再用万用表量 PA 口电平是否随写入变化。第四步接灯组和数码管,限流电阻别省,论文用 0.3K 左右,直接灌电流容易烧口。第五步接拨码键盘到 P1 和 P2.0,最后接蜂鸣器到 P3.0。

模块关键引脚连接对象备注
74LS373LE / OEALE / GND锁存低 8 位地址
8255ACS / A0 / A1P0.7 / P0.0 / P0.1端口地址 00-03H
灯组PA0-PA5红黄绿灯共阳,低电平亮
数码管PC0-PC7 / PB0-PB1段选 / 位选共阴,段码表见论文
拨码P1.0-P1.7时间设定P1.7 区分红/绿
车流按键P2.0地低电平有效

4.2 编译与烧录

论文代码是汇编,用 Keil 建工程选对应芯片型号,把源文件加进去,输出 HEX。烧录器选对应封装,注意 8031 需要外部 ROM 的话,HEX 要烧到外部存储器而不是单片机内部。如果你用的是带内部 Flash 的兼容型号,EA 接高、HEX 直接烧片内即可,但地址译码部分要确认片选没有和内部地址冲突。

# Keil C51 命令行编译示例(工程已建好的情况下) C51 main.c # 编译源文件 BL51 main.obj TO main.abs # 链接 OH51 main.abs # 转 HEX

烧录后先不接灯,用万用表量 PA 口在四个相位下的输出值,对照论文的 0DDH、0D4H、0EBH、0E2H 是否一致。一致再接灯,避免灯组接错导致误判程序问题。

4.3 分阶段验证

上电后先看数码管是否显示 60 并每秒递减,这说明 T0 中断和显示子程序正常。再看灯是否按红绿黄顺序切换,切换点是否和倒计时归零对齐。然后拨动 P1 拨码改时间,确认新值生效。最后按 P2.0 模拟车流,看计数是否累加、满 100 是否归零。每一步只验证一个变量,出问题时范围立刻缩小。

注意:论文的显示子程序在 T0 中断里调用,如果 DISP 执行时间超过 50ms,中断会重入导致显示乱码。实测时如果数码管闪烁异常,先量 DISP 的耗时,必要时把显示拆到主循环做。

5. 避坑与排查:这套方案最容易翻车的五个点

5.1 倒计时整体偏快或偏慢

现象是数码管每秒跳两下或两秒跳一下。原因几乎都是晶振频率和定时初值不匹配,论文按 6MHz 算的 3CB0H 用在 11.0592MHz 板子上就会偏。解决是按实际晶振重算:TC = 65536 - (50000 × f / 12),f 单位 MHz,算完拆高低字节写进 TH0/TL0,同时软件延时子程序的循环次数也要按比例缩放。

5.2 8255 控制字写了但灯不响应

现象是 PA 口电平不随 MOVX 写入变化。先查 CS 是否真的在 P0.7 为低时有效,再查 WR/RD 有没有接反,最后确认地址译码:论文用 P0.7 做片选、P0.1/P0.0 做端口选择,如果 P0 口同时接了 373 做地址锁存,写 8255 时地址会经过锁存器,时序上要保证 ALE 下降沿后地址稳定。常见错误是把 8255 的 A0/A1 接到了 P2 口,导致地址对不上。

5.3 黄灯闪烁期间数码管停显

现象是黄灯 5 秒内数码管不刷新或定格。原因是闪烁延时用 CJNE 空转,CPU 被占死,T0 中断虽然还能进,但 DISP 里的位选切换被打断。解决是把闪烁节拍交给 T0 中断做状态翻转,主循环只等相位结束标志,不在主循环里写死延时。

5.4 报警后系统卡死不复位

现象是蜂鸣器一直响,倒计时不动。查 R2 的递减是否在 T0 中断里执行,如果报警分支里又开了循环等待,中断进不来 R2 永远不减。另外 P3.0 复用问题会导致报警拉低后主程序误判为“设置模式”,逻辑直接跑飞。把报警输出改到 8255 的 PB 高位,P3.0 只做模式位,这个坑就绕过去了。

5.5 拨码设定时间不生效

现象是拨了 P1 但倒计时还是默认值。论文的设定逻辑要求 P3.1 为低才进入设定分支,且 P1.7 区分红绿,很多人只拨了数据位没拨 P3.1,程序一直在运行态。另外 P1 口内部有上拉,拨码开关要接成对地短路才有效,接 VCC 反而读不到变化。用万用表量 P1 各脚在拨码前后的电平,能快速定位是硬件还是分支判断问题。

6. 二次开发:把这份毕设改成能演示的完整作品

论文的代码能跑,但离“拿得出手”还差几步。我一般会做三件事:把时序从软件延时迁到定时中断、把状态机改成表驱动、把车流量检测从按键模拟换成可扩展的输入。

先说时序迁移。论文里黄灯闪烁和部分延时靠空转,换晶振就失准。改造思路是只保留 T0 的 50ms 中断做唯一时基,中断里维护一个 tick 计数,主循环用if (tick % 10 == 0)判断 0.5 秒、tick % 20 == 0判断 1 秒,所有相位时长都换算成 tick 数。这样晶振变了只改初值,逻辑一行不动。

// 表驱动相位:每项为 灯码, 持续秒数, 是否黄闪 const unsigned char phase_tab[4][3] = { {0xDD, 60, 0}, // 东西红 南北绿 {0xD4, 5, 1}, // 黄闪过渡 {0xEB, 80, 0}, // 东西绿 南北红 {0xE2, 5, 1} // 黄闪过渡 }; unsigned char phase_idx = 0; unsigned int phase_tick = 0; void t0_isr(void) interrupt 1 { TH0 = 0x3C; TL0 = 0xB0; // 50ms if (++phase_tick >= phase_tab[phase_idx][1] * 20) { phase_tick = 0; phase_idx = (phase_idx + 1) & 0x03; P8255_PA = phase_tab[phase_idx][0]; } if (phase_tab[phase_idx][2] && (phase_tick % 10 == 0)) P8255_PA ^= 0x18; // 黄灯位翻转 }

这段改造的关键是把“相位表”和“时基”解耦,加一个相位只改表,不动中断逻辑。车流量检测同理,把 P2.0 的按键读改成定时采样,连续 N 次为低才计一次,消抖后累加,满阈值就动态延长当前绿灯相位——论文里“绿灯时间可检测车流量”的设想,到这一步才算真正闭环。

验证方法也简单:拿秒表对着数码管掐 60 秒,误差在 1 秒内算过;拨码改时间后重新掐一遍;黄灯阶段盯着数码管确认不停显;报警触发后确认 3 秒自动恢复且倒计时继续。这套流程我每次改完时序都会走一遍,因为时序类 bug 在实验室短时间看不出来,跑一晚上才暴露,那时候再回头查成本太高。从那以后我每次动定时器初值,都强制用秒表对一遍再收工。希望帮到你。

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

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

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

立即咨询