资讯详情

资讯详情

三菱PLC时间锁机程序2.0:多期扩展+分级锁机防破解

做设备的朋友多少都遇到过这种事设备发到客户现场尾款没结清机器却在车间里跑得正欢。催款电话打了七八遍人家一句“最近资金紧张”就把你打发了。三菱PLC的时间锁机程序就是干这个用的但以前那种“到期直接锁死”的写法太粗暴客户一闹就得很尴尬。这次我搞了个2.0版本直接支持三期时间锁还能无限扩展到期先提醒、再限速、最后才锁死给双方都留了缓冲。咱们直接上硬货先把这套程序的核心逻辑讲透。1. 2.0版的设计思路为什么从单点锁死升级到三期1.1 时间锁机程序到底解决了什么问题先捋清楚需求。时间锁机程序不是单纯用来“卡脖子”的它背后对应的是设备分期付款、租赁计费、Demo演示限时、定期维保提醒这几类真实业务场景。比如一台贴标机卖给客户约定分三期付款每期30天机器运过去之前就得把“到期自动停机”的逻辑写进PLC里。客户按期付款你远程给一组延期密码输入以后继续跑客户不付款到期机器自动停你没损失。但1.0版有个很大的问题只有“锁死”和“不锁”两个状态。到期那天设备直接停掉客户说“我明天就付款你先把机器恢复”但走流程需要时间产线停一天损失可能是几千上万客户急眼了你也不好收场。这种非黑即白的逻辑在真实商业环境里太僵硬。1.2 1.0版的三个典型痛点我最早写的那版程序功能其实就三块读PLC内置时钟拿当前日期和预设死限比较超了就置位一个输出禁止继电器。当时觉得挺简单用下来才发现问题一堆。一是没有任何缓冲。到期时间一到不管客户是在调试还是赶货机器说停就停连个预警都没有。二是解除锁定特别麻烦。1.0版用的是固定密码一个密码能用到天荒地老客户之间只要有人把密码透出去整套锁机机制形同虚设。三是扩展性差。客户临时说“我们想改成五期分期”我得打开工程改程序、改参数区、重新下载还得祈祷现场PLC的电池没掉电否则全部白干。1.3 2.0版的设计目标这次重写2.0版之前我给自己定了几条硬性要求。第一必须支持多期时间锁具体几期不能写死在程序里最好通过数据寄存器配置这样现场调整期数不用改程序。第二到期处置要分级不能只做锁死一种动作至少要区分“提示期”“限制期”“锁死期”三档。第三密码必须动态化每次解除使用的密码要跟当前日期绑定防止一个密码传遍全行业。第四要防住客户改PLC时间这种最常见的破解手段。所以2.0版的核心就落在“表格化参数 分级处置 动态密码 时间回拨检测”这四个关键词上。后面每一节我都会展开讲。2. 时间从哪里来PLC的RTC与软元件规划2.1 FX系列PLC的实时时钟寄存器速览做时间锁机第一前提是PLC得带实时时钟。三菱FX3U、FX3G这些系列都内置RTC晶振和时钟电路靠外部电池保持走时。FX3U用的电池一般是FX3U-32BL断电后时钟能走很久。你如果用的是老型号FX1S、FX1N有些没有内置时钟要么加时钟模块要么从触摸屏同步时间过来但稳定性就差一截。FX3U的系统寄存器里D8013到D8019专门存放当前时间具体分配是这样的寄存器含义取值范围D8013秒0-59D8014分0-59D8015时0-23D8016日1-31D8017月1-12D8018年公历低两位0-99D8019星期0-6注意D8018只存年份的低两位比如2025年它存的实是25。这个设计在跨世纪的时候会有个隐藏坑后面我会专门说到。读取时间很简单用MOV D8018 D0这种指令就能把数据搬到普通数据寄存器里。拿这些寄存器和定位好的死限参数做大小比较就是整个锁机判断的基础。2.2 软元件规划把程序的数据区当一张配置表1.0版我习惯把死限时间直接写到比较指令里比如CMP D8018 K25这种看着直观但改起来难受。2.0版我彻底改成了“配置表驱动”的思路PLC的数据寄存器就是一张可以现场修改的表格程序逻辑只是这张表的阅读器。我以FX3U为例给一套可以直接套用的软元件规划方案地址范围用途说明D100期数N总共有几期2.0版的程序不做三期写死读这个数D101-D105第1期死限依次为年、月、日、时、分D106-D110第2期死限依次为年、月、日、时、分D111-D115第3期死限依次为年、月、日、时、分D116及以后第4期及以后按每5个寄存器一组继续排D200当前到期等级0正常1第1期到期2第2期到期3第3期到期D210动态服务码程序根据当前日期算出来的6位数字供售后远程指导输入D500解锁输入框客户在触摸屏上输入动态密码后写到这里每期死限固定占5个寄存器期与期之间连续排列。这样做最大的好处是客户要改分期方案售后远程指导现场人员直接在触摸屏上改D100和参数区就行梯形图和ST程序一个字节都不用动。表格化设计是“无限扩展”的地基这个思路后面第4节我还会专门展开。2.3 日期比较的三种实现方式对比日期大小比较看着简单实际一写代码就发现有点绕。PLC里没有现成的“日期比较”指令直接拿年月日两个整数比大小是错的比如2025年1月31日和2025年2月1日整数比较会认为1月31日大实际日期是相反。我见过有人把日期拼成一个8位整数直接比比如20250131和20250201这样比年比月比日确实可以但跨月、跨年的进位问题其实还是隐藏在拼数逻辑里。也有高手把日期换算成自某个基准日以来的总天数这样最精确但要处理每月天数、闰年逻辑量不小。我这次采用的办法是“树状级联比较”先比年年相同再比月月相同再比日日相同再比时分。每一层分支都只处理一个量逻辑清楚、不容易出错客户现场也容易排查。ST语言写这种级联判断比梯形图舒服得多我后面代码直接给你看。3. 核心逻辑实现期数判断、锁机动作与恢复流程3.1 用ST语言写出可循环遍历的到期判断2.0版的核心判断块我用的是三菱结构化工程的ST语言。在GX Works2里新建结构化工程选择ST程序体FX3U是支持这种写法的。如果你还用传统梯形图这套算法思路也能翻译过去只是会繁琐不少。先声明全局变量把D区地址映射成数组这样循环遍历参数表就顺手了VAR_GLOBAL time_limits : ARRAY[0..49] OF WORD AT D100; // 死限参数表每组5个字 lock_level : WORD AT D200; // 当前到期的最高等级 now_time : WORD AT D210; // 预留当前时间快照区 END_VARAT关键字的意思是把数组直接“钉”在D100开始的地址上time_limits[0]就是D100time_limits[1]就是D101依次类推。这比在ST里用D100Z变址要直观得多。主判断逻辑如下VAR now_y, now_m, now_d, now_h, now_mi : WORD; limit_y, limit_m, limit_d, limit_h, limit_mi : WORD; i : INT; expire : BOOL; END_VAR (* 读取FX3U实时时钟D8018年、D8017月、D8016日、D8015时、D8014分 *) now_y : D8018; now_m : D8017; now_d : D8016; now_h : D8015; now_mi : D8014; (* 遍历所有期限找出已到期的那一期最高等级 *) lock_level : 0; FOR i : 0 TO D100 - 1 DO limit_y : time_limits[i * 5 1]; limit_m : time_limits[i * 5 2]; limit_d : time_limits[i * 5 3]; limit_h : time_limits[i * 5 4]; limit_mi : time_limits[i * 5 5]; expire : FALSE; (* 级联比较年 - 月 - 日 - 时 - 分 *) IF now_y limit_y THEN expire : TRUE; ELSIF now_y limit_y AND now_m limit_m THEN expire : TRUE; ELSIF now_y limit_y AND now_m limit_m AND now_d limit_d THEN expire : TRUE; ELSIF now_y limit_y AND now_m limit_m AND now_d limit_d AND now_h limit_h THEN expire : TRUE; ELSIF now_y limit_y AND now_m limit_m AND now_d limit_d AND now_h limit_h AND now_mi limit_mi THEN expire : TRUE; END_IF; IF expire THEN lock_level : i 1; END_IF; END_FOR;这段代码是所有扩展功能的“发动机”。每一期到期lock_level就变成对应的期号。比如第1期到期后D200变成1第2期也到期后D200变成2到期期数越多D200越大。后面所有锁机动作都以D200的值为依据。3.2 三级处置提醒、限速、彻底锁死拿到D200之后就要执行不同等级的处置。我设计了三个动作等级分别对应三个内部继电器M500、M501、M502(* 第3期及以后到期彻底锁机 *) IF lock_level 3 THEN M500 : TRUE; ELSE M500 : FALSE; END_IF; (* 第2期到期禁止自动运行只保留手动调试 *) IF lock_level 2 THEN M501 : TRUE; ELSE M501 : FALSE; END_IF; (* 第1期到期正常运行但限速并弹窗提示 *) IF lock_level 1 THEN M502 : TRUE; ELSE M502 : FALSE; END_IF;M500触发后直接置位M8037。M8037是三菱FX系列的一个特殊继电器一旦置ONPLC所有Y输出点被强制切断这是最彻底、最底层的锁机手段比你从程序里一个个断Y点靠谱得多M8037 : M500;M8037的作用是全局输出禁止ON的时候所有输出全是OFF设备主接触器断开伺服使能断开变频器启动信号断开机器根本动不起来。等锁机密码验证通过M500复位M8037跟着变OFF输出自动恢复不需要重新上电。第1期和第2期怎么限制我实际项目里是这么做的第1期到期后触摸屏每30分钟弹一次“请及时联系设备供应商服务码D210”的提示同时把PLC发送给变频器的最高频率上限从50Hz压到40Hz让客户感觉到“有点不对劲”但不至于停机。第2期到期后禁用自动模式只允许手动和点动设备基本只能做调试不能正常生产。到了第3期直接M8037锁死。这个阶梯式设计给了客户足够的反应时间也给了你自己足够的回旋空间实际执行下来比1.0版那种锁死效果好太多。3.3 解锁流程与触摸屏联动解锁这块我单独分配了一块逻辑。触摸屏上做一个数值输入框客户把售后远程给出的动态密码输进去PLC把输入值跟程序内算出的当前有效密码比对一致则清零所有锁机标志IF D500 0 AND D500 D210 THEN M500 : FALSE; M501 : FALSE; M502 : FALSE; lock_level : 0; D500 : 0; END_IF;这里有个小细节动态密码D210是程序根据当天日期实时算出来的客户当天输入有效到了第二天日期变了D210跟着变昨天的密码就作废了。这也是防破解的核心手段之一。触摸屏上最好再加一个“剩余天数”显示把当前日期和最近一期死限的差值算出来让客户直观看到还有几天到期商业谈判的时候这是个非常有用的筹码。4. 无限扩展的秘密表驱动设计怎么做到“加期不改程序”4.1 为什么FOR循环加数组就是扩展性的答案“无限扩展”听起来玄乎其实原理特别简单期数N放在D100死限参数每5个字一组连续摆开程序循环次数直接取D100。客户说要改成五期现场把D100改成5往后多写两组参数就完事了。ST里的FOR循环次数完全可以用变量控制FOR i : 0 TO D100 - 1 DO (* 循环体 *) END_FOR;D100改成多少循环就执行多少轮程序本身不需要再动。这里有个特别要注意的点D100必须做上下限约束。ST代码里建议加上这样一段IF D100 20 THEN D100 : 20; END_IF; IF D100 1 THEN D100 : 1; END_IF;把这个限制放在FOR循环之前否则客户或者现场维护人员误操作把D100写成999循环体执行几百次PLC扫描周期暴增分分钟触发看门狗超时报警。我实际测试过FX3U每次循环里做一组5个WORD的比较几百次循环大概会增加零点几毫秒扫描时间但如果里面再塞一堆其他逻辑风险就大了。所以期数上线根据自己项目情况掐一个合理值我一般限制在20期以内。4.2 参数现场修改的正确姿势参数区改起来方便但也容易被乱改。我建议在触摸屏上单独做一页“参数配置”进入这个页面需要二级密码普通操作工看不到。页面里列出当前期数、每一期的死限时间修改后用“写入确认”按钮统一写到D区不要做边改边写防止客户改了一半断电把参数区搞乱。D区默认很多是不掉电保持的FX3U的D区有一部分断电即清零。这套参数必须放到锁存区域内我通常用D512之后的地址然后在PLC参数里把保持范围设置好。D100和参数区一旦断电丢失PLC重启后时间锁机逻辑直接失效等于白做。所以上电初始化时要检查D100是否在合法范围内如果不在就恢复默认值并把所有锁机标志置位宁可误锁也不能让设备“裸奔”。4.3 和HMI对接时的一个避坑提示触摸屏读写D寄存器很容易但要注意数据类型匹配。三菱的D寄存器是16位无符号整数死限的年份、月份、日期分别存一个D字触摸屏上显示就是普通整数没问题。但如果你把“年月日时分”做成一个32位整数存到两个D里触摸屏侧的32位格式选错读出来的数值就会很怪。我做的时候为了省事全部用单个D分别存界面上一行显示5个数丑是丑了点但排查故障的时候一眼就能看明白。触摸屏页面上我固定放这几个元素当前日期时间、当前期数、最近一期死限、剩余天数、当前服务码、解锁输入框、解除状态指示。客户打开触摸屏就知道自己的设备处于什么状态不至于到期锁死了还一头雾水找你要说法。5. 防破解设计动态密码、时间回拨防御与程序加密5.1 动态密码算法日期绑定的6位服务码固定密码的缺陷很明显一个密码传开以后整个地区的设备都形同虚设。2.0版我改成动态服务码算法核心是把当前日期揉进一个简单不可逆的变换里。VAR y, m, d : WORD; code, seed : INT; END_VAR y : D8018; m : D8017; d : D8016; code : (y * 3721 m * 17 d * 97) MOD 899999 100000; D210 : code;这个公式不是说有多强它本来就不是密码学级别的只是让每一组日期对应唯一一个6位数字而且不能从服务码反推出规则来。关键是整个算法的种子只在设备厂和售后手里客户就算拿到今天的码也推不出明天该用什么码。售后人员在电话里问一句“你们机器屏幕上显示的服务码是多少”然后按同样算法一算就能报出解锁码。这个流程哪怕客户跟售后人员没有见过面也能顺利完成。5.2 防时间回拨的三层防御客户破解锁机最常用的招数不是逆向算法而是直接把PLC的时间往回改。三菱FX3U没有专门的防改写时间寄存器但你可以自己检测异常。我在程序初始化段加了一个“基准日”判断(* 首次上电时写入当前日期作为基准日D230基准日格式为年*10000月*100日 *) IF D230 0 THEN D230 : D8018 * 10000 D8017 * 100 D8016; END_IF; (* 每次上电检查当前日期是否远早于基准日 *) IF D8018 * 10000 D8017 * 100 D8016 D230 - 7 THEN M500 : TRUE; END_IF;这里判断的是“当前日期比第一次运行时的基准日还早超过7天”基本可以断定有人把时间调回去了。正常情况下PLC的时间只会往前走偶尔因为电池问题回退几小时可以容忍回退超过7天绝对是人为操作。一旦触发直接锁死连第1期、第2期的缓冲都不给因为客户已经动了一轮手脚说明诚信出问题了。另外两层防御一是PLC程序密码。GX Works2里给PLC设置口令上载程序需要密码防止客户把程序读出来分析逻辑。二是把时间锁机程序封装成子程序不提供注释和变量表。这不算加密但能大幅提高破解门槛。5.3 关于破解与反破解的务实看法这里说点题外话防破解的本质是提高破解成本而不是做到绝对不可破解。任何运行在客户现场的PLC只要人能接触到硬件理论上都能被重置。你能做的是让破解行为变得“不值得”锁机逻辑加动态密码、时间回拨检测、程序密码三层下来能搞定的只剩专业PLC工程师而专业工程师不会为了帮客户赖几千块钱尾款去冒法律风险。商业合同上把设备所有权和停机条款写清楚比技术锁机更重要。6. 现场排查实录常见坑与对策6.1 时间寄存器类型与格式踩坑FX3U的D8013-D8019在GX Works监控模式下可以看到实时数值但有些老工程师习惯用梯形图写CMP D8018 K25结果发现年份寄存器D8018在不同固件版本里存储格式存在差异。部分老型号FX系列里D8018存的可能是BCD码而不是纯二进制直接拿整数比较会得到错误结果。我的排查习惯是先用MOV D8018 D0把年份寄存器搬到普通D区再在触摸屏上显示D0看它显示的是“25”还是“25”的十六进制值。如果显示十进制25那就是二进制存储直接用整数比较如果显示37之类的怪值就得先做BCD转换。踩过一次坑之后我在程序开篇统一加了一个转换函数不管什么格式都转成标准二进制再参与比较。6.2 电池没电导致时间归零FX3U电池电量正常能用好几年但总有点背的情况。电池耗尽后PLC掉电再上电D8013-D8019会回到初始值我遇到过最典型的场景是PLC时间跳回2000年1月1日。这时候锁机程序会立刻判定“严重超期”直接触发M500锁死设备。排查时先不要急着怀疑锁机程序逻辑先看PLC当前时间对不对。触摸屏上如果时间显示明显不对优先换电池并重新校时。校时方法不复杂在三菱GX Works里可以直接写时间到D8013-D8019或者通过触摸屏的“系统时间设置”功能同步过去。我建议在客户现场都做一页“维护校时”界面让售后人员不用带电脑就能校准PLC时间。6.3 锁机误动作排查表时间锁机程序出问题通常集中在几个环节。我做了一张排查表现场照着查一般都能快速定位现象可能原因排查方法设备上电后突然全部输出没反应M8037被置位监控M500和M8037状态判断是锁机逻辑触发还是误触发还没到期就锁死PLC时间被改快或时间寄存器格式异常查看D8013-D8019实际时间和标准时间对比到期了却不锁机参数区D区没保持断电丢失检查D100和参数区是否掉电归零确认保持范围设置输入正确密码无法解锁动态服务码随日期变化密码已过期重新读取当天D210服务码再算当天密码触摸屏上锁机提示正常但机器照跑M8037与Y输出控制逻辑冲突检查是否使用了带机械保持的接触器或中间继电器FOR循环后扫描周期暴增D100被误改为超大数监控D100数值确认程序有上下限约束其中“输入密码无法解锁”是我自己踩过最频繁的坑。客户头天晚上打电话拿了个密码第二天早上到现场输入发现没用其实是因为日期变了动态密码已经更新。这个需要在售前培训里就讲清楚解锁动作和日期严格绑定必须在当天联系售后重算密码。6.4 锁机输出方式的务实建议M8037直接锁掉所有Y输出最简单也最暴力但有个副作用它会同时断开设备的报警灯、触摸屏蜂鸣器这些外围输出。设备锁死后想通过PLC输出闪灯提醒客户“该缴费了”不好意思全断了。所以有条件的话我建议锁机动作不要只依赖M8037而是在主电路里加一个“运行允许继电器”KM1PLC的Y10专门控制它锁机时把Y10断开。这样设备总电源接触器能正常吸合触摸屏能亮报警灯能闪但主电机、伺服这些负载全部断掉。客户看得到提示设备动不了视觉效果和商业效果都更好。7. 2.0版本后续还能怎么玩这套程序做完之后我发现时间锁机还能延伸出不少玩法。比如把“期数到期”扩展成“维保周期提醒”定期保养时间到了设备自动进入限速模式保养完成输入服务码恢复这比贴一张“下次保养时间”的标签纸有效得多。再比如跟产量计数联动不按时间按产量锁机约定生产满10万件需要结款逻辑上也就多一个计数器比较的事。还有多台设备联动厂区里10台设备共用一套锁机服务器某台设备到期后其他设备联动降产这种场景用在租赁产线上也很实用。时间锁机这种功能说白了就是给商业合同加了一道技术保险。技术本身不难难的是把分级处置、动态密码、防回拨这些细节做到位让客户既感到压力又不至于彻底撕破脸。这套2.0版的框架我后来移植到FX5U上也没费多大事核心逻辑完全不变你们如果有类似需求照着这个思路搭一套应该能少走不少弯路。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →