☰
西门子S7-1200/1500增量式PID程序:ST语言实现温度控制方案
2026/10/17 7:23:07 网站建设 项目流程

简介:这是一份面向西门子1200与1500系列PLC的增量式PID控制程序,源自真实工程项目,主要适合工业自动化工程师、PLC开发人员及自动控制学习者使用,解决实际生产中的闭环调节与稳定控制问题。程序基于博途(TIA Portal)V15.1及以上版本编写,压缩包内提供完整博途项目文件、SCL源程序、数据块及HMI相关文件,全程带注释且无密码,可直接打开查看、移植或二次修改。资源共49个文件,核心包括.ap15_1工程文件、.scl程序代码、.db数据块,另有.cfg/.xml配置文件以及日志、图标等辅助内容,整体仅1.26MB,体积小巧、下载快捷。目前已有752人浏览学习,且该程序已在现场运行验证,参考价值较高。通过该资源,可以系统掌握增量式PID的编程架构、比例/积分/微分参数整定思路,以及误差实时处理与输出更新逻辑;还能参考实际项目的模块划分、变量命名和注释风格,对理解SCL语言和博途工程组织也有实际帮助。

1. 西门子增量式PID程序:一套能让1200和1500通吃的温度控制方案

做自动化这行的都知道,博途里自带PID_Compact指令,但实际项目里真正敢直接把它用到工艺控制上的并不多。原因很简单:PID_Compact封装太深,参数整定像个黑匣子,而且不同CPU之间升级迁移、版本兼容的问题也够折腾一阵子。这篇要拆的项目,是一套手写的西门子增量式PID程序,在S7-1200和S7-1500两款PLC上都能直接跑,已经在实际产线的温度控制场景里稳定运行过。它没有用系统自带的PID块,而是用ST语言从底层实现了增量式PID算法的核心逻辑,配合数据块做参数管理和手自动切换。

这套程序适合谁用?如果你是做设备集成、非标自动化或者过程控制的工程师,手头正好是1200或1500的CPU,又要面对温度、压力、流量这类慢过程的闭环调节,那这份程序比你去啃PID_Compact的底层帮助文档要省事得多。它能帮你把PID控制从“黑匣子”变成自己可控的逻辑,从采样周期、微分增益到输出限幅,每一个参数都看得见、改得动。

2. 增量式PID原理与架构选型:为什么不用自带指令,算法怎么落到PLC里

2.1 增量式与位置式的本质差异

先厘清一个基础概念。增量式PID和位置式PID的区别不在比例、积分、微分的计算方式上,而在输出含义上。位置式PID直接输出控制量的绝对值u(k),一旦积分项饱和或者偏差突变,输出会有大幅度跳变,这对阀门、变频器这类执行机构很不友好。增量式PID输出的只是控制量的变化量Δu(k),执行机构在当前基础上叠加这个增量,天然具备抗冲击能力。

增量式公式写出来是这样的:

Δu(k) = Kp * [e(k) - e(k-1)] + Ki * e(k) + Kd * [e(k) - 2*e(k-1) + e(k-2)]

对应的实际输出是:

u(k) = u(k-1) + Δu(k)

从公式能看出,增量式算法只需要保存最近三次的偏差值e(k)、e(k-1)、e(k-2),不需要累加历史偏差,这就从结构上规避了积分饱和的问题。而且Δu是增量,即使计算出现异常,输出也只会产生小幅波动,不会让阀门从全开瞬间变全关。

2.2 在西门子PLC上的实现方案选择

S7-1200和S7-1500都支持PID_Compact,为什么还要自己写?我在项目里遇到过两个痛点:第一,PID_Compact的调试面板和参数结构在1200和1500之间的版本适配有细微差异,换CPU型号就要重新验证;第二,PID_Compact是封装好的黑盒,输出限幅、微分滤波、抗积分饱和这些细节不开放,排查问题的时候很难定位到底是哪一环出了问题。

自己写增量式PID,技术路线上要考虑的点如下:

项目选择原因
编程语言ST结构化文本算法实现清晰,便于移植和二次修改
函数块类型FB函数块生成独立背景DB,支持多重实例,方便多回路复用
循环扫描OB30循环中断固定采样周期,不依赖主程序扫描周期
参数存放背景数据块每个控制回路一套参数,互不干扰
手自动切换内置于FB手动模式直通操作值,自动模式下增量叠加

这里要特别说采样周期的选择。PID算法对采样周期Ts有硬性要求:Ts必须小于被控对象时间常数的1/5到1/10。温度控制一般取1到5秒,压力控制取100到500毫秒,流量控制取50到200毫秒。程序里我把采样周期放在中断组织块里实现,让它独立于主程序运行,这样主程序怎么改都不会影响PID的运算节拍。

2.3 程序整体架构

整个PID程序分三层:最上层是OB30中断组织块,负责按固定周期调用PID计算;中间层是FB_PID_Incremental功能块,封装了PID算法核心逻辑;最底层是物理I/O映射,把模拟量输入模块读到的工程量转换为偏差值,把PID计算出的增量累加到操作值并输出到模拟量模块。

OB30(循环中断,Ts=500ms) | +---> FB_PID_Incremental(背景DB:DB_PID_Temp) | +---> 模拟量输入:PV(过程值) +---> 设定值:SP(来自HMI或上位机) +---> 输出操作值:MV(到阀门/变频器) +---> 手自动切换:Auto_Man_Switch

这个架构最核心的设计是FB块的复用能力。一个PID回路用一套背景DB,如果现场有4个温度区,就调用同一个FB四次,配上四个不同的背景DB。在博途里这叫做多重实例或者参数化调用,后面第3章会看到具体代码。

3. 程序落地:FB块设计与核心代码逐段拆解

3.1 功能块接口定义

打开博途,新建一个FB块,语言选ST,名字叫FB_PID_Incremental。接口参数是这样定义的:

FUNCTION_BLOCK FB_PID_Incremental VAR_INPUT SP_Real : REAL; // 设定值,来自HMI PV_Real : REAL; // 过程值,来自模拟量输入转换 Auto_Man_Switch : BOOL; // TRUE=自动模式,FALSE=手动模式 Man_Value : REAL; // 手动模式下的操作值 Kp : REAL := 2.0; // 比例增益 Ki : REAL := 0.1; // 积分增益(针对Ts归一化后的值) Kd : REAL := 0.0; // 微分增益 Ts : REAL := 0.5; // 采样周期,单位秒 Out_Max : REAL := 100.0; // 输出上限 Out_Min : REAL := 0.0; // 输出下限 END_VAR VAR_OUTPUT MV_Out : REAL; // 操作值输出(到模拟量输出模块) Delta_U : REAL; // 本次增量值(用于监视) In_Service : BOOL; // 功能块正在自动运行标志 END_VAR VAR e_k1 : REAL := 0.0; // 上一次偏差 e(k-1) e_k2 : REAL := 0.0; // 上上次偏差 e(k-2) MV_Auto : REAL := 0.0; // 自动模式下的内部叠加值 END_VAR

接口设计的几个考虑点:所有PID参数都用REAL类型,不用INT,避免量程转换带来的精度损失。Kp、Ki、Kd三个参数开放成输入变量,可以直接在背景DB在线监视界面修改,调试时不用反复下载程序。Out_Max和Out_Min是输出限幅参数,防止阀门在自动模式下一次跳变过大。

3.2 增量式PID算法核心实现

进入FB块主体,核心算法在主程序区(不是初始化区)逐行执行:

// 自动模式:执行增量式PID计算 IF Auto_Man_Switch THEN // 第一步:计算当前偏差 e_k := SP_Real - PV_Real; // 第二步:增量式PID公式 Delta_U := Kp * (e_k - e_k1) + Ki * e_k + Kd * (e_k - 2.0 * e_k1 + e_k2); // 第三步:累加到内部操作值 MV_Auto := MV_Auto + Delta_U; // 第四步:输出限幅处理 IF MV_Auto > Out_Max THEN MV_Auto := Out_Max; ELSIF MV_Auto < Out_Min THEN MV_Auto := Out_Min; END_IF; // 第五步:将操作值送到输出变量 MV_Out := MV_Auto; // 第六步:更新偏差历史,准备下一次计算 e_k2 := e_k1; e_k1 := e_k; In_Service := TRUE; ELSE // 手动模式:直接透传手动值,同时同步内部状态 MV_Out := Man_Value; MV_Auto := Man_Value; e_k1 := 0.0; e_k2 := 0.0; Delta_U := 0.0; In_Service := FALSE; END_IF;

这段代码的逻辑要说一下:第一步计算偏差,做的是SP减PV方向,也就是正作用。如果现场是反作用回路(比如阀门开大温度反而降低的特殊工艺),只需要把SP_Real和PV_Real互换,或者在前面加一个负号。

第二步是算法的灵魂。注意这里Ki前面没有乘以Ts的显式写法,因为我约定的Ki参数本身就是经过归一化的值——也就是说,在整定的时候我直接把Ts的影响并入了Ki数值中。这样做的好处是目标程序里的公式简洁,坏处是Ki的量纲不直观。如果你喜欢教科书式的写法,可以把公式改成Ki * Ts * e_k,那就要把Ts作为一个单独参数传入并参与乘法。

第三步的MV_Auto累加是增量式的核心特征。它替代了位置式PID里的积分项,但又不是传统意义上的积分,而是一个不断累积的操作基准值。这个基准值配合输出限幅,保证了执行机构不会跑出安全范围。

3.3 模拟量输入信号的处理

PID算法本身算的是实数,但PLC读到的温度变送器信号是4到20毫安电流,通过模拟量模块转换后变成0到27648的整数。所以必须在调用PID之前完成量程转换。这里我给了一个标准化函数FC_AI_Scale:

FUNCTION FC_AI_Scale : REAL VAR_INPUT Raw_Value : INT; // 模拟量模块原始值 AI_Min : REAL; // 量程下限,例如0.0 AI_Max : REAL; // 量程上限,例如100.0 END_VAR VAR_TEMP Raw_Float : REAL; Range_Scale : REAL; END_VAR BEGIN Raw_Float := INT_TO_REAL(Raw_Value); // 0~27648线性映射到工程量,同时处理超量程(如断线时读到32767) IF Raw_Value > 27648 THEN FC_AI_Scale := AI_Max; ELSIF Raw_Value < 0 THEN FC_AI_Scale := AI_Min; ELSE Range_Scale := (AI_Max - AI_Min) / 27648.0; FC_AI_Scale := AI_Min + Raw_Float * Range_Scale; END_IF; END_FUNCTION

这里有个工程细节值得注意:模拟量模块断线或者变送器故障时,读到的原始值会跳到32767(超上限),如果不做限制,转换后的过程值会飙到极大值,PID会把阀门往反方向打到极限。所以我在转换函数里加了上限判断。

3.4 在OB30循环中断里调用PID

创建一个循环中断组织块,命名为OB30,中断周期设成500毫秒。在OB30里写调用代码:

// 温度区1的PID控制回路 "DB_PID_Temp_Zone1".SP_Real := "HMI_Temp_SP_Zone1"; "DB_PID_Temp_Zone1".PV_Real := "FC_AI_Scale"(Raw_Value := "AI_Raw_Temp_Zone1", AI_Min := 0.0, AI_Max := 100.0); "DB_PID_Temp_Zone1".Auto_Man_Switch := "Zone1_Auto_Man"; "DB_PID_Temp_Zone1".Man_Value := "HMI_Man_Value_Zone1"; "FB_PID_Incremental".Instance := "DB_PID_Temp_Zone1".Instance; "FB_PID_Incremental"(SP_Real := "DB_PID_Temp_Zone1".SP_Real, PV_Real := "DB_PID_Temp_Zone1".PV_Real, Auto_Man_Switch := "DB_PID_Temp_Zone1".Auto_Man_Switch, Man_Value := "DB_PID_Temp_Zone1".Man_Value, Kp := 1.8, Ki := 0.05, Kd := 0.0, Out_Max := 100.0, Out_Min := 0.0);

在博途里,FB块的背景DB地址有精细符号寻址和多重实例两种方式。上面这种写法用的是多重实例方式——在OB30的局部变量表中定义了一个静态调用。你也可以直接在OB30里写一条"FB_PID_Incremental_Instance"(...)的调用语句,然后把接口参数连到全局DB变量上,两种方式效果一样,看个人习惯。

4. 参数整定实战与避坑指南:现场调试的血泪经验

4.1 工程上常用的整定步骤

拿到这套增量式PID程序,不要急着把Kp、Ki、Kd填上就投自动。我调试过各种温控设备,总结了一套相对稳的整定流程:

第一步,手动模式到稳态。把Auto_Man_Switch切到手动,手动给一个操作值让被控对象稳定在某个工作点,比如给阀门40%开度,让温度稳定在60度左右。

第二步,临界比例度法初调Kp。把Ki和Kd先设成0,只保留比例项。手动模式把设定值改成目标值,然后切自动。观察过程值的响应曲线——如果等幅振荡,说明Kp已经到临界值,记下这个Kp值,最终Kp取它的40%到60%。如果没有振荡但响应太慢,逐步加大Kp,每次加0.2到0.5,直到出现轻微振荡再往回调。

第三步,加入积分消除静差。保持上述Kp不动,逐步增加Ki。每增加一点,观察稳态时过程值和设定值是否重合。这里有个判断技巧:如果过程值到稳态后和设定值之间有固定偏差,就是Ki太小;如果出现缓慢的周期波动,就是Ki偏大。以采样周期0.5秒为例,我常用的Ki初始值是Kp的1/20到1/50。

第四步,按需加微分。温度控制的大惯性系统一般可以不加Kd,如果超调抑制不住,再加一个很小的Kd,典型值在Kp的1/10到1/30。Kd加多了输出会抖,阀门会频繁动作,反而烧执行器。

4.2 避坑指南:三个最常踩的坑

第一个坑:输出限幅值设成了0到100,但执行机构实际收到的是0到27648。这会造成PID输出100%时阀门只开一半。

原因是对应关系搞混。程序里Out_Max和Out_Min是PID内部标准化的百分比量程,但模拟量输出模块要的是原始整数。正确做法是在PID输出后面再级联一个工程量转原始值的函数,把0到100的百分比映射到0到27648。

解决办法是在OB30中PID调用后面加一行转换:

"QW_Temp_Zone1" := REAL_TO_INT("DB_PID_Temp_Zone1".MV_Out / 100.0 * 27648.0);

第二个坑:手自动切换瞬间,输出跳变。现象是手动模式下给了阀门50%开度,切自动的一瞬间阀门猛地开到100%或者关到0。

原因是手动模式切自动时,MV_Auto被直接赋值为Man_Value,但PID内部残留的e_k1和e_k2没有清零。如果切换前手自动状态一直保持偏差,剩下的偏差历史会在切换后第一拍产生一个很大的Δu,叠加在MV_Auto上,就造成输出跳变。

解决办法看我上面代码的手动分支:切换手动时把e_k1清零、e_k2清零、Delta_U清零。同时把MV_Auto同步成当前的手动值。这样切自动后第一步的偏差计算是从零开始的,增量不会突变。

第三个坑:程序下载后,FB块的背景DB被初始化导致输出归零。现象是在线监视时一切正常,但只要把程序停止再运行,或者做一次完全下载,阀门就会全关,影响到现场。

原因是背景DB的保持性设置。默认新建的DB是非保持性的,CPU冷启动或者程序重新下载后所有变量回到初始值。MV_Auto回到0,PID在自动模式第一拍就会从0开始累加,阀门从全关慢慢爬升。

解决办法是把背景DB的设置改成“保持性”:

打开DB_PID_Temp_Zone1 -> 属性 -> 保持性 -> 在掉电保持中保持

这样CPU重启后MV_Auto恢复成最后的值。或者在上电初始化程序里,把MV_Auto读入之前保存的EEPROM/RETAIN值。

4.3 在线调试的监视方法

博途在线监视时,我一般强制打开背景DB的监视表,同时观察三组变量:

一是偏差相关变量e_k、e_k1、e_k2,确认偏差数据是实时更新的,如果e_k1一直不变说明PID采样可能没进中断OB30。

二是Delta_U增量值,它在稳态时应该趋近于零或在小范围内波动。如果Delta_U恒定输出正值或负值,说明存在恒定偏差,积分在起作用,还需要微调Ki。

三是MV_Auto操作值,它应该平缓变化。如果MV_Auto在一个扫描周期内从10跳到90,说明Kp或Kd过大,或者输出限幅设得太宽了。

5. 实际项目应用:从温度区到多回路系统的适配

5.1 单回路温度控制的完整接线示例

我在某条产线的加热炉项目上跑过这套程序,控制对象是电加热丝,执行机构是固态继电器配合PWM驱动,反馈元件是热电偶配温度变送器。整个信号链路如下:

热电偶 -> 温度变送器(4~20mA) -> 模拟量输入模块(SM1231 AI) -> FC_AI_Scale -> FB_PID_Incremental -> 模拟量输出模块 -> 固态继电器 -> 电加热丝

这里有个改动点:标准的模拟量输出模块输出的是4到20毫安或0到10伏电压,固态继电器用的是PWM触发。所以我在PID输出后面不是直接送给模拟量输出,而是先做PWM转换——把0到100的输出百分比折算成导通时间,写进一个定时中断里控制固态继电器的通断。

PWM转换的思路:设定一个PWM周期,比如2秒,输出百分比50%就意味着在2秒内导通1秒、关断1秒。对于加热这种大惯性对象,20Hz以下频率的PWM是完全够用的,周期太长会导致温度波动,周期太短会频繁开关导致固态继电器损坏。

5.2 扩展成多回路温控的工程做法

加热炉往往不止一个温区,这套增量式PID程序的多回路扩展方式我之前提过——复制FB调用,配新的背景DB。在博途里操作是这样的:

第一步,在程序资源里复制FB_PID_Incremental,生成FB_PID_Incremental_Zone2,或者直接复用同一个FB。推荐复用同一个FB,因为算法完全一样。

第二步,在DB文件夹里新建两个背景DB,比如DB_PID_Temp_Zone1和DB_PID_Temp_Zone2,都分配给FB_PID_Incremental。

第三步,在OB30里写两次调用,各自绑定自己的背景DB和输入输出变量。

示意图如下:

OB30 ├── FB_PID_Incremental(DB_PID_Temp_Zone1) 温区1 ├── FB_PID_Incremental(DB_PID_Temp_Zone2) 温区2 ├── FB_PID_Incremental(DB_PID_Temp_Zone3) 温区3 └── FB_PID_Incremental(DB_PID_Temp_Zone4) 温区4

注意:如果四路的PID参数差异比较大,每路的Kp、Ki、Kd都要独立整定;如果四路是完全一样的对称结构,可以调好一路后把参数复制到其他路,微调即可。

5.3 1500PLC上的迁移要点

这套程序在1200和1500上是通用的,但迁移时有几个要确认的点。第一,OB30的中断周期在1500上可以设得更短,CPU处理能力更强,对于需要更快响应速度的流量控制场景可以把Ts设到100毫秒甚至50毫秒。

第二,1500PLC支持IEC定时器,如果你想把采样周期改成用定时器事件触发而不是循环中断,在1500上要注意定时器分辨率和中断抖动的问题。建议还是用循环中断,省去时间同步的麻烦。

第三,1200和1500的地址空间不同。1200的模拟量输入输出地址从IW64或QW80开始,1500的模拟量模块地址可能在不同槽位上,迁移时要把程序里的I/O地址全局替换。

6. 二次开发:让这套PID程序适配更多场景的技巧

到了这个阶段,你已经能把程序跑起来了,接下来聊怎么改。二次开发的核心是把通用性和特殊性分离。

针对特殊工艺的改造,最容易踩的一个点是对执行机构类型做适配。目前程序输出的是0到100的百分比,对应线性阀门或者连续调节的变频器。如果在现场碰到快开阀、等百分比阀这样有非线性特性的执行机构,纯粹的输出百分比跟不上流量特性,会导致PID参数在低开度区准确、高开度区失调。处理方法是在PID输出后面加一个非线性补偿查表函数:

FUNCTION FC_Valve_Compensate : REAL VAR_INPUT MV_Percent : REAL; // PID输出的百分比 END_VAR VAR_TEMP Comp_Tab : ARRAY[0..10] OF REAL; // 补偿曲线表 END_VAR

补偿表的思路是把阀门的实际流量特性标定出来——在手动模式下给不同的开度值,记录对应的实际流量或温度变化率,得到一组离散映射,然后在线性PID输出和真实输出之间做插值补偿。这样PID的线性模型假设就重新成立了。

针对执行机构频繁动作的场景,可以加一个输出变化率限制。目前程序里只有输出限幅,也就是限制MV_Auto的绝对范围,没有限制它每次的增量幅度。在实际项目里,变频器驱动的风机如果PID增量太大,转速会突变,对机械结构有冲击。我给程序加了一个增量限幅系数:

// 在Delta_U计算之后执行增量限幅 IF Delta_U > Delta_Max THEN Delta_U := Delta_Max; ELSIF Delta_U < -Delta_Max THEN Delta_U := -Delta_Max; END_IF;

Delta_Max作为TH输入加到FB接口里,我一般取输出量程的2%到5%作为每步最大增量。这样就算是Kp调得偏大,输出也会被限制在平滑变化的范围之内,保护后端的执行机构。

第三个可扩展方向是前馈补偿。如果现场有可测的扰动量——比如蒸汽加热系统里进料流量变化会直接影响温度,可以把扰动量引入到操作值里,做一个静态前馈补偿。前馈叠加到MV_Auto上,PID只负责修正前馈的偏差部分。这样扰动量一出现,输出立即响应,不用等温度偏差产生了再靠PID慢慢拉回来。

我习惯的做法是在FB的VAR_INPUT里增加一个FF_FeedForward变量,在自动模式计算完成后:

MV_Out := MV_Auto + FF_FeedForward; // 再次限幅 IF MV_Out > Out_Max THEN MV_Out := Out_Max; END_IF; IF MV_Out < Out_Min THEN MV_Out := Out_Min; END_IF;

前馈量用标定好的比例系数乘以扰动量实测值算出,这个比例系数同样可以在线调整。

最后想分享一个小教训:做完任何一项改动,不管是自己写还是抄网上的,都不要跳过全流程验证。从那以后我每次拿到新的PID需求,都强制走一遍“手动标定特性曲线→纯比例临界振荡→依次加积分微分→切自动联调”这个流程,宁可多花两小时在现场,也不再迷信一次就能把参数填好。调试PID这件事,方法论比经验重要,经验比玄学重要。希望这套增量式PID程序能帮你少走几个弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询