每周一个编程小例子:官方模拟量输入处理模块
引言
在现代工业自动化领域,传感器如同设备的神经末梢,源源不断地将物理世界的信息(温度、压力、流量等)转化为电信号。而 PLC(可编程逻辑控制器)的核心任务之一,就是精准解读这些电信号。西门子标准库中的LBC_AnalogInput_v2功能块,正是承担这一重任的。它高效地将原始模拟量信号(如 4-20mA 电流或 0-10V 电压)转换为具有实际工程意义的数值(如 0-100℃的温度),并进行智能监控与报警,是构建稳定可靠自动化系统的基石。
1 程序代码(官方LBC库)
下面是完整的 PLC 程序代码(代码基于 TIA 平台的 SCL 语言):
- FUNCTION_BLOCK "LBC_AnalogInput_v2"
- { S7_Optimized_Access := 'TRUE' }
- VERSION : 0.1
- VAR_INPUT
- enable : Bool;
- analogValue : Int;
- quality { S7_HiddenAssignment := 'Hide'} : Bool := TRUE;
- simulation { S7_HiddenAssignment := 'HideIfNoParamAssigned'} : Bool;
- simulatedAnalogValue { S7_HiddenAssignment := 'HideIfNoParamAssigned'} : Int;
- END_VAR
- VAR_OUTPUT
- error { ExternalWritable := 'False'} : Bool;
- status { ExternalWritable := 'False'} : Word := #STATUS_NO_CALL;
- processValue { ExternalWritable := 'False'} : LReal;
- limitHigh2 { ExternalWritable := 'False'; S7_HiddenAssignment := 'HideIfNoParamAssigned'} : Bool;
- limitHigh1 { ExternalWritable := 'False'; S7_HiddenAssignment := 'HideIfNoParamAssigned'} : Bool;
- limitLow1 { ExternalWritable := 'False'; S7_HiddenAssignment := 'HideIfNoParamAssigned'} : Bool;
- limitLow2 { ExternalWritable := 'False'; S7_HiddenAssignment := 'HideIfNoParamAssigned'} : Bool;
- maxValueReached { ExternalWritable := 'False'; S7_HiddenAssignment := 'HideIfNoParamAssigned'} : Bool;
- minValueReached { ExternalWritable := 'False'; S7_HiddenAssignment := 'HideIfNoParamAssigned'} : Bool;
- END_VAR
- VAR_IN_OUT
- configuration : "LBC_typeAnalogInputConfiguration";
- moduleInterface : "LBC_typeAnalogInputInterface";
- END_VAR
- VAR
- statProcessValues { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'; S7_SetPoint := 'False'}: "LBC_typeAnalogProcessValues";
- statDiagnostics { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'; S7_SetPoint := 'False'}: "LBC_typeDiagnostics" := (#STATUS_NO_CALL, (), ());
- statReferenceDesignator { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : String[20];
- statLimitationMessage { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : String[40];
- statLimitMessage { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : String[40];
- statDisableAlarms { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool;
- statEnablePrevious { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool;
- END_VAR
- VAR CONSTANT
- OVER_RANGE : Int := 27649;
- OVERFLOW : Int := 32511;
- UNDER_RANGE_UNIPOLAR : Int := -1;
- UNDERFLOW_UNIPOLAR : Int := -4864;
- UNDER_RANGE_BIPOLAR : Int := -27649;
- UNDERFLOW_BIPOLAR : Int := -32512;
- STATUS_NO_ERROR_OCCURRED : Word := 16#0000;
- STATUS_NO_CALL : Word := 16#7000;
- STATUS_ENABLED : Word := 16#7002;
- ALARM_LIMIT_HIGH_2 : Word := 16#7601;
- ALARM_LIMIT_HIGH_1 : Word := 16#7602;
- ALARM_LIMIT_LOW_1 : Word := 16#7603;
- ALARM_LIMIT_LOW_2 : Word := 16#7604;
- ALARM_MAX_VALUE_REACHED : Word := 16#7605;
- ALARM_MIN_VALUE_REACHED : Word := 16#7606;
- ERR_CONFIGURATION_RANGE_PARAMETRIZATION : Word := 16#8201;
- ERR_CONFIGURATION_SCALE_ANALOG_POINTS : Word := 16#8202;
- ERR_CONFIGURATION_LIMIT_LOW1_LOW2 : Word := 16#8211;
- ERR_CONFIGURATION_LIMIT_LOW1_HIGH1 : Word := 16#8212;
- ERR_CONFIGURATION_LIMIT_HIGH1_HIGH2 : Word := 16#8213;
- ERR_QUALITY_BAD : Word := 16#8401;
- ERR_HIGH_LIMIT_OVERFLOW : Word := 16#8402;
- ERR_HIGH_LIMIT_OVER_RANGE : Word := 16#8403;
- ERR_LOW_LIMIT_UNDER_RANGE_UNIPOLAR : Word := 16#8404;
- ERR_LOW_LIMIT_UNDERFLOW_UNIPOLAR : Word := 16#8405;
- ERR_LOW_LIMIT_UNDER_RANGE_BIPOLAR : Word := 16#8406;
- ERR_LOW_LIMIT_UNDERFLOW_BIPOLAR : Word := 16#8407;
- END_VAR
- BEGIN
- REGION BLOCK INFO HEADER
- //=======================================================
- // Siemens AG / (c)Copyright 2020
- //-------------------------------------------------------------------------------
- // Title: LBC_AnalogSignal
- // Comment/Function: The function is used for processing (scaling) a value from analog input card and converts it
- // into a meaningful unit (temperature, height, pressure...) that is within a user defined range.
- // The periphery I/O card is working with current or voltage - depending on the card and its configuration.
- // Library/Family: LBC - Library of Basic Control modules
- // Author: Siemens Digital Industries // Tested with: S7-PLCSIM Advanced 3.0
- // Engineering: TIA Portal V16
- // Restrictions: ENO mechanism is not used - forced to true.
- // Requirements: PLC (S7-1200 / S7-1500)
- //-------------------------------------------------------------------------------
- // Change log table:
- // Version | Date | Expert in charge | Changes applied
- //----------|------------|-------------------------|-----------------------------
- // 01.00.00 | 15.02.2021 | SIMATIC Systems Support | First released version
- //===========================================================
- END_REGION
- REGION DESCRIPTION
- (/**/)
- END_REGION DESCRIPTION
- REGION PROCESS INPUT SIGNALS
- // Assign and initialize internal variables
- #statProcessValues.enable := #enable;
- #statProcessValues.simulation := #simulation;
- // Check if simulation is activated
- IF #statProcessValues.simulation THEN
- #statProcessValues.analogValue := #simulatedAnalogValue;
- ELSE
- #statProcessValues.analogValue := #analogValue;
- END_IF;
- #statProcessValues.limitHigh2 := FALSE;
- #statProcessValues.limitHigh1 := FALSE;
- #statProcessValues.limitLow1 := FALSE;
- #statProcessValues.limitLow2 := FALSE;
- #statProcessValues.maxValueReached := FALSE;
- #statProcessValues.minValueReached := FALSE;
- // Copy configuration to static for usage in supervision
- #statDisableAlarms := #configuration.disableAlarms;
- END_REGION PROCESS INPUT SIGNALS
- REGION PARAMETER CHECK
- // Check parameter if block is enabled
- IF #statProcessValues.enable THEN
- #statDiagnostics.status := #STATUS_ENABLED;
- // Validation of hardware range limits
- // Check if parameters for hardware signal limits are within correct values
- IF #configuration.processValueMin >= #configuration.processValueMax THEN
- #statProcessValues.processValue := #configuration.default;
- #statDiagnostics.status := #ERR_CONFIGURATION_RANGE_PARAMETRIZATION;
- ELSIF #configuration.scaleProcessLowPoint >= #configuration.scaleProcessUppPoint THEN
- #statProcessValues.processValue := #configuration.default;
- #statDiagnostics.status := #ERR_CONFIGURATION_SCALE_ANALOG_POINTS;
- // Validation of limits
- // limitLow2 < limitLow1 < limitHigh1 < limitHigh2
- // Limit Low 2
- ELSIF ((#configuration.limitLow2 > #configuration.limitLow1) OR
- (#configuration.limitLow2 > #configuration.limitHigh1) OR
- (#configuration.limitLow2 > #configuration.limitHigh2)) THEN
- #statProcessValues.processValue := #configuration.default;
- #statDiagnostics.status := #ERR_CONFIGURATION_LIMIT_LOW1_LOW2;
- // Limit low 1
- ELSIF ((#configuration.limitLow1 > #configuration.limitHigh1) OR
- (#configuration.limitLow1 > #configuration.limitHigh2)) THEN
- #statProcessValues.processValue := #configuration.default;
- #statDiagnostics.status := #ERR_CONFIGURATION_LIMIT_LOW1_HIGH1;
- // Limit high 1
- ELSIF (#configuration.limitHigh1 > #configuration.limitHigh2) THEN
- #statProcessValues.processValue := #configuration.default;
- #statDiagnostics.status := #ERR_CONFIGURATION_LIMIT_HIGH1_HIGH2;
- END_IF;
- END_IF;
- END_REGION PARAMETER CHECK
- REGION ENABLING/DISABLING
- IF #enable AND NOT #statEnablePrevious THEN
- // Copy configuration to static for usage in associated value of supervision
- #statReferenceDesignator := #configuration.referenceDesignator;
- // Initializes moduleInterface configuration with process configuration
- #moduleInterface.configuration := #configuration;
- END_IF;
- #statEnablePrevious := #enable;
- END_REGION ENABLING/DISABLING
- REGION PROCESS LOGIC
- // Use default value and set no call status if block is disabled
- IF NOT #statProcessValues.enable THEN
- #statProcessValues.processValue := #configuration.default;
- #statDiagnostics.status := #STATUS_NO_CALL;
- // In case of Error return default
- ELSIF #statDiagnostics.status.%X15 THEN
- #statProcessValues.processValue := #configuration.default;
- // Checking if quality of signal is bad
- ELSIF NOT #quality AND NOT #simulation THEN
- // In case of bad quality from hardware module
- #statProcessValues.processValue := #configuration.default;
- #statDiagnostics.status := #ERR_QUALITY_BAD;
- // No error - do process
- ELSE
- // Write status message, set no error
- #statDiagnostics.status := #STATUS_NO_ERROR_OCCURRED;
- // Validation of signal
- // Check input signal for over/underflow in system analog value range
- IF (#statProcessValues.analogValue > #OVERFLOW) THEN
- #statProcessValues.analogValue := #OVERFLOW;
- #statDiagnostics.status := #ERR_HIGH_LIMIT_OVERFLOW;
- ELSIF (#statProcessValues.analogValue >= #OVER_RANGE) THEN
- #statProcessValues.analogValue := #OVER_RANGE;
- #statDiagnostics.status := #ERR_HIGH_LIMIT_OVER_RANGE;
- ELSIF (#statProcessValues.analogValue < #UNDERFLOW_UNIPOLAR) AND #configuration.isUnipolarSignal THEN
- #statProcessValues.analogValue := #UNDERFLOW_UNIPOLAR;
- #statDiagnostics.status := #ERR_LOW_LIMIT_UNDERFLOW_UNIPOLAR;
- ELSIF (#statProcessValues.analogValue <= #UNDER_RANGE_UNIPOLAR) AND #configuration.isUnipolarSignal THEN
- #statProcessValues.analogValue := #UNDER_RANGE_UNIPOLAR;
- #statDiagnostics.status := #ERR_LOW_LIMIT_UNDER_RANGE_UNIPOLAR;
- ELSIF (#statProcessValues.analogValue < #UNDERFLOW_BIPOLAR) AND NOT #configuration.isUnipolarSignal THEN
- #statProcessValues.analogValue := #UNDERFLOW_BIPOLAR;
- #statDiagnostics.status := #ERR_LOW_LIMIT_UNDERFLOW_BIPOLAR;
- ELSIF (#statProcessValues.analogValue <= #UNDER_RANGE_BIPOLAR) AND NOT #configuration.isUnipolarSignal THEN
- #statProcessValues.analogValue := #UNDER_RANGE_BIPOLAR;
- #statDiagnostics.status := #ERR_LOW_LIMIT_UNDER_RANGE_BIPOLAR;
- END_IF;
- // Scaling the analog input
- #statProcessValues.processValue := (((INT_TO_LREAL(#statProcessValues.analogValue) - #configuration.scaleAnalogLowPoint) / (#configuration.scaleAnalogUppPoint - #configuration.scaleAnalogLowPoint))
- * (#configuration.scaleProcessUppPoint - #configuration.scaleProcessLowPoint) + #configuration.scaleProcessLowPoint);
- // Check if process values are within the configured range
- IF #statProcessValues.processValue < #configuration.processValueMin THEN
- #statProcessValues.processValue := #configuration.processValueMin;
- #statProcessValues.minValueReached := true;
- #statLimitationMessage := CONCAT(IN1 := LREAL_TO_STRING(#statProcessValues.processValue), IN2 := #configuration.physicalUnit, IN3 := ' <= ', IN4 := LREAL_TO_STRING(#configuration.processValueMin), IN5 := #configuration.physicalUnit);
- ELSIF #statProcessValues.processValue > #configuration.processValueMax THEN
- #statProcessValues.processValue := #configuration.processValueMax;
- #statProcessValues.maxValueReached := true;
- #statLimitationMessage := CONCAT(IN1 := LREAL_TO_STRING(#statProcessValues.processValue), IN2 := #configuration.physicalUnit, IN3 := ' >= ', IN4 := LREAL_TO_STRING(#configuration.processValueMax), IN5 := #configuration.physicalUnit);
- ELSE // Clear alarm message string
- #statLimitationMessage := '';
- END_IF;
- // Checking if scaled value is within configured limits
- IF #statProcessValues.processValue >= #configuration.limitHigh2 THEN
- #statProcessValues.limitHigh2 := TRUE;
- #statLimitMessage := CONCAT(IN1 := ' >= ', IN2 := LREAL_TO_STRING(#configuration.limitHigh2));
- ELSIF #statProcessValues.processValue >= #configuration.limitHigh1 THEN
- #statProcessValues.limitHigh1 := TRUE;
- #statLimitMessage := CONCAT(IN1 := ' >= ', IN2 := LREAL_TO_STRING(#configuration.limitHigh1));
- ELSIF #statProcessValues.processValue <= #configuration.limitLow2 THEN
- #statProcessValues.limitLow2 := TRUE;
- #statLimitMessage := CONCAT(IN1 := ' <= ', IN2 := LREAL_TO_STRING(#configuration.limitLow2));
- ELSIF #statProcessValues.processValue <= #configuration.limitLow1 THEN
- #statProcessValues.limitLow1 := TRUE;
- #statLimitMessage := CONCAT(IN1 := ' <= ', IN2 := LREAL_TO_STRING(#configuration.limitLow1));
- ELSE // Clear alarm message string
- #statLimitMessage := '';
- END_IF;
- IF LEN(#statLimitMessage) > 0 THEN
- #statLimitMessage := CONCAT(IN1 := LREAL_TO_STRING(#statProcessValues.processValue), IN2 := #configuration.physicalUnit, IN3 := #statLimitMessage, IN4 := #configuration.physicalUnit);
- END_IF;
- END_IF;
- END_REGION PROCESS LOGIC
- REGION CONFIGURATION HANDLING
- // Refresh module interface configuration with process configuration
- IF #moduleInterface.commands.refreshConfiguration AND NOT #moduleInterface.commands.editConfiguration THEN
- #moduleInterface.configuration := #configuration;
- END_IF;
- #moduleInterface.commands.refreshConfiguration := FALSE;
- // Save module interface configuration to process configuration
- IF #moduleInterface.commands.saveConfiguration AND #moduleInterface.commands.editConfiguration THEN
- #configuration := #moduleInterface.configuration;
- #statReferenceDesignator := #configuration.referenceDesignator;
- #moduleInterface.commands.saveConfiguration := FALSE;
- END_IF;
- END_REGION CONFIGURATION HANDLING
- REGION PROCESS OUTPUT SIGNALS
- REGION Write Process data to module interface
- #statProcessValues.error := #statDiagnostics.status.%X15;
- #moduleInterface.monitoring := #statProcessValues;
- #moduleInterface.diagnostics := #statDiagnostics;
- END_REGION Write Process data to module interface
- REGION Write work data to interface and outputs
- // Write application specific static values to outputs
- #processValue := #statProcessValues.processValue;
- #limitHigh2 := #statProcessValues.limitHigh2;
- #limitHigh1 := #statProcessValues.limitHigh1;
- #limitLow1 := #statProcessValues.limitLow1;
- #limitLow2 := #statProcessValues.limitLow2;
- #maxValueReached := #statProcessValues.maxValueReached;
- #minValueReached := #statProcessValues.minValueReached;
- // Function status
- #error := #statDiagnostics.status.%X15;
- #status := #statDiagnostics.status;
- // ENO mechanism disabled, ENO - forced to true
- ENO := TRUE;
- END_REGION Write static values to outputs
- END_REGION PROCESS OUTPUT SIGNALS
- END_FUNCTION_BLOCK
2 程序解析
2.1 关键接口 (Input/Output/In-Out):
VAR_INPUT (输入):
-
enable: 功能块使能开关。True时工作,False时输出默认值并停止处理。
-
analogValue: 来自模拟量输入模块的原始整数值(如 27648 对应 20mA)。
-
quality: (通常隐藏) 信号质量位,False表示硬件信号异常(如断线)。
-
simulation: (通常隐藏) 仿真模式开关。True时忽略analogValue。
-
simulatedAnalogValue: (通常隐藏) 仿真模式下使用的模拟量值。
VAR_OUTPUT (输出):
-
error: 错误标志,True表示处理过程中发生错误。
-
status: 详细的状态/错误码(如#STATUS_ENABLED, #ERR_QUALITY_BAD)。
-
processValue: 核心输出!转换后的工程值(LReal 浮点数,如温度值)。
-
limitHigh2, limitHigh1, limitLow1, limitLow2: 多级越限报警标志。例如,limitHigh1=True表示过程值超过了用户设定的“高警告”限值。
-
maxValueReached/minValueReached: 指示过程值被强制限制在用户设定的最大/最小值上。
VAR_IN_OUT (输入输出):
-
configuration:连接到一个结构体(LBC_typeAnalogInputConfiguration)。
-
moduleInterface: 用于与更高级别的模块或 HMI 交互配置和状态信息(LBC_typeAnalogInputInterface)。
2.2 核心处理逻辑 (PROCESS LOGIC):
信号选择: 根据simulation状态,选择真实analogValue或仿真值simulatedAnalogValue。
参数校验: 在enable状态下,严格检查configuration中的参数是否合理(如量程上下限是否反序、报警限值是否满足低 2<低 1<高 1<高 2)。参数错误会设置相应status并输出default值。
信号质量检查: 若非仿真模式且quality=False(信号差),输出default值并设置#ERR_QUALITY_BAD。
信号有效性检查: 检查原始值是否超出硬件允许范围(超量程OVER_RANGE、溢出OVERFLOW、欠量程UNDER_RANGE_*、下溢UNDERFLOW_*),并进行饱和处理并记录错误状态。
核心转换: 使用线性标定公式将原始整数值转换为工程值:processValue = ((原始值 - scaleAnalogLowPoint) / (scaleAnalogUppPoint - scaleAnalogLowPoint)) * (scaleProcessUppPoint - scaleProcessLowPoint) + scaleProcessLowPoint
工程值限幅: 确保processValue不超出用户设定的processValueMin/Max,若触及边界则设置minValueReached/maxValueReached标志并生成限幅信息。
多级报警判断: 检查processValue是否触达用户设定的四个报警限值(limitLow2->limitLow1->limitHigh1->limitHigh2),设置相应报警标志并生成报警信息(包含具体值和单位,如"75.3°C >= 75.0°C")。
配置管理: 通过moduleInterface实现配置的刷新(refreshConfiguration)和保存(saveConfiguration),支持在线修改。
2.3 错误处理与状态管理:
使用丰富的status代码(#ERR_*常量)精确指示错误类型(配置错误、信号错误、超限错误等)。
error输出是status最高位(Error Bit)的简化表示。
内部状态变量(statDiagnostics, statProcessValues)记录详细过程数据和诊断信息,供接口或调试使用。
3 核心应用场景
LBC_AnalogInput_v2功能块是工业自动化中处理连续过程信号的通用解决方案,典型应用包括:
过程监控:
-
温度控制: 读取热电偶/热电阻信号,转换为实际温度值,监控是否超温(limitHigh1/2)或低温(limitLow1/2)。例如,反应釜温度超过安全上限触发紧急停机。
-
压力监测: 转换压力变送器信号,监控管道压力是否过高(limitHigh1/2)或过低(limitLow1/2)。例如,液压系统压力过低触发泵保护。
-
液位测量: 转换液位计信号,监控储罐液位是否溢出(maxValueReached)或空罐(minValueReached)。例如,污水池液位超高触发报警。
-
流量计量: 转换流量计信号,累积流量或监控流量异常。
设备保护:
-
利用多级报警限值实现预警(limitHigh1/limitLow1)和紧急停机(limitHigh2/limitLow2)。
-
quality和信号有效性检查(OVERFLOW, UNDERFLOW_*)可及时发现传感器故障或线路问题。
仿真与调试:
-
通过simulation和simulatedAnalogValue,可在无真实硬件连接的情况下测试程序逻辑和 HMI 显示,极大提高调试效率和安全性。
标准化与可维护性:
-
作为西门子标准化库的一部分,统一了不同项目、不同工程师处理模拟量输入的方法,提高代码可读性和可维护性。
-
清晰的接口和配置结构便于集成到更复杂的模块化系统中。
4 拓展思考:功能增强与优化方向
信号滤波: 当前版本未内置滤波算法。可在原始值输入功能块之前或在功能块内部statProcessValues.analogValue赋值后,加入移动平均滤波、一阶滞后滤波(低通滤波) 等算法,有效抑制现场干扰引起的信号波动。
报警死区(Hysteresis): 当前报警是瞬时触发的。添加报警死区逻辑可防止过程值在限值附近微小波动时造成报警频繁通断(抖动)。例如,温度从 75.0℃触发limitHigh1报警后,需降到 74.5℃以下才复位报警。
自定义标定曲线: 对于非线性传感器(如某些热敏电阻),线性标定可能不够精确。可扩展配置结构,支持查表法(Lookup Table)或分段线性插值,甚至接入高阶多项式拟合参数。
更丰富的诊断: 增加对历史报警/错误事件的记录功能(时间戳、值),便于故障追溯和分析。
与 IT 系统集成: 通过moduleInterface扩展,将过程值、报警状态、诊断信息更便捷地推送至 MES(制造执行系统)或 SCADA(数据采集与监控系统)平台,实现数据上云和高级分析。
总结
LBC_AnalogInput_v2功能块是西门子 TIA Portal 生态中处理模拟量输入的强大且标准化的工具。它通过清晰定义的接口、严谨的参数校验、灵活的配置管理、实时的信号转换与多级报警监控,将原始的、冰冷的模拟量信号转化为具有明确物理意义、可直接用于控制和决策的工程值。其模块化设计显著提高了 PLC 程序的开发效率、可读性和可维护性,是构建稳定、可靠、易维护的工业自动化系统不可或缺的基石。
掌握并善用此类标准化功能块,是每一位 PLC 工程师提升工程效率、保障系统质量的关键一步。它不仅处理了信号,更赋予了机器“感知”世界并做出智能响应的能力。
你来出题 我来答
欢迎大家在评论区提一些标准功能块的需求,如果合适,我们会在以后的文章中与大家分享。
往期回顾
每周一个编程小例子 :Bit 到 Word 转换的两种实现方案对比
2025年07月