这个红绿灯控制仿真系统是我在工业自动化培训中经常使用的教学案例,基于西门子S7-1200 PLC和HMI人机界面开发。系统最突出的特点是采用模块化设计,通过三种不同的显示方式演示交通信号灯控制逻辑:
提示:系统使用博途V16平台开发,程序同时包含梯形图(LAD)和SCL语言实现,特别适合PLC初学者理解两种编程方式的差异。
系统采用经典的Moore型状态机,定义6个基本状态:
| 状态编号 | 南北方向 | 东西方向 | 持续时间(s) |
|---|---|---|---|
| 1 | 绿灯 | 红灯 | 30 |
| 2 | 黄灯 | 红灯 | 5 |
| 3 | 红灯 | 红灯 | 2 |
| 4 | 红灯 | 绿灯 | 20 |
| 5 | 红灯 | 黄灯 | 5 |
| 6 | 红灯 | 红灯 | 2 |
scl复制// SCL状态机实现片段
CASE #currentState OF
1: // 南北绿灯,东西红灯
#northSouthGreen := TRUE;
#timerValue := 30;
IF #timerDone THEN
#currentState := 2;
#timerRestart := TRUE;
END_IF;
// ...其他状态处理逻辑
END_CASE;
在HMI画面中创建IO域控件,绑定到PLC的定时器当前值变量。关键配置参数:
使用HMI的图形控件模拟七段数码管:
#displayValuescl复制#hundreds := #displayValue / 100;
#tens := (#displayValue MOD 100) / 10;
#units := #displayValue MOD 10;
通过系统时钟判断是否进入夜间模式(22:00-6:00):
scl复制IF (#currentHour >= 22) OR (#currentHour < 6) THEN
#nightMode := TRUE;
// 黄灯闪烁逻辑
#blinkTimer(IN := NOT #blinkTimer.Q, PT := T#500MS);
#allYellow := #blinkTimer.Q;
ELSE
#nightMode := FALSE;
END_IF;
定义信号灯状态数组,简化程序逻辑:
scl复制VAR
// 信号灯状态数组 [1..6]对应6个状态
#lightStates : ARRAY[1..6] OF STRUCT
northSouthGreen : BOOL;
northSouthYellow : BOOL;
eastWestGreen : BOOL;
eastWestYellow : BOOL;
duration : INT;
END_STRUCT;
END_VAR
// 初始化数组
#lightStates[1] := (northSouthGreen := TRUE, duration := 30);
#lightStates[2] := (northSouthYellow := TRUE, duration := 5);
// ...其他状态初始化
传统自减实现:
scl复制#counter := #counter - 1;
IF #counter <= 0 THEN
// 处理超时逻辑
END_IF;
优化后的定时器方案:
scl复制#tonTimer(IN := #enableTimer, PT := T#1S);
IF #tonTimer.Q THEN
#counter := #counter - 1;
#tonTimerRST := TRUE;
END_IF;
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| HMI无法连接PLC | IP地址冲突 | 检查子网掩码和默认网关设置 |
| 数码管显示异常 | 变量类型不匹配 | 确认显示变量为INT类型 |
| 夜间模式不触发 | 系统时钟未同步 | 在OB1中调用RD_LOC_T指令 |
| 状态切换卡顿 | 定时器未复位 | 添加timerRestart逻辑 |
注意:在修改程序前务必做好备份,特别是涉及硬件配置的部分。建议使用TIA Portal的"比较编辑器"功能检查更改。
我在实际教学中发现,初学者最容易犯的错误是忽略定时器的复位逻辑。一个可靠的实践是在状态切换时同时复位相关定时器:
scl复制IF #stateChanged THEN
#tonTimerRST := TRUE;
#timerValue := #lightStates[#currentState].duration;
#stateChanged := FALSE;
END_IF;
这个项目虽然简单,但完整展示了PLC编程的核心概念。建议学习者可以尝试扩展以下功能: