浏览示例
把语法放回完整程序里看:边沿、定时器、状态机、缓冲站、阀门控制。
打开示例库 →一页掌握 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:
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 |
常量 | 只读 |
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 |
匿名结构 | 见缓冲站示例 |
从高到低(同一行按从左到右):
() 括号NOT、一元 -*、/、MOD+、-=、<>、<、>、<=、>=ANDXOROR建议:混合运算一律加括号,别依赖记忆。
1#Ok := (#Temp > #Min) AND (#Temp < #Max) AND NOT #Fault;
1#Count := #Count + 1;
2#Total += #Value; // 等价于 #Total := #Total + #Value
3#Total -= #Value;
4#Total *= 2;
5#Total /= 2;
:= 是赋值;= 是比较。不要在 IF 里写 :=。
1IF #Start THEN
2 #Run := TRUE;
3ELSIF #Fault THEN
4 #Run := FALSE;
5ELSE
6 #Run := #Run;
7END_IF;
CASE 适合状态机:
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;
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 静态变量里声明实例:
1VAR
2 Timer : TON_TIME;
3END_VAR
4
5#Timer(IN := #Start, PT := T#3S);
6#Q := #Timer.Q;
7#ET := #Timer.ET;
注意:
TON 是“接通延时”,TOF 是“断开延时”,TP 是“脉冲”;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 等。
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 实例:
1VAR
2 Trig : R_TRIG;
3END_VAR
4
5#Trig(CLK := #Signal);
6#Rising := #Trig.Q;
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';
结构体整体赋值会复制所有成员:
1#Slots[#i] := #Slots[#i - 1];
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。
1#RealValue := INT_TO_REAL(#IntValue);
2#IntValue := REAL_TO_INT(#RealValue);
3#WordValue := INT_TO_WORD(#IntValue);
TIA 的转换指令名通常是 <源类型>_TO_<目标类型>;不要依赖隐式转换,尤其是在 Int/DInt/Real 之间。
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 更稳,也更容易在云仿真里复现。
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,不能保存状态。
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 标签报错 | 标签用了不支持的常量表达式;先用数字标签,再在分支里用常量赋值 |
可以。同一个 PLC 项目里,OB 可以调用 LAD 块,也可以调用 SCL 块;LAD 和 SCL 之间通过块接口传递参数。
VAR 是 FB 的静态变量,扫描间保持,相当于背景 DB 里的存储;VAR_TEMP 是临时变量,每次调用重新创建,不能用来保存边沿历史或定时器状态。
把语法放回完整程序里看:边沿、定时器、状态机、缓冲站、阀门控制。
打开示例库 →把示例导入你的 TIA Portal 工程,生成块、编译并读回核对。
了解 TiaLink →不装博途,用 MCP 逐扫描运行 SCL,做场景验收。
打开云仿真 →