跳到正文
Learn-SCL
SCL 示例库/SCL 指南/SCL 语法速查:块、变量、控制流与常用指令

SCL 语法速查:块、变量、控制流与常用指令

一页掌握 TIA Portal SCL 的块结构、接口声明、运算符、IF/CASE/FOR、定时器/计数器/边沿、数组/结构、字符串和类型转换。

语法

一句话:SCL 是 TIA Portal 的结构化文本语言:用 FB/FC 组织逻辑,用 VAR_* 声明接口,用 IF/CASE/FOR 写控制流,用 TON_TIME/T_ADD 处理时间和定时器。

这页不是 TIA 帮助文档的翻译,而是把本库示例里反复出现的 SCL 写法压缩成一张“查得到、抄得走”的速查表。遇到不认识的写法,先在这里找;找不到再去 TIA 帮助里查对应指令。

块类型

关键字 用途 结束行
FUNCTION_BLOCK "FB_Name" 功能块,有背景 DB,能保存状态 END_FUNCTION_BLOCK
FUNCTION "FC_Name" : Void 函数,无背景 DB,适合纯计算/一次性逻辑 END_FUNCTION
ORGANIZATION_BLOCK "OB_Name" 组织块,由操作系统调用 END_ORGANIZATION_BLOCK
DATA_BLOCK "DB_Name" 数据块,保存全局数据 END_DATA_BLOCK

最简 FB:

SCL
1FUNCTION_BLOCK "FB_Lamp"
2{ S7_Optimized_Access := 'TRUE' }
3VERSION : 0.1
4   VAR_INPUT
5      Switch : Bool;
6   END_VAR
7   VAR_OUTPUT
8      Lamp : Bool;
9   END_VAR
10BEGIN
11   #Lamp := #Switch;
12END_FUNCTION_BLOCK

接口区块

FB/FC 的接口按下面的顺序声明;没有成员的空区块可以省略。

区块 含义 是否保持
VAR_INPUT 输入参数 由调用方给值
VAR_OUTPUT 输出参数 由块写回调用方
VAR_IN_OUT 按引用传递 调用方和被调用方共享
VAR FB 静态变量 扫描间保持(相当于背景 DB)
VAR_TEMP 临时变量 每个扫描周期重建
VAR CONSTANT 常量 只读
SCL
1FUNCTION_BLOCK "FB_Counter"
2VERSION : 0.1
3   VAR_INPUT
4      CountUp : Bool;
5   END_VAR
6   VAR_OUTPUT
7      Count : Int;
8   END_VAR
9   VAR
10      Prev : Bool;
11   END_VAR
12   VAR_TEMP
13      Rising : Bool;
14   END_VAR
15   VAR CONSTANT
16      STEP : Int := 1;
17   END_VAR
18BEGIN
19   #Rising := #CountUp AND NOT #Prev;
20   #Prev := #CountUp;
21   IF #Rising THEN
22      #Count := #Count + #STEP;
23   END_IF;
24END_FUNCTION_BLOCK

数据类型

类型 说明 字面量示例
Bool 位 TRUE / FALSE
Byte / Word / DWord 位串 16#FF / 2#1010_1010
SInt / Int / DInt / LInt 有符号整数 -12 / 1000
USInt / UInt / UDInt / ULInt 无符号整数 16#FFFF
Real / LReal 浮点 1.5 / 1.0E-3
Time / LTime 时间 T#5S / T#100MS
Date / TOD / DTL 日期/时间 D#2026-01-01 / TOD#12:00:00
String[n] / WString[n] 字符串 'Hello'
Array[a..b] of T 数组 Array[1..8] of Bool
Struct ... END_STRUCT 匿名结构 见缓冲站示例

运算符与优先级

从高到低(同一行按从左到右):

  1. () 括号
  2. NOT、一元 -
  3. *、/、MOD
  4. +、-
  5. =、<>、<、>、<=、>=
  6. AND
  7. XOR
  8. OR

建议:混合运算一律加括号,别依赖记忆。

SCL
1#Ok := (#Temp > #Min) AND (#Temp < #Max) AND NOT #Fault;

赋值

SCL
1#Count := #Count + 1;
2#Total += #Value;   // 等价于 #Total := #Total + #Value
3#Total -= #Value;
4#Total *= 2;
5#Total /= 2;

:= 是赋值;= 是比较。不要在 IF 里写 :=。

条件分支

SCL
1IF #Start THEN
2   #Run := TRUE;
3ELSIF #Fault THEN
4   #Run := FALSE;
5ELSE
6   #Run := #Run;
7END_IF;

CASE 适合状态机:

SCL
1CASE #State OF
2   0:
3      IF #Start THEN
4         #State := 1;
5      END_IF;
6   1:
7      IF #Done THEN
8         #State := 2;
9      END_IF;
10   ELSE
11      #State := 0;
12END_CASE;

循环

SCL
1FOR #i := 1 TO 8 DO
2   #Sum := #Sum + #Array[#i];
3END_FOR;
4 
5FOR #i := 8 TO 2 BY -1 DO
6   #Array[#i] := #Array[#i - 1];
7END_FOR;
8 
9WHILE #i < 10 DO
10   #i := #i + 1;
11END_WHILE;
12 
13REPEAT
14   #i := #i + 1;
15UNTIL #i >= 10
16END_REPEAT;

EXIT 立即退出循环,CONTINUE 进入下一次循环。

定时器

IEC 定时器的数据类是 TON_TIME / TOF_TIME / TP_TIME / TONR_TIME。在 FB 静态变量里声明实例:

SCL
1VAR
2   Timer : TON_TIME;
3END_VAR
4 
5#Timer(IN := #Start, PT := T#3S);
6#Q := #Timer.Q;
7#ET := #Timer.ET;

注意:

计数器

SCL
1VAR
2   Counter : CTU_DINT;
3END_VAR
4 
5#Counter(CU := #Pulse, R := #Reset, PV := 10);
6#Done := #Counter.Q;
7#Count := #Counter.CV;

CTU 加计数,CTD 减计数,CTUD 加减计数。数据类可以用 CTU_DINT / CTU_INT 等。

边沿检测

SCL
1VAR
2   Prev : Bool;
3END_VAR
4 
5#Rising := #Signal AND NOT #Prev;
6#Falling := NOT #Signal AND #Prev;
7#Prev := #Signal;

也可以直接用 R_TRIG / F_TRIG 实例:

SCL
1VAR
2   Trig : R_TRIG;
3END_VAR
4 
5#Trig(CLK := #Signal);
6#Rising := #Trig.Q;

数组与结构

SCL
1VAR
2   Slots : Array[1..8] of Struct
3      Loaded : Bool;
4      Age : Time;
5   END_STRUCT;
6   Names : Array[0..3] of String[20];
7END_VAR
8 
9#Slots[1].Loaded := TRUE;
10#Slots[1].Age := T#0MS;
11#Names[0] := 'Part-A';

结构体整体赋值会复制所有成员:

SCL
1#Slots[#i] := #Slots[#i - 1];

字符串

SCL
1VAR
2   Text : String[60];
3   Len : Int;
4END_VAR
5 
6#Text := 'Valve not opening';
7#Len := LEN(#Text);
8#Text := CONCAT(IN1 := 'Valve: ', IN2 := #Text);

常用:LEN、CONCAT、LEFT、RIGHT、MID、FIND、INSERT、DELETE、REPLACE。

类型转换

SCL
1#RealValue := INT_TO_REAL(#IntValue);
2#IntValue := REAL_TO_INT(#RealValue);
3#WordValue := INT_TO_WORD(#IntValue);

TIA 的转换指令名通常是 <源类型>_TO_<目标类型>;不要依赖隐式转换,尤其是在 Int/DInt/Real 之间。

时间运算

SCL
1#Total := T_ADD(IN1 := #Total, IN2 := #CycleTime);
2#Diff := T_SUB(IN1 := #EndTime, IN2 := #StartTime);
3#Ms := TIME_TO_DINT(#Total);

部分编译器支持 Time + Time,但用 T_ADD 更稳,也更容易在云仿真里复现。

块调用

SCL
1// 调用 FB,使用背景 DB
2"DB_Motor"(Start := #Start, Stop := #Stop, Motor => #Motor);
3 
4// 调用 FC(无背景 DB)
5#Result := "FC_Add"(A := 1, B := 2);

FB 调用需要背景 DB(单实例 DB 或 FB 内的多实例)。FC 没有背景 DB,不能保存状态。

注释与分段

SCL
1// 单行注释
2(* 块注释,可嵌套 *)
3REGION 状态机
4   // ...
5END_REGION

REGION 只是阅读辅助,不改变执行顺序;但本库用它来分段讲解和构建门禁。

常见错误速查

现象 常见原因
边沿只出现一次,后面再也没有 Prev 放在 VAR_TEMP,或先更新 Prev 再判断
定时器不走 实例没有每个周期调用,或 PT 单位错
数组越界 循环边界写错;Array[1..8] 的有效下标是 1..8
编译报类型错误 Int/DInt/Real/Time 混用,需要显式转换
字符串乱码 源文件编码不是 UTF-8;TiaLink 会补 BOM,但内容必须是 UTF-8
CASE 标签报错 标签用了不支持的常量表达式;先用数字标签,再在分支里用常量赋值

常见问题

SCL 和 LAD 可以混用吗?

可以。同一个 PLC 项目里,OB 可以调用 LAD 块,也可以调用 SCL 块;LAD 和 SCL 之间通过块接口传递参数。

SCL 的 VAR_TEMP 和 VAR 有什么区别?

VAR 是 FB 的静态变量,扫描间保持,相当于背景 DB 里的存储;VAR_TEMP 是临时变量,每次调用重新创建,不能用来保存边沿历史或定时器状态。

下一步

浏览示例

把语法放回完整程序里看:边沿、定时器、状态机、缓冲站、阀门控制。

打开示例库 →

TiaLink

把示例导入你的 TIA Portal 工程,生成块、编译并读回核对。

了解 TiaLink →

PLC 云仿真

不装博途,用 MCP 逐扫描运行 SCL,做场景验收。

打开云仿真 →