
简介针对工业自动化中模拟量信号处理与重复编程的痛点这份基于 TIA 博途与 SCL 语言的技术文档面向 PLC 编程人员和自动化项目工程师系统讲解模拟量输入输出全局库的设计思路与实现细节集成高/低报警与死区滤波功能可直接用于工程项目的标准化模块开发。文档仅包含 1 个 docx 文件压缩包约 689KB内容围绕模拟量输入块、模拟量输出块和全局库封装展开先说明 FB 的接口变量定义与量程转换公式再介绍单双极性选择、超上下限自动处理方法以及如何结合死区宽度抑制噪声并生成稳定报警信号最后演示将程序封装为跨项目调用的全局库并提供 V2 版本库文件的使用说明。目前已有 931 人学习下载适合希望提高 PLC 编程效率、统一模拟量处理逻辑并增强系统稳定性的工业自动化从业者。1. 用SCL做模拟量I/O全局库把反复画的图纸变成可复用的模块设备调试时最烦人的往往不是PID而是每个模拟量通道的量程转换、滤波限幅和报警处理。每个项目里都有人把同一套逻辑用梯形图重画一遍报警阈值散落在几十个网络里改一个量程要翻遍整个程序。把SCL写成的模拟量输入输出处理逻辑放进TIA博途全局库一次设计、多次调用报警和滤波能跟随库版本统一升级新项目只拖块不写逻辑。这篇文章从SCL语言的适用性讲起给出可直接建立的UDT、滤波FC、输入报警FB、输出斜坡FB并介绍如何导入全局库并完成参数整定。适合在用TIA博途V13以上版本、想用结构化文本来统一模拟量处理逻辑的自动化工程师。2. 模拟量处理的理论与全局库结构设计要让库不只是“一个函数”先得把信号链路拆开。模拟量通道从硬件采集到HMI显示至少经过原始值读取、量程归一化、滤波、报警判断和输出限幅五个环节。如果每个工程师都按自己的习惯写项目越大越难维护。在TIA博途中把这类逻辑收拢到全局库依赖的是SCL语言对数据运算和流程控制的支持。SCL不是用来替代梯形图的而是用来封装那些“每次做都一样、但又不愿意每次重新排线”的算法。2.1 SCL语言为什么适合做功能库优点与边界SCL结构化控制语言是IEC 61131-3标准下的文本语言语法接近Pascal。做模拟量算法时它的优点是表达式直接、分支清楚可以写多层IF和FOR循环做线性插值、移动平均、滞回比较都比梯形图省网络。在库开发中SCL最常见的用法是写带参数化接口的FB和FC外部调用者只关心输入输出参数内部处理细节被封装起来。TIA博途的全局库本意就是让这类FB跨项目复用而SCL恰好能把算法写清楚适合长期维护。不过SCL也有边界。早期版本没有真正的指针处理批量通道时通常要用VAR_IN_OUT或者Variant接口不能像高级语言那样灵活地操作任意地址。有的工程师会把所有通道装进数组用FOR循环遍历这时要留意PLC扫描周期和循环指令耗时。另一个常见误区是把SCL当计算机语言写复杂状态机嵌套过深在线监控很不方便。库内代码尽量保持层次浅把单算法拆成小型FC或FB方便逐层调试。2.2 模拟量处理信号链量程转换、滤波、报警的顺序模拟量处理的基本顺序是先规格化再滤波最后做报警比较。原始值可能是0到27648的整数也可能来自总线上的REAL。量程转换用线性比例关系即可先把原始值归一化再映射到工程量程。在SCL里可以这样写不需要NORM_X和SCALE_X指令块rNorm : (rRaw - rRawLo) / (rRawHi - rRawLo); rScaled : rEngLo rNorm * (rEngHi - rEngLo);这段代码适合S7-1200/1500全系列不会因为固件版本不同出现指令差异。rScaled是工程量供PID、HMI和报警比较使用。量程转换应该限制原始值的上下边界不然超出量程的信号会把工程值推到比例范围外。常见做法是加MIN/MAX限幅或把超量程标记为质量故障。滤波放在线性缩放之后目的是让报警和调节环节看到平滑的工程量。常用的滤波方式有三类限幅滤波适合消除信号尖峰移动平均适合周期性噪声一阶惯性滤波适合热工过程。滤波参数的作用范围差异很大可以用下表快速对比滤波方式适用场景需要设定的参数曲线特点限幅滤波偶发尖峰如电磁干扰相邻差值上限毛刺被削平趋势保持原样移动平均周期性波动如泵振动窗口长度曲线平滑但滞后与窗口正相关PT1惯性滤波温度、液位等缓慢过程时间常数平滑度由时间常数控制高频噪声衰减明显报警比较通常在滤波之后进行但保护性限值最好同时看原始值。如果液位下降速率很快滤波延迟可能导致高报不触发。为了兼顾稳定和快速可以在报警FC里同时接收滤波值和原始值报警逻辑按“取大”或“取小”组合。2.3 全局库的内容和文件布局全局库不只是一个FB。我一般把三类对象放进库函数块FB、函数FC和全局数据类型UDT。它们的接口保持同一个命名前缀版本集体提升避免多个项目混用不同结构。模拟量输入库至少要有UDT_AnalogChannel保存通道参数和状态FB_AnalogIn负责线性缩放和滤波FC_AlarmCompare负责上下限报警判断。模拟量输出库则用一个FB_AnalogOut做限幅、斜坡和安全值输出。库对象类型主要职责对外接口UDT_AnalogChannel结构保存通道参数与在线状态作为FB的VAR_IN_OUTFB_AnalogIn功能块量程转换、滤波、调用报警输入原始值输出工程值和报警位FC_AlarmCompare函数滞回比较防止输出抖动输入当前值、限值、滞回区间FB_AnalogOut功能块输出限幅、斜坡限制、安全值输入设定值输出AO值在TIA博途中创建全局库可在左侧“库”选项卡里新建类型然后右键选择“存储为”并拖动对象到全局库。全局库可以导出成独立库文件便于团队成员共享。项目库只属于当前项目全局库可以被多个TIA项目打开。两者的选择取决于是要长期沉淀成企业标准还是只在当前项目内部复用。3. 用SCL实现带报警和滤波的模拟量输入输出FB把设计变成可编译的SCL最好的起点是从数据结构的定义开始。模拟量通道的参数多如果每个FB输入都列十几二十个引脚调用时很容易漏填或填错。用UDT把通道参数和状态打包成一个整体FB只是更新这个结构既清晰又方便在监控表里整体查看。3.1 定义UDT_AnalogChannel一个结构管住一个通道单个模拟量输入通道需要量程上下限、滤波方式、滤波时间常数、报警上下限、滞回区间和在线状态。把这些字段放在同一个UDT里实例化时就等于拿到了一个独立的通道对象。在TIA博途的“PLC数据类型”中新建如下结构TYPE UDT_AnalogChannel STRUCT rRawLo : REAL; // 原始值下限如 0.0 rRawHi : REAL; // 原始值上限如 27648.0 rEngLo : REAL; // 工程值下限如 0.0 rEngHi : REAL; // 工程值上限如 100.0 iFilterMode : INT; // 0-不过滤1-PT12-移动平均 rFilterT : REAL; // PT1时间常数单位秒 rLastOut : REAL; // 上次滤波输出由FB更新 rScaled : REAL; // 滤波后的工程值 rAlmHi : REAL; // 高报警限值 rAlmLo : REAL; // 低报警限值 rHysHi : REAL; // 高报警返回滞回 rHysLo : REAL; // 低报警返回滞回 bAlmHi : BOOL; // 高报警状态 bAlmLo : BOOL; // 低报警状态 bEnable : BOOL; // 通道使能 END_STRUCT END_TYPE这段定义把滤波所需的中间量rLastOut也放进了结构而不是放在FB静态变量里。这样做的原因是后边的滤波FC不占用FB实例可以被多个通道共享调用中间状态放在通道自己的数据结构中互不干扰。3.2 滤波FC与输入FB的SCL实现PT1和移动平均滤波功能建议写成FC因为FC不消耗背景数据块调用灵活。下面这个FC_Filter支持三种模式不过滤、PT1惯性滤波和双值移动平均。真实的移动平均窗口较大需要在通道结构中增加数组这里用一个简化版本说明调用方式FUNCTION FC_Filter VAR_INPUT rVal : REAL; // 输入的工程量 iMode : INT; // 滤波模式 rT : REAL; // PT1时间常数 dt : REAL; // 采样周期单位秒 END_VAR VAR_IN_OUT rLast : REAL; // 上次滤波输出 END_VAR VAR_OUTPUT rFval : REAL; // 本次滤波输出 END_VAR IF iMode 0 OR rT 0.0 THEN rFval : rVal; ELSIF iMode 1 THEN // PT1滤波系数 1 - e^(-dt/T) rFval : rLast (rVal - rLast) * (1.0 - EXP(-dt / rT)); ELSE // 简化的双值滑动平均 rFval : (rVal rLast) / 2.0; END_IF; rLast : rFval;dt是功能块两次执行的间隔。工程中若OB1固定为10ms循环可以传入0.01若循环不固定建议在调用侧用Time计算后转成REAL。这样滤波系数才符合实际运行的周期。PT1的时间常数rT越大曲线越平滑但信号滞后越明显报警比较必须考虑这个滞后所以前面才强调“滤波后置报警、前置限幅保护”的折中。有了FC_Filter再写FB_AnalogIn把量程转换、滤波和后续报警串起来。FB_AnalogIn负责维护UDT_AnalogChannel结构并调用滤波FCFUNCTION_BLOCK FB_AnalogIn VAR_INPUT bEnable : BOOL; rRaw : REAL; // 来自硬件IO的原始值 rRawLo : REAL; rRawHi : REAL; rEngLo : REAL; rEngHi : REAL; iFilterMode : INT; rFilterT : REAL; rAlmHi : REAL; rAlmLo : REAL; rHysHi : REAL; rHysLo : REAL; dt : REAL; END_VAR VAR_IN_OUT stChan : UDT_AnalogChannel; END_VAR VAR_TEMP rNorm : REAL; rScaled : REAL; rFilt : REAL; END_VAR // 量程转换 rScaled : rEngLo (rRaw - rRawLo) * (rEngHi - rEngLo) / (rRawHi - rRawLo); stChan.rScaled : rScaled; // 调用滤波FC结果写回通道结构 FC_Filter(rVal : rScaled, iMode : iFilterMode, rT : rFilterT, dt : dt, rLast : stChan.rLastOut, rFval stChan.rLastOut);stChan.rLastOut既是滤波器的“输入引脚”也是“输出引脚”通过VAR_IN_OUT传往FC内部。这种写法让FB本身不需要静态变量实例化多个通道时互不干扰。滤波后的输出保存在stChan.rLastOut后续报警比较直接读这个值。3.3 报警比较的滞回逻辑FC_AlarmCompare报警模块最容易犯的错是直接比较当前值和阈值结果信号在限值附近波动时报警点一会儿置位一会儿复位。解决方法是把报警状态记住加上滞回区间。FC_AlarmCompare如下FUNCTION FC_AlarmCompare VAR_INPUT rNow : REAL; // 当前值 rHi : REAL; // 高报警限值 rLo : REAL; // 低报警限值 rHysHi : REAL; // 高报警滞回 rHysLo : REAL; // 低报警滞回 END_VAR VAR_IN_OUT bAlmHi : BOOL; bAlmLo : BOOL; bEnable : BOOL; END_VAR IF NOT bEnable THEN bAlmHi : FALSE; bAlmLo : FALSE; RETURN; END_IF; // 高报警进入按rHi退出按rHi - rHysHi IF bAlmHi THEN bAlmHi : rNow rHi - rHysHi; ELSE bAlmHi : rNow rHi; END_IF; // 低报警进入按rLo退出按rLo rHysLo IF bAlmLo THEN bAlmLo : rNow rLo rHysLo; ELSE bAlmLo : rNow rLo; END_IF;滞回区间的作用是让报警状态具有一点“记忆”。例如高报警触发后需要降到rHi - rHysHi以下才会解除。rHysHi一般取量程的1%到5%信号抖动严重时取到10%。这个FC要在每次扫描周期都调用因为报警状态要持续监控不能在触发后停更。3.4 模拟量输出FB限幅、斜坡和安全值模拟量输出虽然不一定需要报警但必须有限幅和斜坡。阀门、变频器在接收设定值时如果直接跳变到新值容易造成机械冲击。FB_AnalogOut用斜坡来限制每周期变化量同时用上下限约束最终输出FUNCTION_BLOCK FB_AnalogOut VAR_INPUT bEnable : BOOL; rSetpoint : REAL; // 外部设定值 rOutLo : REAL; // 输出下限 rOutHi : REAL; // 输出上限 rRampUp : REAL; // 每周期允许最大增量 rRampDn : REAL; // 每周期允许最大减量 rSafeVal : REAL; // 禁止输出时的安全值 END_VAR VAR_IN_OUT rLastOut : REAL; // 上次输出 END_VAR VAR_OUTPUT rOut : REAL; END_VAR IF NOT bEnable THEN rOut : rSafeVal; rLastOut : rOut; RETURN; END_IF; // 先限幅再做斜坡限制 rOut : LIMIT(rOutLo, rSetpoint, rOutHi); rOut : rLastOut LIMIT(-rRampDn, rOut - rLastOut, rRampUp); rLastOut : rOut;LIMIT是SCL原生的三段限制函数LIMIT(最小值, 输入值, 最大值)返回限制后的结果。斜坡限制实际上是把本次期望输出与上次输出做差再限制每次变化量。rLastOut必须由调用方的DB或数据块保存因为FB的局部变量在调用结束时不保留。禁止输出时用rSafeVal回到预设安全开度这是仪表安全联锁的常用做法。3.5 把函数块和类型拖入全局库当UDT、FC和FB都在当前项目程序块中可编译后在TIA博途左侧库面板里展开“全局库”目录右键选择“新建全局库”然后从项目树的“PLC数据类型”和“程序块”中将对象直接拖到库中。保存全局库时TIA会生成一个.zap压缩文件路径可以放到共享服务器。再次打开其他项目时通过“打开全局库”选择该文件即可。库对象被项目拖入使用后就成为本地副本和源库断开联系。后续源库更新后用户可以在库面板的“版本”标签里查看库版本差异选择“更新”以使本地副本与库版本一致。如果FB的接口变化过大更新会要求重新编译背景数据块。所以在库开发阶段尽量增加新接口而不删除旧接口能降低项目升级成本。4. 在TIA博途中调用全局库并完成参数验证库文件做得再好调用方式不对也会变成一堆在线监控难题。这一章将三个常见步骤串起来从全局库导入类型、实例化多个通道、用PLCSIM和监控表验证滤波与报警效果并给出适合现场的参数表。4.1 从全局库导入类型并建立多个通道实例打开目标项目后在全局库中把FB_AnalogIn、FB_AnalogOut、FC_Filter、FC_AlarmCompare和UDT_AnalogChannel拖到项目程序中。程序块中可以直接调用FB_AnalogIn并创建背景数据块。建议为一个模拟量通道建立一个独立的背景DB这样HMI变量表引用时可以一次读完整结构。调用示例放在循环OB中// 通道1温度信号 #instAI1( bEnable : #bEn1, rRaw : #aiRaw1, rRawLo : #aiRawLo1, rRawHi : #aiRawHi1, rEngLo : #aiEngLo1, rEngHi : #aiEngHi1, iFilterMode : #iMode1, rFilterT : #rT1, rAlmHi : #rAlmHi1, rAlmLo : #rAlmLo1, rHysHi : #rHysHi1, rHysLo : #rHysLo1, dt : #rDt1, stChan : #ch1);stChan是UDT_AnalogChannel类型的变量可以从背景DB中直接创建。调用后#ch1.rScaled保存滤波后的工程值#ch1.bAlmHi和#ch1.bAlmLo保存报警状态。HMI画面只需访问#ch1.rScaled和各报警位不关心FB内部算法。这就是把库对象当作“黑盒”的配合方式。4.2 参数设置建议与库参数经验表模拟量库在现场最常见的输入类型是4-20mA和0-10V。S7-1200/1500的模拟量模块默认原始值范围是0到27648。按上述FB接口一张经验参数表可以覆盖多数工艺点参数名4-20mA变送器0-10V传感器说明rRawLo0.00.0对应4mA或0VrRawHi27648.027648.0对应20mA或10VrEngLo0.0-1.0工艺量程下限rEngHi100.010.0工艺量程上限rFilterT0.5 ~ 2.00.5 ~ 1.0PT1时间常数rHysHi0.05 * 量程0.03 * 量程高报警滞回rHysLo0.05 * 量程0.03 * 量程低报警滞回滤波时间常数不是越大越好。用于PID控制的流量信号如果滤波太强反而造成控制滞后通常设置在0.2秒以内温度信号可以放宽到2秒。报警滞回以工程量为单位需要和仪表精度匹配。若仪表重复精度为0.5%量程滞回至少取1%量程否则仪表自身噪声就会导致报警反复翻转。4.3 用PLCSIM和监控表验证滤波与报警验证滤波效果的一个简单办法是把模拟量原始值从0直接跳变到满量程然后观察rScaled的更新曲线。PT1滤波输出会按指数规律上升理论到终值的63%大约需要一个时间常数rT。如果实际曲线比理论快很多说明dt的设置不等于扫描周期需要检查OB的执行周期并修正。验证报警则应从零开始逐步增大rRaw直到bAlmHi变为TRUE。记录下触发时的工程值应与rAlmHi一致。然后缓慢减小输入观察报警复位点是否在rAlmHi - rHysHi附近。若报警在两个阈值之间来回抖动说明rHysHi过小。这是SCL库函数最应该做自动化测试的一项因为报警抖动在梯形图时代常常是现场反复调线的根因。用TIA博途的监控表可以直接修改输入。先建立数据块并在“监控”页面写入原始值再切到程序块在线状态就能看到UDT结构中的rScaled和bAlmHi实时变化。PLCSIM并不支持模拟量硬件强制但可对DB中的rRaw修改来模拟。真机调试时再接入信号发生器比较PIW值对应的原始值是否与模块量程一致。5. 库接口版本维护盘点SCL语言的取舍如果库需要跨多个工厂使用接口的版本管理比代码逻辑本身更重要。常见做法是只在旧接口基础上追加参数不删除已有字段否则已完成的项目背景DB会被强制重建。以UDT_AnalogChannel为例如果要新增一个传感器断线检测位我会在STRUCT末尾增加bWireBreak : BOOL;并把新逻辑放独立的FC中不破坏旧项目的调用。与此同时给库文件写一个简短版本说明记录接口变动内容方便现场工程师判断是否需要升级。SCL语言的优点在库开发中体现得很明显表达式直观适合数学运算函数块封装后代代码可读性比梯形图高。但它也有缺点运算符优先级容易看错尤其是在乘除和比较混写时字符串和数组处理不如高级语言方便在线调试时如果在一个FB里嵌套了多层FOR循环逐行跟踪会非常繁琐。因此我通常把单个算法拆成小型FC让每个SCL网络只做一件事库调用时层次简单查找问题才快。SCL库还有一个容易被忽略的设计点调用上下文。FC不能持有静态变量报警状态这类记忆如果放在FC内部就不可能跨扫描周期保持。于是我在UDT中把rLastOut、bAlmHi、bAlmLo都设计成通道结构的一部分FC只是无状态计算器每次调用都把最新状态写回UDT。这样的库函数可以被OB参数不同区调用多个实例不会出现静态数据冲突也便于单元测试和未来扩展。本文还有配套的精品资源点击获取