西门子S7-1200/1500的PLC编程里,指示灯定时闪烁大概是最常被拿来练手的小功能。可就这么一个小功能,我这些年没少看见有人翻车:用两个定时器互相复位却出现奇偶扫描周期不一致,用M点做时钟位又和报警输出冲突,改完占空比下载后灯干脆不亮了。这篇文章不打算讲空泛的"定时器原理",而是直接把三种可落地的梯形图方案摆出来——双TON互锁、TON加比较器、系统时钟位,每种都附上完整的梯形图写法和选型理由,适合正在学S7-1200/1500、或者做设备调试时被闪烁逻辑折腾过的朋友。
这三个方法里,前两种用程序内部定时器实现,第三种直接"白嫖"CPU自带的脉冲信号。它们没有绝对的好坏,只看你手头场景适合哪种。我尽量把时序、踩坑点和使用边界都讲透,你照着抄就能用,改参数也能自己搞定。
1. 动手前必懂:扫描周期、线圈唯一性和IEC定时器
1.1 扫描周期:PLC不是"同时"干活的
很多初学者容易把PLC梯形图理解成"通电瞬间所有触点一起动作",这是最大的误区。PLC的工作方式是循环扫描:读输入→执行用户程序→写输出,然后不断重复。一个扫描周期内,程序按网络顺序从上到下执行,前面的网络先执行,后面的网络后执行。
这个特性对闪烁逻辑影响很大。举个例子:你写了两个定时器互相复位的网络,它们不可能"同一时刻"完成动作,一定有一个先、一个后。如果网络顺序和你的时序设计不匹配,灯可能多亮一个扫描周期,或者出现一次不期望的抖动。对指示灯来说影响不大,但如果你把这个逻辑用在高频输出上,问题就放大了。
我用一个生活化类比解释:PLC像食堂一个打饭窗口,一次只能处理一个人的需求,但速度快到肉眼以为所有人在同时打饭。你设计逻辑时,必须按照"排队顺序"来想,而不是"所有人都同时动"。
1.2 线圈唯一性:同一个输出只能写一次
这是我在现场见过最多的问题。TIA Portal里,同一个Q0.0如果出现在两个网络的输出线圈位置,那么执行顺序靠后的网络会"覆盖"前面的结果。也就是说,灯会不会亮,取决于最后一个网络的状态。
很多人写闪烁逻辑时,在A网络给Q0.0赋值1,又在B网络给Q0.0赋值0,心里想的是"这两个条件共同决定输出"。但PLC不这么理解,它会老老实实从上往下执行,后写的覆盖先写的。结果就是:灯要么常亮,要么常灭,怎么调都不对。
正确做法是:一个输出线圈只在一个网络里出现,其他所有条件都通过中间M点来组合。比如先把定时器的状态送到M1.0、M1.1,再在最后一个网络里把M1.0和其他条件串联,最终驱动Q0.0。这样逻辑清晰,交叉引用也好查。
1.3 IEC定时器:S7-1200/1500里没有"T1"这种全局定时器
从S7-200/300/400时代过来的人,习惯了直接用T1、T37这种全局定时器地址。但在S7-1200/1500和TIA Portal里,定时器变成了IEC定时器,也就是基于函数块的实例,每个定时器都要挂一个背景数据块(DB)。
这意味着两件事:
- 定时器数量几乎不受限制,只要你CPU内存够,想建多少建多少;
- 定时器的Q、ET等状态不是全局地址,而是DB里的数据元素。你没法直接在别的网络写一个
T1触点,得先把Q引到M点再使用。
下面三种方案里,我会用中间M点来接收定时器的Q状态,这是工程上最清晰、也最不容易出问题的写法。S7-1500同样如此,虽然它的背景DB可以优化访问,但"Q引脚接M点"这套做法一样适用。
2. 方法一:双TON互锁,最经典的等宽闪烁电路
2.1 为什么要用两个定时器
你可能会想:"一个TON定时1秒,到达后灯灭,不就行了吗?"问题在于,TON到达后如果输入条件还一直为1,它的Q会保持为1,不会自动变回0。你没法用一个定时器同时完成"亮1秒"和"灭1秒"两个动作。
所以最朴素的想法是:一个定时器管亮的时间,另一个定时器管灭的时间,两个定时器互相"掐脖子"——你到时间了我就复位,我到你复位了就开始。这就像两个人轮流值班,一个下班另一个上班,循环往复。
这套逻辑的好处是:亮和灭的时间可以分别设置,不要求等宽。比如你让灯亮2秒、灭0.5秒,只需要把管亮的定时器PT设为T#2s,管灭的定时器PT设为T#500ms,结构完全不用改。
2.2 完整梯形图与网络解释
下面这套梯形图以通用启停逻辑为框架,I0.0是启动按钮,I0.1是停止按钮,M0.0是运行标志。三个方案我都复用这个框架。
网络1:启停回路 "I0.0_启动" "I0.1_停止" "M0.0_运行标志" ------| |-------------------|/|--------------------( ) "M0.0_运行标志" ------| | 网络2:灭灯计时 "M0.0_运行标志" "M1.1_亮灯计时中间位" "IEC_Timer_Dark" ------| |-------------------|/|-----------------------(TON) PT := T#1s // IEC_Timer_Dark 的 Q 输出引脚接到 M1.0_暗计时完成 网络3:亮灯计时 + 驱动输出 "M1.0_暗计时完成" "Q0.0_指示灯" ------| |--------------------------------------------( ) "M1.0_暗计时完成" "IEC_Timer_Light" ------| |--------------------------------------------(TON) PT := T#1s // IEC_Timer_Light 的 Q 输出引脚接到 M1.1_亮灯计时中间位这套逻辑的时序是这样的:
- 按下启动,M0.0为1,开始第一次扫描。此时M1.1为0,网络2中M1.1常闭触点闭合,暗灯定时器开始计时1秒。
- 这一秒内,暗灯定时器Q没有输出,M1.0为0,网络3里灯不亮,亮灯定时器也不计时。
- 1秒后,暗灯定时器Q置位为1,M1.0变为1。网络3导通,灯亮,同时亮灯定时器开始计时1秒。
- 再来1秒后,亮灯定时器Q置位为1,M1.1变为1。下一个扫描周期,网络2中M1.1常闭触点断开,暗灯定时器被复位,M1.0变0,灯灭,亮灯定时器也被复位,M1.1变0。
- 网络2里M1.1常闭触点的条件重新满足,暗灯定时器再次开始计时,循环从第2步开始。
最终结果就是:上电先灭1秒,再亮1秒,周期2秒,占空比50%。
2.3 初始相位和参数调整的细节
用这套方案,有一个容易被忽略的初始相位问题:上电后灯先经历一个"暗的时间",然后才亮。如果你希望一上电就立即亮1秒,可以调整定时器角色,把亮灯定时器放在网络2里先计时。
非等宽闪烁也很简单:暗灯定时器PT设成你想要的灭灯时间,亮灯定时器PT设成你想要的亮灯时间。比如设备运行指示灯,通常亮1秒灭1秒,人眼舒服;故障报警灯则常用亮0.5秒灭0.5秒,紧急感更强。这些都只需要改两个定时器的PT值,结构不用动。
这套方案最大的优点是时序逻辑完全由自己控制,适合和别的动作联动。比如某个阀门要间歇动作,开2秒、停3秒,你控制两个定时器的PT就能直接复用。
3. 方法二:一个TON加比较器,闪烁占空比随心调
3.1 思路转换:让定时器"循环跑",再用比较器截取窗口
方法一虽然好懂,但占空比调节要同时改两个定时器。如果你需要频繁换参数,或者想通过触摸屏实时调整亮灭比例,方法二会更轻松。
思路很简单:只用一个TON定时器做"周期计时"。这个定时器到达设定周期后立刻复位,从头开始再计时,这样它的当前累计时间ET就会在一个固定范围内反复从0涨到PT。然后我用一个比较指令判断:"ET在0到X之间时让灯亮",这样亮的时间就被精确截出来了。
3.2 完整梯形图与参数含义
网络1:周期循环计时 "M0.0_运行标志" "M1.1_周期到达中间位" "IEC_Timer_Cycle" ------| |-------------------|/|-----------------------(TON) PT := T#2s // IEC_Timer_Cycle 的 Q 输出引脚接到 M1.1_周期到达中间位 网络2:占空比窗口判断 + 运行允许 "M0.0_运行标志" CMP < "Q0.0_指示灯" ------| |------------------| |------------------------( ) "IEC_Timer_Cycle".ET T#1s理解这个逻辑,核心是理解ET的波形:
- TON周期设为2秒,所以ET从T#0s涨到T#2s,到达后复位,重新从0开始。
- 比较器判断"ET < T#1s",代表在一个2秒周期里,前1秒条件成立,后1秒条件不成立。
- 所以灯前1秒亮,后1秒灭,循环反复。
要想改占空比,只改比较器右边的T#1s;要想改闪烁频率,只改定时器的PT。比如想要亮0.3秒、灭1.7秒,就把比较值改成T#300ms,周期还是2秒。想要1分钟闪一次,就把PT改成T#1min,比较值改成T#30s。
注意:比较器两个输入别接反。我把ET放在IN1,T#1s放在IN2,触点导通条件是IN1 < IN2。如果你反着接,会得到完全相反的闪灭逻辑,当时监控时还很难看明白。
3.3 停止状态容易踩的"常亮"坑
方法二有个比方法一更隐蔽的坑:如果TIA程序里M0.0为0,TON不运行,IEC_Timer_Cycle的ET会停在0。此时比较器"ET < T#1s"是恒成立的,如果你比较器后面不串联M0.0,灯会一直亮着,而不是灭掉。
所以网络2里必须把M0.0运行标志和比较器触点串联。这是我在现场帮人排查过的问题:对方说"按下停止灯还在闪",我一看就是少了这个串联触点。方法一没有这个问题,因为M0.0为0时暗灯定时器不运行,M1.0本来就是0,灯自然灭。这也是方法二在结构上不如方法一直观的一个点。
另外要注意:ET的数据类型是Time,比较器左右两边都得是Time类型的值。T#1s这种写法是正确的,别顺手写成1或1000。如果你用的不是TIA Portal的IEC定时器,而是自己用DINT变量累加的毫秒计数器,那比较器就按整数比较,两边数值含义要统一。
4. 方法三:系统时钟位,几乎零成本的"白嫖"方案
4.1 开启时钟存储器,CPU自动给你发脉冲
S7-1200和S7-1500的CPU本身就带一组时钟脉冲信号,不用写任何定时器就能用。你只需要在组态里把它打开:
在设备组态中选中CPU,打开"属性"→"系统与时钟存储器",勾选"启用时钟存储器字节",把字节地址设为比如100。这样MB100的每一位都会按固定频率输出方波,占空比都是1:1。
常见频率对应关系如下:
| 位地址 | 频率 | 周期 |
|---|---|---|
| M100.0 | 10 Hz | 0.1秒 |
| M100.1 | 5 Hz | 0.2秒 |
| M100.2 | 2.5 Hz | 0.4秒 |
| M100.3 | 2 Hz | 0.5秒 |
| M100.4 | 1.25 Hz | 0.8秒 |
| M100.5 | 1 Hz | 1秒 |
| M100.6 | 0.5 Hz | 2秒 |
| M100.7 | 0.1 Hz | 10秒 |
这里"1Hz"意味着1秒内高低电平各0.5秒,也就是灯亮0.5秒、灭0.5秒。如果需要非常快的闪烁,用M100.0(10Hz);如果要做周期很长的呼吸灯,可以用M100.7(10秒一个周期)。
4.2 只用两个触点,梯形图短到极致
网络2:指示灯闪烁 "M0.0_运行标志" "M100.5_1Hz" "Q0.0_指示灯" ------| |-------------------| |-----------------------( )你没有看错,闪烁逻辑就这一行。如果不需要启停条件,甚至可以只剩一个触点、一个线圈。
这套方案的优势是资源占用几乎为0,不消耗定时器,不产生额外的扫描周期延时,逻辑一目了然。现场如果有一排指示灯都要闪,用系统时钟位就是最优解:每个灯串一个不同频率的时钟位,程序代码量极小,调试成本低,运维也清楚。
4.3 时钟位的边界:为什么它不是万能的
系统时钟位虽然省事,但局限性也很明显:
- 频率只能从表里选档,不能自定义任意频率。想要1.8Hz、2.2Hz这种频率,时钟位做不到。
- 占空比固定1:1,没法做"亮3秒灭0.5秒"这种非对称闪烁。
- 它是CPU属性,必须下载硬件配置才生效。如果你只下载程序块,时钟位可能不工作。
- 时钟位共享MB100这个字节,如果你程序里不小心把M100.5当普通中间点写过,它的脉冲信号就被覆盖了。所以设置地址时最好选一个程序里没用到的高位字节,比如MB100、MB200,而不是默认的M0区。
我在一个项目里用过M0.3接故障灯快闪,后来另一个工程师在程序里用M0.3做了普通中间继电器逻辑,排查了很久才发现是两个用途撞了地址。从那以后,我习惯把时钟存储器地址固定设到MB100,并在程序注释里明确写上"MB100为系统时钟,禁止程序写入",避免后人踩坑。
5. 三种方法放一起比,现场怎么选
5.1 对比表:一眼看清差异
| 对比项 | 双TON互锁 | TON+比较器 | 系统时钟位 |
|---|---|---|---|
| 定时器占用 | 2个 | 1个 | 0个 |
| 占空比调节 | 分别改两个PT | 改比较值即可 | 固定1:1,不可调 |
| 频率调节 | 两个PT都改 | 改PT | 固定8档 |
| 资源开销 | 中 | 中低 | 极低 |
| 初始相位控制 | 可调 | 受ET趋势影响 | 不可控 |
| 逻辑复杂度 | 中等 | 中高 | 极低 |
| 典型场景 | 设备间歇动作、多逻辑联动 | 报警灯、可调占空比指示 | 批量指示灯、状态指示 |
5.2 我的选型心法
我自己的取舍标准很简单:
- 只要频率在表里、占空比不需要特殊处理,优先用系统时钟位。三个指示灯、八个指示灯,全部用时钟位,代码清爽到爆炸。
- 需要自定义占空比、或者要频繁改参数,用TON加比较器。比如"设备需要保养了"这种黄灯,亮0.3秒灭1.7秒,比均匀闪烁更容易被注意到,又不刺眼,尤其适合。
- 如果闪烁这个动作要和别的动作逻辑联动,比如"亮灯的同时打开注油阀""闪烁3秒后启动下一工序",用双TON互锁。因为你可以从定时器的Q状态引出各种中间M点,灵活性最高。
实际项目里我经常混用。一个典型场景:设备面板上有运行灯、故障灯、维护灯。运行灯用系统时钟位1Hz慢闪,故障灯用5Hz快闪,维护灯用TON加比较器实现自定义占空比"亮0.3秒灭2秒"。这样一个项目里,三种方案各司其职,没有一种浪费。
5.3 一个容易忽略的精度问题
三种方案的实际闪烁周期都会受到扫描周期影响。OB1扫描周期如果是10ms,那么定时器ET的精度大约就是10ms,1秒的闪烁周期可能是0.99秒或1.01秒。对指示灯这个精度完全够。
如果你在S7-1500里做高速输出、或者要做精密节拍控制,别用OB1里的普通定时器,应该把逻辑放到循环中断OB里,并设置一个较短的循环时间(比如10ms或1ms)。这个思路比纠结用哪种闪烁方案更关键。
6. 从现场调试里捞出来的坑与排查套路
6.1 灯不闪,反而常亮:先查交叉引用
现象:下载程序后灯常亮,按停止也不灭。
排查:打开TIA Portal的"交叉引用"功能,搜索Q0.0。这时候你会看到Q0.0的"写访问"可能出现在好几个地方。如果确实有多个线圈写同一个Q0.0,那就是覆盖问题。把除最终输出外的所有线圈改成中间M点,重新下载,问题解决。
这是我踩过最多次的坑,而且每次踩完都很懊恼——因为TIA的交叉引用功能就在那里,我却总是先怀疑PLC坏了。
6.2 定时器Q状态在别的网络用不了:先引到M点
现象:方法一里,你写了"暗灯定时器Q触点"在网络3中用,但编译报错,或者在线监视一直为0。
原因:IEC定时器的Q是引脚状态,不是一个可以直接在任意网络引用的全局操作数。你需要在TON方框的Q引脚上接一个M点,让M点接收这个状态,其他网络再用M点。
我在第2章给的梯形图里就是这么做的:M1.0接暗灯定时器Q,M1.1接亮灯定时器Q。如果不这样做,你会在TIA里绕很大一圈,最后还是得乖乖回到M点中转。
提示:给M点起名字时别起"定时器1完成中间位"这种含糊的名字,直接写"暗灯计时完成""亮灯计时完成",后面看程序的人能少死很多脑细胞。
6.3 系统时钟位下载后不工作:可能没下硬件组态
现象:时钟表也勾了,地址也设了,在线监视M100.5却一直是0。
原因:时钟存储器属于CPU的硬件设置,不是用户程序内容。很多人只下载了PLC程序,没有下载硬件配置,CPU里还是旧参数。
解决:在TIA Portal里执行"下载到设备"时,勾选"硬件配置"部分,或者直接选择"全部下载"。下载完成后可以通过"在线与诊断"里查看CPU属性,确认时钟存储器字节地址是否生效。
6.4 闪烁周期和设定值差一个扫描周期
现象:设了1秒,实际亮灭周期是1.01秒或1.02秒,用秒表能感觉出来。
原因:TON的计时精度受扫描周期限制,并且网络执行顺序导致定时器复位和重新启动之间存在一个扫描周期的间隔。
处理:对指示灯无所谓。如果非要对时间敏感的场景较真,把相关逻辑放到循环中断OB里,保证固定的执行周期。S7-1200/1500都支持循环中断OB,在CPU属性里可以设置循环时间。
6.5 停止后灯竟然还闪一下
现象:按下停止按钮后,灯还会再闪一次才彻底灭掉。
原因:这是双TON互锁方案里常见的"复位延迟"现象。停止信号到来时,当前扫描周期可能已经执行到亮灯定时器那段网络,灯在本周期内继续保持输出,直到下一个扫描周期输出才被清零。
处理:如果要求停止后最多几十毫秒内必须灭灯,可以在启停回路的最后加一个"停止标志"对输出做强制清零,或者把输出刷新放到更靠后的OB里。实际应用中,这个延迟通常在几十毫秒以内,大多数现场完全能接受。
结尾:我的习惯用法
搞这么多年设备调试,我现在遇到灯光闪烁需求,第一反应永远是问三个问题:要不要自定义占空比?要不要自动调节频率?这个灯和别的动作有没有联动?答案组合下来,基本就落在上面三种方案里。我也经常用系统时钟位做运行指示,用双TON做间歇动作逻辑,两种思路在公司好几个项目里来回用,目前没有因为闪烁逻辑本身出过问题。
如果你刚接触S7-1200/1500,建议把三种方案都在TIA Portal里建个测试项目跑一遍,用PLCSIM仿真观察ET和Q的变化,再把占空比参数改一改,直观对比它们的行为差异。纸上谈兵看十遍,不如自己动手调试半小时。真到现场遇到闪烁相关的疑难问题,回来翻这篇文章,应该能帮你省下不少排查时间。