denghuagong
级别: 探索解密
精华主题: 0
发帖数量: 27 个
工控威望: 174 点
下载积分: 1950 分
在线时间: 74(小时)
注册时间: 2011-10-15
最后登录: 2026-04-01
查看denghuagong的 主题 / 回贴
楼主  发表于: 4天前
SET  
      SAVE  
      =     L     68.1
      A     #COM_RST
      JCN   A7d0
      L     #I_ITLVAL
      T     #sIanteilAlt
      L     0.000000e+00
      T     #LMN
      CLR  
      =     #QLMN_HLM
      =     #QLMN_LLM
      T     #LMN_P
      T     #LMN_I
      T     #LMN_D
      L     W#16#0
      T     #LMN_PER
      TAK  
      T     #PV
      T     #ER
      T     #sInvAlt
      T     #sRestInt
      T     #sRestDif
      T     #sRueck
      T     #sLmn
      =     #sbArwHLmOn
      =     #sbArwLLmOn
      JU    A7d1
A7d0: L     #CYCLE
      DTR  
      L     1.000000e+03
      /R    
      T     #rCycle
      L     #PV_PER
      ITD  
      DTR  
      L     3.616898e-03
      *R    
      T     #Istwert
      L     #PV_FAC
      *R    
      L     #PV_OFF
      +R    
      T     #Istwert
      CLR  
      A     #PVPER_ON
      NOT  
      JCN   A7d2
      L     #PV_IN
      T     #Istwert
A7d2: L     #Istwert
      T     #PV
      L     #SP_INT
      TAK  
      -R    
      T     #ErKp
      L     #DEADB_W
      NEGR  
      <R    
      JCN   A7d3
      L     #ErKp
      L     #DEADB_W
      +R    
      T     #ER
      JU    A7d4
A7d3: L     #ErKp
      L     #DEADB_W
      >R    
      JCN   A7d5
      L     #ErKp
      TAK  
      -R    
      T     #ER
      JU    A7d4
A7d5: L     0.000000e+00
      T     #ER
A7d4: L     #ER
      L     #GAIN
      *R    
      T     #ErKp
      L     #TI
      DTR  
      L     1.000000e+03
      /R    
      T     #rTi
      L     #TD
      DTR  
      L     1.000000e+03
      /R    
      T     #rTd
      L     #TM_LAG
      DTR  
      L     1.000000e+03
      /R    
      T     #rTmLag
      L     #rCycle
      L     5.000000e-01
      *R    
      L     #rTi
      TAK  
      <R    
      JCN   A7d7
      L     #rCycle
      L     5.000000e-01
      *R    
      T     #rTi
A7d7: L     #rTd
      L     #rCycle
      <R    
      JCN   A7d8
      T     #rTd
A7d8: L     #rCycle
      L     5.000000e-01
      *R    
      L     #rTmLag
      TAK  
      <R    
      JCN   A7d9
      L     #rCycle
      L     5.000000e-01
      *R    
      T     #rTmLag
A7d9: CLR  
      A     #P_SEL
      JCN   A7da
      L     #ErKp
      T     #Panteil
      JU    A7db
A7da: L     0.000000e+00
      T     #Panteil
A7db: CLR  
      A     #I_SEL
      JCN   A7dc
      A     #I_ITL_ON
      JCN   A7dd
      L     #I_ITLVAL
      T     #Ianteil
      L     0.000000e+00
      T     #sRestInt
      JU    A7e2
A7dd: CLR  
      A     #MAN_ON
      JCN   A7df
      L     #sLmn
      L     #Panteil
      -R    
      L     #DISV
      -R    
      T     #Ianteil
      L     0.000000e+00
      T     #sRestInt
      JU    A7e0
A7df: L     #rCycle
      L     #rTi
      /R    
      L     #ErKp
      TAK  
      T     LD    70
      TAK  
      L     #sInvAlt
      +R    
      L     LD    70
      *R    
      L     5.000000e-01
      *R    
      L     #sRestInt
      +R    
      T     #Diff
      L     0.000000e+00
      >R    
      A     #sbArwHLmOn
      O     #INT_HOLD
      L     #Diff
      L     0.000000e+00
      =     L     68.2
      <R    
      A     #sbArwLLmOn
      O     L     68.2
      JCN   A7e1
      T     #Diff
A7e1: L     #sIanteilAlt
      L     #Diff
      +R    
      T     #Ianteil
      L     #sIanteilAlt
      TAK  
      -R    
      L     #Diff
      +R    
      T     #sRestInt
A7e0: JU    A7e2
A7dc: L     0.000000e+00
      T     #Ianteil
      T     #sRestInt
A7e2: L     #ErKp
      T     #Diff
      CLR  
      A     #MAN_ON
      NOT  
      A     #D_SEL
      JCN   A7e3
      L     #rCycle
      L     5.000000e-01
      *R    
      L     #rTmLag
      +R    
      L     #rTd
      TAK  
      /R    
      T     #Verstaerk
      L     #Diff
      L     #sRueck
      -R    
      L     #Verstaerk
      *R    
      T     #Danteil
      L     #sRueck
      T     #RueckAlt
      L     #rCycle
      L     #rTd
      /R    
      L     #Danteil
      *R    
      L     #sRestDif
      +R    
      T     #RueckDiff
      L     #RueckAlt
      +R    
      T     #sRueck
      L     #RueckAlt
      TAK  
      -R    
      L     #RueckDiff
      +R    
      T     #sRestDif
      JU    A7e4
A7e3: L     0.000000e+00
      T     #Danteil
      T     #sRestDif
      L     #Diff
      T     #sRueck
A7e4: L     #Panteil
      L     #Ianteil
      +R    
      L     #Danteil
      +R    
      L     #DISV
      +R    
      T     #dLmn
      CLR  
      A     #MAN_ON
      JCN   A7e5
      L     #MAN
      T     #dLmn
      JU    A7e7
A7e5: CLR  
      A     #I_ITL_ON
      NOT  
      A     #I_SEL
      JCN   A7e7
      L     #LMN_HLM
      L     #DISV
      -R    
      L     #Ianteil
      TAK  
      >R    
      L     #dLmn
      L     #LMN_HLM
      =     L     68.2
      >R    
      A     L     68.2
      L     #dLmn
      L     #LMN_D
      -R    
      L     #LMN_HLM
      =     L     68.2
      >R    
      A     L     68.2
      JCN   A7e8
      L     #DISV
      -R    
      T     #rVal
      L     #dLmn
      L     #LMN_HLM
      -R    
      T     #gf
      L     #Ianteil
      L     #rVal
      -R    
      T     #rVal
      L     #gf
      >R    
      JCN   A7e9
      T     #rVal
A7e9: L     #Ianteil
      L     #rVal
      -R    
      T     #Ianteil
      JU    A7e7
A7e8: L     #LMN_LLM
      L     #DISV
      -R    
      L     #Ianteil
      TAK  
      <R    
      L     #dLmn
      L     #LMN_LLM
      =     L     68.2
      <R    
      A     L     68.2
      L     #dLmn
      L     #LMN_D
      -R    
      L     #LMN_LLM
      =     L     68.2
      <R    
      A     L     68.2
      JCN   A7e7
      L     #DISV
      -R    
      T     #rVal
      L     #dLmn
      L     #LMN_LLM
      -R    
      T     #gf
      L     #Ianteil
      L     #rVal
      -R    
      T     #rVal
      L     #gf
      <R    
      JCN   A7ec
      T     #rVal
A7ec: L     #Ianteil
      L     #rVal
      -R    
      T     #Ianteil
A7e7: L     #Panteil
      T     #LMN_P
      L     #Ianteil
      T     #LMN_I
      L     #Danteil
      T     #LMN_D
      L     #ErKp
      T     #sInvAlt
      L     #Ianteil
      T     #sIanteilAlt
      CLR  
      =     #sbArwHLmOn
      =     #sbArwLLmOn
      L     #dLmn
      L     #LMN_HLM
      >=R  
      JCN   A7ed
      SET  
      =     #QLMN_HLM
      CLR  
      =     #QLMN_LLM
      T     #dLmn
      SET  
      =     #sbArwHLmOn
      JU    A7ee
A7ed: CLR  
      =     #QLMN_HLM
      L     #dLmn
      L     #LMN_LLM
      <=R  
      JCN   A7ef
      SET  
      =     #QLMN_LLM
      T     #dLmn
      =     #sbArwLLmOn
      JU    A7ee
A7ef: CLR  
      =     #QLMN_LLM
A7ee: L     #dLmn
      T     #sLmn
      L     #LMN_FAC
      *R    
      L     #LMN_OFF
      +R    
      T     #dLmn
      T     #LMN
      L     2.764800e+02
      *R    
      T     #dLmn
      L     3.251100e+04
      >=R  
      JCN   A7f1
      T     #dLmn
      JU    A7f2
A7f1: L     #dLmn
      L     -3.251200e+04
      <=R  
      JCN   A7f2
      T     #dLmn
A7f2: L     #dLmn
      RND  
      T     #LMN_PER
A7d1: CLR  
      A     L     68.1
      SAVE  
      BE    
附件: STL.doc (40 K) 下载次数:10
zx1234
级别: 论坛先锋
精华主题: 0
发帖数量: 923 个
工控威望: 1285 点
下载积分: 8177 分
在线时间: 654(小时)
注册时间: 2012-10-02
最后登录: 2026-04-01
查看zx1234的 主题 / 回贴
1楼  发表于: 4天前
这段代码是西门子S7系列PLC的标准PID控制功能块(FB41 "CONT_C")的STL语句表源码,是工业控制中最经典的连续量PID算法实现,我帮你完整解析其结构、原理和每段逻辑作用:

一、整体功能定位

这是CONT_C FB41的核心STL实现,用于连续量PID调节,包含:

- 复位初始化
- 过程值PV处理与标定
- 死区非线性处理
- 比例P、积分I、微分D分离计算
- 抗积分饱和(Clamping Anti-Windup)
- 手动/自动切换
- 输出限幅与百分比转换
- 周期时间标定与离散化处理

二、代码分段详细解析

1. 复位初始化段(A7d0之前)

SET
SAVE
=     L     68.1
A     #COM_RST
JCN   A7d0
 

-  COM_RST=1  时执行冷启动复位
- 清零所有中间变量、PID分量、状态位
- 初始化历史值寄存器( sIanteilAlt 、 sRueck 等)
- 跳转到A7d1结束本次扫描

2. 周期时间与过程值PV处理(A7d0开始)

L     #CYCLE
DTR
L     1.000000e+03
/R
T     #rCycle
 

- 将调用周期 CYCLE (ms)转为秒 rCycle ,用于离散PID计算

L     #PV_PER
ITD
DTR
L     3.616898e-03
*R
T     #Istwert
L     #PV_FAC
*R
L     #PV_OFF
+R
T     #Istwert
 

- 模拟量输入 PV_PER (0~27648)标定转换为工程值 Istwert 
- 支持 PVPER_ON 选择直接使用 PV_IN 浮点数

3. 偏差计算与死区处理

L     #SP_INT
TAK
-R
T     #ErKp
L     #DEADB_W
NEGR
<R
JCN   A7d3
...
 

- 计算设定值SP与过程值PV的偏差 ErKp 
- 死区 DEADB_W 判断:死区内偏差ER=0,抑制小幅度振荡

4. PID参数时间常数转换

L     #TI
DTR
L     1.000000e+03
/R
T     #rTi

L     #TD
DTR
L     1.000000e+03
/R
T     #rTd
 

- 积分时间TI、微分时间TD(ms)→ 秒 rTi / rTd 
- 同时做最小时间钳位,避免分母为0或算法不稳定

5. 比例分量P计算

A     #P_SEL
JCN   A7da
L     #ErKp
T     #Panteil
 

-  P_SEL=1 启用比例, Panteil = GAIN * ER 
- 否则P分量清零

6. 积分分量I计算(核心抗积分饱和)

A     #I_ITL_ON
JCN   A7dd
L     #I_ITLVAL
T     #Ianteil
 

-  I_ITL_ON 积分初始化赋值
- 手动模式 MAN_ON 时积分跟踪输出,实现无扰切换
- 采用**梯形积分(Trapezoidal Integration)**提高精度
- 关键逻辑:输出限幅时抑制积分累积(Anti-Windup)
-  sbArwHLmOn / sbArwLLmOn 饱和标志
- 积分增量被钳位,防止积分饱和失控

7. 微分分量D计算

A     #D_SEL
JCN   A7e3
L     #rCycle
L     5.000000e-01
*R
L     #rTmLag
+R
L     #rTd
TAK
/R
T     #Verstaerk
 

- 带一阶滤波 TM_LAG 的微分算法,抑制噪声
- 微分针对偏差变化率计算,避免设定值跳变引起冲击

8. 输出合成与手动/自动切换

L     #Panteil
L

这是豆包解读的
楼的话
级别: 正式会员
精华主题: 0
发帖数量: 11 个
工控威望: 56 点
下载积分: 601 分
在线时间: 8(小时)
注册时间: 2024-01-09
最后登录: 2026-03-30
查看楼的话的 主题 / 回贴
2楼  发表于: 3天前
这段代码是用西门子S7系列PLC的语句表(STL)编写的。它实现了一个带有限幅和标度转换功能的PID控制器输出处理程序。
代码功能解析:
PID参数赋值 (A7ec - A7e7):
将内部变量 #Panteil, #Ianteil, #Danteil 的值分别传送给系统的PID功能块接口变量 #LMN_P, #LMN_I, #LMN_D。
将 #ErKp 和 #Ianteil 的值存储到 #sInvAlt 和 #sIanteilAlt,这通常用于计算积分饱和。
将 #rVal 的值传递给 #Ianteil。
高低限位比较与输出 (A7e7 - A7ef):
代码读取计算后的PID输出值 #dLmn。
首先判断 #dLmn 是否大于等于高限值 #LMN_HLM:
如果是,则将输出 #QLMN_HLM 置位,#QLMN_LLM 复位,并将 #dLmn 设为高限值。同时设置标志位 #sbArwHLmOn。
如果不是,则进入下一步。
接着判断 #dLmn 是否小于等于低限值 #LMN_LLM:
如果是,则将输出 #QLMN_LLM 置位,#QLMN_HLM 复位,并将 #dLmn 设为低限值。同时设置标志位 #sbArwLLmOn。
如果不是,则两个限位输出 #QLMN_HLM 和 #QLMN_LLM 都被复位。
标度变换与限幅 (A7ee - A7f2):
线性变换: 将经过限幅的 #dLmn 通过公式 #dLmn = #dLmn * #LMN_FAC + #LMN_OFF 进行线性标度变换,结果存入 #dLmn 并最终输出到 #LMN。
工程量程转换: 将 #dLmn 乘以系数 2.764800e+02 (即276.48),这个系数通常是将浮点数形式的百分比(0-100%)转换为STEP 7中标准模拟量输出的整型格式 (0 - 27648)。
最终钳位: 最后,将计算结果 #dLmn 与最大值 3.251100e+04 (32511) 和最小值 -3.251200e+04 (-32512) 进行比较,确保其在INT类型的有效范围内,超出则强制设为边界值。
四舍五入: 使用 RND 指令对最终结果进行四舍五入,并通过 T 指令传输给 #LMN_PER。
程序结束 (A7d1):
CLR 清除RLO(逻辑运算结果)。
A L 68.1 是一个无操作指令,常用于调试或作为跳转目标。

SAVE 将当前RLO状态保存到BR(位堆栈寄存器),用于块调用后的返回状态。
BE 结束当前逻辑块的执行。

转换成SCL
// --- PID 参数赋值 ---
LMN_P := Panteil;
LMN_I := Ianteil;
LMN_D := Danteil;

sInvAlt := ErKp;
sIanteilAlt := Ianteil;

Ianteil := rVal;

// --- 高低限位比较与输出 ---
sbArwHLmOn := FALSE; // 初始状态复位
sbArwLLmOn := FALSE;

// 判断是否高于高限
IF dLmn >= LMN_HLM THEN
    QLMN_HLM := TRUE;
    QLMN_LLM := FALSE;
    dLmn := LMN_HLM; // 将输出钳位到高限值
    sbArwHLmOn := TRUE;
ELSE // 如果不高于高限,则检查是否低于低限
    QLMN_HLM := FALSE; // 先复位高限输出
    
    IF dLmn <= LMN_LLM THEN
        QLMN_LLM := TRUE;
        dLmn := LMN_LLM; // 将输出钳位到低限值
        sbArwLLmOn := TRUE;
    ELSE
        QLMN_LLM := FALSE; // 不在限值内,复位所有报警输出
    END_IF;
END_IF;

// --- 标度变换与限幅 ---
sLmn := dLmn; // 可能的内部状态反馈

// 应用线性变换因子和偏移量
dLmn := (dLmn * LMN_FAC) + LMN_OFF;
LMN := dLmn; // 输出中间结果

// 转换为S7标准模拟量输出格式 (INT)
dLmn := dLmn * 2.7648e+02;

// 对最终输出值进行钳位,防止溢出 INT 范围
IF dLmn >= 32511.0 THEN
    dLmn := 32511.0;
ELSIF dLmn <= -32512.0 THEN
    dLmn := -32512.0;
END_IF;

// 四舍五入并赋值给最终输出变量
LMN_PER := ROUND(dLmn);