ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

51单片机交通灯设计:8255A扩展与可配置配时方案

51单片机交通灯设计:8255A扩展与可配置配时方案

简介:这份毕业设计论文面向电子信息、自动化等专业的学生与单片机初学者,围绕城市路口车流管理这一实际问题,给出了一套基于MSC-51系列ATSC51单片机与8255A可编程并行I/O接口芯片的交通灯控制方案。论文从交通灯的发展演进切入,剖析了8051内部CPU、ROM、RAM、定时/计数器、并行与串行接口及中断系统等结构,并完整呈现硬件原理图、接口电路连接说明与单片机源程序,涵盖初始化、时间设定、状态切换等模块,还实现了按车流量调整红绿灯时长、倒计时剩5秒黄灯闪烁、闯红灯报警及绿灯期间车流检测显示等智能化功能。资源包共1个doc文件,约257KB,内容为27页左右的完整论文正文,结构清晰、图文与代码兼备。目前已有1007人学习,适合作为课程设计或毕业设计的参考范本,也可为智能交通控制方向的入门研发提供可复用的设计思路与测试验证经验。

1. 从一次答辩被问懵说起:这套交通灯方案到底解决什么

答辩现场最容易被问住的一句话不是“你这个电路怎么画的”,而是“东西向 60 秒、南北向 80 秒,这个数你凭什么定”。很多基于单片机控制交通灯的设计,硬件搭得挺漂亮,一到“为什么”就卡壳。这套方案要解决的正是这个问题:它不只是让红黄绿三个灯轮流亮,而是把配时初值做成可设置、把绿灯期间的车流量做成可检测、把闯红灯做成可报警,让一个 51 单片机系统具备“能解释、能调整、能验收”的完整闭环。适合正在做单片机课程设计、毕业设计,或者要给出一份可交付控制方案的人。整套东西围绕 MCS-51 系列单片机加 8255A 并行接口展开,硬件不复杂,但每个模块都有明确职责,后面我会把总体设计、关键代码和验收方法一层层拆开。

2. 需求与选型:为什么是 51 单片机加 8255A 这套组合

2.1 先把功能需求钉死,别急着画原理图

做这类设计最常见的翻车方式,是先照着别人的图把线连上,再回头想“我这系统到底要干嘛”。我一般会先把需求写成一张能逐条验收的表,后面画图、写代码、答辩都对着它走。这套交通灯的功能边界其实很清楚:十字路口东西、南北两组红黄绿三色灯,红灯禁行、绿灯放行、黄灯作为切换前的公共停车警示;红绿灯循环点亮,倒计时剩 5 秒时黄灯闪烁;红、绿灯燃亮时间能通过 P1 口按键设置初值;绿灯期间能检测车流量并在双位数码管上显示;有车辆闯红灯时蜂鸣器报警约 3 秒后恢复。把这些写成表,需求就不再是模糊的“做个交通灯”,而是可测的条目。

编号功能需求验收方式
F1东西/南北两组红黄绿循环点亮上电观察一个完整周期
F2倒计时剩 5 秒黄灯闪烁警示秒表对照闪烁起止
F3P1 口按键设置红、绿灯初值按键后数码管与灯时同步变化
F4双位数码管显示当前倒计时逐秒读数无跳变、无重影
F5绿灯期间检测车流量并显示触发检测开关,读数递增
F6闯红灯蜂鸣报警约 3 秒模拟闯红灯信号,计时报警时长

这张表的价值在答辩时特别明显:老师问“你这系统实现了什么”,你不需要背,直接按编号讲,每条都能现场演示。需求先立住,后面的选型才有依据——比如为什么需要扩展 I/O,就是因为 F3、F4、F5 同时要占用按键输入、数码管段选位选、信号灯输出,8051 自身的口根本不够分。

2.2 选型逻辑:51 够用,8255A 补的是 I/O 缺口

8051 有 P0、P1、P2、P3 四组 8 位 I/O 口,看着不少,但真正能自由支配的并不多。P0 和 P2 通常要用来传送外部地址和数据,P3 口带着第二功能(串口、外中断、定时器输入等),实际能借用的主要就是 P1。而这套系统里,信号灯输出要一组口、数码管段码要一组、位选要两根线、按键输入要占用 P1、车流量检测还要一根输入线,算下来 8051 自己的口明显不够。所以方案里用 8255A 做并行 I/O 扩展,这是这套设计最关键的选型决策,也是答辩常被追问的点。

8255A 有三个 8 位端口 A、B、C 和一个控制寄存器。方案里的分工是:PA 口输出红黄绿信号灯状态,PC 口和 PB 口配合驱动双位数码管(段码走 PC/PB,位选另接),控制口用来写方式控制字。8255A 工作在方式 0,即基本输入输出方式,三个端口都能独立做输入或输出,输出可锁存——这一点对信号灯很重要,灯的状态写进去后能保持住,不会因为 CPU 去干别的就灭掉。方式 1 是选通输入输出、方式 2 是双向总线,这套系统用不上,选方式 0 最省事也最稳。

除了 8255A,硬件清单里还有 74LS373 做地址锁存、74LS07 做驱动、MAX692 看门狗防程序跑飞、7805 稳压、双向晶闸管驱动信号灯、共阴极七段数码管两只。这里要提醒一句:看门狗不是摆设,51 系统在强电环境附近跑,程序跑飞是真实会发生的,答辩时能说清“为什么加看门狗、喂狗周期怎么定”,比多焊两个灯加分得多。

2.3 配时方案:60 秒和 80 秒背后的取舍

原始方案里东西向红灯 60 秒、绿灯 80 秒,南北向对应反过来,中间各插 5 秒黄灯闪烁。这个配时的逻辑是“东西道车流量比南北道大,所以东西向通行时间长”。注意这里的 60 和 80 不是拍脑袋,而是对应“东西红灯时南北绿灯 60 秒、东西绿灯 80 秒”的相位关系,黄灯的 5 秒是两方向的公共停车时间,谁都不能走。整个周期就是 60+5+80+5=150 秒一轮。

我在带项目时一般会强调:配时参数一定要做成“可设置初值”,而不是写死在代码里。原因很实际——答辩老师很可能让你现场改个数看看,如果改不了,说明你的系统是死的。这套方案通过 P1 口按键把红、绿初值送进 R0、R7 这类寄存器,再参与倒计时,正好满足这个要求。下面这段是初值设置的核心逻辑,按键判断和寄存器赋值都在里面:

AGAIN: JB P3.1, N0 ; P3.1 为 1 表示进入工作态,为 0 进入初值设置 MOV A, P1 ; 读 P1 口按键状态 JB P1.7, RED ; P1.7 为 1 则设置红灯时间,否则设绿灯时间 MOV R0, #00H MOV R0, A ; 绿灯初值存入 R0 MOV R3, A LCALL DISP1 ; 设置过程中同步显示,便于确认 LCALL DELAY AJMP AGAIN RED: MOV A, P1 ANL A, #7FH ; 屏蔽 P1.7,取低 7 位作为红灯时间值 MOV R7, #00H MOV R7, A ; 红灯初值存入 R7 MOV R3, A LCALL DISP1 LCALL DELAY AJMP AGAIN

这段代码的设计意图值得说清楚:P3.1 是“工作/设置”的模式开关,为 0 时系统停在设置态等按键,为 1 才进入正常循环;P1.7 用来区分当前设的是红灯还是绿灯,避免两个初值互相覆盖;设置过程中调用 DISP1 把刚设的值显示出来,是为了让人按键时能看到反馈,不然设没设进去全靠猜。参数上,R0 存绿灯初值、R7 存红灯初值,后面倒计时都从这两个寄存器取,改配时只需要改按键输入,不用动程序。这种“参数与逻辑分离”的写法,是这类课设能不能拿高分的一个分水岭。

3. 总体设计与硬件落地:从框图到每一根线的职责

3.1 系统总框图与模块职责划分

整套系统按职责可以切成四块:控制核心(8051/8031 单片机)、I/O 扩展(8255A)、人机交互(P1 按键、双位数码管、蜂鸣器)、执行输出(红黄绿信号灯、晶闸管驱动)。数据流是这样的:单片机定时器产生 1 秒基准,主循环根据当前相位把信号灯状态字写到 8255A 的 PA 口,把倒计时数值经段码转换写到 PC/PB 口驱动数码管;P1 口读按键做初值设置,P2.0 读车流量检测开关,P3.0 控制报警输出。8255A 通过 P0 口与单片机相连,片选由 P0.7 控制,端口地址由 P0.1、P0.0 译码。

这里有个容易被忽略的设计点:8255A 的片选和端口选择。方案里 P0.7=0 时片选有效,P0.1、P0.0 组合出四个地址——00H 是 PA 口、01H 是 PB 口、02H 是 PC 口、03H 是控制口。写 8255A 初始化时往 03H 写方式控制字 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 位输出。一个字节把三个端口的方向全定了,这就是 8255A 方式 0 的省心之处。

MOV DPTR, #0003H ; 指向 8255A 控制口 MOV A, #80H ; 方式0,PA/PB/PC 全部输出 MOVX @DPTR, A ; 写入方式控制字,完成初始化

初始化只做一次,放在主程序开头。要注意的是,8255A 复位后所有端口默认是输入态,如果不写这个控制字,你往 PA 口写信号灯数据是写不进去的,灯根本不亮——这是新手最常踩的坑之一,后面避坑章节还会展开。

3.2 信号灯与数码管的接口设计

信号灯接在 8255A 的 PA 口,采用共阳极接法,也就是说端口输出低电平对应的灯才亮。方案里用状态字控制:比如东西红灯亮、南北绿灯亮时写 0DDH,两方向黄灯亮时写 0D4H,东西绿灯亮、南北红灯亮时写 0EBH。这些十六进制值不是随便编的,每一位对应一个灯,写之前要对着接线表核一遍哪一位管哪个灯,核错了就会出现“该亮的不亮、该灭的乱闪”。

数码管是共阴极七段管,段码走 PC/PB 口,位选另接。共阴极的意思是段码给高电平才亮,所以数字 0 到 9 的段码表和共阳极是反的。方案里给了完整的驱动代码表,比如显示 0 是 3FH、显示 1 是 06H、显示 8 是 7FH。写显示程序时,先把倒计时数值做二转十的除法拆成十位和个位,再查表取段码送出去,最后给位选信号选通对应那一位。双位数码管要动态扫描,两位轮流点亮,靠人眼视觉暂留看起来是同时亮的,扫描频率太低会闪,太高又增加 CPU 负担,一般几百赫兹比较合适。

DISP: MOV B, #0AH MOV A, R3 ; R3 中是当前倒计时值 DIV AB ; A 得十位,B 得个位 MOV 79H, A MOV 7AH, B MOV A, 79H ; 取十位 MOV DPTR, #TAB ; 段码表首地址 MOVC A, @A+DPTR ; 查表得段码 MOV DPTR, #0002H ; 送 PC 口 MOVX @DPTR, A MOV DPTR, #0001H ; 送位选,选通十位 MOV A, #0F7H MOVX @DPTR, A LCALL DELAY MOV A, 7AH ; 取个位,重复上述过程 MOV DPTR, #TAB MOVC A, @A+DPTR MOV DPTR, #0002H MOVX @DPTR, A MOV DPTR, #0001H MOV A, #0FBH MOVX @DPTR, A RET

这段显示子程序的关键在 DIV AB 和查表两步:DIV AB 把 0 到 99 的倒计时拆成十位个位,省去复杂的除法逻辑;MOVC 查表把数值转成七段段码,改字形只需要改表不用改逻辑。位选值 0F7H 和 0FBH 分别对应选通十位和个位,具体哪一位取决于你的位选接线,接线变了这两个值要跟着改,这是移植时最容易忘的地方。

3.3 定时基准与 1 秒的生成

51 单片机的定时器在 12MHz 晶振下,方式 1 最大定时约 65.5 毫秒,直接定 1 秒是做不到的,所以方案采用“定时器中断 + 软件计数”的组合:T0 定 50 毫秒,中断里对一个软件计数器减一,减到 0 就表示 1 秒到了。初值算法是 TC = M − T/T计数,方式 1 下 M 为 2 的 16 次方即 65536,T 取 50 毫秒、T计数 为 1 微秒,算出来 TC = 65536 − 50000 = 15536,换成十六进制就是 3CB0H,所以 TH0 装 3CH、TL0 装 B0H。

START: MOV TMOD, #01H ; T0 方式1,16 位定时 MOV TH0, #3CH ; 装初值高字节 MOV TL0, #0B0H ; 装初值低字节 MOV IE, #82H ; 开 T0 中断 SETB TR0 ; 启动 T0 MOV R0, #14H ; 软件计数器初值 20,20×50ms=1s LOOP: SJMP $

中断服务里每进一次就把 R0 减一,减到零说明 1 秒到,重新装初值并跳去刷新显示和倒计时。这里 R0 初值 14H 就是十进制 20,20 乘 50 毫秒正好 1 秒,这个数改大改小就能微调秒基准,答辩时如果被问“你的秒准不准”,可以现场用这个参数解释误差来源。要注意中断里重装初值和恢复软件计数器这两步不能漏,漏了要么时间越走越偏,要么倒计时直接停住。

4. 软件流程与关键功能实现:状态机、报警与车流量检测

4.1 主循环状态机:四个相位怎么转

交通灯的本质是一个有限状态机,这套方案里就是四个相位循环:东西红/南北绿(60 秒)→ 双黄闪(5 秒)→ 东西绿/南北红(80 秒)→ 双黄闪(5 秒)→ 回到起点。主程序用标号 N00、N1、N2、N3 把四个状态串起来,每个状态里先写信号灯状态字,再进倒计时循环,倒计时到零就跳到下一个状态。这种写法直白、好调试,缺点是状态多了会乱,但四个相位完全够用。

N00: MOV A, 76H ; 取东西红灯时间 MOV R3, A MOV DPTR, #0000H ; 指向 PA 口 MOV A, #0DDH ; 东西红、南北绿 MOVX @DPTR, A N01: JB P2.0, B0 ; 检测闯红灯信号 N02: SETB P3.0 CJNE R3, #00H, N01 ; 倒计时未到零则继续

这段是第一个相位的骨架。R3 是当前倒计时寄存器,中断里每秒减一,主循环里不断比较它是否为零。P2.0 在这里兼做闯红灯检测输入,一旦检测到就跳去报警程序 B0。状态机的每个状态都遵循“写灯态—等倒计时—判特殊事件”这个套路,理解了第一个,后面三个是同样的结构,只是状态字和初值不同。

4.2 黄灯闪烁与闯红灯报警

黄灯闪烁的实现思路是“亮 0.5 秒、灭 0.5 秒,循环 5 次”,总共 5 秒。代码里用 R3 记闪烁次数,R4 做 0.5 秒的粗延时,先写黄灯亮的状态字,延时后写灭的状态字,再延时,次数减到零退出。这里用的是软件延时而不是定时器,精度差一些但够用,因为黄灯闪烁对时间精度要求不高,能看出“闪”就行。

闯红灯报警的逻辑是:检测到 P2.0 有效且倒计时还没结束,就拉低 P3.0 驱动蜂鸣器,同时 R2 记 3 秒,3 秒后恢复。这里有个细节要处理好——报警期间如果倒计时正好到零进入下一相位,应该停止报警,否则会出现“绿灯了还在响”的怪现象。方案里用 JZ N1 判断倒计时是否归零来规避,这个判断看着小,实际是保证逻辑自洽的关键。

B0: MOV R2, #03H ; 报警持续 3 秒 B01: MOV A, R3 JZ N1 ; 倒计时已归零则不再报警 CLR P3.0 ; 拉低驱动蜂鸣器 CJNE R2, #00H, B01 ; 3 秒未到继续 SJMP N02

4.3 车流量检测:绿灯期间的一次计数

车流量检测放在绿灯相位里做,逻辑是:绿灯倒计时还没结束时,不断查询 P2.0 电平,每检测到一次有效信号就把计数寄存器 R7 加一,计到 64H(十进制 100)就回零重新计,同时把数值送数码管显示。这个功能在答辩时是个亮点,因为它把“固定配时”往“感知车流”方向推了一步,虽然只是简单计数,但能讲清楚“检测—计数—显示”这条链路。

T03: MOV A, R3 SUBB A, #00H ; 判断绿灯是否已结束 JZ N3 ; 结束则不再检测 JB P2.0, T03 ; 无信号则继续查询 INC R7 ; 有信号,计数加一 CJNE R7, #64H, E1 ; 满 100 回零 MOV R7, #00H

要注意的是,检测开关的抖动会带来误计数,实际做的时候一般会在检测到信号后加一小段延时再确认,或者用硬件消抖。方案原文没细写消抖,但这是现场演示时很容易暴露的问题——按一下开关数字跳好几下,老师一眼就看出来。我的习惯是软件里加 10 到 20 毫秒延时确认,成本很低,效果立竿见影。

5. 避坑与排查:这类设计最容易翻车的五个点

5.1 灯不亮或乱亮:先查 8255A 初始化

现象是上电后信号灯完全不亮,或者亮的顺序和预期对不上。原因通常有两个:一是忘了往 8255A 控制口写方式控制字,端口还停在默认输入态,写数据写不进去;二是状态字和实际接线对不上,比如共阳极接法却按共阴极写状态字,逻辑整个反了。解决办法是先单独写一段测试程序,往 PA 口轮流写 0FFH 和 00H,看灯是否全灭全亮,确认端口方向和接法没问题,再回去查状态字每一位对应的灯。

5.2 数码管重影或闪烁:扫描与位选没配合好

现象是两位数显示重叠、发虚,或者肉眼可见地闪。原因是动态扫描时位选切换和段码输出的时序没处理好,前一位的段码还没消掉就选了下一位,或者扫描间隔太长。解决方法是每次切换位选前先把段码口清零(消隐),再送新段码、选通新位;扫描延时控制在毫秒级,别用太长的软件延时。另外共阴极段码表如果误用了共阳极的值,会显示成乱码,这个也要对着表核一遍。

5.3 倒计时不准或停住:中断里的重装和计数漏了

现象是秒走得明显偏快偏慢,或者走到某个数就不动了。原因多半在定时器中断服务里:要么忘了重装 TH0、TL0 初值,要么软件计数器减到零后没恢复初值,要么中断里干了太多活导致下次中断被延误。解决办法是把中断服务写短,只做计数和标志置位,显示刷新放到主循环;重装初值和恢复计数器这两步固定成模板,每次改中断都对照检查一遍。

5.4 按键设初值没反应:模式开关和消抖

现象是按了设置键,数码管和灯时都不变。原因可能是 P3.1 模式开关没拨到设置态,或者按键抖动导致读到的值不稳定,也可能是设置值和运行值用了不同的寄存器,设进去了但主循环没读。解决办法是先确认模式开关电平,再在按键读取后加延时消抖并二次确认,最后核对初值寄存器(R0、R7)和倒计时取值处是不是同一套。

5.5 报警误触发或不停:输入判断和退出条件

现象是没闯红灯也报警,或者报警响起来停不下来。原因是 P2.0 输入没有上拉或消抖,悬空时读到随机电平;或者报警循环的退出条件写错,倒计时归零后没跳出。解决办法是给输入脚加上拉电阻、软件消抖,报警循环里明确加“倒计时归零则退出”的判断,并且报警时长用独立计数器控制,别和倒计时寄存器混用。

6. 验收与答辩:怎么把一套交通灯讲成一份能交付的方案

验收这套东西,我一般分三步走,每一步都有明确的通过标准,答辩时也按这个顺序演示,节奏最稳。第一步是静态检查:断电状态下对照原理图核对 8255A 片选、端口地址、信号灯和数码管接线,确认 74LS373 锁存、看门狗、稳压部分没有虚焊。这一步不通过,后面全是白搭。第二步是分模块上电测试:先只测 8255A 端口输出(写 0FFH/00H 看灯全灭全亮),再测数码管扫描(固定显示 88 看有无缺段重影),再测定时基准(用秒表对 60 秒倒计时,误差控制在可接受范围),最后测按键设初值和车流量计数。第三步是整机联调:跑完整 150 秒周期,观察四个相位切换、黄灯闪烁起止、报警触发与恢复是否都符合需求表。

答辩时最值钱的是“能解释每个参数”。下面这张表建议直接背下来,被问到张口就能答:

被问到的点回答要点
为什么用 8255A8051 可用 I/O 不够,PA 出灯态、PC/PB 出段码,方式 0 输出可锁存
60/80 秒怎么定东西向车流大给长绿灯,黄灯 5 秒为公共停车时间,周期 150 秒
1 秒怎么来T0 定 50ms,软件计数 20 次,初值 3CB0H
状态字 0DDH 含义共阳极接法,对应位低电平点亮,按接线表逐位核对
车流量检测怎么做绿灯期间查 P2.0,有效则 R7 加一,满 100 回零并显示

还有一个答辩技巧:主动暴露一个你解决过的问题,比等老师来挑刺强。比如你可以说“最初黄灯闪烁用的是定时器,后来发现和倒计时中断抢资源,改成软件延时后稳定了”,这种“踩坑—定位—解决”的叙述,比干巴巴念功能列表有说服力得多。老师要看的不是你做了多复杂的系统,而是你有没有工程判断力。

从那以后我每次带这类单片机课设,都强制让学生先交需求表再动烙铁,验收时按表逐条打勾,答辩前把参数表背熟。这套流程走下来,系统还是那个系统,但讲出来的东西完全不一样。希望帮到你。

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

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进