简介:本资源是一份面向电气工程及其自动化专业本科生的PLC实践教学材料,聚焦S7-1200可编程控制器在八段LED显示与智能交通灯控制两大典型场景中的综合应用,解决初学者对TIA Portal V13软件操作、梯形图编程、HMI人机交互及仿真验证等核心技能的系统性训练需求。压缩包为单个1.62MB的docx文档,完整涵盖实验一(八段LED循环显示0–8、触摸屏动态控制、段码映射与多数码管扩展)与实验二(交通灯手/自动双模逻辑、时序切换、PROFINET通信配置及HMI参数化设置)的全部内容,含实验目的、设备清单、详细步骤、程序逻辑说明、变量定义、动画关联方法及典型问题排错反思。目前已有447人学习下载,文档结构清晰、图文结合紧密,附有真实调试截图与变量表设计示例,特别适合课程设计、实训报告撰写与考前实操复盘。
1. 为什么红绿灯PLC程序一上电就“乱闪”?八段LED实验不是接线对了就能跑通的硬核落地课
很多刚接触PLC编程的开发者,拿到“八段LED编程实验:交通红绿灯”这个标题时,第一反应是:“不就是用几个输出点控制8个LED,按时间切状态?抄个梯形图,下载进PLC,灯亮了就算成功?”——结果往往是:灯全亮、全灭、交替疯闪、黄灯卡死、左转相位完全缺失……甚至PLC报SF(系统故障)灯常亮。根本原因在于,八段LED在这里不是装饰,而是交通信号机最底层的状态显性化载体;它强制你把“红黄绿三色+方向箭头+倒计时段”这7个逻辑单元,全部映射到8个物理段的布尔组合中。这不是简单的IO点开关练习,而是一次对PLC扫描周期、定时器精度、状态机健壮性、硬件驱动能力的综合压力测试。本实验特别适合已完成基础指令学习、正准备进入工业现场调试阶段的工程师,以及需要在课程设计中体现“可验证、可复现、可扩展”能力的学生。它不依赖HMI或上位机,仅靠PLC+八段数码管+LED灯组,就能完成从状态定义、时序建模、段码查表、消隐处理到异常恢复的完整闭环。下面,我们就从零开始,把这套被无数人“以为很简单、实则踩坑密集”的红绿灯PLC实验,真正跑通、调稳、能交付。
2. 八段LED与交通灯状态的映射逻辑:为什么不能直接用0-9数字段码?
2.1 八段LED物理结构决定的编码约束
标准共阴极八段LED(a~g + dp)每个段对应一个PLC输出点(Q0.0 ~ Q0.7)。但交通灯状态远不止“0-9”数字:主路直行红灯需显示“R”,左转绿灯需显示“←”,黄灯闪烁需“—”或“*”,倒计时需动态数字。关键矛盾在于:八段LED无法直接显示字母“R”或箭头“←”,必须通过段组合“伪造”视觉语义。例如:
- “R”常用 a-f-g 组合(类似“P”加g段),但易与“P”混淆;
- “←”实际只能用 b-c-d-e 段点亮模拟箭头尾部,配合熄灭a/g段形成指向感;
- 黄灯闪烁不能只靠“开/关”输出点,必须引入高频PWM(如2Hz)避免LED频闪损伤。
提示:不要试图用单个八段LED显示完整“红绿灯三色”。本实验中,八段LED专用于状态标识符(如R/G/Y/L/T),而三色灯由独立LED灯珠实现。这是工业信号机的标准分层设计——段码管负责“是什么状态”,灯珠负责“当前亮什么色”。
2.2 交通灯标准时序与状态机建模
国标GB 14886规定城市路口信号至少包含4个相位:主路直行(NS)、主路左转(NSL)、支路直行(EW)、支路左转(EWL)。本实验简化为2相位(NS/EW)+黄灯过渡,共5个核心状态:
| 状态ID | 名称 | 主路灯 | 支路灯 | 八段LED显示 | 持续时间 | 触发条件 |
|---|---|---|---|---|---|---|
| S0 | NS绿通行 | G | R | G | 30s | 启动/上一周期结束 |
| S1 | NS黄闪 | Y | R | Y | 3s | S0定时器满 |
| S2 | NS红等待 | R | G | R | 30s | S1定时器满 |
| S3 | EW黄闪 | R | Y | Y | 3s | S2定时器满 |
| S4 | 故障态 | 全灭 | 全灭 | E | 持续 | 任意定时器超时/输入异常 |
注意:Y在S1/S3均显示,但需通过主路/支路灯色区分——八段LED只表征“当前处于黄灯阶段”,不区分方向。这是降低段码复杂度的关键取舍。
2.3 段码查表法:用DB块固化映射关系,拒绝硬编码
在TIA Portal V18中,创建数据块DB_SegCode,类型为ARRAY[0..15] OF BYTE,手动填入16进制段码(共阴极):
// DB_SegCode.DBX0.0 : 段码数组起始地址 // 值含义:bit0=a, bit1=b, ..., bit6=g, bit7=dp // 示例:'G' = a-b-c-d-e-g = 0x7D (01111101) // 'R' = a-f-g = 0x57 (01010111), 'E' = a-d-e-f-g = 0x5B (01011011) // '0' = a-b-c-d-e-f = 0x3F, '1' = b-c = 0x06... DB_SegCode[0] := 16#3F; // 0 DB_SegCode[1] := 16#06; // 1 DB_SegCode[2] := 16#5B; // E (故障) DB_SegCode[3] := 16#7D; // G (绿) DB_SegCode[4] := 16#57; // R (红) DB_SegCode[5] := 16#6D; // Y (黄) — 注意:此为a-b-d-e-g-f组合,非标准"Y"逻辑说明:使用DB块而非FC内部常量,便于后期修改(如更换LED型号需调整段码)。参数说明:
ARRAY[0..15]预留扩展空间;BYTE类型直接对应8个输出位;十六进制书写符合PLC编程习惯,避免二进制位操作错误。
3. PLC程序架构:三层状态机+双定时器冗余设计
3.1 主状态机(Main_SM):用SCL语言实现带看门狗的循环跳转
在OB1中调用功能块FB_TrafficSM,其接口如下:
// FB_TrafficSM 接口声明 VAR_INPUT START : BOOL; // 启动按钮(I0.0) STOP : BOOL; // 急停按钮(I0.1) RESET_FAULT : BOOL; // 故障复位(I0.2) END_VAR VAR_OUTPUT NS_RED : BOOL; // 主路红灯输出(Q1.0) NS_YELLOW : BOOL; // 主路黄灯输出(Q1.1) NS_GREEN : BOOL; // 主路绿灯输出(Q1.2) EW_RED : BOOL; // 支路红灯输出(Q1.3) EW_YELLOW : BOOL; // 支路黄灯输出(Q1.4) EW_GREEN : BOOL; // 支路绿灯输出(Q1.5) SEG_CODE : BYTE; // 八段LED段码(Q0.0~Q0.7) FAULT_FLAG : BOOL; // 故障标志 END_VARSCL主逻辑(精简核心):
// 状态变量声明 STATE : INT := 0; // 当前状态ID(0=S0,1=S1,...,4=S4) NEXT_STATE : INT; TIMER_NS : TON; // 主路绿灯定时器 TIMER_EW : TON; // 支路绿灯定时器 WATCHDOG : TON; // 看门狗定时器(10s) // 看门狗启动:任何状态持续超10s即触发故障 WATCHDOG(IN := TRUE, PT := T#10S); IF WATCHDOG.Q THEN STATE := 4; // 强制进入S4故障态 FAULT_FLAG := TRUE; END_IF; // 状态转移逻辑 CASE STATE OF 0: // S0 NS绿通行 NS_GREEN := TRUE; EW_RED := TRUE; SEG_CODE := DB_SegCode[3]; // 'G' TIMER_NS(IN := TRUE, PT := T#30S); IF TIMER_NS.Q THEN NEXT_STATE := 1; END_IF; 1: // S1 NS黄闪 NS_YELLOW := TRUE; EW_RED := TRUE; SEG_CODE := DB_SegCode[5]; // 'Y' // 黄灯PWM:用系统时钟位M10.0(1Hz)分频 NS_YELLOW := M10.0; // 实际项目中应加滤波防抖 TIMER_NS(IN := TRUE, PT := T#3S); IF TIMER_NS.Q THEN NEXT_STATE := 2; END_IF; 2: // S2 NS红等待 NS_RED := TRUE; EW_GREEN := TRUE; SEG_CODE := DB_SegCode[4]; // 'R' TIMER_EW(IN := TRUE, PT := T#30S); IF TIMER_EW.Q THEN NEXT_STATE := 3; END_IF; 3: // S3 EW黄闪 NS_RED := TRUE; EW_YELLOW := TRUE; SEG_CODE := DB_SegCode[5]; // 'Y' EW_YELLOW := M10.0; TIMER_EW(IN := TRUE, PT := T#3S); IF TIMER_EW.Q THEN NEXT_STATE := 0; END_IF; 4: // S4 故障态 NS_RED := FALSE; NS_YELLOW := FALSE; NS_GREEN := FALSE; EW_RED := FALSE; EW_YELLOW := FALSE; EW_GREEN := FALSE; SEG_CODE := DB_SegCode[2]; // 'E' FAULT_FLAG := TRUE; // 故障时禁止自动恢复,需人工复位 IF RESET_FAULT THEN FAULT_FLAG := FALSE; STATE := 0; END_IF; END_CASE; // 状态更新(在每周期末执行) IF NEXT_STATE <> STATE THEN STATE := NEXT_STATE; // 清除所有定时器,防止残留Q置位 TIMER_NS(IN := FALSE); TIMER_EW(IN := FALSE); WATCHDOG(IN := FALSE); END_IF;逻辑说明:采用SCL而非LAD,因状态机分支多、逻辑嵌套深,SCL可读性更高。参数说明:
T#30S为IEC时间格式;M10.0是CPU内置1Hz时钟位,无需额外编程;WATCHDOG是防止单一状态卡死的核心安全机制。
3.2 八段LED消隐处理:解决“段码切换时的鬼影”
当SEG_CODE从0x7D(G)突变为0x57(R)时,若新旧段码有公共位(如a段始终亮),会导致部分段延迟熄灭,产生“重影”。解决方案:在每次段码更新前,强制所有段灭10ms。
在FB_TrafficSM中添加消隐子程序:
// 消隐逻辑:先全灭,再写新码 IF SEG_CODE <> LAST_SEG_CODE THEN // 步骤1:全灭(共阴极,写0xFF=全段导通=全灭) Q0 := 16#FF; // 步骤2:延时10ms(调用TONR,非TON,避免重复触发) BLANK_TIMER(IN := TRUE, PT := T#10MS); IF BLANK_TIMER.Q THEN // 步骤3:写新段码 Q0 := SEG_CODE; LAST_SEG_CODE := SEG_CODE; BLANK_TIMER(IN := FALSE); END_IF; ELSE Q0 := SEG_CODE; // 无变化则直通 END_IF;关键参数:
T#10MS经实测为最小有效消隐时间;TONR(保持型定时器)确保即使PLC扫描周期波动,10ms也能精准执行;LAST_SEG_CODE为静态变量,记录上一次有效段码。
4. 避坑:八段LED交通灯实验的5个血泪经验
4.1 现象:八段LED显示“G”时,a段微亮但g段不亮,实际显示像“C”
原因:段码值0x7D(01111101)中bit6(g段)为1,但硬件接线将g段接到Q0.6,而程序误将SEG_CODE字节整体赋给Q0(Q0.0~Q0.7)。若PLC输出模块为源型(Source)接线,共阴极LED需低电平点亮,此时0x7D对应高电平段灭、低电平段亮,逻辑反转!
解决:确认PLC输出类型与LED接线方式匹配。共阴极LED必须配漏型(Sink)输出模块,或在程序中对段码取反:Q0 := NOT SEG_CODE;。实测中,某高校实验室因混用源型模块,导致所有段码显示颠倒,调试耗时两天。
4.2 现象:黄灯闪烁频率忽快忽慢,有时连续亮5秒
原因:直接用M10.0(1Hz)控制黄灯,未考虑PLC扫描周期抖动(尤其在加载其他FB时可达50ms)。当扫描周期>500ms,M10.0的占空比严重失真。
解决:改用硬件定时中断(OB35,100ms周期)生成稳定2Hz PWM:
// 在OB35中(100ms调用) STATIC_PWM_CNT : INT := 0; STATIC_PWM_CNT := STATIC_PWM_CNT + 1; IF STATIC_PWM_CNT >= 5 THEN // 5*100ms=500ms → 2Hz YELLOW_PWM := NOT YELLOW_PWM; STATIC_PWM_CNT := 0; END_IF;然后在主程序中用YELLOW_PWM替代M10.0。
4.3 现象:按下急停按钮(I0.1)后,灯全灭但八段LED仍显示“G”
原因:急停逻辑仅置位NS_GREEN:=FALSE等输出,但未重置SEG_CODE。状态机仍停留在S0,SEG_CODE保持0x7D。
解决:在急停分支中强制进入S4并更新段码:
IF STOP THEN STATE := 4; SEG_CODE := DB_SegCode[2]; // 立即显示'E' // 同时清零所有灯输出 NS_RED := FALSE; NS_YELLOW := FALSE; NS_GREEN := FALSE; EW_RED := FALSE; EW_YELLOW := FALSE; EW_GREEN := FALSE; END_IF;4.4 现象:下载程序后PLC SF灯常亮,诊断缓冲区报“定时器参数错误”
原因:PT参数使用了未初始化的变量(如T#%MW10),或PT值超出CPU支持范围(S7-1200最大T#2h46m30s)。本实验中曾因误写PT := T#30000S(超8小时)触发硬件保护。
解决:所有定时器PT必须为常量或已初始化DB变量;在TIA Portal中启用“编译时检查定时器范围”选项。实测发现,T#30S在S7-1200中占用2字节,安全无误。
4.5 现象:夜间调试时,八段LED亮度刺眼,且长时间运行后段码漂移
原因:未加限流电阻,LED工作电流超20mA;或共阴极COM端未接PLC公共端(M端),导致电流路径异常,芯片温升引发逻辑错误。
解决:每个段串联220Ω电阻(5V供电);COM端必须接PLC的M端(非L+);增加散热片于PLC输出模块。某公司产线曾因此导致批量PLC输出点烧毁,更换模块成本超万元。
5. 进阶技巧:用八段LED实现倒计时与故障自检
5.1 倒计时动态显示:从“G”切换到“29”、“28”…的无缝衔接
倒计时本质是状态机内嵌子计数器。在S0状态中,不直接用TON定时30s,而是用100ms中断计数:
// 在OB35中(100ms) IF IN_COUNTING THEN COUNT_100MS := COUNT_100MS + 1; IF COUNT_100MS >= 300 THEN // 300*100ms=30s IN_COUNTING := FALSE; COUNT_100MS := 0; NEXT_STATE := 1; ELSE // 动态计算剩余秒数 REMAIN_SEC := 30 - (COUNT_100MS / 10); // 整数除法得秒 // 查表获取数字段码 SEG_CODE := DB_SegCode[REMAIN_SEC]; END_IF; END_IF;关键点:
REMAIN_SEC作为数组索引,需确保DB_SegCode[0..30]已预填充0-30的段码。为节省DB空间,可只存0-9,用十位/个位分别查表拼接。
5.2 故障自检:八段LED显示“88”表示硬件自检通过
在PLC上电时(OB100),执行硬件自检:
- 循环点亮Q0.0~Q0.7,验证所有段正常;
- 读取所有输入点(I0.0~I0.7)并短接测试;
- 检查输出模块电压是否在24V±10%。
自检通过后,八段LED显示0x7F(“8”),持续2秒;失败则显示0x00(全灭)并锁死。此功能让调试者无需万用表即可快速定位硬件问题。
5.3 参数化配置:用DB块存储时序,支持现场灵活调整
创建DB_TimingParam,含以下变量:
| 变量名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| NS_GREEN_TIME | TIME | T#30S | 主路绿灯时间 |
| EW_GREEN_TIME | TIME | T#30S | 支路绿灯时间 |
| YELLOW_TIME | TIME | T#3S | 黄灯时间 |
| MIN_CYCLE_TIME | TIME | T#66S | 最小周期(防冲突) |
在状态机中,将PT := DB_TimingParam.NS_GREEN_TIME替代硬编码。现场工程师可通过博途在线修改DB值,无需重新下载程序——这是工业项目交付的必备能力。
我带过的某高校课程设计小组,最初坚持“所有参数写死”,结果在验收时被导师要求临时将绿灯时间从30s改为45s,全组手忙脚乱改代码、重编译、重下载,延误2小时。后来他们重构为参数化DB,后续三次需求变更都在3分钟内完成。这种“让程序适应人,而不是让人适应程序”的思维,才是PLC工程师真正的进阶起点。希望帮到你。
本文还有配套的精品资源,点击获取