04 标准库与常用功能: TIA Portal 指令全景与实战 (S7-1200 + SCL)
面向有 10 年 C/Python 经验、正在学 S7-1200 + TIA Portal + SCL 的工程师。本章把 TIA Portal 的指令体系当作“标准库“来梳理: 怎么查找、怎么在 SCL 里调用、每类常用指令的精确语义, 以及模拟量 / PID / HSC / 运动控制 / 通信 / 诊断这些“应用层大件“的完整走查。所有 SCL 代码均按 TIA Portal V16~V20、S7-1200 (一代, 固件 V4.x) 可用语法书写, 变量声明区与代码区分开。
目录
- 指令体系如何组织与查找
- SCL 中的调用形态
- 基础指令精讲: MOVE 与选择类
- 转换指令族
- 移位与字逻辑
- 模拟量: 27648 的世界与 NORM_X / SCALE_X
- PID: PID_Compact 完整走查
- 高速计数器 HSC
- 运动控制 (PTO 基本定位)
- 通信: OUC / Modbus TCP / PROFINET / OPC UA / Web server
- 库工程化: 项目库、全局库、第三方库
- 诊断类指令与系统功能一览
- 收尾: 用库思维写 SCL
1. 指令体系如何组织与查找
TIA Portal 的程序编辑器右侧有一条 Instructions task card(指令任务卡), 指令按三个层级组织:
| 层级 | 内容 | 类比 |
|---|---|---|
| Basic instructions | 位逻辑、定时器、计数器、比较、数学、MOVE、转换、移位、字逻辑 | C 的 stdlib.h / 运算符 |
| Extended instructions | 日期时间、中断、诊断、通信 (TSEND_C、MB_CLIENT)、PID、字符串、数据日志等 | Python 的 batteries included 标准库 |
| Libraries | 项目库 (Project library)、全局库 (Global library)、西门子自带库 (如 LBC, Library of General Functions) | npm 包 / 公司内部 pip index |
几点精确说明:
- Basic / Extended 的区分只是组织方式, 不代表编译产物不同; 两者在 SCL 里都是“函数/功能块调用“或“表达式风格指令“。
- Technology(工艺)指令单独成组: PID_Compact/PID_Temp 在 Extended > PID control; HSC 的 CTRL_HSC 在 Technology > Counting (High-speed counters); 运动控制 MC_xxx 在 Technology > Motion control。
- 指令的 CPU 支持范围以在线帮助条目标题为准: 官方文档对 SCL 参考里每条指令都标注
(S7-1200, S7-1500)或(S7-1500), 后者即 1200 不可用 (典型: REF 引用类型、POINTER/ANY 参数、遗留 S5 定时器/计数器、TypeOfDB、ARRAY DB、断点调试、LTIME 等)。 - 查找方式: 在 task card 顶部的搜索框输入指令名 (如
MUX) 或在编辑器内直接键入指令名前几个字母, TIA 会弹出匹配列表 (类似 IDE 的补全); 按 F1 打开该指令的在线帮助页, 这是唯一权威语义来源。
一个重要的“程序员直觉校准“: TIA 的指令不是宏, 而是编译器内建操作 + 预编译库块的混合体。Basic 指令多数编译为内建操作 (无调用开销感), Extended/Technology 指令多数是库 FB/FC, 拖入时会让你创建 instance DB。
2. SCL 中的调用形态
2.1 三种形态
1) 表达式风格 (仅 Basic 类): #y := SEL(G := #g, IN0 := #a, IN1 := #b);
2) FC 调用 (无状态): #ok := "LBC".Denoise(...); // 返回值可接可不接
3) FB 调用 (必须有实例): "PID_DB"(Setpoint := 100.0, Input := #pv);
- FC (Function): 无实例、无状态 (VAR_TEMP 生命周期仅当次调用), 相当于纯函数 —— 但注意 S7-1200 的 FC 也允许写全局 DB / Q, 编译器不强制纯度。
- FB (Function Block): 必须绑定 instance DB (单独实例) 或作为 multi-instance 壌在调用者 FB 的 static 区 (相当于“调用者对象内嵌子对象“)。SCL 中 FB 调用形如
"InstDB"(参数表), 参数表里没出现的引脚沿用实例 DB 中的上次值 —— 这是与 C 最大的差异: FB 调用是“有状态的调用“, 省略参数不等于使用默认值, 而是沿用上次调用的值。 - 从 task card 拖 FB 到 SCL 代码区, TIA 弹出“调用选项“对话框, 让你选 single instance (新建独立 DB) 还是 multi-instance (存在当前 FB 的 static 区)。SCL 亦可在块接口的 Static 区手写
MyInst : TON;然后#MyInst(IN := ...)。
2.2 EN/ENO 语义 (必懂)
多数指令支持 EN 与 ENO。SCL 中:
- 块属性 “Set ENO automatically” (自动生成 ENO) 开启时, 运行期错误 (除零、CONV 溢出等) 会把 ENO 置 FALSE 并继续执行下一条语句 —— 类似 Python 的“异常被吞掉但留了 flag“, 而不是 C 的段错误。
- 用
=>语法接 ENO:"CONV_DB"(..., ENO => #ok);或对表达式风格指令#ok := ...之外的独立检测。 - 已核实的错误行为 (S7-1200): 整数除零 → 结果置 0、ENO=0、保持 RUN; CONV 溢出 → ENO=0 (OUT 取值不同版本文档表述有差异, 以 ENO 为准); 数组越界 → 记入诊断缓冲、保持 RUN, 但 ENO 不会因此置 FALSE。详见第 12 节与 03 章。
3. 基础指令精讲: MOVE 与选择类
3.1 MOVE
MOVE 把 IN 复制到 OUT (可挂多个输出)。在 SCL 里 := 赋值就是 MOVE, 所以 MOVE 指令的真正用途只剩两个: 需要在 F1 帮助里查 ENO 行为时; 以及需要在 EN=FALSE 时保持“整段复制不发生“的可视化场景。SCL:
// 两种写法等价:
"DB_Data".Cmd := #cmd; // 赋值即 MOVE
MOVE(IN := #cmd, OUT1 => "DB_Data".Cmd, OUT2 => #bak); // 指令形态: 一次复制两份
注意: MOVE 走的是“符号赋值“语义, 数据类型必须赋值兼容 (隐式转换规则见 4.1); 要按原始字节复制请用 POKE_BLK 或对标准 DB 用 PEEK/POKE 家族 (见 03 章)。
3.2 选择类指令 (SEL/MUX/MIN/MAX/LIMIT)
这一族是 SCL 里最像“三元运算符 / switch / clamp“的东西, 但语义有细节差异, 逐个给出:
| 指令 | 语义 | C/Python 类比 | 类比不成立之处 |
|---|---|---|---|
SEL(G, IN0, IN1) | G=FALSE 选 IN0, G=TRUE 选 IN1 | G ? IN1 : IN0 | 注意参数顺序: FALSE 走 IN0, 与 C 三元表达式前后位置相反, 极易写反 |
MUX(K, IN0..INn, ELSE) | 整数 K 选第 K 个输入; K 超范围 → ELSE 且 ENO=0 | 数组下标 + default | MUX 是“位置参数即下标“, 不是数组访问; 超范围不报异常而是走 ELSE |
MIN(IN1..) / MAX(IN1..) | 多输入取最小/最大 | Python min()/max() | 结果类型跟随输入类型 (整型家族按声明类型截断/符号处理), 无 Python 的跨类型提升 |
LIMIT(MN, IN, MX) | 夹紧到闭区间 | max(MN, min(IN, MX)) | MN > MX 时 ENO=0 且行为未定义 (C 里同样 UB, 这点类比成立) |
示例 FB —— 一个“限幅三态选择器“, 把四种选择指令串起来用:
// FB 接口:
// Input: selMode : Int // 0=取最小 1=取最大 2=取A 3=取B 4=按K选择
// valueA : Int
// valueB : Int
// clampLo : Int
// clampHi : Int
// k : Int // MUX 的选择号
// Output: result : Int
// valid : Bool
// Static: 无
// 代码区:
CASE #selMode OF
0: // 两个输入取较小者
#result := MIN(IN1 := #valueA, IN2 := #valueB);
#valid := TRUE;
1: // 取较大者
#result := MAX(IN1 := #valueA, IN2 := #valueB);
#valid := TRUE;
2: // 选 A
#result := SEL(G := FALSE, IN0 := #valueA, IN1 := #valueB);
#valid := TRUE;
3: // 选 B
#result := SEL(G := TRUE, IN0 := #valueA, IN1 := #valueB);
#valid := TRUE;
ELSE // 4 或其它值: 用 MUX 在 A/B/夹紧后的A 三者中选
MUX(K := #k,
IN0 := #valueA,
IN1 := #valueB,
IN2 := LIMIT(MN := #clampLo, IN := #valueA, MX := #clampHi),
ELSE => #result,
ENO => #valid); // K 超范围: ELSE 生效, valid=FALSE
END_CASE;
// 最终结果统一限幅; MN>MX 时 ENO=0
LIMIT(MN := #clampLo, IN := #result, MX := #clampHi, OUT => #result, ENO => #valid2);
实践建议: SEL/MUX/LIMIT 的参数必须用命名参数 (G := , IN0 := ) 写, 位置参数在这里几乎是可读性灾难。
4. 转换指令族
4.1 隐式转换 vs 显式 CONV
SCL 赋值/传参时, 整型家族 (SInt..DInt/USInt..UDInt) 与 REAL 之间按“宽度提升“隐式转换; 但有以下硬规则:
- REAL → 整型必须显式 (ROUND/TRUNC/CEIL/FLOOR), 直接
#i := #r;不编译 —— 比 C 严格, 类似 Rust 的 as 语义要求显式。 - String ↔ 数值必须走 S_CONV / STRG_VAL / VAL_STRG (字符串细节见 03 章)。
- 位串家族 (Byte/Word/DWord) 与整型之间可以 CONV, 但 Bool → Byte 之类的“放大“要用 CONVERT 指令形态。
4.2 指令清单
| 指令 | 语义 | 备注 |
|---|---|---|
CONV | 显式类型转换 | 溢出: ENO=0 (OUT 取值以 ENO 为准, 不要依赖); 这是“越界不抛异常但留痕“的又一例 |
ROUND | REAL → 整型, 就近取整 | .5 边界的舍入方向以在线帮助为准 (待核实) |
TRUNC | REAL → 整型, 向零截断 | 等价 C 的 (int)x |
CEIL / FLOOR | 向 +∞ / −∞ | 等价 math.ceil/floor |
NORM_X / SCALE_X | 归一化 / 定标 | 见第 6 节, 模拟量核心 |
S_CONV / STRG_VAL / VAL_STRG | 字符串 ↔ 数值 | 非法字符/超范围: ENO=0 且 OUT=0 (已核实) |
CHAR ↔ INT 等 | CONV 的具体实例 | #i := CONV(Int, #ch); — 待核实: V16~V20 具体拼写以帮助为准 |
示例: 把 Word 原始值安全转成工程量 (显式 + 错误检测):
// Input: rawW : Word // 如来自 %IW
// Output: asInt : Int
// asReal: Real
// ok : Bool
CONV(IN := #rawW, OUT => #asInt, ENO => #ok);
IF #ok THEN
#asReal := TRUNC(IN := CONV(Real, #asInt)); // 先显式 Int->Real, 再截断回 Int? 不: 见下
END_IF;
上面第二行故意写成错的示范 —— TRUNC 的输出是整型, 不能赋给 #asReal。正确写法:
#asReal := CONV(Real, #asInt); // Int -> REAL 显式转换 (也可隐式, 显式更清晰)
CONV(目标类型, 表达式) 是 V16+ 的函数风格写法; 拖拽指令时 TIA 会生成带 => 的指令形态, 两种都合法。待核实: 函数风格 CONV(Real, x) 的确切括号语法在你所用 TIA 版本的编辑器里可能是 Real#(x) 之外的写法, 以 F1 帮助为准。
5. 移位与字逻辑
5.1 SHL/SHR/ROL/ROR 与 SWAP
| 指令 | 语义 | 备注 |
|---|---|---|
SHL(IN, N) | 左移, 空位补 0 | 操作数按位模式处理; 有符号整型右移不保留符号位 (待核实: 帮助中 SHR 的空位填充描述为 0) |
SHR(IN, N) | 右移, 空位补 0 | 对 Int 想要算术右移时, 先转无符号再移, 或用除法 |
ROL / ROR | 循环左/右移 | 移位数按操作数位宽取模 |
SWAP(IN) | 字节序交换 (16/32 位) | Word/DWord/Real 通信场景必备, 等价 Python struct.unpack('>H', ...) 前的手工翻转 |
示例: 从 Word 中按位打包/解包状态 (比 AT 覆盖更直观, 比 PEEK 便宜):
// Input: statusWord : Word
// bitNo : UInt
// Output: bitOut : Bool
// highByte : Byte
// Static: tmp : Word
// 取第 bitNo 位 (0 = LSB)
#tmp := SHR(IN := #statusWord, N := #bitNo); // 右移使目标位到 bit0
#bitOut := (#tmp MOD 2) = 1; // 或用 PEEK_BOOL 亦可
// 取高字节: 右移 8 位后 CONV 成 Byte
#highByte := CONV(Byte, SHR(IN := #statusWord, N := 8) AND 16#00FF);
// 反过来打包: 把 8 个 Bool 装进一个 Byte (用 SHL 累积)
// Input: b : Array[0..7] of Bool Output: packed : Byte
#packed := 0;
FOR #i := 0 TO 7 DO
IF #b[#i] THEN
#packed := #packed OR SHL(IN := CONV(Byte, 1), N := #i);
END_IF;
END_FOR;
5.2 字逻辑: AND/OR/XOR/INV + DECO/ENCO
AND / OR / XOR: 位逻辑, 操作数是位串或整型; SCL 里对 Bool 表达式也用同名关键字 (IF #a AND #b THEN), 语义与 C 的&/|/^对齐。INV或NOT: 按位取反; SCL 表达式#y := NOT #x;对整型同样按位取反。DECO/ENCO: n 选 1 位译码 / 1-of-n 编码 (K → bit K 置 1; 反向求最高/最低置位位号)。批量指示灯/优先编码时比手写循环清晰。
SWAP 的典型场景 (见 10.3 字节序坑):
#swapped := SWAP(IN := #rawWord); // 大端 <-> 小端 (按字节对换)
6. 模拟量: 27648 的世界与 NORM_X / SCALE_X
6.1 机制: 为什么是 27648
S7-1200 模拟量输入/输出通道的“额定范围“统一映射到整数 0..27648 (单极性) 或 −27648..27648 (双极性)。27648 不是 2 的幂, 它 = 0x6C00, 是西门子历史选择的“满量程标称值“, 让各种量程有公共的整数标尺。类比: 这是一个定点数格式, 小数点位置由通道量程定义, 27648 即 100.0%。
关键分区表 (以 4..20 mA 电流输入为例, 数值已对照官方手册):
| 数字值 | 物理电流 | 含义 |
|---|---|---|
| 32767 | > 约 22.81 mA | 溢出 / 故障态 (如断线诊断值) |
| 27649..32511 | 20..约 22.81 mA | 过量程 (overrange): 合法但超出标称 |
| 0..27648 | 4..20 mA | 额定范围 (normal range): 正常工作区 |
| −6912..−1 | 0..4 mA | 欠量程 (underrange): 0 mA 恰对应 −6912 |
| ≤ −32768 | 断线/短路 | 故障态, 配合通道诊断 |
注意: 若通道组态为 0..20 mA, 则 0 mA 对应 0 而非 −6912; 上表仅适用于组态为 4..20 mA 时。CPU 本体自带的 AI (0..10 V) 分辨率为 10 位, 信号板/信号模块 (SB/SM 1231 等) 可到 12~16 位 (以模块手册为准)。输出侧对称: AQ 额定 0..27648, 过量程到 32511。
6.2 NORM_X + SCALE_X: 标准两段式
思路与 Python 手写 x/(hi-lo) 再 lo + x*(hi-lo) 相同: 先把任意量纲归一到 0.0..1.0, 再定标到工程单位。
// FB "FB_Ai4to20" 接口:
// Input: raw : Int // 来自 %IW (Word 读入后 CONV 成 Int, 或直接 Int)
// eMin, eMax : Real // 工程量程, 例: 0.0 ~ 100.0 (单位自定)
// Output: value : Real // 工程值
// quality : Int // 0=好 1=过量程 2=欠量程 3=故障(溢出)
// valid : Bool // quality=0 时 TRUE
// Static: norm01 : Real
// 代码区:
// 第一步: 判质量。参考 6.1 表 (4..20 mA 组态)
IF #raw >= 32767 OR #raw <= -32768 THEN
#quality := 3; // 溢出/断线区, 数值不可信
ELSIF #raw > 32511 THEN
#quality := 1; // 过量程上限之外 (32512..32766)
ELSIF #raw > 27648 THEN
#quality := 1; // 过量程: 合法, 可选择是否使用
ELSIF #raw < -6912 THEN
#quality := 2; // 深度欠量程
ELSIF #raw < 0 THEN
#quality := 2; // 欠量程 (4 mA 以下)
ELSE
#quality := 0;
END_IF;
// 第二步: NORM_X 把 4..20 mA 的额定区间 (0..27648) 归一到 0.0..1.0
// MIN/MAX 必须与 VALUE 同型 (这里 Int); 输出建议 Real
NORM_X(MIN := 0, VALUE := #raw, MAX := 27648, OUT => #norm01);
// 第三步: SCALE_X 把 0.0..1.0 定标到工程量程
// 注意 SCALE_X 的 VALUE 期望 0.0..1.0, MIN/MAX 是工程单位
SCALE_X(MIN := #eMin, VALUE := #norm01, MAX := #eMax, OUT => #value);
// 第四步: 对带"质量非好"的值做限幅与置无效
IF #quality <> 0 THEN
// 钳到边界, 避免下游拿到外推值; 断线区保持上一拍工程值也可以是另一种策略
#value := LIMIT(MN := #eMin, IN := #value, MX := #eMax);
END_IF;
#valid := (#quality = 0);
语义细节 (容易踩):
NORM_X(MIN, VALUE, MAX)允许 MIN > MAX (反向换算), SCALE_X 同理; 但两段必须方向一致, 否则换算翻转。- NORM_X/SCALE_X 对区间外输入不报错也不夹紧, 只会线性外推 —— 所以质量判断必须自己做, 这是与“带饱和的库函数“的本质区别。
- 若模块组态为 0..20 mA 而现场仪表是 4..20 mA (活零点), 把 NORM_X 的 MIN 改为 5529 (4 mA 在 0..20 mA 标尺上的数字值, 27648 × 0.2 ≈ 5529), MAX 仍 27648, 即可让 4 mA 对应 0%。
- 输出侧同理: 工程值 → NORM_X → SCALE_X 到 0..27648 → CONV 到 Word → %QW。
6.3 滤波与平滑
一阶低通 (PT1) 滤波、滑动平均、以及“坏点剔除 + 保持“的质量机, 在练习章里会以独立练习完整实现 (y += k*(x-y), k 由扫描周期与时间常数折算), 本章不重复展开。要点预告: S7-1200 没有内建的模拟量滤波指令 (部分 SM 模块有硬件滤波, 组态里开), 软件滤波必须自己考虑采样周期不等间隔的问题 (scan cycle 抖动), 所以滤波器要挂循环中断 OB 而不是 OB1。
7. PID: PID_Compact 完整走查
7.1 定位与版本
| 块 | 适用 | 说明 |
|---|---|---|
PID_Compact | 通用过程量 (压力/流量/液位/速度) | V1.x 遗留; V2.x 需 S7-1200 固件 V2.0 以上 (待核实: 具体最低固件以帮助 Requirements 为准); 新项目直接用 V2.x |
PID_Temp | 温度专用 | S7-1200 需固件 V4.0 + STEP 7 V13 SP1 引入; 支持加热+制冷双输出、级联; V2.0 起支持纯制冷 |
PID_Compact 与 PID_Temp 都是库 FB, 拖入即建实例 DB; 所有组态 (量程、输出限幅、采样时间、PID 参数) 都存在实例 DB 的 Config 结构里, 可在 TIA 的组态界面 (工艺对象组态窗口) 里填, 也可在 SCL 里运行期改 —— 但 Config 属于保持性数据, 下载/上载会覆盖, 自整定结果也写在实例 DB 中。
7.2 从组态到 SCL 调用 (完整流程)
- 拖 PID_Compact (Extended > PID control) 到 OB1 的 SCL 代码区, 选 single instance, 命名
PID_DB。 - 打开组态界面 (双击调用处或项目树 “Technology objects” 下的对应项):
- Controller basic settings: Input type 选 Input (工程单位 REAL, 推荐: 你自己先做 NORM_X/SCALE_X) 或 Input_PER (直接接 Word 原始值, 块内自动换算); 标定 PV 上下限; Output 类型同理 (Output / Output_PER / Output_PWM)。
- Advanced settings: 输出限幅、手动值限幅、采样时间
CycleTime(默认由块估计, 见 7.4)。
- 在循环中断 OB (如 OB30, 100 ms) 中调用它 —— PID 的采样时间假设“每次调用间隔恒定“, 放 OB1 会被扫描周期抖动破坏。
// OB30 (100 ms 循环中断) 中的调用 —— 变量在 OB30 的接口/全局 DB 中:
// "PID_DB" : PID_Compact 的实例 DB
// "DB_Analog".PV : Real // 6.2 换算好的工程值
// "DB_Analog".SP : Real // 设定值
// "DB_PID".heat : Real // 输出 0..100 (%)
"PID_DB"(Setpoint := "DB_Analog".SP,
Input := "DB_Analog".PV,
// 手动模式接管 (见 7.5):
ManualEnable := "DB_PID".manualMode,
ManualValue := "DB_PID".manualOut,
// 复位/模式切换 (上升沿有效):
Reset := "DB_PID".reset,
ModeActivate := "DB_PID".modeAct);
"DB_PID".heat := "PID_DB".Output; // 0..100.0
"DB_PID".state := "PID_DB".State; // 控制器状态 (Int)
"DB_PID".err := "PID_DB".Error;
"DB_PID".errBits := "PID_DB".ErrorBits; // DWord, 见下
接口要点 (V2.x):
Input与Input_PER二选一 (组态决定哪个生效);Output/Output_PER/Output_PWM同理。Reset上升沿: 控制器回到未激活状态, 输出置 0; 再由ModeActivate上升沿切换模式。ModeActivate上升沿: 自动/手动模式切换的“确认键“。上电或 Reset 后控制器处于未激活态, 必须给一次 ModeActivate 边沿才会按当前 ManualEnable 进入自动或手动。State(Int) 指示当前所处阶段 (未激活/预整定/精确整定/自动/手动等), 取值表见在线帮助 (待核实: 各值枚举以帮助为准)。Error/ErrorBits: ErrorBits 是 DWord 位掩码; 已核实的典型值16#00000800= 采样时间错误 (PLCSIM 仿真最常见)。
7.3 自整定 (auto-tuning) 流程
- 组态好 Input/Output 标定与输出限幅, 接好真实 (或高保真模拟的) 过程。
- 控制器先处于自动模式且过程量稳定在设定值附近 (预整定要求过程处于稳态, 否则整定结果差)。
- 在调试界面 (工艺对象 > Commissioning) 点 Start pre-tuning + fine-tuning (或分步), 或在 SCL 里对实例 DB 的整定控制位写上升沿 (组态界面里可查到对应位名; 待核实: 位名称随版本变化)。
- 整定完成后新的 Gain/Ti/Td 写回实例 DB 的
sPid_Calc结构, 并提示“是否将参数复制回组态“ (不复制则只存在于实例 DB, 覆盖下载会丢)。
7.4 PLCSIM 仿真的限制 (已核实)
官方明确: PID_Compact V2.x 在一代 S7-1200 上不支持 PLCSIM 仿真; 只有 S7-1500 与 S7-1200 G2 可仿真。此外, 仿真中 PLCSIM 的循环时钟抖动会触发 ErrorBits = 16#00000800 (采样时间错误) 并中止进行中的整定, 官方给出的对策是在实例 DB 中关闭相关检测:
// PID_Compact V2.x (S7-1500 / 1200 G2 仿真时), 在线/离线访问实例 DB:
"PID_DB".CycleTime.EnEstimation := FALSE; // 关闭采样时间自动估计
"PID_DB".CycleTime.EnMonitoring := FALSE; // 关闭采样时间监视
V1.x 的对应做法 (官方 V1 页面): 关闭 sb_EnCyclEstimation / sb_EnCyclMonitoring, 手动给 sPid_Calc.r_Cycle 赋采样时间。两代成员名不同, 以你版本的帮助为准。
7.5 手动模式接管示例
运维常见需求: 自动到一定条件切手动开度。注意 ManualEnable 是电平, ModeActivate 是边沿, 组合逻辑如下:
// "DB_PID" 接口: manualMode, manualOut (0..100), reset, modeAct : Bool
// 上升沿检测:
"DB_PID".modeAct := "DB_PID".manualMode AND NOT "DB_PID".manualMode_last;
IF "DB_PID".manualMode THEN
// 手动: 输出直接跟踪 manualOut (块内部做无扰切换准备)
;
ELSE
// 自动: 正常控制
;
END_IF;
"PID_DB"(Setpoint := "DB_Analog".SP,
Input := "DB_Analog".PV,
ManualEnable := "DB_PID".manualMode,
ManualValue := LIMIT(MN := 0.0, IN := "DB_PID".manualOut, MX := 100.0),
Reset := "DB_PID".reset,
ModeActivate := "DB_PID".modeAct);
"DB_PID".manualMode_last := "DB_PID".manualMode;
PID_Temp 与 PID_Compact 的调用形态几乎一致, 差异在: 加热/制冷双输出 (OutputHeat/OutputCool), 加热制冷切换的死区/滞后组态, 以及针对温度过程 (大滞后) 的整定策略。做温控直接选 PID_Temp, 不要拿 PID_Compact 硬凑。
8. 高速计数器 HSC
8.1 组态思路
S7-1200 的 HSC 是 CPU 内建硬件, 不是指令: 在 Device configuration > CPU 属性 > High speed counters (HSC) 里启用并组态。注意 HSC 与 PTO/PWM 共用物理输出/输入资源 (脉冲发生器占用高速输入作反馈等, 具体复用规则以 CPU 手册为准), 组态冲突 TIA 会报错。
组态项: 功能选择 (counting 计数 / frequency 频率测量 / period 周期测量, 依 HSC 编号可用性不同)、计数类型 (单相加/减、加/减双脉冲、A/B 正交 ×1/×2/×4)、初始/比较值、以及中断事件 (如 CV = RV 比较匹配触发硬件中断 OB)。组态完成后, 当前计数值被映射到一个 32 位输入映像区地址 (I 区, 如 %ID1000), 每个扫描周期由操作系统自动刷新 —— 这是最重要的一个事实: 读 HSC 不需要任何指令, 直接读 %ID。
8.2 SCL 读取与控制
// 周期性读取当前值 (放在循环中断 OB 中):
"DB_Speed".count := %ID1000; // 直接读输入映像, DInt
// CTRL_HSC (Technology > Counting): 运行期改变计数参数 (方向/写新计数 CV/写新参考值 RV)
// 典型用途: 回零时写 0, 或改比较值触发下一档中断
// "HSC_Ctrl_DB" : CTRL_HSC 实例, 组态时已关联具体 HSC 硬件对象
IF "DB_Hsc".doWriteZero THEN
"HSC_Ctrl_DB".CV := TRUE; // 允许写新当前值
"HSC_Ctrl_DB".NewCV := 0; // 新计数初值 (成员名待核实, 以帮助为准)
"HSC_Ctrl_DB".REQ := TRUE;
END_IF;
// REQ 完成后由 Busy=FALSE 收尾, 具体成员名以在线帮助的 CTRL_HSC 参数表为准
上面的 CTRL_HSC 成员名在不同 TIA 版本 (legacy CTRL_HSC 与较新的 CTRL_HSC_EXT) 有差异, 使用前以 F1 参数表核对; 但“读 %ID 不需要指令“这一点在所有版本都成立。
8.3 编码器测速示例思路
两种做法:
- 频率测量模式: HSC 组态为 frequency measurement, %ID 直接给出 Hz (每秒脉冲数)。换算:
rpm := freq_Hz * 60.0 / pulses_per_rev(pulses_per_rev = 编码器线数 × 倍频)。适合中高速; 低速时刷新周期内脉冲太少导致量化误差大。 - 周期测量模式 (T 法, 低速优): HSC 组态为 period measurement, 测量固定脉冲数的时间,
%ID给出周期值,rpm ∝ 1/period。 - M 法 (通用): 计数模式 + 循环中断固定周期采样 %ID 差分:
rpm := DINT_TO_REAL(count_now - count_last) * 60.0 / (pulses_per_rev * sample_s), 差分要用无符号回绕安全的算法 (DInt 减法天然模 2^32 回绕, 直接相减再解释即可, 与 C 的无符号减法同理)。
选型口诀: 高速用 M 法 (频率模式), 低速用 T 法 (周期模式), 全范围用 M/T 切换 —— 与编码器测速的所有嵌入式方案同构。
9. 运动控制 (PTO 基本定位)
S7-1200 的运动控制 = PTO (Pulse Train Output) 脉冲输出 + 工艺对象 (Technology Object, TO) + PLCopen 指令。要求: S7-1200 固件 V4.0 起支持 (对应 TIA V13 时代引入), TO 本身有版本 (V4.0~V7.x, 在指令任务卡 Technology > Motion control 下选版本); 一代 CPU 各型号集成 2~4 路 PTO (1215C 为 4 路, 其余多为 2 路, 以样本手册为准)。步进/伺服驱动器接脉冲+方向, 位置闭环在驱动器内, PLC 侧是“脉冲数即位置“的半闭环。
三步走:
- 组态 TO: 项目树 Add new technology object > Positioning axis (TO_PositioningAxis), 组态 PTO 脉冲源、方向输出、加减速、回零方式、软限位、跟随误差。
- MC_Power 使能轴 (必须每周期调用):
// "Axis1_Power_DB" 等实例 DB; 轴与 TO 的关联在插入指令时组态 (不是形参)
"Axis1_Power_DB"(Enable := "DB_Mc".powerOn,
StopMode := FALSE); // FALSE=受控停止
- MC_MoveJog (点动) / MC_MoveRelative (相对定位):
// 点动: JogForward 按住正转
"Axis1_Jog_DB"(JogForward := "DB_Mc".jogF,
JogBackward := "DB_Mc".jogB,
Velocity := 100.0); // 单位由 TO 组态决定 (如 mm/s 或 rpm)
// 相对移动: Execute 上升沿启动, 走 500.0 个单位
"Axis1_Rel_DB"(Execute := "DB_Mc".startRel,
Distance := 500.0,
Velocity := 200.0);
// 读取轴状态
"DB_Mc".busy := "Axis1_Rel_DB".Busy;
"DB_Mc".done := "Axis1_Rel_DB".Done;
"DB_Mc".axisPos := "Axis1".ActualPosition; // TO 的动态数据 (符号访问)
完整指令族一览: MC_Power(使能), MC_Reset(故障复位), MC_Home(回零), MC_Halt(暂停), MC_MoveJog(点动), MC_MoveRelative(相对), MC_MoveAbsolute(绝对), MC_MoveVelocity(速度控制), MC_GroupInterrupt/MC_GroupContinue(组中断/恢复, 版本相关, 待核实 1200 可用性)。共同编程规则: MC_Power/MC_Reset 等“管理类“每周期调用; “执行类”(Move/Home) 用 Execute 上升沿触发, Busy/Done/CommandAborted/Error 报状态 —— 这是一台显式状态机, 和 C 里手写 motion state machine 的差别在于状态机被标准化了。
10. 通信
10.0 PLCSIM 仿真支持度总表 (先看这个再选方案)
| 功能 | 标准 PLCSIM (V16~V21) | 说明 |
|---|---|---|
| TSEND_C/TRCV_C (OUC) | 部分 | 仅经内部 Softbus 在本机内互通, 无真实 TCP/IP; 与外部 PC 程序通信不可仿真 |
| MB_CLIENT / MB_SERVER (Modbus TCP) | 不支持 | 需真实 CPU 或 PLCSIM Advanced (Advanced V8+ 才支持 1200 G2, 一代 1200 不支持) |
| PROFINET IO controller | 不支持真实 IO | PLCSIM 内无 PROFINET IO 设备可挂 (仿真 PN 设备需第三方工具) |
| OPC UA Server | 不仿真 | 官方对比表明确无 OPC UA |
| Web server | 无 | 官方对比表明确 |
结论: 通信类功能的学习与验证必须上真实 CPU; PLCSIM 只能验证指令调用逻辑与状态机 (还常因时钟问题误报错误)。
10.1 TSEND_C / TRCV_C (开放用户通信, 与 socket 类比)
OUC = CPU 集成网口上的原生 TCP/UDP 套接字通信。类比表:
| socket API | TIA 对应 |
|---|---|
socket() + connect() | TCON (或 TSEND_C/TRCV_C 内建连接管理) |
send() | TSEND / TSEND_C |
recv() | TRCV / TRCV_C |
close() | TDISCON |
bind()+listen() | TCON 组态为被动 (服务端) 模式 |
TSEND_C = “建连 + 发送” 的合体 (带 CONT 参数控制连接保持), TRCV_C = “建连 + 接收” 的合体。连接参数 (对端 IP/port、连接 ID、TCP 还是 UDP) 不在参数表里, 而在指令实例的属性面板 (Configuration > Connection data) 中组态, 存在一个连接 DB (如 TCON_IP_v4) 里。
最小可用示例 —— 每 1 秒发送 8 字节, 异步接收:
// OB1 / 循环中断中调用。变量:
// "DB_OUC".sendReq : Bool // TON 产生的 1s 脉冲
// "DB_OUC".txBuf : Array[0..7] of Byte
// "DB_OUC".rxBuf : Array[0..63] of Byte
// "DB_OUC".rcvdLen : UInt
// 实例: "TS_CDB" (TSEND_C), "TR_CDB" (TRCV_C)
// 发送: REQ 上升沿触发; CONT=TRUE 保持连接
"TS_CDB"(REQ := "DB_OUC".sendReq,
CONT := TRUE,
DATA := "DB_OUC".txBuf,
LEN := 8);
// 接收: EN_R=TRUE 常开接收; NDR=TRUE 表示收到新数据
"TR_CDB"(EN_R := TRUE,
CONT := TRUE,
DATA := "DB_OUC".rxBuf,
LEN := 0, // 0 = 接收最多到 DATA 尺寸
NDR => "DB_OUC". newData,
RCVD_LEN => "DB_OUC".rcvdLen,
ERROR => "DB_OUC".rxErr,
STATUS => "DB_OUC".rxStatus);
要点:
- 这些指令是异步的: REQ 发出后要靠 BUSY/DONE/ERROR/STATUS 状态机轮询, 不是阻塞调用 —— 类似非阻塞 socket + 事件标志, 而不是 Python
socket.send()一把梭。 STATUS(Word) 在 ERROR=FALSE 时是通知码 (如 1=状态切换), ERROR=TRUE 时是错误码, 必须区分读。- 字节序: S7 内存按大端存 16/32 位值, TCP 线上原样发送, 所以 Python 端用
struct.unpack('>h', ...)即可直接解析, 无需翻转。
配套 Python 测试端 (真机调试用):
# echo 服务器: 与 PLC 的 TSEND_C/TRCV_C 对测 (PLC 侧组态对端 IP=本机, port=2000)
import socket
srv = socket.socket(); srv.bind(('0.0.0.0', 2000)); srv.listen(1)
conn, _ = srv.accept()
while True:
data = conn.recv(64)
if not data: break
print(data.hex())
conn.send(data) # 回发, PLC 的 TRCV_C 会收到
10.2 Modbus TCP (MB_CLIENT / MB_SERVER)
S7-1200 既是 Modbus TCP client (MB_CLIENT) 也可作 server (MB_SERVER)。与 OUC 的区别: Modbus TCP 是带标准寄存器模型的应用层协议, 适合与第三方设备 (变频器、仪表、网关) 交互; 同网口可共存。
布局硬性要求 (寄存器 ↔ DB 映射):
- 数据缓冲 (
MB_CLIENT.DATA_PTR/MB_SERVER.MB_HOLD_REG) 必须指向标准 (非优化) DB 或 M 存储区 —— 优化 DB 会报错 (典型 STATUS 8383/8384 类错误)。做法: 新建 DB 时在属性里取消勾选 “Optimized block access”。 - Modbus 寄存器 = 16 位 Word; DB 里用
Array[0..N] of Word(或连续的 Word/DWord 结构体) 排布, 不要在中间插 Bool/Byte 破坏连续性; Bool 量凑成 16 的倍数打包进 Word。 - 字节序坑: S7 的 Word 本身是大端 (与 Modbus 线序一致), 单寄存器无问题; 但 32 位值 (DInt/Real) 占两个寄存器, 很多第三方设备 (尤其部分国产表/网关) 是 little-endian 字序 (低字在前), 这时要么设备侧改字序设置, 要么 PLC 侧用
SWAP+ 拼接手动换:
// Input: regLo, regHi : Word (两个保持寄存器, 字序存疑时)
// Output: valBE, valLE : DInt
// 大端字序 (高字在前 = regHi 是高 16 位):
#valBE := CONV(DInt, SHL(IN := CONV(DWord, #regHi), N := 16) OR CONV(DWord, #regLo));
// 小端字序 (低字在前): 交换两个字即可
#valLE := CONV(DInt, SHL(IN := CONV(DWord, #regLo), N := 16) OR CONV(DWord, #regHi));
// Real 场景: 同样拼出 DWord 后用 SCAT/位重解释, 或标准 DB 中直接以 Real 声明并整体 SWAP
MB_CLIENT 最小示例 (周期读 4 个保持寄存器, 40001 起):
// 变量:
// "MBMap" (标准 DB): holdRegs : Array[0..3] of Word
// "DB_Mb".req : Bool (定时脉冲), .done, .busy, .err : Bool; .status : Word
// 实例 "MB_CL" : MB_CLIENT
// 连接参数在实例属性中组态: 对端 IP、端口 502、连接 ID、MB_UNIT_ID
"MB_CL"(REQ := "DB_Mb".req,
MB_ADDR := 1, // Modbus 站地址 (unit id), 0..247
MODE := 0, // 0=读 1=写
DATA_ADDR := 40001, // 保持寄存器起始 (Modbus 习惯地址; 40001=第一个 4x 寄存器)
DATA_LEN := 4, // 读 4 个寄存器
DATA_PTR := "MBMap".holdRegs,
DONE => "DB_Mb".done,
BUSY => "DB_Mb".busy,
ERROR => "DB_Mb".err,
STATUS => "DB_Mb".status);
MB_SERVER 最小用法: 组态端口 (默认 502), MB_HOLD_REG 指向标准 DB 的 Word 数组, 客户端 (如 PC 上 pymodbus) 读 40001 起的寄存器即映射到数组 [0]:
"MB_SRV"(DISCONNECT := FALSE,
MB_HOLD_REG := "MBMap".holdRegs); // 供客户端读写的寄存器区
注意: MB_SERVER 在 1200 上主要支持保持寄存器 (读写 4x 区); 线圈/离散量 I/O 的支持情况随固件版本演进, 用前查帮助 (待核实)。地址习惯: DATA_ADDR 用 Modbus 习惯地址 (4xxxx), 而非 0 基协议地址 —— 这是与 pymodbus (read_holding_registers(0, ...) 用 0 基) 对接时最常见的差一错误源。
10.3 PROFINET IO controller (概念)
S7-1200 的集成网口默认可充当 PROFINET IO controller: 在 Devices & Networks > Network view 里拖入 IO 设备 (西门子 ET 200SP 远程 IO、带 GSD 文件的第三方设备, 或另一台组态为智能设备 (IO device) 的 CPU), 用网线/拓扑连接并分配 IO 设备名与 IP。之后不需要写任何通信代码: 远程 IO 的输入/输出被操作系统周期性 (PROFINET RT, 默认 1~2 ms 发送时钟, 组态可调) 映射进本地过程映像, SCL 里就像访问本地 I/O 一样 %I0.0 / 符号访问。类比: PROFINET GSD+组态 ≈ Linux device tree + 内核驱动, 你写的是应用层。诊断: 断线等产生机架/站故障 OB86 类事件 (S7-1200 上对应拔插/站故障事件, 优先级 6), 或在组态里为子模块设硬件中断。注意一代 S7-1200 只支持 RT, 不支持 IRT (G2 才支持, 见 02 章硬件对比)。
10.4 OPC UA Server (组态 + 客户端读取)
固件要求 (已核实): 一代 S7-1200 固件 V4.4 起内置 OPC UA Server (V4.5 增加方法调用与结构化数据访问); G2 亦内置 (需较新固件, 第三方资料称 v4.1 起, 待核实)。注意区别于 Web server: OPC UA 是面向 SCADA/IT 的数据接口, 不是网页。
组态步骤:
- CPU 属性 > OPC UA Server: 勾选激活; 选地址 (默认 4840); 配 Server interface (新增一个 server interface 块, 把要暴露的变量拖进去, 可分组/设读写权限); 安全策略按需 (最低 None 无加密, 生产建议至少 Basic256Sha256 签名加密并管好证书)。
- 编译下载。客户端测试 (Python,
asyncua或 UaExpert 图形客户端):
# pip install asyncua
from asyncua.sync import Client
with Client("opc.tcp://192.168.0.1:4840") as c:
v = c.get_node("ns=3;s=\"DB_Opc\".\"speed\"") # 命名空间与节点名以 TIA 生成的地址为准
print(v.read_value())
限制: 一代 1200 的 UA Server 以读/写变量为主 (V4.5 前无方法与结构化类型); 订阅 (monitored items) 数量与采样率受 CPU 性能限制, 大量高频数据建议走别的路 (如 OUC)。
10.5 内置 Web server
CPU 属性 > Web server: 勾选激活, 配置用户与权限 (只读诊断用户/管理员), 浏览器访问 http://<cpu-ip>。能看到的标准页面 (以 CPU 手册 Web server 章为准):
- 概览/标识页: CPU 状态、运行模式、IP、固件版本;
- 诊断缓冲 (diagnostic buffer): 与 TIA 在线看到的一致, 现场 laptop-less 排障第一入口;
- 模块状态、连接表、PROFINET 拓扑;
- Data log 页面: 把 SCL 数据日志 (Data log 指令写入的 CSV) 直接下载回 Excel 分析;
- 用户管理下可远程改 CPU 运行模式 (需相应权限)。
自定义页面: 用西门子 Web2PLS 工具 (SIOS 68011496 应用示例) 把 HTML+JS 处理成 WWW 数据块下载进 CPU, 页面通过 AWP 命令读写 PLC 变量 —— 相当于给 CPU 挂一个只读为主的轻量 dashboard。注意 PLCSIM 无 Web server, 须真机调试。
11. 库工程化: 项目库、全局库、第三方库
11.1 两级库与版本控制 (类比 npm + git)
| 概念 | TIA 机制 | 类比 |
|---|---|---|
| 项目库 (Project library) | 随项目文件保存的私有库 | 项目内 vendor/ 目录或 private registry |
| 全局库 (Global library) | 独立 .al16/.al17/.al18/... 文件 (扩展名随 TIA 版本), 跨项目共享 | npm registry / git 子模块 |
| 库类型 (Library type) | 库中的 FB/FC/UDT/全局 DB 常量等, 带版本号, 可随修改递增版本、保留历史版本 | npm 包的 version + git tag |
| 库副本 (Library copy) | 从库拖到项目里的一次使用实例; 项目内修改不回写库, 除非“作为类型上传回库“ | node_modules 里的副本 vs registry 里的包 |
| 类型版本调用 | 项目中的调用可钉在旧版本, 或“更新调用“升到新版本 | package.json 钉版本 vs npm update |
工程化要点:
- 把稳定代码沉到库, 把项目差异留在调用参数: 库类型接口一旦被别的项目引用, 改接口必须升版本而不是原地改语义 —— 和 semver 的破坏性变更同理。
- 版本更新链路: 修改项目中的库副本 → 右键“上传到库“并选升版本 (如 0.1 → 0.2) → 其他项目“更新调用“。全局库文件本身用 git 管理 (
.al18是二进制, diff 无意义, 但可追踪版本节点); 也有团队用“库项目 (library project)+ 库版本发行“工作流, 官方称 Type/version 一致性检查会在下载时校验版本漂移。 - 全局库文件向后兼容性差: 高版本 TIA 可打开低版本库 (升级), 反向不行 —— 与 TIA 项目一样只能往上走。
11.2 导出/导入与第三方库
- 全局库导出/导入即拷贝
.al1x文件; 老项目块可用 “External source” (导出.scl/.awl源) 交换纯代码, UDT/FB/FC 均可 (类似把 C 源码 tar 出来)。 - 西门子官方库: LBC (Library of General Functions, 通用函数库) 自带于 TIA, 含边沿检测、去抖、限幅、看门狗等通用封装, 新手可直接读它的 SCL 源码学风格。
- OSCAT (Open Source Community for Automation Technology, oscat.de) 是工业自动化领域最大的开源块库 (数百个 FB/FC: 数学、控制、字符串、网络)。它原生面向 CODESYS, 社区有人移植到 TIA。移植注意:
- OSCAT 大量使用 ANY/POINTER/引用与内存映射, 而 S7-1200 接口不支持 POINTER/ANY/REF_TO (1500 才有) —— 这些块必须改写为 VARIANT 或显式数组参数才能在 1200 用;
- 数组变址下限: OSCAT 常按 0 基, TIA 数组上下限任意, 逐块核对;
- STRING 处理 (前 2 字节头 + 长度语义) 与 CODESYS 不同, 字符串块几乎都要手改;
- 优化的访问模型差异: OSCAT 里若用了绝对地址/AT 覆盖, 在优化块上不成立。 结论: OSCAT 在 1200 上“当算法参考实现“价值最大 (读伪代码级 SCL/ST 源码), 整库搬用前逐块审查。
12. 诊断类指令与系统功能一览
12.1 GET_ERROR / GET_ERR_ID
S7-1200 没有 OB121/OB122 (编程错误/I/O 访问错误组织块), 替代机制是块内局部错误处理:
// 在任意块中, 手动读最近一次块内错误 (在块内放置 GET_ERROR/GET_ERR_ID 指令即启用该块的局部错误处理——这不是块属性开关):
// "DB_Diag".err : ErrorStruct (系统预定义结构体类型)
IF "DB_Diag".checkErr THEN
GET_ERROR(ERR => "DB_Diag".err); // 详细: 错误 ID + 块/偏移 + 区域信息
GET_ERR_ID(ID => "DB_Diag".errId); // 轻量: 只要 16 位错误码
END_IF;
语义: 这两个指令读走当前块最近发生的编程/访问错误 (读后即清), 相当于 errno + strerror 的组合; 不启用局部处理时, 错误写诊断缓冲且 CPU 保持 RUN。用它做“防御性日志点“比依赖 CPU STOP 更符合 24×7 连续运行的需求。
12.2 RD_SYS_T 与时间类
// 读系统时间 (DTL, 12 字节: 1970-01-01 ~ 2262):
RD_SYS_T(OUT => "DB_Clock".now);
// 写系统时间 (需权限, 慎用): WR_SYS_T(IN := "DB_Clock".set);
// 读本地时间 (按 CPU 时区组态偏移): RD_LOC_T(OUT => "DB_Clock".local);
// 计时基准: 注意 TIME_TCK() 是 S7-1500 专属指令, 在 1200 上编译报错!
// S7-1200 测耗时用 RUNTIME() (返回 LReal 秒; 内部计数器溢出时返回 <= 0, 该次读数应忽略):
"DB_Clock".elapsed := RUNTIME();
TIME 类型是 32 位有符号毫秒, 范围 ±24d20h31m23.647s; S7-1200 不支持 LTIME (1500 专属)。
12.3 常用系统功能一览表
| 指令 | 类别 | 用途 | 备注 |
|---|---|---|---|
GET_ERROR / GET_ERR_ID | 诊断 | 读块内错误 (1200 的 OB121 替代) | 见 12.1 |
RD_SYS_T / WR_SYS_T / RD_LOC_T | 时间 | 系统时间读写 (DTL) | WR 需相应权限 |
RUNTIME | 时间 | 耗时测量, 返回 LReal 秒 (1200 可用) | 内部计数器溢出时返回 <= 0 应忽略; 注意 TIME_TCK() 为 S7-1500 专属, 1200 编译报错 |
RE_TRIGR | 看门狗 | 重启当前扫描的监视计时 | 当前周期须 < 10×最大扫描时间 (默认 150 ms, 1..6000 ms 可配) |
STP | 控制 | 把 CPU 切到 STOP | 调试/致命错误兜底 |
ATTACH / DETACH | 中断 | 运行期把事件 (如硬件中断) 动态挂/摘到指定 OB | 比静态组态灵活 |
RDREC / WRREC | 诊断 | 读写模块数据记录 (细粒度模块诊断/组态) | 参数复杂, 配合模块手册 |
RALRM | 中断 | 在硬件中断 OB 里取中断详情 | 1200 支持 (待核实: 依固件版本) |
TSEND/TRCV/TCON/TDISCON | OUC | 底层 socket 族 | 见 10.1 |
TSEND_C/TRCV_C | OUC | 带连接管理的封装 | 见 10.1 |
MB_CLIENT/MB_SERVER | Modbus | Modbus TCP 主/从 | 见 10.2 |
CTRL_HSC | HSC | 运行期改 HSC 参数 | 读计数值用 %ID 直读 |
PID_Compact / PID_Temp | PID | 见第 7 节 | |
Data log (LOG_GEN 等) | 数据记录 | 写 CSV 到 CPU/存储卡, 经 Web server 下载 | PLCSIM 不仿真 Web |
RTM / 运行小时计 | 维护 | 操作系统运行时计数器 | 1200 支持情况以 CPU 属性/帮助为准 (待核实) |
诊断缓冲的软件侧入口: TIA 在线诊断对话框; Web server 诊断页 (10.5); 或 GetSystemError 类库块 (待核实名称与 1200 可用性) —— 一般前两者已够用。
13. 收尾: 用库思维写 SCL
把本章所有内容压缩成可执行的工程习惯:
- 先搜库再写循环: LBC、PID_Compact、MC_xxx、MB_CLIENT 都是“官方 pip 包“; 自研一个通用函数前先 F1 搜指令卡与 LBC。90% 的“我写个工具 FB“在西门子生态里已有带测试的版本。
- 每个 FB 都按“库类型“标准写: 参数全命名化、接口一次定稳、语义内聚 (一个 FB 一件事)、不偷写全局 DB —— 今天的项目块就是明天的库类型。接口演进靠版本号, 不靠原地改语义。
- 状态机思维而不是阻塞思维: TSEND_C 的 DONE/BUSY/ERROR、MC 指令的 Busy/Done、PID 的 State, 全是显式状态机。写 SCL 时自己的功能也按“输入边沿触发 + 状态字 + 完成位“的模式封装, 调用者用起来就和官方库一致。
- 错误处理三件套: ENO/ERROR+STATUS 结构贯穿所有库块, 自己的库块也输出同构的 (done, busy, error, status) 四元组; 1200 上没有异常机制, “留痕不中断“是唯一正解, GET_ERROR 兜底。
- 数据接口要“布局自觉“: 模拟量按 0..27648 标尺 + 质量位; 通信缓冲用标准 DB + Word 对齐 + 字节序显式约定 (SWAP 在手); 跨界数据结构写成 UDT 进库, 别散落各 DB。
- 能组态的不编程: PID、HSC、运动控制、PROFINET 的参数都在组态/实例 DB 里, 代码只做“调用 + 状态机 + 边沿“; 组态参数变化要纳入版本管理 (项目文件即配置)。
- PLCSIM 是逻辑仿真器, 不是控制器仿真器: 时钟敏感 (PID) 与网络功能 (OUC/Modbus/OPC UA/Web) 不仿真或行为失真, 上真机前把这两类验证单列。
- F1 是唯一权威: 本章所有事实均可在 TIA 在线帮助 / S7-1200 manual collection 对应页复核; 标注 (待核实) 之处, 使用前请以你手上版本的 F1 为准。
参考来源:
- S7-1200 手册集合 (TIA Portal V20 在线帮助): https://docs.tia.siemens.cloud/r/simatic_s7_1200_manual_collection_enus_20
- SCL 指令参考 (S7-1200/S7-1500, V20): https://docs.tia.siemens.cloud/r/en-us/v20/scl-s7-1200-s7-1500
- PID_Compact V2.x PLCSIM 仿真: https://docs.tia.siemens.cloud/r/en-us/v20/using-pid_compact-s7-1200-s7-1500/pid_compact-as-of-v2-s7-1200-s7-1500/simulating-pid_compact-as-of-v2-with-plcsim-s7-1200-s7-1500
- PLCSIM 产品对比 (TCP/Web/OPC UA/Trace): https://docs.tia.siemens.cloud/r/simatic_s7_1500_et_200mp_manual_collection_enus_21/comprehensive-information/cpu-function-manuals/s7-plcsim-advanced/product-overview/s7-plcsim-products
- MB_CLIENT 指令 (S7-1200 手册集合): https://docs.tia.siemens.cloud/r/simatic_s7_1200_manual_collection_enus_20/communication-processor-and-modbus-tcp/modbus-communication/modbus-tcp/modbus-tcp-instructions/mb_client-communicate-using-profinet-as-modbus-tcp-client-instruction
- CTRL_HSC 指令 (S7-1200 手册集合): https://docs.tia.siemens.cloud/r/simatic_s7_1200_manual_collection_enus_20/technology-instructions/counting-high-speed-counters/legacy-ctrl_hsc-control-high-speed-counter-instruction/ctrl_hsc-control-high-speed-counter
- S7-1200 运动控制功能手册 (109773400): https://support.industry.siemens.com/cs/attachments/109773400/s71200_motion_control_function_manual_en-US_en-US.pdf
- 模拟量表示范围 (S7-1200 G2 手册集合, 数值对照): https://docs.tia.siemens.cloud/r/simatic_s7_1200_g2_manual_collection_zhcn_20/technical-specifications/analog-signal-boards-sbs/measurement-ranges-of-the-analog-inputs-for-voltage-and-current
- OPC UA for S7-1200/1500 (固件 V4.4 要求): https://docs.tia.siemens.cloud/r/simatic_et_200bl_manual_collection_frfr_20/comprehensive-information/communication-function-manuals/communication/opc-ua-communication/what-you-need-to-know-about-opc-ua/opc-ua-for-s7-1200/s7-1500-cpus
- 用户自定义 Web 页面应用示例 (SIOS 68011496): https://support.industry.siemens.com/cs/document/68011496/
- Web server 概览 (S7-1200 手册集合): https://docs.tia.siemens.cloud/r/simatic_s7_1200_manual_collection_frfr_20/web-server/web-server-overview
- PID_Temp 多区控制应用例 (109740463): https://cache.industry.siemens.com/dl/files/463/109740463/att_993000/v1/109740463_PidTemp_MultiZone_DOC_V11_en.pdf
- MB_CLIENT DATA_PTR 标准库要求 (SIOS 91696622): https://support.industry.siemens.com/cs/mdm/91696622
- 4-20 mA 换算数值解说 (第三方对照): https://industrialmonitordirect.com/blogs/knowledgebase/siemens-s7-1200-analog-input-4-20ma-scaling-explained