文章目录

ST模拟量转换:NORM_X和SCALE_X在ST中的参数填写顺序易错点

发布于 2026-03-20 10:48:06 · 浏览 4 次 · 评论 0 条

ST语言中处理模拟量信号时,NORM_XSCALE_X 是两个最常用、也最容易填错参数顺序的功能块。它们本身不复杂,但一旦参数位置颠倒或数据类型错配,程序不会报错,却会导致输出值恒为0、跳变、偏移100%或完全反向——这类故障在调试现场极难定位,常被误判为硬件损坏或传感器故障。

以下内容仅围绕参数填写顺序这一具体易错点展开,不讲原理推导、不堆砌标准定义,只告诉你:在哪填、填什么、为什么这个顺序不能换、填错后现象是什么、如何一秒自检


一、先看结论:两个功能块的参数顺序对比表

功能块 输入引脚(IN) 最小输入值(MIN_IN) 最大输入值(MAX_IN) 最小输出值(MIN_OUT) 最大输出值(MAX_OUT) 输出引脚(OUT)
NORM_X X X_MIN X_MAX Y_MIN Y_MAX Y
SCALE_X IN IN_MIN IN_MAX OUT_MIN OUT_MAX OUT

⚠️ 关键差异:

  • NORM_X第一参数是 X(待转换的原始值),紧接着才是 X_MINX_MAX
  • SCALE_X第一参数是 IN(待转换的原始值),紧接着才是 IN_MININ_MAX
    表面看顺序一致?不——真正陷阱藏在命名暗示与实际调用习惯的错位中。

二、为什么你会填错?——命名误导 + 编辑器补全惯性

多数工程师写 NORM_X 时,凭直觉认为:“既然是‘归一化’,那应该先给范围,再给值”,于是写出:

NORM_X(
    X_MIN := 4.0,
    X_MAX := 20.0,
    Y_MIN := 0.0,
    Y_MAX := 100.0,
    X := CurrentRaw,   // ❌ 错!X 放最后,但X是主输入,必须放第一位
    Y => NormValue
);

这段代码语法合法、编译通过、运行不报错,但 Y 永远输出 0.0。原因:NORM_X位置绑定(positional binding)优先 的功能块。当未使用 := 显式指定参数名时,PLC严格按声明顺序匹配参数。

NORM_X 的标准声明(IEC 61131-3 标准库)为:

FUNCTION_BLOCK NORM_X
VAR_INPUT
    X       : REAL;     // 第1位:原始输入值 → 必须是第一个实参
    X_MIN   : REAL;     // 第2位:输入下限
    X_MAX   : REAL;     // 第3位:输入上限
    Y_MIN   : REAL;     // 第4位:输出下限
    Y_MAX   : REAL;     // 第5位:输出上限
END_VAR
VAR_OUTPUT
    Y       : REAL;     // 第6位:归一化结果
END_VAR

因此,若你写成:

NORM_X(CurrentRaw, 4.0, 20.0, 0.0, 100.0, Y => NormValue);

✅ 正确:5个输入按声明顺序依次填入,CurrentRaw 占第1位,Y 自动接收计算结果。

而若你写成(带名参数但顺序混乱):

NORM_X(
    X_MIN := 4.0,
    X := CurrentRaw,
    X_MAX := 20.0,
    Y_MIN := 0.0,
    Y_MAX := 100.0,
    Y => NormValue
);

❌ 仍错误:X_MIN := 4.0 是第1个实参 → PLC将其赋给 X(第1位变量),X 被强制设为 4.0X := CurrentRaw 是第2个实参 → 赋给 X_MIN(第2位变量),X_MIN 变成 CurrentRaw 的值;后续全部错位。最终 X 固定为 4.0X_MIN 变成传感器值,逻辑彻底崩坏。

✅ 正确带名写法(推荐用于复杂项目):

NORM_X(
    X      := CurrentRaw,
    X_MIN  := 4.0,
    X_MAX  := 20.0,
    Y_MIN  := 0.0,
    Y_MAX  := 100.0,
    Y      => NormValue
);

注意:所有 := 左侧名称必须与声明中 VAR_INPUT 名称完全一致(大小写敏感),且顺序可任意——因为此时是“名称绑定(named binding)”。


三、SCALE_X 的陷阱更隐蔽:IN/OUT 命名让你放松警惕

SCALE_X 声明为:

FUNCTION_BLOCK SCALE_X
VAR_INPUT
    IN      : REAL;     // 第1位
    IN_MIN  : REAL;     // 第2位
    IN_MAX  : REAL;     // 第3位
    OUT_MIN : REAL;     // 第4位
    OUT_MAX : REAL;     // 第5位
END_VAR
VAR_OUTPUT
    OUT     : REAL;     // 第6位
END_VAR

看似 IN 开头很清晰?问题出在:工程师常把 SCALE_X 当作“缩放器”,下意识认为“先输范围,再输值”,尤其当从 HMI 或 Excel 复制参数时,习惯按「输入范围→输出范围→当前值」排列:

// ❌ 典型错误:把当前值 CurrentRaw 放最后,以为是“输入值”
SCALE_X(4.0, 20.0, 0.0, 100.0, CurrentRaw, OUT => ScaledVal);

这行代码中:

  • 4.0 → 赋给 IN(第1位)→ IN = 4.0
  • 20.0 → 赋给 IN_MIN(第2位)→ IN_MIN = 20.0
  • 0.0 → 赋给 IN_MAX(第3位)→ IN_MAX = 0.0
  • 100.0 → 赋给 OUT_MIN(第4位)→ OUT_MIN = 100.0
  • CurrentRaw → 赋给 OUT_MAX(第5位)→ OUT_MAX = CurrentRaw
  • OUT => ScaledVal → 第6位,正常

结果:IN_MIN > IN_MAX(20.0 > 0.0),SCALE_X 内部计算时直接返回 OUT_MIN(即 100.0),ScaledVal 恒为 100.0,且不报警。

✅ 正确位置绑定写法:

SCALE_X(CurrentRaw, 4.0, 20.0, 0.0, 100.0, OUT => ScaledVal);

✅ 正确带名写法(强烈建议):

SCALE_X(
    IN      := CurrentRaw,
    IN_MIN  := 4.0,
    IN_MAX  := 20.0,
    OUT_MIN := 0.0,
    OUT_MAX := 100.0,
    OUT     => ScaledVal
);

四、填错后的四大典型现象及速查法

现象 可能原因 速查动作
YOUT 恒为 0.0 XIN 位置错填为 X_MIN/IN_MIN,导致主输入被固定为极小值(如 0.04.0 查看该功能块调用处,确认第一个实参是否为你的实时变量(如 AI[0].Value
YOUT 恒为 100.0(或 OUT_MAX 值) IN_MININ_MAX 颠倒,或 X_MIN > X_MAX,触发边界保护返回 OUT_MAX 检查第2、第3个实参数值:是否 IN_MIN > IN_MAX?如 20.0, 4.0 就是错的
YOUT 随输入线性变化但全程偏移(如 4–20mA 对应 0–100,实测却为 5–105) Y_MIN/OUT_MINY_MAX/OUT_MAX 填反(如把 OUT_MINOUT_MAX 填) 检查第4、第5个实参:OUT_MIN 是否真比 OUT_MAX 小?
YOUT 值随输入反向变化(输入增大,输出减小) IN_MININ_MAX 数值正确但位置互换(如 IN_MIN := 20.0; IN_MAX := 4.0 在线监控 IN_MININ_MAX 的实际值,确认大小关系

💡 速查口诀:“一值二下三上,四下五上六出”

  • 第1位:必须是你读到的实时原始值AI[0].Value, PIW100, CurrentRaw
  • 第2位:该信号的物理量下限(如 4.0, 0.0, -10.0
  • 第3位:该信号的物理量上限(如 20.0, 100.0, +10.0
  • 第4位:你要映射的目标下限(如 0.0, 0.0, 0.0
  • 第5位:你要映射的目标上限(如 100.0, 1.0, 32767.0
  • 第6位:Y => ...OUT => ...

五、实战防错三招(立即生效)

1. 统一用带名参数 + 按声明顺序书写(杜绝位置依赖)

// ✅ 推荐模板(复制即用)
NORM_X(
    X      := AI_4_20mA,
    X_MIN  := 4.0,
    X_MAX  := 20.0,
    Y_MIN  := 0.0,
    Y_MAX  := 100.0,
    Y      => FlowPercent
);

SCALE_X(
    IN      := PT100_Raw,
    IN_MIN  := 100.0,   // PT100 0°C = 100Ω
    IN_MAX  := 138.5,   // PT100 100°C = 138.5Ω
    OUT_MIN := 0.0,
    OUT_MAX := 100.0,
    OUT     => TempPercent
);

2. 在变量声明区加注释,锁定物理意义

VAR
    AI_4_20mA     : REAL;  // 4–20mA电流信号,经AD转换,范围0–32767 → 但NORM_X中填4.0/20.0!
    FlowPercent   : REAL;  // 归一化后0.0–100.0,供HMI显示
    PT100_Raw     : REAL;  // PT100电阻值(Ω),非温度值!
    TempPercent   : REAL;  // 温度百分比,0°C=0%,100°C=100%
END_VAR

⚠️ 注意:NORM_X / SCALE_XX_MIN/IN_MIN 等,必须填信号的工程单位值(4.0 mA, 100.0 Ω),不是AD码值(0, 32767)。AD码换算应在前级完成,或用 SCALE(整型版)处理。

3. 用临时变量做“范围检查”,运行期捕获错配

// 在主程序循环中插入(调试期启用,上线前删除)
IF AI_4_20mA < 3.9 OR AI_4_20mA > 20.1 THEN
    // 触发报警或置位诊断位
    Fault_4_20mA_OutOfRange := TRUE;
END_IF;

// 检查参数合理性(防止烧写错误配置)
IF 4.0 > 20.0 THEN  // 永假,但编译器会警告;真实项目中用变量
    // 这里永远不执行,但提醒你:X_MIN 必须 < X_MAX
END_IF;

六、附:常见信号工程单位对照表(直接填入 MIN/MAX)

传感器类型 信号形式 X_MIN X_MAX 典型Y_MIN/Y_MAX 备注
4–20mA 电流 电流 4.0 20.0 0.0, 100.0 mA 单位值,非电压或AD码
0–10V 电压 电压 0.0 10.0 0.0, 100.0 同上,单位 V
PT100 热电阻 电阻 100.0 138.5 0.0, 100.0 0°C=100Ω,100°C≈138.5Ω
K型热电偶 mV(查表后) 0.0 41.27 0.0, 1372.0 0–1372°C对应0–41.27mV(需冷端补偿)
Modbus RTU 浮点数 工程值 0.0 1000.0 0.0, 1000.0 若已为工程单位,SCALE_X 可跳过,直接用 LIMIT 限幅

✅ 记住:X_MIN/X_MAX你期望该通道接收到的物理量合理范围,不是传感器极限值,也不是AD极限值。


七、终极验证:用一个已知值手动验算

选一个确定值代入,心算结果是否合理。例如:

  • 输入 AI_4_20mA = 12.0 mA
  • NORM_X(X:=12.0, X_MIN:=4.0, X_MAX:=20.0, Y_MIN:=0.0, Y_MAX:=100.0)
  • 手算:(12.0 − 4.0) / (20.0 − 4.0) × (100.0 − 0.0) + 0.0 = 8.0 / 16.0 × 100 = 50.0
  • 在线监控 Y 是否为 50.0?是 → 参数正确;否 → 检查第1~5位实参顺序。

此法10秒完成,比翻手册、查库、重编译快10倍。


不要背公式,只记顺序:一值二下三上,四下五上六出。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文