STL 语句表编程
1. 理解 STL 语句表编程的基础
-
基于指令的顺序执行: STL 程序由一系列指令顺序组成,PLC 按照指令在程序中的排列顺序逐条执行。
-
累加器 (Accumulator) 的核心作用: STL 指令的操作通常围绕着 累加器 (ACCU) 进行。 累加器可以理解为一个临时存储和处理数据的寄存器。 很多 STL 指令会将操作数加载到累加器,或者对累加器中的数据进行处理,并将结果放回累加器或存储到其他地址。
-
程序状态字 (Program Status Word - PSW) 的状态标志: PSW 包含一系列状态标志位,例如:
- OV (溢出): 指示算术运算是否发生溢出。
- OS (存储溢出): 指示是否发生存储区溢出。
- CC (条件代码): 通常有两个条件代码位 (CC0, CC1),用于指示比较或逻辑运算的结果 (例如,相等、大于、小于等)。
- BR (二进制结果): 通常用于位逻辑指令的结果。
- 其他标志位: 例如,零标志、符号标志等。
理解 PSW 的状态标志非常重要,因为很多 STL 指令的执行结果会影响这些标志位,而后续的条件跳转指令 (例如,
JC
,JCN
,JE
,JNE
等) 会根据这些标志位的状态来决定程序的执行流程。 -
操作数类型和寻址方式: STL 指令可以操作不同类型的数据,例如位 (Bit)、字节 (Byte)、字 (Word)、双字 (Double Word) 等。 支持多种寻址方式,例如:
- 直接地址: 例如
I0.0
,Q1.5
,M2.0
,VW100
,DB1.DBW20
等。 - 立即数: 例如
TRUE
,FALSE
,10
,16#FF
,REAL#3.14
等。 - 间接寻址: 通过地址寄存器或指针来访问数据,在 STL 中间接寻址相对较少使用,但在更高级的 PLC 编程中很常见。
- 直接地址: 例如
2. 常用的 STL 指令分类和详解 (S7-200 Smart & S7-200)
以下列举一些常用的 STL 指令类型,并提供简要说明和示例 (注意:S7-200 Smart 和 S7-200 的指令集基本兼容,但某些高级指令可能有所不同,请查阅具体型号的指令手册):
-
位逻辑指令 (Bit Logic): 用于位操作和逻辑运算。
A <位地址>
(与): 将指定位地址的信号状态与累加器 ACCU 0 的逻辑与结果存入 ACCU 0。 例如:A I0.0
(如果 ACCU 0 和 I0.0 都为 TRUE, 则 ACCU 0 结果为 TRUE)。AN <位地址>
(与非): 将指定位地址的信号状态取反后与累加器 ACCU 0 进行逻辑与。例如:AN I0.1
(如果 ACCU 0 为 TRUE 且 I0.1 为 FALSE, 则 ACCU 0 结果为 TRUE)。O <位地址>
(或): 逻辑或运算。 例如:O M1.0
。ON <位地址>
(或非): 逻辑或非运算。例如:ON M1.1
。X <位地址>
(异或): 逻辑异或运算。例如:X Q0.0
。XN <位地址>
(异或非): 逻辑异或非运算。NOT
(非): 将累加器 ACCU 0 的逻辑值取反。例如:NOT
(如果 ACCU 0 为 TRUE, 执行后变为 FALSE)。= <位地址>
(赋值): 将累加器 ACCU 0 的逻辑值赋值给指定的位地址。例如:= Q0.1
(如果 ACCU 0 为 TRUE, 则 Q0.1 输出为 TRUE)。S <位地址>
(置位): 如果累加器 ACCU 0 为 TRUE, 则将指定位地址置为 TRUE (SET)。例如:S M2.0
。R <位地址>
(复位): 如果累加器 ACCU 0 为 TRUE, 则将指定位地址复位为 FALSE (RESET)。 例如:R M2.1
。SET
(置位累加器): 将累加器 ACCU 0 置为 TRUE。CLR
(复位累加器): 将累加器 ACCU 0 复位为 FALSE。NOP <n>
(空操作): 执行 n 条空操作指令,不执行任何实际操作,通常用于程序调试或占位。
-
比较指令 (Compare): 比较操作数,并根据比较结果设置 PSW 的条件代码位 (CC0, CC1)。
==I, <>I, >I, <I, >=I, <=I
(整数比较): 比较两个整数。 例如:==I VW10, 100
(比较 VW10 和立即数 100 是否相等)。==R, <>R, >R, <R, >=R, <=R
(实数比较): 比较两个实数。 例如:>R VD20, REAL#5.0
(比较 VD20 是否大于实数 5.0)。==D, <>D, >D, <D, >=D, <=D
(双整数比较): 比较两个双整数。
比较指令通常与条件跳转指令配合使用。
-
算术运算指令 (Arithmetic Operations): 进行数值计算。
+I, -I, *I, /I
(整数运算): 加、减、乘、除整数。 例如:+I VW30, 5
(将 VW30 的值加上 5,结果存回累加器)。+R, -R, *R, /R
(实数运算): 加、减、乘、除实数。 例如:-R VD40, REAL#1.2
(从 VD40 的值减去实数 1.2,结果存回累加器)。+D, -D, *D, /D
(双整数运算): 加、减、乘、除双整数。INC <字/双字地址>
(递增): 将指定地址的字或双字值加 1。 例如:INC MW10
(将 MW10 的值加 1)。DEC <字/双字地址>
(递减): 将指定地址的字或双字值减 1。 例如:DEC VD20
(将 VD20 的值减 1)。MOD
(取模/余数): 整数除法后取余数。
-
数据传送指令 (Move): 将数据从一个地址传送到另一个地址。
L <操作数>
(加载): 将指定的操作数加载到累加器 ACCU 0。 例如:L IW0
(将 IW0 的值加载到 ACCU 0)。T <地址>
(传送): 将累加器 ACCU 0 的值传送到指定的地址。 例如:T QW2
(将 ACCU 0 的值传送到 QW2)。MOVB <源字节地址>, <目标字节地址>
(传送字节): 传送一个字节。MOVW <源字地址>, <目标字地址>
(传送字): 传送一个字。MOVD <源双字地址>, <目标双字地址>
(传送双字): 传送一个双字。
-
定时器指令 (Timer): 实现时间延时功能。
TON <定时器号>, <预设时间>
(接通延时定时器): 当输入条件满足时,定时器开始计时,到达预设时间后,定时器输出位 Q 置位。 例如:TON T37, VW50
(启动定时器 T37,预设时间从 VW50 读取)。TOF <定时器号>, <预设时间>
(断开延时定时器): 当输入条件由 TRUE 变为 FALSE 时,定时器开始计时,到达预设时间后,定时器输出位 Q 复位。TP <定时器号>, <预设时间>
(脉冲定时器): 当输入条件由 FALSE 变为 TRUE 时,定时器输出位 Q 置位一个脉冲宽度的时间。
-
计数器指令 (Counter): 进行计数功能。
CTU <计数器号>, <预设值>, <复位输入>, <计数输入>
(加计数器): 当计数输入端有上升沿信号时,计数器当前值加 1,当达到预设值时,计数器输出位 CU 置位。 复位输入端为 TRUE 时,计数器复位。 在 STL 中,通常使用多条指令组合实现计数器功能。CTD <计数器号>, <预设值>, <复位输入>, <计数输入>
(减计数器): 类似加计数器,但进行减计数。CTUD <计数器号>, <预设值>, <复位输入>, <加计数输入>, <减计数输入>
(加/减计数器): 具有加计数和减计数功能。
-
跳转指令 (Jump): 控制程序的执行流程,实现条件跳转或无条件跳转。
JMP <标号>
(无条件跳转): 程序无条件跳转到指定的标号处继续执行。 例如:JMP NEXT_STEP
。JC <标号>
(条件跳转 - Carry/进位): 如果 PSW 的进位标志位 (Carry Flag) 为 1,则跳转到指定标号。JCN <标号>
(条件跳转 - 非 Carry/非进位): 如果 PSW 的进位标志位为 0,则跳转。JE <标号>
(条件跳转 - Equal/相等): 如果比较结果为相等 (通常由比较指令设置),则跳转。JNE <标号>
(条件跳转 - Not Equal/不相等): 如果比较结果为不相等,则跳转。JL <标号>
(条件跳转 - Less than/小于): 如果比较结果为小于,则跳转。JG <标号>
(条件跳转 - Greater than/大于): 如果比较结果为大于,则跳转。JLZ <标号>
(条件跳转 - Less than or Equal/小于等于): 如果比较结果为小于等于,则跳转。JGZ <标号>
(条件跳转 - Greater than or Equal/大于等于): 如果比较结果为大于等于,则跳转。JUO <标号>
(条件跳转 - Unordered/无序): 用于实数比较,如果比较结果为无序 (例如,NaN 与任何数比较),则跳转。LOOP <标号>
(循环): 实现循环结构。
-
程序控制指令 (Program Control):
CALL <子程序名>
(调用子程序): 调用指定的子程序。 例如:CALL SUB_ROUTINE_1
。RET
(子程序返回): 从子程序返回到主程序。MEND
(程序结束): 标志程序段的结束。
-
数据类型转换指令 (Convert): 在不同数据类型之间进行转换。
I_DI
(整数到双整数): 将整数转换为双整数。DI_I
(双整数到整数): 将双整数转换为整数。I_R
(整数到实数): 将整数转换为实数。R_I
(实数到整数): 将实数转换为整数 (注意舍入)。BCD_I
(BCD码到整数): 将 BCD 码转换为整数。I_BCD
(整数到 BCD码): 将整数转换为 BCD 码。
-
移位和循环移位指令 (Shift and Rotate): 对数据进行位移操作。
SHL <字/双字地址>, <移位位数>
(左移): 将字或双字向左移位,空出的低位补 0。 例如:SHL MW20, 3
(将 MW20 左移 3 位)。SHR <字/双字地址>, <移位位数>
(右移): 向右移位,空出的高位补 0。ROL <字/双字地址>, <循环移位位数>
(循环左移): 循环左移,移出的位填补到空出的低位。ROR <字/双字地址>, <循环移位位数>
(循环右移): 循环右移。
3. STL 语句表程序设计方法 - 步骤和技巧
-
清晰理解控制任务: 如同任何编程语言,首先要明确你的控制目标。 详细分析控制逻辑、输入输出关系、顺序控制流程、数据处理需求等。
-
I/O 分配和地址规划: 确定程序中使用的输入 (I)、输出 (Q)、存储器 (M)、变量存储区 (V)、数据块 (DB) 等地址,并做好记录。
-
算法设计 (流程图或伪代码): 在编写 STL 代码之前,先用流程图或伪代码描述控制算法的步骤。 这对于组织复杂的逻辑至关重要,尤其是在 STL 这种文本语言中。
-
STL 代码编写: 根据算法,逐条编写 STL 指令。 注意以下技巧:
- 注释: 在 STL 代码中添加 详细的注释! 由于 STL 代码相对抽象,充分的注释是提高代码可读性和可维护性的关键。 可以使用行注释 (
;
开头) 和块注释 (例如,使用(* ... *)
)。 - 合理使用累加器: 理解累加器的工作方式,高效地利用累加器进行数据处理和逻辑运算,减少不必要的加载和传送指令。
- 利用 PSW 状态标志: 充分利用 PSW 的状态标志位,结合条件跳转指令,实现复杂的条件控制逻辑。
- 程序分段和模块化: 对于较长的 STL 程序,可以将程序分解成多个功能相对独立的段 (例如,使用标号分隔),甚至编写子程序 (Subroutine),提高程序结构清晰度。
- 使用标号 (Label): 合理使用标号 (例如
NEXT_STEP:
) 作为跳转指令的目标位置,使程序流程更易于理解。 标号的命名应具有描述性。 - 数据类型匹配: 确保指令的操作数数据类型匹配,避免数据类型错误。
- 代码格式化: 保持一致的代码缩进和格式,提高代码可读性。 尽管 STL 的格式不如 LAD/FBD 那么直观,但合理的缩进和对齐仍然重要。
- 注释: 在 STL 代码中添加 详细的注释! 由于 STL 代码相对抽象,充分的注释是提高代码可读性和可维护性的关键。 可以使用行注释 (
-
程序测试与调试:
- 语法检查: 使用 STEP 7 Micro/WIN SMART 软件进行语法检查,消除语法错误。
- 逻辑仿真: 在软件仿真环境下,模拟输入信号,检查程序逻辑是否符合预期。
- 在线监控: 将程序下载到实际 PLC 中,使用在线监控功能,观察程序运行状态、变量值、I/O 状态等,进行在线调试。
- 逐步调试: 对于复杂的程序,可以采用逐步调试的方法,一段一段地测试程序的功能,逐步排查错误。
4. STL 语句表编程风格建议
- 注释先行: 先写注释,描述程序段的功能和逻辑,再编写 STL 指令。
- 指令分解: 对于复杂的逻辑运算,可以分解成多条简单的 STL 指令,提高代码可读性。 避免写过于复杂的单行 STL 指令。
- 使用有意义的符号地址: 尽量使用符号地址 (而不是绝对地址),提高程序的可读性和可移植性。 在 STEP 7 Micro/WIN SMART 中,可以创建符号表,为 I/O 点、存储器位、变量等定义符号名称。
- 避免过度优化 (除非必要): 过度的代码优化可能会降低代码的可读性。 除非对程序执行效率有非常高的要求,否则应优先考虑代码的可读性和可维护性。
- 程序版本管理: 使用版本控制工具 (例如 Git) 管理 PLC 程序代码,方便代码的版本管理、回溯和团队协作。
5. STL 语句表编程的优缺点
-
优点:
- 执行效率高: STL 代码通常比 LAD/FBD 代码执行效率更高,尤其是在进行复杂的数据处理和运算时。
- 控制精确: STL 提供了更底层的硬件控制能力,可以实现更精细的控制逻辑。
- 适合复杂逻辑和算法: 对于复杂的逻辑控制、数学运算、数据处理等,STL 表达能力更强,更灵活。
- 系统级编程: 在编写 PLC 系统程序、通信程序、驱动程序等底层程序时,STL 更为适用。
- 代码紧凑: 在某些情况下,使用 STL 可以编写出更紧凑的代码。
-
缺点:
- 学习曲线陡峭: STL 相对于 LAD/FBD 更难学习和掌握,需要理解累加器、PSW、指令执行机制等底层概念。
- 可读性较差: 文本化的 STL 代码不如图形化的 LAD/FBD 直观,可读性和可维护性相对较差 (尤其在缺乏注释的情况下)。
- 调试难度较高: 相对于 LAD/FBD,STL 程序的调试可能更具挑战性,需要更强的调试技巧。
- 不适合所有应用: 对于简单的开关量逻辑控制,LAD 通常更直观易用,STL 的优势不明显。