1. 从“开关”到“逻辑”:为什么基本指令是PLC编程的基石
如果你刚接触西门子S7-200 SMART PLC,面对编程软件里那一堆指令图标,可能会有点懵。很多人会急着去学复杂的通信、运动控制,但我的经验是,所有高级应用都建立在扎实的基本指令功底之上。这就好比盖房子,高级功能是精装修,而基本指令就是钢筋混凝土的地基和框架。地基不稳,房子盖得再漂亮也经不起风雨。
S7-200 SMART作为西门子经典的入门及小型自动化控制器,其编程思想与更大型的S7-1200/1500一脉相承。它的“基本指令”主要指的是位逻辑指令、定时器、计数器、比较指令、数学运算等最基础、最核心的功能块。这些指令直接对应着工业现场最普遍的需求:检测一个按钮(输入)、控制一个继电器(输出)、让一个动作延时执行、或者统计产品的数量。
我见过不少新手写的程序,为了实现一个简单的互锁,用了好几行复杂的比较和跳转,其实一个简单的“常闭触点”就能搞定。这就是没有吃透基本指令的表现。掌握它们,不仅能让你写出更简洁、高效、稳定的程序,更能帮你建立起清晰的PLC程序执行逻辑思维。今天,我们就抛开那些花哨的概念,深入S7-200 SMART的基本指令世界,我会结合自己调试设备时踩过的坑,告诉你这些指令到底该怎么用,以及为什么这么用。
2. 位逻辑指令:程序世界的“是与非”
位逻辑指令是PLC编程的字母表,一切复杂的逻辑都由此构建。在S7-200 SMART中,位逻辑主要围绕“触点”和“线圈”展开,它们操作的对象是I(输入)、Q(输出)、M(存储位)、V(变量存储区)等布尔量(Bit)。
2.1 常开、常闭与输出线圈:最基础的逻辑单元
常开触点(Normally Open, NO)和常闭触点(Normally Closed, NC)是理解PLC逻辑的起点。千万别把它们和实物开关的状态完全等同,这是新手最容易混淆的地方。
- 常开触点(┃┃):你可以把它想象成一个“条件判断”。当它关联的位状态为“1”(ON)时,这个触点就“导通”,逻辑流可以通过;状态为“0”(OFF)时,则“断开”。比如
I0.0对应一个启动按钮,当按钮被按下,I0.0=1,I0.0的常开触点导通。 - 常开触点(┃/┃):与常开相反。当关联位状态为“0”时导通,为“1”时断开。比如
I0.1对应一个急停按钮(常闭触点型),正常情况下按钮未被按下,I0.1=1,但我们需要急停有效时断开电路,所以程序中应该使用I0.1的常闭触点。这样,正常时触点导通(因为I0.1=1,常闭触点断开?这里需要纠正:急停按钮通常使用常闭触点接入PLC,这样断线时也能触发停机。实物常闭触点接入,PLC输入点平时就有信号,为1。当急停被按下,实物触点断开,PLC输入点失电,变为0。因此,在程序里,如果我们希望“急停信号有效时断开逻辑”,就应该使用这个输入点的常开触点。因为急停按下(信号有效)时,输入点为0,常开触点不通。这是一个非常经典的“物理常闭”与“程序逻辑”的反向关系案例,务必理解透彻。
输出线圈(—( )—)是逻辑的终点。当连接到线圈左侧的逻辑运算结果为“1”时,线圈被“通电”,它关联的位(如Q0.0,M0.0)被置为1;结果为“0”时,线圈“失电”,关联位被复位为0。
一个最简单的启保停电路是理解它们的最佳例子:
网络 1 LD I0.0 // 启动按钮(常开) O Q0.0 // 并联自锁触点 AN I0.1 // 串联停止按钮(常闭,此处指程序中使用I0.1的常闭触点) = Q0.0 // 输出到电机接触器这段梯形图(LAD)对应的语句表(STL)如上。它的逻辑是:按下I0.0,或Q0.0自身已经得电,并且I0.1没有动作(常闭触点导通),则Q0.0输出并自锁。这是99%的电机控制基础。
注意:在S7-200 SMART中,一个线圈(如
= Q0.0)在同一个程序扫描周期内,其状态取决于最后一次对它进行写操作的结果。如果你在程序的不同位置多次对同一个线圈进行输出,只有最后一个生效。这被称为“双线圈输出”,是初学者常犯的错误,会导致逻辑混乱,调试起来极其痛苦。务必确保一个输出位只在一个地方被线圈驱动。
2.2 置位(S)与复位(R):让状态“锁定”和“清除”
线圈输出是瞬时的,一旦左侧逻辑不通,线圈立刻失电。但在很多场景,我们需要“点动一下,状态保持”,直到另一个条件来清除它。这就是置位(Set)和复位(Reset)指令的用武之地。
- 置位指令(S):当使能条件从0变1(上升沿)时,它将指定的位(或位范围)置为1,并且保持为1,即使使能条件后来变为0。
- 复位指令(R):当使能条件从0变1时,它将指定的位(或位范围)置为0,并且保持为0。
它们通常成对使用,实现一个类似“启保停”但更清晰的状态保持逻辑,尤其适用于步进顺序控制。例如,自动线的一个“夹紧”工步:
网络 1 LD I0.2 // 夹紧启动信号 S Q0.2, 1 // 置位Q0.2(夹紧电磁阀) 网络 2 LD I0.3 // 检测到夹紧到位信号 R Q0.2, 1 // 复位Q0.2(松开电磁阀)这里,I0.2一个短脉冲就能让夹紧阀一直得电,直到到位信号I0.3到来才松开。逻辑比用自锁更清晰,尤其在多步流程中,不容易因互锁复杂而出错。
实操心得:在复杂的顺序控制中,我强烈建议使用“置位/复位”来管理各工步的标志位(M区),而不是直接用输出点自锁。这样,工步逻辑和实际输出驱动可以分离,程序结构更清晰,调试时也更容易跟踪状态。例如,用M10.0代表“步骤1进行中”,条件满足后置位M10.0,然后在另一个统一的网络里,根据M10.0的状态去驱动实际的Q点。
2.3 边沿检测:捕捉“变化”的瞬间
这是位逻辑指令中的精髓,也是区分新手和老手的一个标志。边沿检测用于捕捉某个信号从0到1(上升沿,P)或从1到0(下降沿,N)的跳变瞬间,并只在这个瞬间输出一个扫描周期的脉冲。
S7-200 SMART提供了两种形式的边沿检测:
- 触点边沿指令:在LAD中表现为
P或N触点。例如I0.4的上升沿触点,只在I0.4从0变1的那个扫描周期导通。 - 指令盒边沿指令:
EU(上升沿)和ED(下降沿)指令盒,它们检测前面逻辑运算结果的跳变。
为什么需要边沿检测?举个例子,一个按钮I0.5用来计数。如果你直接用I0.5的常开触点去触发计数器加1,那么按钮按下的整个期间(可能几十个扫描周期),计数器会疯狂地连续计数几十次。这显然不是我们想要的。我们只希望按钮每次按下时计数一次。这时就需要上升沿检测:
网络 1 LD I0.5 EU // 检测I0.5的上升沿 CTU C0, +1 // 计数器C0加1这样,无论按钮按下多久,C0都只加1。
踩坑记录:边沿指令必须使用位存储区(如M0.0)作为“记忆位”。这个记忆位用于在相邻的两个扫描周期比较信号状态。PLC系统会自动分配这个位,但在编程时你需要指定它。一个常见的错误是重复使用同一个记忆位去检测不同的信号,或者在一个扫描周期内多次使用同一个记忆位,这会导致检测失灵。我的习惯是为每个边沿检测分配一个独立的M位,并在符号表里做好注释,比如
M_Edge_I0_5。
3. 定时器与计数器:让程序拥有“时间”和“数量”的概念
如果说位逻辑定义了程序的静态逻辑,那么定时器和计数器就赋予了程序动态和计数的能力。它们是实现延时、定时触发、流程节拍、产量统计等功能的核心。
3.1 定时器:工业节奏的掌控者
S7-200 SMART有三种定时器:TON(接通延时)、TOF(断开延时)、TONR(保持型接通延时)。最常用的是TON。
TON定时器的工作逻辑很简单:当使能端(IN)为1时,定时器开始计时,当前值(Txxx)从0递增。当当前值达到预设值(PT)时,定时器位(Txxx)被置为1。无论何时,只要使能端变为0,定时器立即复位,当前值清零,定时器位变为0。
一个典型应用是电机星三角启动的延时转换:
网络 1 LD I0.6 // 启动总信号 AN I0.7 // 停止信号 = M0.0 // 系统运行标志 网络 2 LD M0.0 = Q0.3 // 主接触器吸合 S Q0.4, 1 // 立即置位星型接触器 TON T37, 50 // 启动50*100ms=5秒的定时器 网络 3 LD T37 // 5秒时间到 R Q0.4, 1 // 复位星型接触器 S Q0.5, 1 // 置位三角型接触器这里T37是100ms基准的定时器(预设值50代表5秒)。注意定时器编号(T37)决定了它的时间基准(1ms, 10ms, 100ms)。在编程手册里有详细的对应表,选型错误会导致定时精度不对。
TONR定时器的不同之处在于,它累积计时。使能端为1时计时,为0时暂停计时但当前值保持。需要用专门的复位指令(R)来清零它。常用于统计设备的总运行时间。
注意事项:定时器的预设值(PT)可以来自常数,也可以来自变量(如VD100)。这带来了灵活性,但也带来了风险。如果来自变量的值被意外写为0或负数,定时器可能立即到位或出错。在重要的安全延时环节,建议使用常数预设值。如果必须用变量,务必在程序中对变量范围进行限制(使用比较指令)。
3.2 计数器:生产数据的记录员
计数器用于对事件进行计数。S7-200 SMART主要有CTU(加计数器)、CTD(减计数器)和CTUD(加减计数器)。
CTU加计数器是最常用的。它有两个输入端:CU(加计数脉冲)和R(复位)。每个CU信号的上升沿,计数器当前值(Cxxx)加1。当当前值大于等于预设值(PV)时,计数器位(Cxxx)置1。复位信号R的上升沿会将当前值和计数器位清零。
例如,流水线上的光电传感器检测产品:
网络 1 LD I1.0 // 光电传感器信号 EU // 上升沿,每过一个产品触发一次 CTU C1, 100 // 计数器C1,预设100 网络 2 LD C1 // 计满100个 = Q1.0 // 触发满箱报警灯 S M1.0, 1 // 置位满箱标志,通知机械手取箱 网络 3 LD I1.1 // 取箱完成复位按钮 R C1, 1 // 复位计数器C1 R M1.0, 1 // 复位满箱标志CTUD加减计数器则有两个脉冲输入:CU和CD,分别对应加和减。它常用于有进有出的仓库库存管理。
经验技巧:计数器的预设值PV也支持变量。但和定时器一样,要注意数据安全。另外,计数器的当前值范围是0-32767。在高速计数场合(如编码器),普通计数器可能因扫描周期限制而漏计,此时应使用PLC的高速计数器(HSC)功能,这是基本指令的扩展,其配置在系统块中完成,通过专用指令进行读写。
4. 比较、传送与数学运算:处理数据的“大脑”
当程序需要判断数值、移动数据或进行计算时,就需要用到比较、传送和数学运算指令。这些指令操作的对象不再是单个的位,而是字节(B)、字(W)、双字(D)、整数(I)、双整数(DI)和实数(R)。
4.1 比较指令:做出判断的依据
比较指令用于比较两个数值IN1和IN2的大小关系,结果为真时导通后续逻辑。类型包括:等于(==)、不等于(<>)、大于(>)、小于(<)、大于等于(>=)、小于等于(<=)。
一个恒温控制的简化例子:假设模拟量输入AIW0代表温度值(已转换为0-100度的整数)。
网络 1 LDW>= AIW0, 800 // 温度值 >= 80度(假设800对应80.0度) = Q0.6 // 关闭加热器 网络 2 LDW<= AIW0, 750 // 温度值 <= 75度 = Q0.7 // 打开加热器这里就用了大于等于和小于等于比较,形成了一个75-80度的死区控制,防止继电器在临界点频繁动作。
关键点:比较指令的数据类型必须匹配!用字节比较指令去比较两个字,结果是不确定的。在LAD中,指令图标上会标注数据类型(如
==I表示整数比较,==R表示实数比较)。在STL中,指令本身不同(如LDW=用于字比较,LDD=用于双字比较)。这是编程时最容易导致逻辑错误的地方之一,务必仔细核对。
4.2 传送指令:数据的搬运工
传送指令(MOV)用于将数据从一个地方复制到另一个地方。它不改变源数据。这是初始化、赋值、数据转移中最常用的指令。
网络 1 LD SM0.1 // 首次扫描周期为1 MOVB 16#0F, QB0 // 将十六进制0F(二进制00001111)传送到输出字节QB0,初始化Q0.0-Q0.3为1,其余为0。 MOVW 100, VW10 // 将常数100传送到VW10,作为某个参数的默认值。SM0.1是特殊的系统存储器位,仅在PLC从STOP切换到RUN的第一个扫描周期为1,常用于初始化程序。
4.3 数学运算:从加减乘除到函数
S7-200 SMART支持基本的四则运算(ADD, SUB, MUL, DIV)、递增/递减(INC, DEC),以及更复杂的浮点数运算、三角函数、对数、指数等。对于整数运算,需要注意溢出问题。
例如,计算平均产量:VW20存储总产量,VW22存储总批次。
网络 1 LD I1.2 // 每批次完成信号 EU +I 1, VW22 // 批次计数器加1 网络 2 LD I1.3 // 每次计算平均值的信号 MOVW VW20, VW30 // 将总产量暂存到VW30 /I VW22, VW30 // VW30 = VW30 / VW22 (整数除法) MOVW VW30, VW40 // 平均产量存入VW40这里使用了整数加法(+I)和整数除法(/I)。整数除法会舍去余数。如果需要更精确,应先将整数转换为双整数或实数再进行除法。
避坑指南:整数乘法(
*I)最容易溢出。两个16位整数(范围-32768~32767)相乘,结果可能超过16位范围。例如,200200=40000,仍在16位有符号整数范围内(最大32767),但300300=90000就溢出了。结果会变得不可预测。安全的做法是,在进行可能产生大数的乘法前,先将操作数转换为双整数(使用ITD指令),然后使用双整数乘法(*D)。双整数范围是-2^31 ~ 2^31-1,大得多。除法也要注意除数为零的情况,否则会导致PLC故障停机。好的编程习惯是在除法指令前,用比较指令判断除数是否为零。
5. 程序控制指令:构建清晰的程序骨架
基本指令不仅包括操作数据的,还包括控制程序执行流程的,这就是程序控制指令。它们决定了程序扫描的顺序,对于构建结构良好、易于维护的程序至关重要。
5.1 跳转与标签:实现程序分支
跳转指令(JMP)和标签指令(LBL)配合使用,可以让PLC不按顺序扫描,而是跳转到指定的标签处继续执行。这类似于高级语言中的GOTO语句。
一个典型应用是模式选择:手动、自动、维修三种模式。
网络 1 LD I2.0 // 手动模式选择开关 JMP 0 // 跳转到标签0(手动程序段) 网络 2 LD I2.1 // 自动模式选择开关 JMP 1 // 跳转到标签1(自动程序段) 网络 3 LD I2.2 // 维修模式选择开关 JMP 2 // 跳转到标签2(维修程序段) 网络 4 LBL 0 // 标签0:手动程序开始 ... // 手动模式下的控制逻辑 JMP 3 // 执行完后跳转到程序结尾 网络 5 LBL 1 // 标签1:自动程序开始 ... // 自动模式下的控制逻辑 JMP 3 网络 6 LBL 2 // 标签2:维修程序开始 ... // 维修模式下的控制逻辑 JMP 3 网络 7 LBL 3 // 标签3:公共程序段(如报警处理、数据记录) ... // 所有模式都要执行的公共逻辑这样,PLC在每个扫描周期只执行被选中的模式下的程序段和公共程序段,避免了所有模式的逻辑都被扫描,提高了程序效率,也使得逻辑更清晰。
重要限制:跳转不能从主程序(OB1)跳转到子程序(SBR)内部,也不能从子程序跳转到主程序或其他子程序。跳转和标签必须在同一个程序块内(如同在OB1,或同在一个SBR中)。
5.2 子程序调用:模块化编程的利器
子程序(SBR)是PLC编程实现模块化、结构化的核心手段。你可以将一些重复使用的功能(如气缸控制、报警处理、数据计算)封装成子程序,然后在主程序中多次调用。
S7-200 SMART使用CALL指令来调用子程序。子程序可以带参数(输入、输出、输入-输出),这使得它非常灵活。
例如,封装一个气缸控制子程序SBR_0:
- 输入参数:启动信号(Bool)、复位信号(Bool)、延时时间(Word)。
- 输出参数:气缸伸出到位标志(Bool)、气缸缩回到位标志(Bool)。
- 内部逻辑:实现带延时的伸出和缩回控制,并检测到位传感器。
在主程序中,控制三个相同的气缸:
网络 1 LD M10.0 // 气缸1启动 CALL SBR_0, I2.3, I2.4, 50, M20.0, M20.1 // 调用子程序,传入具体参数 网络 2 LD M10.1 // 气缸2启动 CALL SBR_0, I2.5, I2.6, 50, M20.2, M20.3 网络 3 LD M10.2 // 气缸3启动 CALL SBR_0, I2.7, I3.0, 50, M20.4, M20.5这样一来,主程序非常简洁,所有气缸的控制逻辑都集中在子程序里。修改气缸控制逻辑时,只需改一个地方。
实操心得:使用子程序能极大提高代码的复用性和可维护性。但要注意子程序内的局部变量(L区)的使用。局部变量只在子程序执行期间有效,且每次调用都会重新分配。不要用L区来存储需要保持的状态。对于需要保持的状态,应使用全局变量(V区、M区)或通过输出参数传递出来。另外,过度嵌套调用子程序(子程序调用子程序再调用子程序...)会影响程序扫描时间,需谨慎。
5.3 循环与结束指令
FOR和NEXT指令用于实现循环,适合处理重复性的、有规律的操作,比如初始化一个数据块。
网络 1 LD SM0.1 // 首次扫描 FOR VW100, 1, 10 // 循环索引从1到10 网络 2 LD SM0.0 // 常ON信号 +I 1, *VD102 // 对指针VD102所指向的字加1(需要先给VD102赋初始地址) +D 2, VD102 // 指针指向下一个字(地址加2,因为1个字=2字节) 网络 3 NEXT // 循环结束这段程序将数据区从&VB0开始的连续10个字(VW0, VW2, ..., VW18)依次赋值为1到10。FOR循环必须成对出现,且NEXT指令不能有条件执行(前面不能有触点),否则会出错。
END指令和MEND指令用于条件结束主程序或整个程序扫描周期。但在实际工程中,我强烈不建议新手使用条件结束指令。因为它会提前终止本扫描周期的程序执行,可能导致一些必须每个周期都执行的逻辑(如通信、看门狗复位)被跳过,引发不可预知的问题。让程序自然执行到结尾是最安全的方式。
6. 从指令到程序:一个完整的启停保与报警案例
纸上得来终觉浅,我们把这些指令组合起来,看一个稍微复杂点的例子:一个带运行状态指示、故障报警和复位功能的电机控制单元。
控制要求:
- 按下启动按钮(I0.0,常开),电机(Q0.0)启动并自锁。
- 按下停止按钮(I0.1,常闭触点接入PLC,程序中用常开触点),电机停止。
- 电机运行时,绿色指示灯(Q0.1)常亮;停止时,红色指示灯(Q0.2)常亮。
- 热继电器故障信号(I0.2,常开触点,故障时闭合)到来时,电机立即停止,黄色报警灯(Q0.3)以1Hz频率闪烁,蜂鸣器(Q0.4)鸣响。
- 故障发生后,需按下复位按钮(I0.3)才能清除报警,重新启动。
程序实现与分析:
网络 1: 电机启停核心逻辑(带故障急停) LD I0.0 // 启动按钮 O M0.0 // 自锁触点 AN I0.1 // 停止按钮(物理常闭接入,程序用常开) AN I0.2 // 热继电器故障信号(故障时断开逻辑) = M0.0 // 电机运行标志位 = Q0.0 // 驱动电机接触器 网络 2: 运行/停止状态指示灯 LD M0.0 // 运行标志 = Q0.1 // 绿色运行灯 LDN M0.0 // 取反,停止状态 = Q0.2 // 红色停止灯 网络 3: 故障检测与锁存 LD I0.2 // 热继电器故障信号 S M0.1, 1 // 置位故障锁存标志 网络 4: 报警灯闪烁与蜂鸣器 LD M0.1 // 故障存在 AN T37 // 利用定时器产生闪烁 TON T37, 5 // 100ms基准,0.5秒周期 LD M0.1 A T37 // 定时器位为1时(后0.5秒) = Q0.3 // 黄色报警灯亮 LD M0.1 = Q0.4 // 蜂鸣器长鸣(如需鸣响,可并联一个闪烁触点) 网络 5: 故障复位 LD I0.3 // 复位按钮 R M0.1, 1 // 复位故障锁存标志 网络 6: 复位时同时停止电机(可选,安全考虑) LD I0.3 R M0.0, 1 // 复位运行标志,确保电机在复位后处于停止状态程序解读与技巧:
- 网络1:这是经典的启保停,但增加了
AN I0.2。这意味着一旦故障发生(I0.2=1),逻辑立即断开,电机停止。即使故障瞬间消失,由于自锁回路已断,电机也不会自动重启,符合安全要求。 - 网络2:用运行标志
M0.0直接驱动指示灯,逻辑清晰。停止灯用了LDN(取反)指令。 - 网络3:使用置位指令
S锁存故障信号。即使故障信号是瞬间的脉冲,也能被记住,确保报警持续。 - 网络4:利用一个定时器
T37产生方波。M0.1和T37的常闭触点串联,使T37在0.5秒周期内反复通断,其T37位在前0.5秒为0,后0.5秒为1。再与M0.1串联驱动Q0.3,就实现了闪烁。蜂鸣器这里设计为长鸣,如果需要蜂鸣器也闪烁,可以并联一个和Q0.3同样的逻辑。 - 网络5 & 6:复位按钮清除故障锁存。网络6是一个额外的安全措施,确保在复位故障时,电机运行标志也被清除,必须重新按启动按钮才能运行。这避免了复位后电机意外启动的风险。
这个案例融合了位逻辑、定时器、置位复位和简单的程序结构思想。在实际项目中,报警处理会更复杂,可能涉及多个故障源、故障分级、报警确认、报警历史记录等,但其核心思想——检测、锁存、指示、复位——是不变的。掌握了基本指令,你就有能力搭建起这个核心框架。