
简介这是一个面向单片机课程设计与综合实验的十字路口交通灯控制系统完整方案基于51单片机和Proteus实现。资源压缩包共21个文件大小约358KB内含Proteus仿真工程、Keil工程文件、C语言源码、hex烧录文件以及Word实验报告仿真、代码、报告齐全可直接打开仿真工程运行也可将hex下载到单片机验证。目前已有453人学习适合正在完成交通灯课设或需要学习Proteus仿真的读者参考。方案使用P1.0-P1.5控制四个方向红黄绿灯P0口驱动两位共阳数码管倒计时P2.0-P2.3作为位选定时中断50ms产生秒跳变报告涵盖实验目的、仪器材料、内容要求与原理分析结合源码和仿真图可以清晰理解模块化编程思路也便于修改交通灯配时或扩展为更复杂的控制逻辑。1. 十字路口四向红绿灯仿真四组灯和两位数码管的“同步”才是重点四组红黄绿对应十字路口的四个方向用两位数码管显示剩余时间再用 Proteus 把仿真图画出来——这个题目在单片机课程设计和 proteus 仿真作业里出现频率很高。不少人拿到题先开 Proteus 拖元件拖完才发现四组灯怎么接、数码管显示谁的剩余时间、红灯倒计时从几秒开始这些关键点还悬着。其实灯虽然摆了十二只逻辑上只需要按南北、东西两个车道方向去切换两位数码管也就是一只给南北方向、一只给东西方向各自显示本方向下一次变绿灯或当前绿灯还剩多少秒。下面从状态表、C51 代码、Proteus 连线到报告整理按可复现的顺序走一遍。2. 系统构成与状态切换灯组怎么接、剩余时间怎么算2.1 四个方向四套灯先简化成两组时序十字路口四个方向各有一组红黄绿但真正独立的只有两组南北向车道同步放行东西向车道同步放行。东、西两个方向的灯要同时变因为它们在同一个相位里南、北也一样。所以代码里只需要维护两套输出四个方向的灯组共用这两套驱动。先画一张四状态表后面写代码、画 Proteus 图、写报告都用它状态编号南北向灯组东西向灯组持续时间说明S0绿灯红灯30s南北放行东西禁行S1黄灯红灯3s南北清空路口S2红灯绿灯30s东西放行南北禁行S3红灯黄灯3s东西清空路口注意 S1 和 S3 是短状态只用于黄灯清空。很多人做到这里会直接写成“南北绿30秒然后南北黄3秒然后南北红3秒再东西绿30秒”结果东西向红灯切绿灯的时机不对路口出现四个方向同时绿灯的瞬间。用上面的状态表就不会因为东西向红灯在 S0、S1 两个状态里一直保持S1 结束才切换到绿灯。两位数码管的显示值这样约定南北向数码管显示南北方向的剩余时间东西向数码管显示东西方向的剩余时间。一个方向绿灯时显示本相位剩余秒数黄灯时显示黄灯剩余秒数红灯时显示“离下一次本方向绿灯亮起还剩多少秒”。这个定义决定了一件事红灯显示不是从 30 开始而是从 33 开始。因为南北红灯期间还要等东西绿灯 30 秒和东西黄灯 3 秒才能重新轮到南北绿灯。从 33 倒计时到 1期间数字连续变化不会在状态切换时跳回 33。2.2 主控与 IO 分配AT89C51 在 Proteus 里的最小方案主控选 AT89C51原因是 Proteus 元件库里直接搜“AT89C51”就能放进去不需要额外导入模型。双击元件把时钟频率设为 12MHz这和代码里定时器初值计算一致。用 Proteus 8 Professional 做仿真时P0 口需要注意AT89C51 的 P0 是开漏输出段码输出必须接上拉电阻否则两位数码管亮度很暗或者显示不稳定。我一般接一个 RESPACK-8 排阻一端接 P0另一端统一接 5V。引脚分配如下引脚连接对象说明P1.0东西向绿LED 正极经 220Ω 接 5VP1.1东西向黄同上P1.2东西向红同上P1.3南北向绿同上P1.4南北向黄同上P1.5南北向红同上P0.0 – P0.7两位数码管段码 a – g、dp两个模块并联到同一组段码线P2.0 – P2.3四位数码管位选低电平选中对应位这里说的“两个两位数码管”实际是两颗 7SEG-MPX2-CA。每颗内部有两位外部引出两个位选脚 dig1、dig2。南北方向用一颗东西方向用一颗合起来四位数码管最大能显示 99而我们最大只显示 33两位足够。2.3 共阳数码管动态扫描段码数组和位选时序7SEG-MPX2-CA 是共阳数码管段码低电平有效。按 P0.0 接 a、P0.1 接 b、P0.2 接 c、P0.3 接 d、P0.4 接 e、P0.5 接 f、P0.6 接 g、P0.7 接 dp 的顺序接线数字 0 到 9 的段码是数字段码数字段码00xC050x9210xF960x8220xA470xF830xB080x8040x9990x90动态扫描的核心是“同一时刻只点亮一位”sbit DISP_NS_T P2^0; // 南北十位 sbit DISP_NS_D P2^1; // 南北个位 sbit DISP_EW_T P2^2; // 东西十位 sbit DISP_EW_D P2^3; // 东西个位每次刷新先送段码再选通位选最后延时 2ms。四个位轮流扫一遍约 8ms刷新频率 125Hz人眼看到的就是四个数字同时稳定显示。如果延时调到 5ms 以上会看到明显闪烁小于 1ms亮度又不够。2ms 是仿真和实物都比较稳的经验值。3. 定时器中断、倒计时与显示刷新C51 代码分段拆解3.1 用定时器0产生 1 秒时基重载值怎么算12MHz 晶振下51 单片机机器周期是 12 ÷ 12MHz 1µs。定时器0工作在方式1是 16 位加 1 计数器最大计到 65536 溢出。要产生 50ms 中断需要计数 50000 次初值是 65536 - 50000 15536十六进制是 0x3CB0。定时器初始化和中断服务程序这样写#include reg51.h #define uchar unsigned char #define uint unsigned int volatile uchar tick_50ms 0; volatile uchar sec_flag 0; void Timer0_Init(void) { TMOD 0xF0; /* 只修改定时器0配置 */ TMOD | 0x01; /* 方式116位定时器 */ TH0 0x3C; TL0 0xB0; /* 初值50000次 50ms */ ET0 1; EA 1; TR0 1; } void Timer0_ISR(void) interrupt 1 { TH0 0x3C; TL0 0xB0; /* 重装初值 */ tick_50ms; if (tick_50ms 20) { tick_50ms 0; sec_flag 1; /* 累计到1秒置位标志 */ } }中断里只置标志不在中断里做灯切换和显示刷新避免主循环和中断争用变量。主循环检测到 sec_flag 后再处理倒计时这样秒脉冲误差只来自 50ms 计数的累计代码也容易排查。3.2 状态机主循环切灯、算剩余秒数、刷新显示灯的控制状态用数组保存每个状态持续时间放在表里#define GREEN_TIME 30 #define YELLOW_TIME 3 code uchar state_time[4] {GREEN_TIME, YELLOW_TIME, GREEN_TIME, YELLOW_TIME}; void Light_Set(uchar st) { switch (st) { case 0: /* 南北绿东西红 */ NS_GREEN 1; NS_YELLOW 0; NS_RED 0; EW_GREEN 0; EW_YELLOW 0; EW_RED 1; break; case 1: /* 南北黄东西红 */ NS_GREEN 0; NS_YELLOW 1; NS_RED 0; EW_GREEN 0; EW_YELLOW 0; EW_RED 1; break; case 2: /* 南北红东西绿 */ NS_GREEN 0; NS_YELLOW 0; NS_RED 1; EW_GREEN 1; EW_YELLOW 0; EW_RED 0; break; case 3: /* 南北红东西黄 */ NS_GREEN 0; NS_YELLOW 0; NS_RED 1; EW_GREEN 0; EW_YELLOW 1; EW_RED 0; break; } }两个数码管显示值用独立函数计算uchar Calc_NS_Display(uchar st, uchar remain) { switch (st) { case 0: case 1: return remain; /* 南北绿或黄显示本状态剩余 */ case 2: return remain YELLOW_TIME; /* 南北红剩余 后续黄灯3秒 */ default: return remain; } } uchar Calc_EW_Display(uchar st, uchar remain) { switch (st) { case 0: return remain YELLOW_TIME; /* 东西红显示33到4 */ case 1: case 2: case 3: return remain; /* 东西红尾段、绿、黄 */ default: return remain; } }主循环里每收到一个秒脉冲当前状态剩余秒数减 1减到 0 就切到下一个状态void main(void) { uchar state 0; uchar remain_sec state_time[0]; Timer0_Init(); Light_Set(state); while (1) { if (sec_flag) { sec_flag 0; remain_sec--; if (remain_sec 0) { state (state 1) % 4; remain_sec state_time[state]; Light_Set(state); } } Display_Refresh(Calc_NS_Display(state, remain_sec), Calc_EW_Display(state, remain_sec)); } }为什么 state 2 的南北红要加YELLOW_TIME因为南北红灯期间还剩“东西黄灯3秒 东西绿灯30秒”融成一个连续倒计时显示从 33 一路走到 1中间不会跳变。3.3 绿信比调整把 30 秒和 3 秒做成可配置参数交通灯设计中绿灯和黄灯时长叫绿信比。很多作业只要求固定 30 秒但报告中通常要写“可调”。用宏定义后修改只需要改两个数字参数现在值调整示例作用GREEN_TIME3025调整通行相位总时长YELLOW_TIME35调整清空路口的缓冲时间state_time[0]GREEN_TIME随宏变化南北绿灯state_time[1]YELLOW_TIME随宏变化南北黄灯如果直接写死30和3显示函数里加YELLOW_TIME的位置也要同步改很容易漏。抽出宏之后报告里可以写“改变宏定义即可改变配时”这句话在答辩时很加印象分。周期总长为两个绿灯加两个黄灯也就是2 * (GREEN_TIME YELLOW_TIME)秒。4. Proteus 仿真搭建元件布置、连线与运行4.1 Proteus 元件清单与搜索关键词打开 Proteus 元件库后按下面表格逐个搜索放入元件Proteus 搜索关键词数量备注主控芯片AT89C511双击改频率 12MHz两位共阳数码管7SEG-MPX2-CA2南北、东西各一颗红色 LEDLED-RED4四个方向的红灯黄色 LEDLED-YELLOW4四个方向的黄灯绿色 LEDLED-GREEN4四个方向的绿灯排阻RESPACK-81P0 上拉电阻RES12220Ω LED 限流晶振CRYSTAL112MHz电容CAP422pF 晶振电容电解电容CAP-ELEC110µF 复位电路按键BUTTON1手动复位Proteus 元件库里“7SEG-MPX2-CA”是两位共阳数码管的标准模型不要再用两个 7SEG-COM-CAT-8 拼拼出来的引脚和位选逻辑跟代码对不上。排阻注意选 RESPACK-8不是 RESPACK-7后者少一位。4.2 连线顺序与网络标号先电源和晶振再排 IO打开 Proteus 后先放 AT89C51把 VCC 和 GND 接好再放晶振电路。晶振两端各接一个 22pF 电容到 GND复位电路用 10µF 电解电容接到 VCC、再串联 10kΩ 电阻到 GNDRST 引脚接在电容和电阻中间。这个复位电路在仿真里也能用按一次 BUTTON 相当于硬件复位。然后按下面的顺序分组连线P0 接 RESPACK-8排阻公共端接 5V另一侧接 P0。再把两个 7SEG-MPX2-CA 的八段引脚 a 到 dp 分别接到 P0 的同一组网络上。P2.0 接南北模块 dig1P2.1 接南北模块 dig2P2.2 接东西模块 dig1P2.3 接东西模块 dig2。十二只 LED 分成四组每组一只红、一只黄、一只绿。东西向红灯接 P1.0东西向黄灯接 P1.1东西向绿灯接 P1.2南北向按 P1.3、P1.4、P1.5 对应绿、黄、红。每只 LED 正极接 220Ω 电阻到对应 IO负极统一接地。这样 IO 输出高电平就点亮 LED。连线时可以用网络标号替代实际走线P0 的八根段码线加上排阻和两次数码管用鼠标拉线会非常乱。给每个网络起名 SEG_A 到 SEG_DP数码管和排阻的同名引脚直接标网络号仿真图整洁报告里截图也好看。4.3 加载 HEX 文件与运行前检查Keil 工程里把 main.c 加入然后在 Options for Target 的 Output 选项卡勾选 “Create HEX File”编译后在工作目录生成 hex 文件。回到 Proteus 双击 AT89C51在 Program File 一栏选择这个 hex晶振频率填写 12MHz点运行。如果只想在命令行确认 hex 是否生成可以用if exist .\Objects\*.hex ( echo HEX 文件已生成 ) else ( echo 请先在 Keil 中勾选 Create HEX File )运行后首先看南北绿灯和东西红灯是否同时保持再看两个数码管是不是从 30 和 33 开始倒数。南北绿灯 30 秒结束后南北黄灯亮 3 秒数码管显示 3 到 1然后南北红灯亮南北数码管从 33 重新倒数东西数码管从 30 开始倒数。4.4 Proteus 仿真不动的三排错法仿真最常见的现象是灯不闪、数码管全灭或者数字乱跳按顺序排查现象可能原因处理运行后灯和数码管全不动没加载 hex 或频率不对检查 AT89C51 的 Program File 和 Clock Frequency数码管乱码段码线接错或共阳共阴选错核对 P0 到 a–dp 的顺序倒计时比实际快一倍Keil 和 Proteus 晶振不统一两处都设为 12MHz数字闪烁数码管延时太长把延时降到 2ms四方向绿灯同时亮状态表写错回到第 2 章的状态表逐行核对Proteus 和 Keil 都是默认 12MHz 的话这三排错基本覆盖 80% 的问题。5. 验收清单与报告素材整理仿真图、时序表、参数调优记录5.1 验收时盯住的四个观察点仿真通过后按下面这张表逐项打勾再截图观察点通过标准相位互斥任意时刻只有南北或东西一个方向是绿灯黄灯顺序绿灯熄灭后黄灯亮 3 秒再切红灯倒计时连续性状态切换瞬间数码管数字不跳变、不回弹刷新稳定四位数码管亮度均匀无闪烁截图为证时分别截一张南北绿灯、南北黄灯、东西绿灯、东西黄灯的图四张图能完整表达整个周期。5.2 报告里需要体现的三类素材标题里带“报告”说明最终交付不只有代码和仿真图。报告结构里最少要有三块状态时序表、Proteus 原理图、关键代码段。状态时序表直接复用第 2 章的四状态表原理图用 4.2 节完成后的干净截图不要带交叉杂乱的总线代码段只要贴定时器初始化、状态切换、显示刷新三块并配上每段的功能说明。报告中建议另外画一个简易的系统框体AT89C51 在中间左边是晶振复位电路右边是六只灯的输出下边是两位数码管显示模块。这个框图在答辩时能让老师一眼看出你理解了系统结构。5.3 用参数表做绿信比验证最后一步是验证参数可调。把宏定义改成一组不同值重新编译并加载 hex#define GREEN_TIME 20 #define YELLOW_TIME 5重新运行仿真记录如下表测试序号南北绿灯南北黄灯东西绿灯东西黄灯周期总长130s3s30s3s66s220s3s30s3s56s320s5s25s3s53s每组参数跑完一轮把数码管开始倒计时的画面和灯组切换画面截下来放进报告的“参数分析”小节。最后在报告里写一句结论绿灯时长调整只需修改GREEN_TIME和YELLOW_TIME两个宏重新编译即可生效。保存这两次修改后的仿真截图插入到报告参数分析栏目整套作业从仿真、代码到报告就闭环了。本文还有配套的精品资源点击获取