前阵子一个朋友丢过来一套博途V16的S7-1200工程,说是制药厂生物发酵系统的完整程序,让我帮忙梳理一遍。乍看之下,这套系统好像就是几个发酵罐的温度、pH、DO、搅拌控制,没什么稀奇。可真把程序一段段扒开之后才发现,这玩意儿把PID调节、顺序控制、配方管理、上位机通信、安全联锁全都揉在了一个1200的CPU里,复杂度和精细度远超一般小型设备程序。如果你也在做或准备做发酵、灭菌(SIP)、清洗(CIP)这类偏流程行业的PLC项目,这篇文章值得耐心看完。我会按实际拆解程序的顺序,把架构思路、核心控制逻辑、通信设计、调试踩坑一次讲透。
1. 生物发酵系统为什么用S7-1200 + 博途V16
1.1 先看清发酵系统到底要控制什么
很多人一听“生物发酵”,脑子里想的是一个大罐子,以为就是个温度控制。实际上一个完整的发酵工位,控制对象至少包括:罐内温度、pH、溶解氧DO、搅拌转速、罐压、消泡、补料流量、空气流量,甚至尾气O2和CO2浓度。每个控制对象背后还跟着泵、阀、变频器、模拟量变送器,加起来一个种子罐加三到五个发酵罐的中试车间,I/O点数大概在100到250点之间。
这就决定了这套程序不能像机床或者包装机那样简单写几个电机起停就行。它既要处理连续调节量(温度、DO、pH),又要处理大量的开关量步进顺序(SIP、CIP、接种、放料),还要兼顾批次记录和报警归档。说得直白一点,这是一套微缩版DCS,只不过落在了1200这个小型PLC平台上。
我手里这套程序对应的硬件配置是1215C DC/DC/DC,带两个模拟量输入模块、一个模拟量输出模块,外加一组ET200SP远程IO放在发酵罐平台旁边。选1200而不是1500,核心原因就是点数规模刚好在这个区间,成本差了好几倍,而且博途V16对1200的程序组态、调试监控支持得已经非常完整,现场维护工程师也更容易上手。
1.2 选型不是越大越好,而是刚好够用
有些刚入行的工程师一看到流程行业就本能地想上S7-1500,觉得1200“太小、不靠谱”。但实际做项目时,选型考虑的是控制规模、扫描周期、通信需求、项目预算和维护成本。中小型发酵系统用1200完全足够,CPU再大不会让温度PID控制得更准,反而会让机柜空间、模块价格、培训成本都跟着上去。
需要注意的一个点是固件版本和博途版本的匹配。V16对应1200的固件版本最高支持到V4.5左右,如果你拿到的一台CPU固件是V4.7,那V16是下载不了的,必须升级博途到V17以上,或者让供应商把PLC固件降级。这个坑在调试现场非常常见,很多时候不是程序有错,而是工具版本和硬件固件不匹配。
另外,1200系列里1214C和1215C两个型号差价不大,但1215C多一路以太网口,对于既要接HMI又要接SCADA/MES的项目来说非常实用。我这套程序里就是1215C的第二个网口单独划给了上位机交换机,避免现场调试时HMI在线监控和Modbus TCP轮询互相抢带宽。
1.3 博途V16给这类项目带来的实际变化
博途V16相比老版本,最大的感受是SCL语言的编辑体验好了很多,断点调试、在线监视、Trace曲线工具都齐全。发酵这类程序里顺控逻辑特别多,传统用梯形图写步进器非常占屏幕,而且容易漏条件。SCL可以用CASE语句把每一步的条件、动作、超时都放在一个紧凑的结构里,可读性和维护性都好一个档次。
还有一点是V16对全局库的支持更好了。发酵车间如果不止一个罐子,我会把通用的温度控制FB、pH控制FB、顺控步进FB都做到项目库或者全局库里,然后在每个罐的DB上生成独立背景数据块。这样就避免了复制粘贴程序后忘记改DB的惨剧。这一点我后面会详细讲。
2. 程序总体结构与设计思路拆解
2.1 任务块(OB)怎么分配才算合理
打开这套程序的时候,我第一件事就是看OB列表。一个良好的1200发酵程序,不会把所有东西都塞在OB1里滚动执行。这套程序的OB分配思路大概是这样的:
- OB1负责HMI交互、手动操作、阀位输出刷新、通用报警;
- OB30(循环中断)专门做PID计算和模拟量采样滤波,循环周期设置为100ms;
- OB40用于硬件中断,比如急停回路输入触发后的快速处理;
- OB82诊断中断,用来捕捉模块插拔、短路等诊断事件。
这么分配背后是有原因的。PID运算和模拟量采样对时间确定性要求高,放在OB30里能保证每次循环间隔基本固定。而HMI通讯和手动操作逻辑放OB1,即使因为某些通讯延迟导致OB1扫描时间偶发变长,也不会直接影响PID的控制稳定性。
很多1200初学者会忽略OB30的优先级,一上来就在OB1里直接调用PID_Compact,结果现场发现控制周期忽快忽慢,自整定出来的参数怎么都不对。把运算挂到固定周期中断里,是这类连续控制程序的基本功。
2.2 FC、FB、DB三类程序块的“家族谱”
我把这整套程序的块结构拆开之后,整理出了一个很清晰的职责分工:
- FC(函数):做纯计算和转换,比如模拟量工程量换算、累加量计算、手动/自动模式切换。这类块没有自己的存储区,适合做无状态的计算方法;
- FB(函数块):做有状态的控制逻辑,比如发酵步骤顺控、CIP清洗步进器、PID参数管理。每个FB配一个背景DB,用来保存中间状态和步号;
- DB(数据块):分为接口DB、工艺参数DB、配方DB、报警DB。接口DB专门用于和HMI通信,把所有需要显示的变量集中管理;工艺参数DB存温度设定、pH设定、PID参数等;配方DB按批次号存储不同产品的工艺路径;
- 全局DB和PLC变量表:负责硬件IO映射和跨块共享变量。
这套结构最值钱的地方在于“每个FB只干一件事”。比如发酵顺控FB只负责步进逻辑,它不直接去操作泵和阀的输出点,而是通过接口DB把“目标状态”交给输出刷新FC。这样一来,手动/自动模式切换就是切换输出刷新FC的数据源,程序的安全互锁也只有一个地方维护,不会出现阀被多个地方同时写的情况。
2.3 命名规范:别人能不能看懂你的程序,就看这一步
拆这套程序时我发现,原开发者应该是从DCS转过来的人,因为他的变量命名全部沿用了仪表位号体系。比如TT-101表示温度变送器101,PV表示过程值,SP表示设定值,CV表示控制输出;FIC-201是流量控制指示,AT-101是pH分析仪。这样命名最大的好处是,工艺工程师和设备维护人员拿到程序列表,不需要看注释就能对上现场仪表。
我自己做程序也强烈建议坚持“位号+属性”的命名规则。比如一个阀,不要叫“V12”,要叫“XV-101_OPEN_CMD”或者“FV-201_AUTO_SP”。一开始写起来觉得繁琐,但等到两个人协作调试、或者半年后甲方要求加一个联锁条件时,你会感谢当初的命名习惯。
2.4 联锁和安全设计不是锦上添花
制药发酵系统涉及高温蒸汽、酸碱物料、带压容器,程序里必须有联锁设计。这套程序里,联锁分了两个层次:
第一层是硬联锁,也就是急停回路和关键安全阀的硬接线。比如急停按钮直接切断蒸汽切断阀和酸碱泵的AC220V控制回路,不经过PLC,这是任何时候都优先保证的安全底线。
第二层是程序软联锁,比如温度超过上限时强制关闭蒸汽阀、罐压超高时打开排气阀、pH超过安全范围时禁止加酸泵启动。软联锁写在FB内部,并且优先级高于自动控制输出,同时带有2秒的输入滤波,防止信号抖动导致误动作。
需要强调的是,S7-1200标准型CPU本身不具备功能安全认证,这些软联锁只能作为工艺保护手段,不能作为唯一的人身安全保护。如果要达到SIL等级要求,必须上1200F系列或者单独的安全继电器回路。这一点在做制药项目时如果被问起,一定要讲清楚,别给自己埋雷。
3. 发酵核心控制逻辑:从PID到顺序控制的实操拆解
3.1 温度控制不是简单一个PID就能搞定
发酵罐温度控制表面上就是加热和降温,但实际执行起来牵扯到冷热水阀的分程控制。这套程序里使用的是PID_Compact指令,PID输出0%到100%后,再经过分程计算拆成两路阀位:0%到50%对应冷冻水阀,50%到100%对应蒸汽阀,中间再加一个2%的死区,避免两个阀在切换点附近频繁动作。
PID参数方面,程序初始设定比例增益2.5,积分时间180秒,微分时间设为0,采样周期100ms。先让PID自整定跑一轮,再手动微调。这里有一个很实用的经验:温度对象大滞后,微分时间尽量不要加,加多了反而会在蒸汽阀开启瞬间产生剧烈振荡。真正起作用的是积分分离和输出变化率限制。我在现场经常看到有人拼命调PID参数却忘了把输出变化率限制加上,结果蒸汽阀从0%猛冲到80%,罐温瞬间过冲四五度。限制输出变化率在每分钟不超过30%,温度曲线会平稳得多。
3.2 pH和DO控制:不能用常规PID思维
pH调节和DO调节是发酵程序里最容易写崩的两个回路。pH受加酸泵和加碱泵影响,系统存在严重非线性,而且执行机构是开关量泵,不是连续调节阀。程序里用的是一种非常实用的“死区+时间比例”控制算法:设定目标pH为7.00,死区设为±0.05;偏差超过死区时,每个控制周期内按偏差比例计算泵的启动占空比。偏差小,泵脉冲宽度小,偏差大,泵长开。这样既避免了泵频繁起停烧电机,又能把pH控制在一个较小的波动范围。
我拆开这套程序的内部逻辑时注意到,它的占空比上限被限制在80%,而不是100%。这个细节很妙:留出20%的“不动作时间”用来观察pH变化的真实趋势,防止系统过冲。溶解氧控制则用了串级思路:DO主调节回路的PID输出作为搅拌变频器的转速给定,当搅拌转速已经达到上限而DO仍然偏低时,再通过一个比较器打开补气阀门增大空气流量。串级回路里尤其要注意给定上下限,否则一旦DO偏低,搅拌速度会瞬间冲到最高,发酵液剪切力过大反而影响菌体生长。
3.3 补料策略与消泡逻辑:看似简单实则讲究
发酵过程中的补料控制比想象中要复杂。程序里补料泵有三种模式:连续流加、间歇流加、指数流加。连续流加最简单,按设定流量对应频率运行;间歇流加则是每固定周期启动一段时间,适合需要脉冲式补充营养的工艺;指数流加需要根据当前发酵时间离线算好一个流加曲线,存放在配方DB里,程序按时间点查询并更新泵频率。
消泡逻辑则是另一层戏。消泡电极一旦检测到泡沫接触,程序不是简单启动消泡泵,而是先暂停补料泵,同时将搅拌转速强制提升20%,维持5秒把泡沫甩掉,再恢复原来的电机转速。如果泡沫信号在10分钟内触发了超过5次,系统就判断为严重起泡,触发声光报警并自动停止该罐的补料程序。这个策略既保护了消泡效果,也防止了过度补料。
3.4 SIP/CIP顺序控制:步进器的写法与工程陷阱
发酵罐的在线灭菌和清洗是整个程序里程序步最多、最容易出问题的地方。SIP(在位灭菌)的典型步序大概是:开启排气阀和排污阀,打开蒸汽阀升温,到达灭菌温度后进入保温段,保温计时完成后关闭蒸汽阀,通过夹套冷却循环水降温,最后是保压和排凝。每一步都是一个“条件满足才允许进入下一步”的步进状态机。
程序用SCL的CASE语句实现步进器,每个CASE分支代表一个工艺步。每步包含进入条件、过程动作、超时时间、离开条件。实际操作中最关键的一个细节是步进值的保持:手动/自动模式切换时,不改变当前步号。如果现场人员切到手动动了几个阀,再切回自动,程序必须能感知实际状态并重新同步,否则就会出现“程序以为还在升温,实际上已经冷却”这种严重事故。
还有一点必须强调:跳步操作在制药验证流程里是不允许的。整套程序没有开放强制跳步的工程师按钮,只有长按触摸屏维护密码进入的“强制步进”功能,而且每用一次都会在报警记录里留下审计痕迹。这个小设计非常值得学习,它既照顾了调试期的需求,也守住了合规底线。
3.5 模拟量处理与进制转换的工程细节
博途V16里处理4-20mA模拟量,很多人还在用以前的FC105思路去缩放,但在1200里更标准的方式是NORM_X和SCALE_X组合。这里还有一个容易忽视的点:程序要判断信号是否正常。4-20mA对应NORM_X输入范围为0~27648,如果读取值小于约5530(对应大约4mA以下的断线状态),程序会强制把该点标记为故障,并在HMI上显示灰色故障状态,同时联锁该回路保持安全输出值。这个“故障自动判定”逻辑,比单纯做量程转换要重要得多。
至于“十进制转十六进制”这个搜索热词,在发酵系统里最常见的应用场景是两个:一是驱动HMI显示设备的底层状态字,二是接收第三方分析仪(如尾气分析仪)的通信数据。仪表返回的数据通常是16位字,每一位代表一个状态位。比如DO变送器的状态字Bit0表示传感器连接、Bit1表示温度补偿故障、Bit2表示传感器极化电压异常。程序里通过SCL对Word做移位和按位与运算,把每一位解析成独立布尔量,再映射到报警DB。
// 解析第三方设备状态字,示意代码 #rawWord := "Analyzer".StatusWord; #bitSensorErr := (WORD_TO_INT(#rawWord) AND 16#0002) <> 0; #bitPolarization := (WORD_TO_INT(#rawWord) AND 16#0004) <> 0;这一小段逻辑看着简单,但如果不熟悉位操作,现场排查通信问题时往往会一头雾水。
4. HMI、SCADA与上层系统的数据交互
4.1 博途集成HMI的变量连接方式
这套程序里HMI用的是博途集成的WinCC RT,与PLC通信采用的是标准以太网。我注意到原程序在HMI里没有胡点乱连PLC变量,而是把所有需要显示的变量集中到一个“HMI接口DB”里,HMI的画面直接连接这个DB。
这样做最大的好处是:网络负载小、变量关系清楚、画面快速刷新不卡顿。发酵画面每秒要刷新的数据不少,温度、DO、pH、转速、各阀门状态、批次剩余时间,如果每个控件都单独连PLC变量,HMI通信压力会明显增大。集中到接口DB后,可以统一设置通信周期,比如曲线显示变量用250ms刷新,普通状态量用1秒刷新。
另外V16里1200的DB访问分为优化访问和非优化访问两种方式。优化访问数据块无法被第三方软件用绝对地址直接访问,如果后续要对接SCADA或者用S7协议读数据,这一点要格外注意。我通常会把给上位机用的数据单独放在“非优化访问”的通信DB里,并且地址规划成对齐的Word/DWord结构,方便Modbus TCP和S7通信时做地址映射。
4.2 Modbus TCP与SCADA/MES对接的寄存器映射
制药车间不可能永远只有本地HMI,迟早要接SCADA或MES。这套1200程序里预留了一个Modbus TCP服务器通信块,把需要给上层读的数据统一映射到保持寄存器区。寄存器表设计非常经典,我直接拿过来参考了一下:
- 40001-40020:各罐温度PV/SP/CV,以0.1℃为单位存为整数;
- 40021-40040:pH和DO的PV/SP,扩大10倍存储;
- 40041-40060:搅拌频率、补料累计量、消泡次数;
- 40061-40080:运行模式、步进号、报警状态字;
- 40081-40100:批次号、配方号、批次起始时间戳。
这里有个很重要的工程细节:模拟量全部用扩大10倍或100倍的整数传输,而不是直接传浮点数。原因是很多SCADA组态软件读32位浮点数涉及到字节序和内存对齐问题,非常容易发生高低字节颠倒,现场排查起来无比痛苦。用定点整数虽然损失了一点点精度,但换来的是稳定可靠,对于监控层面的系统完全够用。
4.3 批次记录与电子签名:别等验证时再补
制药行业谈数据完整性和审计追踪已经是很正常的需求了。这套程序里虽然没直接跑MES,但已经在PLC和HMI层面预留了批次记录能力。HMI上操作员必须有登录账号才能切换配方、修改设定值、启动SIP/CIP,每一次关键操作都会写入报警/事件日志,带有时间戳和操作员ID。发酵批次结束时,HMI会将这个批次内的温度曲线、pH曲线、补料总量、报警记录打包成一个CSV文件存档,留存到上位机服务器。
这些功能如果等到FAT或者SAT(工厂验收、现场验收)阶段再要求补,改动会很大,而且验证文档的工程量会翻倍。所以如果你现在正在做类似项目,哪怕业主还没提这些要求,PLC里也要预留操作员管理变量和事件日志结构,至少留出MES接口的DB和通信区域。这算是我做这类项目的血泪经验之一。
5. 调试踩坑与常见问题排查实录
5.1 博途V16连不上PLC的经典原因
调试这套系统时,我远程协助现场工程师查过几次“在线连接失败”。排查顺序基本固定:先看电脑网卡能不能ping通PLC的IP,再看博途“可访问设备”扫描结果,最后检查PG/PC接口设置。
最常见的坑是电脑装了虚拟机软件或者多个虚拟网卡,导致博途扫描时默认走了错误的网卡,明明PLC就在旁边却显示红色离线。解决方法是把除实际物理网卡外的其他网络接口临时禁用,然后重新扫描。另一个常见问题是PLC的IP和电脑不在同一网段,直接改电脑本地连接IP到192.168.0.x就能解决。还有一个隐蔽问题就是PLC固件版本和博途V16不匹配,这时在线列表里能看到设备,但项目里的设备会显示一个问号,下载时提示版本不一致。
5.2 模拟量信号漂移干扰怎么彻底处理
发酵罐现场的变频器一启动,温度变送器信号就在4.3mA和4.8mA之间跳,这是调试期最让人崩溃的问题之一。我当时处理这套程序的AI通道漂移,做了四件事之后彻底变稳:
- 信号线全程采用屏蔽双绞线,屏蔽层在PLC柜侧单端接地;
- 变送器供电采用信号隔离栅,隔离栅在配电柜内单独接地;
- 模拟量信号线敷设时避开变频器输出电缆,间距保持在50cm以上;
- 程序中加了限幅滤波和一阶惯性滤波,滤波时间常数设置为3秒。
有一点必须提醒:屏蔽层千万不要两端都接地,否则会形成地环流,低频干扰反而更大。如果是长距离传输,还要注意信号源是两线制还是四线制,配电方式不同,接线方式完全不同,接错的话没有任何输出或者直接烧掉模拟量模块。
5.3 调节阀频繁动作导致执行器损坏
现场最容易被忽略的是PID输出抖振。发酵罐温度到达设定值附近后,如果死区设置过小,比如0.1℃,导致蒸汽阀和冷水阀在1%和0%之间来回切换,调节阀的执行机构一天之内就可能会出问题。
程序里我在PID_Compact的输出端又加了一个变化率限制块,单次循环输出变化不超过0.5%,同时PID内部死区改为0.2℃。这样阀门动作频率明显下降。这个优化不改变控制精度多少,但能让执行器寿命提升好几倍。
还有个经验:调试时不要一上来就把PID目标值改到工艺值,先用阶梯信号做扰动测试,看系统响应曲线,再决定积分时间放大还是缩小。很多人拿着PID参数表硬套,效果往往很差。
5.4 在线下载程序后设备瞬间跳停
有一次调试CIP程序,我在线修改了步进器某一步的条件,然后执行“下载到运行设备”,结果下载完成的瞬间,罐上的几个阀门同时失电关闭,泵全部停下来,CIP程序直接跳回初始状态。
原因其实很简单:博途在线下载时,背景DB的中间变量被初始化了,步进值回到0,同时输出刷新FC里的输出映像全部清零,阀和泵自然全关。对于发酵这种对连续性要求高的工艺,这种下载行为是不能接受的。
我后来把顺控FB的步进值和关键输出状态全部定义成保持性变量(Retain),下载时选择“保持保持性存储区”选项,就能避免这个问题。但这里有个前提:程序逻辑本身要能处理“步进值保持但过程输出清零”的中间状态,否则重新上电或下载后步进值还在,输出却是0,现场会懵。更稳妥的方案是下载前先将系统切到手动模式,全自动发酵过程中尽量不要在线修改顺控逻辑,调试工作放到批次间隙再做。
5.5 强制变量这个功能能不用就不用
调试初期我看到程序里一堆M0.0、M0.1的强制点,估计之前的人为了模拟信号强了不少东西。强制功能在单机调试时确实方便,但一到联动调试就容易翻车。有一次因为外设强制没有取消,导致安全联锁一直处于绕过状态,后面整套联调好几个小时找不到原因。
在带顺控和联锁的发酵程序里,强制点一旦忘了取消,轻则动作异常,重则锁不住阀。我的习惯是:现场模拟信号尽量在硬件端子旁短接或用信号发生器给真实信号,而不是用博途的强制功能。如果确实需要强制,则现场必须有两个人在场,一人操作强制,一人确认取消清单,调试结束后逐项核对强制表并拍照留档,确认无误后再进入下一阶段。
最后分享一个我实际做这套项目时觉得非常实用的小技巧:把发酵罐所有FB的背景DB做成“多重背景”嵌套在主FB里,而不是每个FB都单独建一个顶层DB。这样在程序树里看起来非常清爽,复制整套程序到第二个罐时,只需要复制主FB和对应的背景DB,不需要七八个DB一起手动关联。我第二次把程序移植到另一台发酵罐上时,大概只花了半天时间就完成了地址映射和参数替换。如果一开始就用凌乱的散DB结构,这活起码要干两天,而且大概率会漏改某个参数。做这类流程控制项目,好的程序结构不是写出来给人看的,是改起来让自己舒服的。