16仓位配方程序,三菱FX3U,这两个词放在一起,基本就是配料线、多仓称重设备或包装机的控制核心。这台设备一共16个料仓(仓位),每个仓位对应一种物料,生产不同产品时,PLC按配方把对应仓位的物料依次投进计量斗称重,16个仓全部完成后再卸料到下游。整套程序的核心不在“称重”,而在“配方管理”:配方怎么存、怎么调、怎么改、掉电能不能保住,以及16个仓位如何高效轮询控制。这篇文章就是这次开发的完整记录,包括配方存储的结构设计、状态机写法、称重落差补偿的调试过程,还有现场踩过的三个典型坑。如果你正在用FX3U做配料、称重、多工位配方类项目,这篇文章可以直接当成参考骨架用。
1. 先把需求弄清楚:16仓位配料到底要做什么
1.1 工艺环节里的核心动作
接到这个项目时,工艺其实不复杂,但细节非常多。设备是16个料仓围着一只计量斗转:每个仓下面有独立的给料机构,常见的是振动给料机或者螺旋给料机,有的仓还分粗给和精给两套执行机构。启动一个批次后,系统从仓1开始,打开粗给快速投料,称重值接近目标值时切换成精给慢慢加,到量后关闭,稳定一下记录实际重量,然后进入仓2,依次跑到仓16,最后开卸料阀,把累计的16种物料一起放进混合机。
这个流程里有几个关键点:一是每个仓的“目标重量”来自配方,不是操作工临时输;二是不同物料流动性差异很大,粗给切换点、精给补偿值、给料超时时间都必须按仓单独配置;三是配方中途不能乱切换,否则一锅料全废。所以需求拆到最后就变成了两件事:配方数据要能安全地编辑、保存、调用;配料动作要能按配方稳定执行,且抗干扰。
1.2 配方和仓位到底是什么关系
很多刚接触配料项目的朋友会把“配方”理解成一组重量数据:产品A是10kg、20kg、5kg……其实不够。对PLC程序来说,一个配方应该是一组完整的“仓位参数集”。这个项目里每个配方包含16组仓位参数,每组仓位参数又包含目标重量、粗给切换提前量、落差补偿值、精给超时时间。原因很简单:同样一袋物料,仓1用振动给料机,惯性大,落差就大;仓3用螺旋给料机,下料慢,落差就小。如果所有仓共用一套粗精给参数,精给阶段要么过冲要么迟迟不到位,配料精度根本没法保证。
所以数据模型上,配方号对应一个产品,产品决定16个仓各自投多少料,而每个仓自身的给料特性参数也一并保存在配方里。这样换产品时,换的不只是“投多少”,还有“怎么投”。这个设计思路直接影响后面的存储区布局,建议做同类项目的朋友一开始就想清楚,别只存16个重量,后面再补参数会非常痛苦。
1.3 为什么选FX3U而不是上更大机型
有人会问,16个仓位、配方存储、称重滤波,这套东西是不是得上中大型PLC?真不用。这个项目实际统计下来:数字量输入大概十几个,输出端16个仓两套给料执行机构加卸料阀、报警器,加起来也就40点左右;模拟量输入只需要一路称重信号;程序容量连FX3U的零头都用不了。FX3U的D寄存器有8000点,支持32位双字运算,锁存范围可以自由配置,做几十组配方完全够。
更关键的是成本。这个方案选的是16个仓共用一只计量斗,所以只需要一个称重变送器、一个模拟量模块,整体硬件非常省。如果现场要求16个仓同时并行配料,那就得挂多路4AD,FX3U的扩展总线也能带得动,只是程序里“并行”和“轮询”的逻辑差别很大。我们这次是串行配料,节奏上每仓多花几秒,但换来的是硬件成本和维护量的直线下降,甲方也能接受。
2. 配方存储与数据结构:先画一张地址地图
2.1 活动区、编辑区、存储区三个区域分开
配方程序的第一个大坑,就是把所有数据堆在同一个地址段里。HMI上改一个数字,生产中的配方立刻跟着变,轻则重量跑偏,重则整批报废。我这次一开始就把区域切成了三块,互相隔开。
第一块是活动配方区,PLC配料逻辑运行时只读这一块;第二块是编辑缓冲区,操作工在触摸屏上改配方时,数据先写到这里,点了“保存”才生效;第三块是配方存储区,保存之后的数据固化到这里,数量上支持20个配方,后续要扩也不难。三层结构的道理很简单:编辑区随便改,存储区稳定存放,活动区生产专用,谁也不会互相污染。运行时你就算不小心在HMI上改了编辑区,生产中的配方纹丝不动。
2.2 每个配方占多少字:一张表讲清地址布局
配方存储区放在D1000开始的位置,按每个配方84字排列。为什么是84字?看下面的表就明白了:
| 偏移 | 参数 | 类型 | 说明 |
|---|---|---|---|
| 0 | 配方号/有效标志 | 16位 | 1~20,0表示空配方 |
| 1~2 | 仓1目标重量 | 32位 | 单位g |
| 3 | 仓1粗给切换提前量 | 16位 | 重量≥目标-该值时切精给 |
| 4 | 仓1落差补偿值 | 16位 | 重量≥目标-该值时停精给 |
| 5 | 仓1精给超时 | 16位 | 单位0.1s |
| 6~10 | 仓2参数 | — | 结构与仓1相同 |
| … | … | — | … |
| 76~80 | 仓16参数 | — | 结构与仓1相同 |
| 81 | 卸料时间 | 16位 | 单位0.1s |
| 82 | 稳定判定时间 | 16位 | 单位0.1s |
| 83 | 备用 | 16位 | 预留 |
仓位n的参数起点偏移量 = 1 + (n-1)×5,记住这个公式,后面所有循环读写都靠它。每个配方84字,20个配方总共1680字,放在锁存范围内的D1000~D2679绰绰有余。实际项目里配方数量再多一些,比如50组,也就4200字,FX3U一样扛得住。
2.3 掉电保存与锁存范围设置
配方数据最怕掉电丢失。FX3U的D寄存器本身有电池保持能力,但有个前提——必须在PLC参数里把“锁存范围”设置好。FX3U默认情况下D512以后的寄存器是带电池保持的,D512之前的默认不锁存。这个设置很多人根本不看,结果配方放在D0~D300里,断电重启就回到初始值,现场就炸了。
我们最终把配方存储区放在D1000起,天然落在锁存区内。这里多说一句:如果配方数量非常大,可以研究FX3U的R文件寄存器(带记忆盒方案),R区是存在非易失存储里的,不依赖电池,寿命和可靠性更好。但对于几十组配方的项目,D区锁存加定期检查PLC电池已经完全够用。PLC电池是易耗件,维护计划里必须写上两年左右更换一次,别等数据丢了我才从甲方打电话来才想起。
3. 程序核心:状态机加索引化处理16个仓位
3.1 地址总表和M点分工
动手写梯形图之前,我先做了一个完整的地址表,这一步省了大量返工时间。关键地址如下:
| 地址 | 作用 |
|---|---|
| D50 | 当前配方号(1~20) |
| D500~D583 | 活动配方区(84字) |
| D600~D683 | 编辑缓冲区(84字) |
| D800 | 当前仓位号(1~16) |
| D810 | 配料状态(0待机/1粗给/2精给/3稳定/4卸料/5完成) |
| D900~D901 | 滤波后称重值(32位) |
| D1000~D2679 | 配方存储区(20组×84字) |
| M50 | 调用配方按钮(HMI置位,PLC处理完复位) |
| M51 | 运行中标志 |
| M53 | 保存配方按钮(HMI置位,PLC处理完复位) |
M点的使用有一个原则:HMI按钮只给脉冲信号,PLC程序处理完立刻RST复位。这样即使操作工手抖多按两下,也不会连续触发两遍配方调用。
3.2 配料主流程状态机
配料动作我用一个状态寄存器D810驱动,状态之间用条件切换,梯形图里就是一组SET/RST加比较。整体流程如下:
| 状态 | 动作 | 切换条件 |
|---|---|---|
| 1 粗给 | 打开当前仓粗给输出 | 称重值≥目标-粗切提前量,切状态2 |
| 2 精给 | 关粗给,开精给 | 称重值≥目标-落差补偿,或超时,切状态3 |
| 3 稳定 | 等称重稳定 | 稳定时间到且波动在范围内,记录实际值,仓号+1 |
| 4 卸料 | 开卸料阀 | 称重值小于空斗阈值,切状态5 |
| 5 完成 | 置批次完成标志 | 等待下一个启动指令 |
仓号D800在状态3里判断:如果D800小于16,仓号加1后回到状态1;如果等于16,说明所有仓位都投完,进入状态4卸料。另外有一个必须处理的边界情况:配方里某个仓目标重量为0,表示这个产品不用这种料,状态3里直接跳过该仓,加仓号返回状态1,否则程序会傻傻地对一个没重量的仓做粗给精给,卡死在那里。
3.3 用Z寄存器索引把16段重复逻辑压成1段
刚开始画梯形图时,我按惯性写了16段一模一样的仓位处理逻辑,写到仓8就已经想骂人了,程序又臭又长,后面改补偿逻辑要改16处。后来全部推倒,用Z寄存器索引重写。核心逻辑是:配料循环里始终只写一份“当前仓处理”的梯形图,所有参数读取都用Z0做偏移。
比如活动配方区里,目标重量是32位数,占两个字。处理仓n时先算偏移:
LD M51 MOV D800 Z0 // 当前仓号 SUB Z0 K1 Z0 // 仓号转0基偏移 MUL Z0 K5 Z0 // 每仓5字 INC Z0 // 加上配方号标志字,得到参数起点 // 此时Z0 = 1 + (仓号-1)*5 // D500Z0 = 当前仓目标重量低位 // D500Z0+1 = 当前仓目标重量高位 // D500Z0+3 = 当前仓粗切提前量 // D500Z0+4 = 当前仓落差补偿 // D500Z0+5 = 当前仓精给超时配料动作里比较重量的地方就用D900(滤波后称重值)和D500Z0取出的目标值做32位比较,切换粗给精给完全由状态机驱动。这套写法写完后,我再改补偿算法只需要改一处,调试时幸福感翻倍。真实项目的梯形图规模也因此只有原来的三分之一。
输出部分我没有强行用索引,因为FX3U的位软元件不好用Z索引。16个仓的粗给信号干脆用16条“CMP D800 K1 变M100后输出Y0”的并行网络分派,虽然看上去重复,但逻辑透明,现场硬件接线对应的就是Y0~Y15和Y20~Y35,谁维护谁少掉头发。
3.4 配方调用和保存的指令片段
配方调用这块,HMI把配方号写进D50后给M50一个脉冲,PLC把这组84字从存储区搬到活动区:
LD M50 ANI M51 // 运行中禁止调用 MOV D50 D52 // 暂存配方号 SUB D50 K1 Z0 // 配方号转0基偏移 MUL Z0 K84 Z0 // 每配方84字 MOV K0 Z1 FOR K84 MOV D1000Z0 D500Z1 INC Z0 INC Z1 NEXT SET M52 // 调用完成显示 RST M50保存配方同理,把编辑区搬到存储区指定位置,只是保存前一定要加校验:目标重量必须是0到量程上限之间的合法值,超出就拒绝并报警。操作工在HMI上少输入一个零这种事,我见过太多次了,程序不拦着,设备就得跟着遭殃。另外我还在保存前做了“配方号非空”检查,防止覆盖掉已有配方。
4. 称重滤波与落差补偿:这关过不了,程序再完美也白搭
4.1 4AD读数和移动平均滤波
称重信号从变送器出来是4~20mA,接到FX3U-4AD的电流输入通道。4AD的数字量读出后不能直接用,因为现场总有干扰,尤其是给料机启动瞬间,称重值会跳。我做了移动平均滤波:用10ms时钟脉冲M8011,每隔10ms把4AD读数写进一个20点的环形队列,求和后除以20得到滤波后的重量。
LD M8011 // 10ms脉冲 PLF M0 LD M0 FROM K0 K0 D100 K1 // 读取4AD第一通道数字值 // 将D100写入环形队列,滚动求和,结果存入D90020点滚动平均相当于200ms时间窗,对粗给精给切换来说是够用的,不会感觉迟钝,又能有效压掉高频抖动。滤波点数做好做成HMI可调,比如8到20之间,现场维护人员可以根据实际情况微调。
4.2 稳定性判断
称重稳定判断我单独用了一段逻辑:状态进入“稳定”后,连续取10次滤波值,比较相邻两次之差,全部在2个字以内才认为稳定。这里有个细节,判定区间要看称重变送器的分辨率,2个字对应多少克要现场实测。本项目量程50kg,一个字大约2g,所以2个字就是4g以内波动,完全满足配料精度5g的要求。
稳定判断最忌讳的是太激进。刚开始程序处理“连续两次差值小于阈值”就判定稳定,结果给料机关闭瞬间机械振动还在,称重值还在缓慢爬升,记录下来的实际重量一看就是偏的。后来改成连续10次一致才判定,稳如老狗。
4.3 落差补偿原理与自学习修正
落差是配料系统的老朋友了。精给停止的瞬间,给料机构里还有一部分物料没落进计量斗,这部分就是“空中料”。要让它正好落到目标值,就必须让精给在“目标值-落差补偿”时就停止。补偿偏小,实际重量过冲;补偿偏大,实际重量偏少。
理解了这个原理,补偿整定的公式就很自然了:
新补偿值 = 旧补偿值 + (本批实际重量 - 目标重量)比如目标1000g,旧补偿30g,精给在970g停止,结果实际到了1022g,过冲22g,那么下一批补偿改为52g,停止点变成948g,实际重量就逼近1000g了。为了防止误修正,我在程序里加了一个死区:误差绝对值小于10g时不修正,防止系统在精度范围内反复抖动。同时补偿值做上下限限制,比如0~500g,防止异常数据把补偿值整到离谱。
第4.3节这里多说一句:粗给切换提前量要不要也跟着修正?我的答案是不用。粗给的任务是把料快速送到接近目标,精度交给精给去兜底,粗切点只要保证切换时粗给不给得过冲,让精给有足够时间修正即可。
4.4 一组实测收敛数据
调试后期记录了一批连续批次数据,很能说明自学习补偿的实际效果:
| 批次 | 目标(g) | 实际(g) | 误差(g) | 修正后补偿(g) |
|---|---|---|---|---|
| 1 | 1000 | 1022 | +22 | 52 |
| 2 | 1000 | 1006 | +6 | 52(死区内不修正) |
| 3 | 1000 | 1003 | +3 | 52 |
| 4 | 1000 | 1001 | +1 | 52 |
从第三批开始精度已经稳定在3g以内。这个收敛过程在实际投产时非常流畅,操作工几乎感觉不到“学习期”。
5. 人机界面与调试中的三个典型坑
5.1 HMI画面怎么分工
触摸屏画面我分了三个页面。配方总览页显示配方号列表和启用状态,操作工选择配方后点“调用”;配方编辑页按仓位号切换,显示当前仓位四个参数,支持上下翻仓,点“保存”写入存储区;运行监控页显示当前仓、当前状态、实时称重和已完成批次。
这里有一个很实际的经验:HMI按钮一律配成“置位”模式,PLC程序里处理完相关标志位后自动RST。如果你让按钮走“瞬时接通”,通讯周期一抖动,PLC可能收不到信号;如果配成“保持”,又容易重复触发。置位加RST是最稳妥的握手方式。
5.2 通信连接不要过度设计
FX3U和触摸屏之间我用了一块FX3U-485-BD通讯板,触摸屏通过FX3U的专用协议直接读写D寄存器和M继电器,PLC梯形图里根本不用写通讯程序。很多人一上来就想上MODBUS或者自己编帧协议,其实在HMI直读直写的场景下完全没必要。PLC侧要做的只是在配方读写逻辑里加互锁和质量校验,把“能读能写”变成“安全地读、安全地写”。
5.3 坑1:配方保存后断电就丢,完整排查链路
这个坑出现在项目交付前夜,现象非常经典:HMI上保存配方数据,监控着D值一切正常,生产也能跑,但只要断电重启,配方就回到初始模样。我复盘了一遍排查链路,写在这里给各位参考。
第一步,先确认“保存动作本身没问题”。把配方号写在纸上,HMI保存后在线监控存储区D值,确认数据确实写进去了。第二步,断电重启后再看同一批D值,发现全部归零,这就把问题锁定到了“掉电保持”上。第三步,打开GX Works2左侧工程导航里的PLC参数,进“软元件”选项卡,看锁存范围设置,发现配方存储区D300~D400压根不在锁存范围内。第四步,解决方案是把配方存储区整体挪到D1000以后,重新下载参数,注意修改锁存范围会重新分配存储区,原有数据全部清空,调试期可以接受,但是量产设备必须在程序设计阶段就定好地址。改完之后断电复测,数据完好。
这个坑的根源其实不是硬件问题,是地址规划时没看锁存默认范围。所以回头来看,2.3节里说的“先画地址地图”真的不是形式主义。
5.4 坑2:精给启动瞬间称重跳变
另一个现场问题更隐蔽。粗给正常,一切入精给,称重值忽然往上跳一二十克,PLC误判“到目标了”直接关断,导致每批都短料。一开始我怀疑是程序逻辑问题,后来用监控功能盯着4AD原始值看,发现跳变时间点和精给变频器启动严丝合缝。这就是典型的电磁干扰:变频器启动瞬间的大电流通过动力线耦合到了称重信号线上。
处理分两步。硬件上把信号线全部换成屏蔽双绞线,屏蔽层在PLC侧单端接地,信号线尽量远离变频器动力线,有条件的话分线槽走线;给变送器电源加隔离,避免和变频器共用开关电源。软件上我在精给状态启动后加了0.5秒的“免疫时间”,这段时间内不做到位判断,让干扰峰值先过去。两招下来,跳变彻底消失。纯粹靠软件滤波治干扰是治标不治本,硬件隔离这一刀必须下。
5.5 坑3:运行中误点调用配方
还有一次是操作工在生产中误触了HMI上的“调用”按钮,当前仓的目标重量瞬间被改掉,一整批物料配比全乱了。事后我在PLC侧加了两道保险:调用和保存指令前都串上M51的常闭触点,运行中直接跳过;HMI配方编辑页面设置操作权限,只有工艺员能进。另外D50配方号写入后,PLC会先做合法性校验,配方号超出1~20的范围直接拒绝执行并报警。以后就算有人误操作,系统也能兜住。
6. 事后复盘:如果再让我写一次,我会这样改
收尾说点个人的真实体会。这套程序跑通之后,我复盘时列了几个改进点,都是下次项目会直接用的。第一,配方存储区要做双备份,同一组配方写两份,开机时校验主备份,如果校验失败自动用副备份恢复。工业现场电池老化或者存储介质异常是慢性的,双备份能把这部分风险压到最低。第二,每个配方加一个版本号或者保存时间戳,HMI总览页直接把版本列出来,现场两个工程师改过同一组配方时,一眼就能看出谁覆盖了谁。第三,给每个配方增加CRC校验字,防止某一位数据异常导致目标重量变成离谱值——这个成本很低,但对安全来说收益极高。
最后再分享一个小技巧:整个程序的核心就是“活动区、编辑区、存储区”三层结构和Z寄存器索引那套轮询逻辑,这两个骨架搭好,后面不管是改成32仓位,还是加网络上传配方到MES,都只是在这个骨架上打补丁。FX3U这台老将做中大型配方应用,潜力比多数人想象的大得多。