简介:西门子S7系列可编程控制器中的FB58 PID功能块自整定源程序包,面向工业自动化工程师、PLC调试人员及过程控制学习者,重点解决传统PID参数整定耗时、依赖人工经验的问题。压缩包共3个文件,约1.04MB,包含C语言源码、PDF说明文档和TXT补充说明。C源码展示FB58功能块的算法实现,可直接查看或导入TIA Portal工程;PDF文档讲解PID温度控制思路和自整定原理;TXT文件给出实际应用时的注意事项。内容涉及比例、积分、微分参数调节逻辑,以及FB58从搜索振荡范围到优化增益的两阶段自整定过程,帮助理解阶跃响应分析、稳态误差消除等关键环节。已有1751人学习下载。通过研读源码与配套文档,可掌握P/I/D增益配置、采样时间与死区参数设置、自整定触发条件等工程技巧,为温度、压力、流量等回路提供可复用的控制方案。
1. 聊程序之前:FB58是做什么的,为什么有人绕过FB41单点找它
做SI的同行应该都有这种经历:一套恒温设备、一条加热炉、一个注塑模温机,工艺要求温度稳态偏差在正负1度以内,结果变频器都调好了,温度还在那儿慢慢晃。很多人第一反应是用FB41做PID,但FB41做温度控制有几个先天毛病——纯滞后大、无自整定,或者自整定效果很迷。西门子专门为温度回路放了个功能块FB58,它内部集成了自整定算法,能根据被控对象的时间延迟和增益自动算出P、I、D参数。这套FB58源程序不是简单复制功能块封装,而是把内部源码、背景DB、调用框架都放在了一起,能让使用者搞清楚整定过程到底在算什么。解决的核心问题是:温度PID回路怎么从反复试凑变成自动整定。适合那些正在用S7-300/400做温度控制、又被PID参数折磨过的工程师。你可以把它理解为西门子给温度控制专用的PID黑匣子,但源码拿到手,黑匣子就变成透明了。
2. 选型与原理:FB58和FB41差在哪,自整定到底在调什么
2.1 功能块选型:温度回路为什么优先用FB58而不是FB41
不少程序习惯用一个FB41走天下,流量、压力、温度都拿它做。但温度对象和流量对象特性差别很大:流量回路惯性小,滞后时间常,PID参数相对好凑;温度回路往往是大惯性、大滞后,还有一个更麻烦的问题——对象增益会随工况漂移,比如散热条件变化、环境温度变化,都会让同一个P值在不同时段产生完全不同的控制效果。FB41的PID参数是固定的,它不管对象变化,整定完了就那样了。FB58的设计目标就是针对这种慢过程、大滞后对象,它在内部多了一个关键环节:自整定。自整定的内涵是,它不去猜,而是主动向对象施加热量扰动信号,然后测量温度上升过程中的响应曲线,从中提取对象的时间常数、滞后时间和静态增益,最后按某种规则换算成PID参数。
FB58和FB41的选型判断,我一般看两点。第一是回路类型,纯温度或者带温度前馈的控制,优先使用FB58;如果是压力、转速这些快回路,继续用FB41反而方便。第二是是否需要自整定,FB41在S7-300/400的标准库里面是没有自整定功能的,如果你需要自动整定,就别想办法补齐FB41,直接用FB58会更省力。这里要注意,FB58虽然名字叫“温度PID”,它也可以用于那些纯滞后明显、时间常数大的非温度回路,但常见用法还是集中在温度上。源程序里给的默认采样时间参数、死区参数也都是按温度应用给出的,所以把它用在别处时,采样时间和延迟补偿参数要重新设定。
2.2 自整定触发逻辑:看相位、测周期、定PID三个过程
FB58的自整定不是一按就完事,它内部是有阶段状态的。整定启动后,功能块会先让控制器输出一个阶跃变化,通常是朝着高于当前给定值的输出走,让实际温度越过给定。这个过程的目的是观测温度上升的斜率。紧接着,功能块会在温度信号里识别出振荡周期和衰减比,这就是自整定的核心:看被控对象在阶跃或继电激励下怎么响应。西门子把这种激励叫做继电整定,它让输出在高低限之间切换,逼迫被控变量产生等幅振荡,然后测量振荡周期和幅度。
源程序里你会看到一些内部变量,比如PHASE、STATE这类状态字,它们就是用来切换整定过程的。整定开始时,STATE从0跳到1,相当于初始化;然后进入激励阶段,STATE跳到2,此时FB58按内部设定的继电幅度输出;之后判断振荡是否形成,进入参数计算阶段,STATE变成3;最后把计算结果写入PID参数相关变量,STATE回到0。三个阶段对应的时间尺度完全不一样。激励阶段可能要等好几个温度周期,一个周期几十秒到几分钟都很正常。所以做自整定时,不能急。
这里有个容易被忽略的细节:FB58自整定计算出来的参数,并不是直接写进它自己的PID参数变量,而是先放在内部结果变量里,比如GAIN、TI、TD这些,需要你再写一段代码把它们转移到正式PID参数区。源代码里一般会提供这种转移逻辑,但也有简化版源码只是把结果暴露出来。拿到源程序后,第一步要做的不是往PLC里灌,而是先读清楚结果变量里这些PID参数是存放在哪个地址、以什么格式保存。常见的是REAL浮点格式,比例增益无量纲,积分时间单位是秒,微分时间单位是秒。后面我会专门讲这个转移怎么写,以及为什么转移这一步能救你一命。
3. 源程序的块结构与参数映射:从源码里找出每个管脚的真实用途
3.1 接口拆解:关键输入/输出参数表
拿到FB58源程序,第一件事是把块接口看清楚。FB58与普通FB块一样,有输入、输出、子过程和维护变量。但它的输入参数比FB41要多出一大半,因为自整定需要额外的控制字和状态字。很多人在用FB58时翻车,就是因为把FB41的使用习惯套过来,只填了Gain、TI、TD,没管自整定相关参数,结果PID功能完全没反应。
我把这套源程序里常见的接口参数列成一张表,按使用频率排序:
| 参数名称 | 类型 | 方向 | 说明 |
|---|---|---|---|
| COM_RST | BOOL | 输入 | 复位信号,为TRUE时整个功能块初始化,PID参数恢复默认 |
| MAN_ON | BOOL | 输入 | 手动/自动切换,TRUE为手动,输出直接跟MANUP |
| CYCLE | TIME | 输入 | 采样周期,必须和OB35中断时间一致,常见设为T#500MS或T#1S |
| SP_INT | REAL | 输入 | 内部给定值,温度设定值,单位由外部统一 |
| PV_IN | REAL | 输入 | 过程变量,即实际温度反馈值,对应模拟量转换后的工程值 |
| MANUP | REAL | 输入 | 手动输出值,在MAN_ON=TRUE时直接作为输出 |
| LMN | REAL | 输出 | 调节值,即PID输出,通常转成0~27648或0~100 |
| LMN_PER | WORD | 输出 | 调节值输出(PER形式),直接输出到模拟量模块 |
| DISV | REAL | 输入 | 前馈扰动值,可以叠加,一般不用 |
| STAT_VAR | 自定义结构 | 参数 | 状态变量块,保存内部状态和自整定结果 |
| TUN_D | TIME | 输入 | 自整定微分时间设定,通常保持默认 |
| TUN_TM | TIME | 输入 | 自整定最长运行时间,超过后自动终止,防止整定卡死 |
| TI | REAL | 输入输出 | 积分时间,单位秒,自整定结果会写到这 |
| TD | REAL | 输入输出 | 微分时间,单位秒 |
| GAIN | REAL | 输入输出 | 比例增益,自整定结果会写到这 |
这张表里最需要注意的是STAT_VAR。它是一个结构体,包含了整定过程中的临时测量值,比如振荡周期、输出幅值、过程模型增益等。源程序里它往往被定义成DB块里的一个结构变量,你不能只给它分配一个REAL地址。很多人把STAT_VAR想当然地填成默认的空地址,导致FB58的存储区冲突,运行中程序卡死,这是很典型的一个坑。
3.2 源程序导入与背景DB创建步骤
FB58源程序通常以STL文本格式提供,在STEP7中导入时需要走几个固定步骤。不要直接双击打开就拖进OB1,那样会损失符号名和注释,后面调错你会后悔的。
第一步,新建一个项目,在“源文件”文件夹里右键,选择“插入新对象”,弹出选项里选择“STL源文件”,然后把源码文本复制进去或导入外部文本。源码文件里通常会包含FB58的接口定义和程序主体,可能还包含一个FC或FB的框架调用代码。
第二步,编译这个源文件。编译前需要检查一下源文件里引用了哪些标准库常量,比如S7_STLIB里的符号。如果编译报错“找不到符号”,多半是库没有集成到项目。需要在菜单里选择“集成库”,把标准库挂上,或者手动创建符号表。
第三步,生成FB58功能块。编译成功后,在块文件夹会出现FB58。此时还需要给它创建背景DB。创建背景DB的方法是:在块文件夹空白处右键,选择“插入新对象” -> “功能块”,但更规范的创建方式是选中FB58,按右键“生成驱动模块”或“更新块”,然后创建数据块时选择“背景数据块”,并关联到FB58。
导入完成后,建议在OB35里写一段周期性调用FB58的代码。因为PID调节需要固定的采样周期,建议把FB58调用放在OB35循环中断组织块里,中断时间设为与CYCLE参数一致的数值。常见做法是OB35设成100ms或500ms。但是注意,FB58内部控制计算要求采样间隔稳定,如果OB35中断被低优先级的OB抢占,采样时间会有抖动,实测会影响自整定的相位判断。我一般会用SFC强制激活OB35的中断周期,再在FB58的CYCLE输入端填上同样的时间。
4. 自整定实操:从冷态到稳定整定的完整参数设定
4.1 整定前的回路参数设置(死区、手动/自动切换、采样时间)
很多人拿源码编译通过后,直接给FB58一个给定,然后启动自整定,结果发现整定出来的参数根本不能用。原因大多出在整定前状态没有理顺。FB58的自整定对控制回路有一个预期:回路处于自动模式,PV反馈稳定,输出没有被限幅钳住,过程处于平衡状态。如果你从冷态直接启动自整定,对象温度还在爬升,FB58会把这种爬升趋势当成对象响应的一部分,导致算出来的增益偏低,积分时间偏大。
所以整定前必须把回路先手动加到工作点附近。我的操作流程一般是:先将MAN_ON置为TRUE,手动输出一个经验值,让温度慢慢升到设定值的85%左右;等PV稳定下来,再把MAN_ON置为FALSE,切回自动,让PID用原始的临时参数先运行一段时间。这一步叫做预平衡。注意,FB58的MAN_ON切换不是无扰切换,如果你在输出相差很大的时候切换,输出会跳变。这也是为什么源码里一定要保留MAN_ON的极性和一个斜坡处理逻辑。实际上,源程序里通常没有自动斜坡输出,需要你用外接的斜坡函数处理MANUP变化。
接下来要设定两个关键参数:死区带和输出限幅。FB58自整定的触发需要检测设定值与PV的偏差,如果死区设得太宽,FB58会认为偏差太小而不启动继电激励。我通常把死区设为温度满量程的0.5%左右。比如量程0到200度,死区设置1.0度。而输出限幅一般在输出模块里就已经限制,FB58内部还有LMN_LMV参数,需要把输出限制在10%~90%之间,这样才能让自整定的继电激励有足够的作用空间。如果输出限幅太窄,比如只允许35%~40%,那自整定时激励幅度不够,振荡出不来,整定时间就会无限拉长。
另外,采样周期CYCLE和OB35中断周期要精确匹配。FB58内部的微分环节和自整定相位计算都用CYCLE作为时间基准。如果CYCLE设成了1秒,而OB35实际是500ms,那么块内部的时间运算结果是双倍采样率,整定出来的TI和TD会差一倍。这是一个非常隐蔽的坑。我一般会在启动自整定前在线监控CYCLE管脚的实际值,确认它和OB35中断时间一致。
4.2 启动自整定并读取整定结果:常见做法与结果换算
FB58启动自整定的方式有两种:一种是在参数接口上把TUN_ON置为TRUE;另一种是在FB内部的状态控制字里进行触发。源程序版本不同,触发位名称可能不一样,常见的是TUN_ON或COM_RST与TUN_ON组合。在源程序中搜索关键字TUN_ON就能找到触发逻辑。启动之前,确保给定SP_INT和实际值PV_IN的偏差在死区范围之内。偏差太大时,FB58会先把偏差处理掉,然后才开始继电激励,这会让整定时间变长。
启动时建议用OB1里的一段临时代码触发,而不是直接在DB里在线修改变量。在线修改虽然也可以,但如果你触发了COM_RST复位,会把整定结果一起清掉。正确做法是写一个带沿检测的启动程序:
// 触发自整定:使用边沿检测避免重复触发 VAR trig_need : BOOL; // 外部启动按钮 tun_on_trig : BOOL; // 上升沿标志 END_VAR // 上升沿检测:只在0变1时置位TUN_ON tun_on_trig := (trig_need AND NOT tun_on_trig_old); tun_on_trig_old := trig_need; IF tun_on_trig THEN fb58_instance.TUN_ON := TRUE; // 启动自整定 END_IF; // 整定完成后自动复位 IF fb58_instance.TUN_OK THEN fb58_instance.TUN_ON := FALSE; // TUN_OK为状态位,源程序中通常有 END_IF;这段代码的逻辑是:用沿检测把外部按钮动作转换成一个扫描周期宽度的脉冲,然后触发TUN_ON。整定结束后,如果源程序里有TUN_OK完成位,就复位TUN_ON。这样不会产生重复触发。注意,有些简化版源程序里没有TUN_OK,只通过STAT_VAR里的状态字判断,比如状态2表示整定完成。这时你需要按状态字判断,不能按TUN_ON判断。我见过有人在状态字已经等于2之后,还一直把TUN_ON置位,导致FB58重新进入整定循环,输出一直波动。这个细节要特别小心。
整定结果读取同样要按状态流程来。自整定结束后,FB58会把结果写到GAIN、TI、TD三个变量里。但问题是这三个变量在整定过程中也是PID运行参数,整定结束瞬间它们被更新,之后如果你没有把结果另存,下一次手动切换参数时,这些值可能会被覆盖。所以整定成功后的第一个动作,应该是把结果转移到一个保持DB里。我常用的转移代码:
// 整定结果转移:把FB58的整定参数写入保持DB IF db_keep.need_save THEN db_keep.gain_saved := fb58_instance.GAIN; db_keep.ti_saved := fb58_instance.TI; db_keep.td_saved := fb58_instance.TD; db_keep.need_save := FALSE; END_IF;这个转移逻辑最好加一个手动确认位need_save,即你在触摸屏上看到整定完成后,按一下“保存参数”按钮,才执行这段转移。这样做的好处是,防止自动转移把一次失败的整定结果覆盖掉。我在现场吃过亏,自动转移会把某次不收敛的整定结果当成宝贝存进去,导致生产时温度失控。从那以后,我坚持整定结果保存必须人工确认一次。转移后的参数可以直接用于后续自动运行。你也可以把保存的参数通过数据块上传到上位机存档,为下次开机做准备。
5. 避坑指南:FB58自整定翻车现场与排查方法
5.1 现象:整定后控制震荡,温度上下波动超过允许范围
原因往往是整定过程中被控对象处于非线性区域。比如加热管老化,低输出段加热效率低,FB58在继电激励阶段测得的过程增益偏低,计算出的比例增益偏大,放到正常工况下就变成增益过高,引发震荡。另一个常见原因是死区设置过窄,FB58把PV信号里的噪声当作振荡,计算出极短积分时间。
解决方法是:先不要急着改整定参数,把整定结果GAIN手动乘以0.7,TI手动乘以1.3,这是一个经验折中,让控制器更鲁棒。同时检查PV_IN的滤波,在模拟量转换处增加一阶惯性滤波,时间常数设为0.5秒到1秒,避免噪声进入FB58。如果震荡是周期性的,且周期接近系统固有周期,那问题在相位裕度不够,应加大积分时间。
5.2 现象:自整定一直不结束,TUN_ON置位后几十分钟还在跳
原因大概率是对象滞后太大,在TUN_TM设定的最长时间内无法完成两次继电切换。比如一个大水池加热系统,从输出变化到温度变化可能要5分钟,一个激励周期就近10分钟,而TUN_TM默认设置成了10分钟或20分钟,自然不够。
解决方法是:源程序中的TUN_TM参数需按对象特性估算。估算方法简单粗暴:手动改变输出10%,观察温度和输出变化的延迟,记录这个延迟时间T_lag,则TUN_TM至少设置为20倍T_lag。比如滞后时间是30秒,TUN_TM设为10分钟。另外,检查一下输出是否被限幅限制在了很窄区间,导致温度变化幅度太小,FB58一直无法识别振荡。处理办法是放宽输出限幅,并放大继电激励幅度相关参数,源程序里通常有TUN_D,即自整定微分时间,如果设得太小,也会影响激励。
5.3 现象:手动切换自动时,输出跳变,现场执行机构咔咔响
原因是没有实现无扰切换。FB58不像某些软PLC PID那样内置输出斜坡,MAN_ON从TRUE变FALSE时,内部PID算法会从当前输出值开始积分,但如果此时给定与反馈偏差很大,积分项迅速饱和,输出就会猛冲一下。源程序里如果不处理MAN_ON切换沿,这个问题必然出现。
解决方法是:在MAN_ON置FALSE之前,把当前手动输出值同步到PID输入给定。常见做法是手动跟踪:当MAN_ON=TRUE时,把SP_INT强等于PV_IN,这样切换到自动时,偏差为0,输出保持。实现代码:
// 手动跟踪,确保无扰切换 IF fb58_instance.MAN_ON THEN fb58_instance.SP_INT := fb58_instance.PV_IN; END_IF;另外,如果现场允许,在切自动前先把输出限幅调成当前手动输出附近,切过来后再慢慢放开限幅。这个做法在反应釜温度控制里很管用。
5.4 现象:FB58运行一段时间后数值漂移,PID输出慢慢变满或变零
原因多出在积分饱和和温度PV工程转换异常。FB58的积分项没有抗饱和措施,源程序里可能没有LMN_AVL动态限制,需要靠外部限幅。当输出长期顶在0%或100%,积分项会继续累积,等到偏差反向时,输出还停留在饱和区,这就是积分饱和。解决方法是加一个跟踪逻辑,当LMN超过限幅值时,把积分项保持。
我处理这类问题时会在FB58外部包一层输出限幅:
// 输出限幅与积分保持 IF fb58_instance.LMN > 90.0 THEN fb58_instance.LMN := 90.0; fb58_instance.INT_HOLD := TRUE; // 源程序中如有积分保持位 ELSIF fb58_instance.LMN < 10.0 THEN fb58_instance.LMN := 10.0; fb58_instance.INT_HOLD := TRUE; ELSE fb58_instance.INT_HOLD := FALSE; END_IF;如果源程序里没有INT_HOLD引脚,可以通过把GAIN强制等于0来冻结比例作用,但积分还是会继续,所以推荐的真正做法是:在手动给定时把SP_INT同步到PV_IN,让偏差归零,积分复位。这是最可靠的。另外,PV_IN如果直接从模拟量模块读取而未做归一化,数值可能在0到27648之间乱跳,要注意在PLC程序中先把原始值转成0~100的工程值,再进行PID运算。
5.5 现象:触摸屏上写的PID参数不生效,在线改完又弹回去
原因是你写入的变量不是FB58真正使用的那个变量。如果你使用的是多重背景方式调用FB58,其实例化DB是调用它的FB块或OB块的背景DB。触摸屏组态时如果连的是FB58功能块符号名,系统会自动指向第一个背景DB,但如果你有多个FB58调用,每个实例的DB不同,触摸屏容易连错。而且,源程序里的GAIN、TI、TD变量名称可能和触摸屏组态时使用的变量名不一致。解决方法是:强制在触摸屏上读写背景DB的具体地址,通过绝对寻址的方式连接变量,避开符号名解析错误。在线调试时,用变量表直接监视背景DB里的GAIN地址,确认修改后是否能保持。如果修改后立刻被源程序某段初始化逻辑复位,要检查COM_RST是否被周期置位。
6. 收尾技巧:把自整定结果变成你日常的“后悔药”
FB58真正好用的地方,并不是永远保持那组整定参数,而是它能提供不同工况下的多套参数。我现场做完恒温项目后,通常会把三套参数存进数据块:冷态快速升温参数、保温精确控制参数、大风冷却工况参数。自整定只能针对当前工况算一组参数,所以在不同工况下分别做一次自整定并保存,这是用活FB58的关键。我的习惯是:设备调试完成后,把每一组整定结果连同当时的输出限幅、采样周期、死区一起存入一个自定义数据块,形成一个参数记录表,并在触摸屏做一个下拉选择。切换工况时,不仅换PID参数,还把CYCLE、死区、输出限幅一起切换。FB58的GAIN/TI/TD作为输入输出变量,可以在程序里直接覆盖。下面是我常用的切换代码:
// 工况切换:从参数记录表装载PID参数 IF hmi_recipe_switch = 1 THEN // 切换请求 // 装载升温参数 fb58_instance.GAIN := db_recipe.cold_gain; fb58_instance.TI := db_recipe.cold_ti; fb58_instance.TD := db_recipe.cold_td; fb58_instance.CYCLE := t#500ms; hmi_recipe_switch := 0; END_IF;这段代码的关键是,切换参数的同时把CYCLE也切换了,否则积分时间和采样周期不匹配,控制效果会完全走样。有一次我在某台设备上只改了GAIN和TI,忘了改CYCLE,结果保温阶段温度波动比原来还大,后来发现是采样周期从500ms变成了1s,微分项和时间基准乱了。从那以后,我每次切换参数都强制把CYCLE、死区、输出限幅和PID参数一起写,不再单独只改某一项。
另一个常用的技巧是定期做一次“扰动自整定”。设备运行半年后,加热元件老化、结垢,过程增益会改变。这时候我会安排停机维护时重新做一次自整定,并把结果与上次保存的参数比较。如果增益下降了20%以上,就说明加热系统效率降低,需要安排清洗或更换加热元件。这个技巧既维护了控制性能,又能作为设备预诊断手段,非常实用。FB58源程序里的自整定不仅仅是调PID的工具,它也是一个过程模型辨识工具,只是很多工程师把它只当PID用,浪费了。
每次做完一组自整定,我都会把原始输出曲线截图存档,和PLC里的状态字一起记录。这套源程序让我在温度控制项目上少走了很多弯路,但真正的收益是自己把参数转移、无扰切换、多工况切换这些外围逻辑补齐之后,FB58才能从“能用”变成“好用”。希望帮到你。
本文还有配套的精品资源,点击获取