S7-1200 PLC交通灯控制实战:比较指令与HMI触摸屏联调方案
发布时间:2026/10/8 16:12:12 作者:尧图编辑部 阅读量:1,286

PLC交通灯控制算是工控入门必练的小项目但真要把东西南北四个方向的红绿灯时序理清楚还能在触摸屏上同步监控和调试比想象中容易踩坑。这篇文章我把博途V15 S7-1200做的一套完整十字路口交通灯控制方案分享出来核心是用比较指令处理相位切换触摸屏部分也已全部调通。适合刚接触PLC编程、正在做毕业设计或者想学HMI联调的朋友参考。这套程序最方便的地方在于只要把“当前第几秒”算清楚剩下所有灯的状态、倒计时、状态码都能靠比较指令一条一条判断出来逻辑非常直观后期要改绿灯时长也只用改几个常数不用像传统定时器方案那样拆了重排。触摸屏上能看到实时灯态、倒计时还能一键切应急模式实用性很强。1. 项目整体思路与方案选型拆解1.1 先理清十字路口的时序逻辑做交通灯控制第一步不是写程序而是把时序表画明白。常见的两相位十字路口可以这样定义方向东西方向为A相南北方向为B相。我采用一个常见且好验证的时序整个周期40秒时间段秒东西方向南北方向0 ~ 14绿灯持续15秒红灯15 ~ 19黄灯持续5秒红灯20 ~ 34红灯绿灯持续15秒35 ~ 39红灯黄灯持续5秒40秒后回到0循环往复。这里有个容易疏忽的点A相绿灯结束后B相不能立即转绿中间必须有5秒黄灯过渡这是为了给正在路口的车辆一个清空时间。反之亦然。所以一个周期内的安全顺序是A绿 - A黄 - B绿 - B黄永远不能出现A绿和B绿同时为真的情况。1.2 为什么选比较指令而不是纯定时器法我知道很多教材喜欢用TON定时器串联比如T1计时15秒后置位YT2再计时5秒以此类推。这种纯定时器方案在简单演示上没问题但一旦想在中途加一个“急停全红”或“夜间黄闪”定时器链条就会变得非常凌乱改起来也痛苦。我在这套程序中改用“全局秒计数 比较指令”的思路用一个1Hz脉冲信号累加出总秒数再用比较指令判断当前总秒数落在哪个区间从而决定每一盏灯的输出状态。这样做的优势有三个时间轴是全局统一的所有相位都由同一个“秒数”驱动不会出现多个定时器各自为政、互相打架的情况。修改绿灯时长只需改比较区间不用重排定时器网络维护成本低。触摸屏需要显示倒计时秒数就在这里直接算非常顺手。1.3 硬件选型与I/O规划这套项目用的是S7-1200系列型号选CPU 1214C DC/DC/DC自带14点数字输入、10点数字输出做交通灯绰绰有余。如果你的CPU是1211C或1212C点数也够只是输出点数少一些布局时稍微挪一挪就行。触摸屏我选了博途V15下同组态的KTP700 Basic PN12寸左右的屏做这个画面非常宽裕。当然用精简系列更便宜原理一样。I/O分配按最直观的方式排地址功能说明I0.0启动按钮按下后系统进入自动运行I0.1停止按钮用于复位和停止运行I0.2手动/应急切换不接硬件时可在触屏上通过M变量替代Q0.0东西方向绿灯Q0.1东西方向黄灯Q0.2东西方向红灯Q0.3南北方向绿灯Q0.4南北方向黄灯Q0.5南北方向红灯实际接线时输出点外接24V灯组或继电器再去带220V红绿灯都可以但感性负载一定要并续流二极管不然PLC输出晶体管容易被反向电动势打坏。这个坑我确实踩过后面还会细说。2. 比较指令的核心玩法与程序编写细节2.1 S7-1200里比较指令到底怎么用博途V15中S7-1200的比较指令在LAD里有EQ、NE、GT、GE、LT、LE六种对应等于、不等于、大于、大于等于、小于、小于等于。它们可以比较两个整数、实数或字符串但两个输入的数据类型必须一致。在我的程序里用得最多的是GE和LE组合。比如判断“当前秒数是否在0到14之间”梯形图里就是两个比较块串联第一个块写总秒数 0第二个块写总秒数 14两个块的结果做与逻辑这样一组“区间判断”就完成了。如果后面想改成10秒绿灯只需把14改成9。如果你更习惯用SCL也可以写得很精练。我经常给朋友们演示的版本是这样的IF #总秒数 0 AND #总秒数 14 THEN 东西绿灯 : TRUE; ELSE 东西绿灯 : FALSE; END_IF;这段代码的本质仍然是若干次比较运算。初学者不要被LAD里的“块”吓到它和C语言里的if判断是一个道理只是图形化表达而已。2.2 秒脉冲与总秒数累加的实现既然要用比较指令做相位判断就得先有一个可靠的“秒发生器”。S7-1200最省事的做法是启用系统时钟存储器。在CPU属性中勾选“启用系统时钟存储器”并指定一个字节地址比如MB100那么M100.4就是1Hz信号周期正好1秒。再用一个R_TRIG上升沿检测指令检测到M100.4从0到1的跳变就把总秒数加1。这段逻辑如果用SCL写大约长这样时钟上升沿(CLK : M100.4, Q 秒脉冲); IF #运行标志 THEN #总秒数 : #总秒数 1; IF #总秒数 39 THEN #总秒数 : 0; END_IF; END_IF;注意几个细节不要直接用M100.4去驱动计数器的边沿当作计数信号因为1Hz信号本身是方波你需要在“上升沿”那一瞬间加1而不是在电平为1的整个1秒内持续加。总秒数上限设为39因为周期是40秒数到39后必须回0否则会一直涨上去。停止时要把运行标志清掉同时把总秒数清零这样下一次启动一定从绿灯第0秒开始不会出现上电直接黄灯或红灯的尴尬。2.3 输出网络的编写顺序与边界值处理输出网络是整个程序最核心的部分。我的做法是分成两组写一组管东西方向一组管南北方向每组内部再用比较指令划分区间。以东西方向为例三个输出分别是东西绿灯、东西黄灯、东西红灯。用SCL写出来的逻辑非常清楚// 东西方向 IF #总秒数 0 AND #总秒数 14 THEN 东西绿灯 : TRUE; 东西黄灯 : FALSE; 东西红灯 : FALSE; ELSIF #总秒数 15 AND #总秒数 19 THEN 东西绿灯 : FALSE; 东西黄灯 : TRUE; 东西红灯 : FALSE; ELSIF #总秒数 20 AND #总秒数 39 THEN 东西绿灯 : FALSE; 东西黄灯 : FALSE; 东西红灯 : TRUE; END_IF;南北方向反着写// 南北方向 IF #总秒数 20 AND #总秒数 34 THEN 南北绿灯 : TRUE; 南北黄灯 : FALSE; 南北红灯 : FALSE; ELSIF #总秒数 35 AND #总秒数 39 THEN 南北绿灯 : FALSE; 南北黄灯 : TRUE; 南北红灯 : FALSE; ELSE 南北绿灯 : FALSE; 南北黄灯 : FALSE; 南北红灯 : TRUE; END_IF;这里有一个非常容易翻车的地方边界值必须用“”和“”仔细对待。比如0到14是绿灯15到19是黄灯如果第一次把绿灯写成“14”第二次黄灯也写成“15”那不会重叠但如果你把灯状态写成独立线圈中间又没有处理好就可能在某一个瞬间同时输出绿和红。还有一点经验分享不要在输出网络里用置位SET和复位RESET来做相位切换。置位复位虽然写着省事但一旦忘记复位某一个灯就会造成两方向同时绿灯的灾难。直接用赋值或线圈方式让每个扫描周期都重新计算一遍输出状态逻辑反而最安全。2.4 触摸屏需要倒计时怎么在PLC里算出来触摸屏上少不了一个“剩余秒数”显示这个数其实就是在PLC里算的。我定义了四个变量东西剩余、南北剩余类型都是Int。当前相位剩余时间的计算思路很简单找到当前相位区间的上边界减去当前秒数即可。// 东西方向当前相位剩余秒数 IF #总秒数 14 THEN #东西剩余 : 14 - #总秒数; ELSIF #总秒数 19 THEN #东西剩余 : 19 - #总秒数; ELSE #东西剩余 : 39 - #总秒数; END_IF;南北方向同理IF #总秒数 20 AND #总秒数 34 THEN #南北剩余 : 34 - #总秒数; ELSIF #总秒数 35 AND #总秒数 39 THEN #南北剩余 : 39 - #总秒数; ELSE #南北剩余 : 19 - #总秒数; END_IF;这样做的好处是触摸屏那边根本不用做任何计算直接显示PLC传上来的数据就行减轻了HMI的负担也避免HMI和PLC两边因刷新周期不一致导致数字跳变。3. 触摸屏组态与联调实战3.1 触摸屏画面怎么规划才实用很多初学者做触摸屏喜欢把画面做得花里胡哨其实工业画面最重要的是信息清晰、操作明确。这套交通灯项目的HMI画面我分成了三个页面主监控画面中央放一个简化的十字路口示意图用四个圆形或方形的“图形I/O域”显示东西南北的灯色旁边放两个IO域显示倒计时下方放启动按钮和停止按钮。模式切换画面放“应急全红”按钮、“夜间黄闪”按钮、“解除”按钮用于不同场景下的手动干预。调试画面直接显示总秒数、当前相位代码、运行标志等内部变量方便排查问题这个画面在真实项目中也建议保留。图形I/O域显示灯色是靠PLC侧算出来的“状态码”驱动的。我给东西方向和南北方向各定义了一个整数变量0表示绿灯1表示黄灯2表示红灯。在SCL里这样赋值IF #总秒数 14 THEN #东西状态码 : 0; ELSIF #总秒数 19 THEN #东西状态码 : 1; ELSE #东西状态码 : 2; END_IF;HMI端的图形I/O域设置成“输入/输出”类型选整数然后在“图形列表”里给0配绿色圆给1配黄色圆给2配红色圆。这样灯色就能跟着PLC实时变化比单纯写个文字“绿灯”直观太多。3.2 变量连接与通信设置的几个关键点在博途V15里给S7-1200和KTP700组态通信其实是在同一个项目里完成的。触摸屏组态时新建一个连接控制器的类型选S7-1200接口选“PROFINET”然后在HMI变量表里直接拖拽PLC变量过来就行。这里有个容易踩坑的点如果PLC侧的DB块或变量启用了“优化块访问”那么HMI可以直接通过符号名访问很方便。但如果你的变量没有勾选优化块访问HMI连的时候就要求你使用绝对地址或填写实际偏移量。为了省事建议新建一个专门给HMI用的DB块名称简单、数据类型尽量用Bool和Int然后在右键属性里把“优化的块访问”保持勾选状态。还要注意IP地址规划。CPU 1214C默认IP是192.168.0.1KTP700默认IP可能不同建议组态时就规划好PLC IP192.168.0.10HMI IP192.168.0.20电脑网卡IP192.168.0.50三者必须处于同一网段但地址不能冲突否则下载的时候谁也找不到谁。3.3 用博途V15仿真联调的操作顺序在没有真实硬件时可以用PLCSIM和WinCC Runtime在电脑上把整套逻辑跑起来。我的操作顺序是这样的在博途V15里编译PLC程序点击“开始仿真”弹出S7-PLCSIM界面。下载程序到PLCSIM点击运行。注意S7-PLCSIM界面里模块的指示灯要变绿CPU状态要设为RUN。回到项目树在HMI文件夹右键选择“开始仿真”此时会启动WinCC Runtime。关键一步HMI运行起来后在HMI连接设置里确认连接属性是“S7-PLCSIM”而不是真实的PN/IE。仿真状态下如果HMI连不上PLC大多是这一步没选对。用PLCSIM调试的好处是可以单步看变量变化。我调试时就盯着“总秒数”这个变量从0一直加到39再清零同时看灯状态变量是否按预期切换。边界点尤其要盯14到15、19到20、34到35、39到0这四下最容易出问题。如果你的PLCSIM启动不了或者启动后下载失败先检查是不是用了S7-PLCSIM Advanced。这里可以说清楚标准的S7-PLCSIM博途自带对S7-1200支持得很好而S7-PLCSIM Advanced主要面向S7-1500和ET200SP做1200仿真没必要用Advanced反而经常因为虚拟网卡权限问题各种“启动不了、还没有报错信息”。老老实实用基础版PLCSIM踏实很多。4. 上电调试中的常见问题与排查实录4.1 上电初始化为什么启动后可能一片红这套程序在开发过程中我遇到的第一类问题全部集中在“上电瞬间”和“停止后再启动”这两个场景。因为总秒数是非保持变量断电后会自动清零这倒还好。但如果你把运行标志也做成了非保持变量上电后运行标志默认是FALSE启动按钮又是普通输入那按下启动按钮之前系统当然不会跑这是对的。问题往往出在有人习惯把启动按钮做成常闭点或者停止按钮用了常开触点导致上电瞬间PLC采集到一个意外的电平信号运行标志被误置位系统突然自动跑起来。我的建议是启动和停止逻辑不要直接依赖输入点本身的电平而要在PLC内部用边沿判断。// 用上升沿检测按钮信号 #启动沿(CLK : I0.0, Q #启动脉冲); #停止沿(CLK : I0.1, Q #停止脉冲); IF #启动脉冲 THEN #运行标志 : TRUE; END_IF; IF #停止脉冲 THEN #运行标志 : FALSE; END_IF;同时停止后要把总秒数清零所有灯输出一个确定的复位状态。我更倾向于停止后保持“全红”或“全灭”。从交通安全角度讲断电逻辑缺失时全灭不如全红安全所以我在停止逻辑里让所有红灯点亮而不是全部熄灭。4.2 比较指令的边界重叠与输出竞争问题我在调试时专门盯过一组边界值总秒数等于14和15、19和20的时候东西方向灯的切换是否干脆利落。结果发现如果程序里某处把绿灯范围写成“15”把黄灯范围写成“15”就会出现同一秒里绿灯和黄灯同时通的情况。这在真实路口的交通灯上是绝对不允许的。解决的办法就是严格使用开闭区间搭配绿灯用“0 AND 14”黄灯用“15 AND 19”红灯用“20 AND 39”。这样每个整数秒都只属于一个区间不重叠、不遗漏。SCL代码里只要统一写法和边界基本不会出这个问题倒是在LAD里如果网络分散、边界常量写错排查起来比较费眼。还有一个问题如果我在程序最后一段给输出用了置位前面某段又用了复位两个网络在一个扫描周期里先后执行就会出现所谓的“输出竞争”。S7-1200的扫描周期很短最终输出状态取决于最后被执行的网络但这会让维护者非常头大。我最终彻底改成每周期直接计算赋值不再使用置位复位从此这类问题绝迹。4.3 触摸屏连不上PLC的排查速查表HMI联调阶段最常见的报错就是“无法建立到控制器的连接”或者触摸屏画面一片灰色。这类问题排查顺序很重要我整理了一个速查表现象可能原因排查动作HMI显示连接中断IP不在同一网段对比PLC和HMI的IPping一下PLC地址仿真HMI连不上PLCSIM连接接口选成了PN/IE在HMI连接里改成“S7-PLCSIM”变量全是0或灰色变量路径没连对在HMI变量表里重新拖拽PLC变量下载HMI时提示找不到设备PG/PC接口类型不对下载窗口里选择实际网卡常用PN/IEHMI显示值跳变HMI刷新周期太快把HMI变量采集周期从1秒改到100毫秒或50毫秒还有一个容易被忽略的点PLC程序中如果开启了“优化块访问”HMI访问DB变量是直接按符号名走的。如果你在某个DB块属性里取消了这个勾选那么HMI访问时需要额外的偏移量和绝对地址一旦组态版本有差异很容易出问题。所以我个人建议给HMI用的变量单独建一个DB并且保持优化块访问开启少折腾很多。4.4 现场接线与抗干扰的经验教训最后再讲一条硬件侧的坑。我第一次用继电器驱动220V交通灯模型时没给继电器线圈并续流二极管结果运行时PLC的输出模块偶尔会自己复位严重时还导致CPU模块通信中断。原因就是继电器线圈断电瞬间会产生反向电动势直接反击到PLC的DO端。正确做法是在继电器线圈两端并联一个反向二极管也就是续流二极管让反向能量在二极管上消耗掉。如果是固态继电器或直接驱动LED灯组一般不用太担心这个问题但只要是感性负载都必须考虑。另外整个控制柜的接地也要处理好PLC的24V电源负极和机柜接地要按说明书接法来做否则调试中会出现各种“灵异”现象。还有一个小细节PLC输出模块的公共端比如1M、2M接线时要特别注意极性S7-1200 DC/DC/DC的输出是晶体管输出公共端正负极接反了灯也能亮但容易导致输出点状态指示异常甚至烧输出。下载程序之前先把每个输出点的接线图对着手册核对一遍比烧掉一个点再去查划算得多。4.5 模式切换与应急控制的扩展做法这套程序我把运行模式做成一个整数变量0是自动1是全红2是黄闪。自动模式就按总秒数和比较指令跑全红模式是所有方向红灯点亮用于紧急封路黄闪模式是东西南北四个方向黄灯一起以1Hz频率闪烁通常用在夜间车流量极小的时候。黄闪的实现也不难直接拿M100.4这个1Hz信号去驱动四个黄灯输出即可但要注意此时要把东西南北两个方向的绿灯和红灯全部清零不能让黄灯和别的灯同时亮。模式切换逻辑可以这样写CASE #运行模式 OF 0: // 自动相位逻辑即上面的输出网络 1: 东西红灯 : TRUE; 南北红灯 : TRUE; 东西绿灯 : FALSE; 东西黄灯 : FALSE; 南北绿灯 : FALSE; 南北黄灯 : FALSE; 2: 东西黄灯 : M100.4; 南北黄灯 : M100.4; 东西绿灯 : FALSE; 东西红灯 : FALSE; 南北绿灯 : FALSE; 南北红灯 : FALSE; END_CASE;在触摸屏上给模式切换按钮写入1或2就能立刻切到应急或夜间模式。调试的时候我试过在自动模式运行到第38秒时直接切全红此时没有出现任何灯同时亮的危险状态说明模式切换逻辑和输出互锁是有效的。5. 调试心得与可以继续扩展的方向做这个交通灯项目我最大的体会是PLC编程的难点从来不是某个指令不会用而是如何把一套逻辑组织得清晰、安全、可维护。比较指令在博途V15里属于最基础的运算指令之一但一旦把它用在“全局秒数与相位区间”的对应关系上整套代码的可读性和可维护性会明显上升。哪怕以后要加左转相位、行人按钮、公交车优先也只需要再增加几个状态区间和相应的比较判断。如果你打算在此基础上继续做我建议优先考虑两个扩展方向。第一个是加倒计时显示到真实路口的数码管上这需要在PLC里额外算倒计时并转成BCD码或段码输出本质上还是基于当前相位剩余秒数的计算。第二个是增加传感器检测和手动干预比如按下行人按钮后在下一个周期插入一个行人绿灯时段这时要把总秒数的周期做动态调整比较区间也会更灵活。这两个方向都是很好的进阶练习也能让这套毕业设计或参赛项目更有亮点。