资讯动态

用PLC改造洗衣机:状态机与参数化实现四重洗涤模式

发布时间:2026/9/10 13:33:49 来源:尧图企业网站定制
1. 为什么我会用PLC去改一台洗衣机先说个背景。家里那台波轮洗衣机服役八年最近电脑板开始抽风时能启动时不能启动偶尔洗到一半就罢工。维修师傅上门看了一眼报价换板子六百多上门费另算。我当时第一反应不是贵不贵而是那台洗衣机的大脑——一块被胶封死的单片机板修都没法修只能整块换。关键在于这种电脑板对你完全是个黑盒进水多久、正反转怎么交替、脱水怎么判断衣服分布厂家预设的逻辑你根本动不了。恰好手里一直有一套西门子S7-1200 PLC和一台三菱FX3U闲置着。我当时就冒出一个念头既然PLC最擅长的就是按时序控制电机、阀门和传感器洗衣机本质上不就是一套典型的顺序控制设备吗进水、洗涤、排水、脱水每个环节都是传感器反馈 → 逻辑判断 → 驱动执行器的闭环。把一套PLC接到洗衣机上完全可行。这个项目做完后我最大的体会是洗衣服这个日常动作拆开看就是一组可编程的时序状态机而四重洗涤模式本质上是四组不同的时间和动作参数组合。你不需要改硬件只需要改代码里的参数表就能让同一台机器跑出完全不同的洗涤策略。这比原厂电脑板灵活太多。所以这篇文章不是用PLC复刻一个洗衣机控制器而是带你走一遍完整思路需求怎么拆解、硬件怎么规划、状态机怎么写、四重模式怎么用一套代码优雅切换、虚拟机里怎么调试。适合正在学PLC编程但缺一个完整实战项目的朋友也适合想做设备改造又不想从零开始做控制逻辑的工程师。2. 四重洗涤模式拆解标准、轻柔、强力、快洗到底在切换什么很多人一听到四种模式就以为要写四套程序。这是最大的误区。洗衣机所谓的不同模式动的并不是程序框架而是几个关键参数。把这一点想透整台设备的控制逻辑就清晰了。2.1 四种模式的本质是参数矩阵我先把这四种模式的差异列出来你感受一下模式目标水位洗涤时间电机节奏漂洗次数脱水时间标准洗中水位8分钟正转10s/停2s/反转10s2次3分钟轻柔洗低水位4分钟正转5s/停5s/反转5s1次1分钟强力洗高水位12分钟正转15s/停2s/反转15s3次5分钟快洗中低水位3分钟正转8s/停2s/反转8s1次2分钟看到没有四种模式的骨架完全一样都是进水—洗涤—排水—脱水—漂洗循环—最终脱水—结束变的只是每个阶段的时长、循环次数和电机转动节奏。这就意味着你只需要写一套状态机把可变的部分做成参数模式切换就是加载不同参数组的事。2.2 为什么模式参数不能写死早期我确实干过蠢事每个模式单独建一个子程序复制粘贴改几行定时器预设值。程序量直接翻四倍改一个细节得同步改四处调试的时候手忙脚乱。后来做设备改造项目时接触到结构化编程的思路才明白一个优秀程序应该做到数据与逻辑分离——逻辑只处理当前处于什么状态、该执行什么动作至于这个状态该维持多久、水位到什么位置交给参数去决定。这样做的实际好处有三点第一以后想加第五种模式不需要动逻辑代码只需新增一组参数第二现场调试改参数时不会误伤其他逻辑第三程序整体短排查故障容易得多。我自己后来维修这台改造洗衣机时基本都是看参数表而不是翻梯形图。2.3 电机节奏里藏着的护衣逻辑有一点需要注意洗涤时的正反转不是简单地正转一会儿反转一会儿中间必须加停止时间。原因有两层。从机械层面说电机带着衣物和水突然换向冲击力很大长期这样会加速离合器磨损。从控制层面说如果正转接触器和反转接触器之间没有间隔切换瞬间可能造成瞬间短路——PLC输出点的晶体管或继电器触点切换速度远快于接触器机械动作一旦接触器还没完全断开另一个已经吸合就是严重的设备事故。所以我在模式参数里专门设计了换向停止时间这个字段。轻柔洗设5秒标准洗设2秒强力洗也设2秒。这个时间放在实战里不是可有可无的小细节而是涉及设备安全的核心保护逻辑。3. 硬件接线与I/O规划先让PLC摸得到洗衣机程序写得再好硬件接不对全部白搭。洗衣机改造和纯逻辑仿真最大的区别就在于你面对的是220V强电、交流电机、电磁阀还有水位传感器、门磁开关这些信号源。规划好输入输出点是第一步也是最容易出问题的一步。3.1 I/O点分配表我选的方案是用中间继电器做隔离PLC不直接驱动220V负载所有强电回路都走继电器触点。这样做的好处是保护PLC输出点后者一旦被感性负载的反向电动势打穿维修成本远高于几个继电器。类型地址信号说明实际接法输入I0.0启动按钮常开触点并联启动指示灯输入I0.1停止按钮常闭触点急停逻辑输入I0.2门盖安全开关常开盖好才闭合输入I0.3高水位开关浮子式水位开关输入I0.4低水位开关浮子式水位开关输入I0.5模式选择旋钮4档旋转开关对应四组参数输出Q0.0进水电磁阀经继电器控制220V进水阀输出Q0.1排水电磁阀经继电器控制220V排水阀输出Q0.2电机正转接触器驱动洗衣机电机正转输出Q0.3电机反转接触器驱动洗衣机电机反转输出Q0.4蜂鸣器洗涤结束后提示输出Q0.5运行指示灯状态指示这里我重点提醒两个坑。第一个是水位开关。很多滚筒或波轮洗衣机用的是气压式水位开关接出来是三根线——一根公共端一根高水位触发一根低水位触发。改造前最好用万用表量一遍确认常开还是常闭以及水位变化时通断状态如何切换。我改造时就用万用表对着水位开关在不同的吹气压力下测通断才确定了对应逻辑。第二个是模式选择旋钮。如果你用的是洗衣机原装的旋转开关它可能是个多刀多掷开关不同档位会同时切换好几组触点。而PLC输入点有限不可能一个档位接一个输入点。实际做法是利用电阻分压加模拟量输入或者干脆用二进制编码三组触点组合出四个档位。我图省事直接用了三个输入点接旋钮的三组独立触点编码分别为001标准洗、010轻柔洗、011强力洗、100快洗。3.2 强电侧的继电器选型继电器选型是个看似不起眼但很关键的环节。洗衣机电机功率大约200W到400W启动电流可能达到正常运行电流的5到7倍。我实测过一台普通波轮洗衣机电机启动瞬间电流能到6A左右。所以中间继电器不能选那种只有1A触点容量的信号继电器至少要用触点容量10A的功率继电器最好是带底座的插拔式继电器方便坏了直接换。另外接触器选型时线圈电压要和你继电器配合好。我用的继电器线圈是DC24VPLC输出也是DC24V直接驱动正好。交流接触器线圈则选AC220V由继电器的常开触点控制。整个链路是PLC输出 → 中间继电器线圈 → 中间继电器触点 → 接触器线圈 → 接触器主触点 → 电机。接线时特别注意电机正转和反转接触器的主触点在电气上必须互锁也就是正转接触器的常闭辅助触点串联在反转接触器的线圈回路里反之亦然。PLC程序里的互锁只是逻辑层面的第一道保险硬件接触器互锁是第二道两者缺一不可。4. 一套状态机打天下程序结构的设计思路这是整个项目的核心。四重洗涤模式要一套代码搞定就不能用传统的顺序功能图一个状态写死一组梯形图而要把状态和参数剥离开。4.1 用状态机而不是顺序控制初学者最爱用M继电器的置位复位做顺序控制M0是进水、M1是洗涤、M2是排水……每个M对应一段固定的程序。这种写法在简单流程里很好用但一旦要支持四种模式你会发现每种模式下各阶段的持续时间不同、漂洗次数不同M继电器逻辑会被参数判断塞满程序立刻膨胀。状态机写法的核心是用一个整数变量记录当前状态用CASE指令SCL里或比较跳转指令梯形图里按状态值分发逻辑。每个状态处理三件事进入时的动作、执行中的条件判断、退出的条件。我把洗涤流程拆成了9个状态状态值状态名称进入时动作退出条件0待机所有输出复位按下启动且门盖闭合1进水开进水阀达到该模式目标水位2洗涤电机按节奏正反转洗涤时间到3排水开排水阀低水位开关断开且排水延时到4脱水电机高速正转脱水时间到5进水漂洗开进水阀达到目标水位6漂洗电机按节奏正反转漂洗时间到7排水漂洗开排水阀低水位开关断开且排水延时到8完成蜂鸣器鸣叫3秒手动按停止复位状态0和状态8是首尾状态1到状态4是主洗流程状态5到状态7是漂洗循环循环次数由模式参数决定。整个状态机的精华在状态4到状态5的跳转判断里——脱水完成后如果当前漂洗次数小于目标次数状态回到5开始下一轮漂洗如果已经完成了状态跳到8结束。4.2 参数数据结构化UDT的妙用为了实现逻辑不动、参数可换我在博途里定义了一个UDT用户自定义数据类型用来描述一种洗涤模式的全部特征TYPE WashMode : STRUCT waterLevel : INT; // 0低水位, 1中水位, 2高水位 washTimeSec : INT; // 主洗时间秒 rinseCycles : INT; // 漂洗次数 spinTimeSec : INT; // 最终脱水时间秒 fwdTimeMs : INT; // 正转时间毫秒 stopTimeMs : INT; // 换向停止时间毫秒 revTimeMs : INT; // 反转时间毫秒 END_STRUCT END_TYPE然后在全局数据块里建一个长度为4的WashMode数组下标0到3分别对应四种模式VAR GLOBAL gWashModes : ARRAY[0..3] OF WashMode : [ (waterLevel:1, washTimeSec:480, rinseCycles:2, spinTimeSec:180, fwdTimeMs:10000, stopTimeMs:2000, revTimeMs:10000), // 标准洗 (waterLevel:0, washTimeSec:240, rinseCycles:1, spinTimeSec:60, fwdTimeMs:5000, stopTimeMs:5000, revTimeMs:5000), // 轻柔洗 (waterLevel:2, washTimeSec:720, rinseCycles:3, spinTimeSec:300, fwdTimeMs:15000, stopTimeMs:2000, revTimeMs:15000), // 强力洗 (waterLevel:1, washTimeSec:180, rinseCycles:1, spinTimeSec:120, fwdTimeMs:8000, stopTimeMs:2000, revTimeMs:8000) // 快洗 ]; END_VAR这下四种模式的差异被压缩进了这一小块数据定义里。主逻辑不需要知道自己在跑什么模式只需要根据当前模式索引去读取对应的参数执行统一的状态机流程。这就是一套代码玩转四重模式的底层原理。4.3 主程序流程SCL做状态机梯形图做互锁我最终采用的是SCL和梯形图混编的方案。状态机的状态转换逻辑用SCL写因为CASE语句在状态分发上比梯形图跳转指令高效得多代码可读性也强。电机正反转互锁、接触器驱动、手自动切换这些偏底层的逻辑用梯形图写便于现场电工维护。原因很简单状态机的流转逻辑属于面向逻辑的代码适合用结构化文本表达而电机驱动和互锁属于面向硬件的电路控制梯形图最直观也最符合电气维修人员的读图习惯。很多工程师只擅长一种语言就一条道走到黑实际上不同语言各有适用场景混编才是工业项目的常态。5. 核心代码实现状态机与模式切换实例这一节直接上实操代码。我用西门子博途的SCL写状态机主体但思路同样适用于三菱GX Works、汇川、台达等品牌——它们都有类似的结构化文本或位置控制指令翻译过去就行。5.1 SCL状态机主体代码状态机部分我放在一个FB块里输入是启动、停止、传感器状态和模式索引输出是各路执行器控制信号。核心结构如下FUNCTION_BLOCK FB_WashMachine VAR_INPUT startBtn : BOOL; // 启动按钮 stopBtn : BOOL; // 停止按钮 doorClosed : BOOL; // 门盖闭合检测 highLevel : BOOL; // 高水位开关 lowLevel : BOOL; // 低水位开关 modeIndex : INT; // 当前模式索引 0~3 END_VAR VAR_OUTPUT inletValve : BOOL; // 进水阀 drainValve : BOOL; // 排水阀 motorFwd : BOOL; // 电机正转 motorRev : BOOL; // 电机反转 buzzer : BOOL; // 蜂鸣器 END_VAR VAR state : INT : 0; // 状态机当前状态 cycleCount : INT : 0; // 已完成漂洗次数 tonMain : TON; // 主定时器 motorSeqTimer : TON; // 电机节奏定时器 motorPhase : INT : 0; // 电机当前相位0停 1正转 2反转 modeParams : WashMode; // 当前加载的模式参数 drainDelayTimer : TON; // 排水延时定时器 END_VAR状态转换部分我简化核心逻辑如下// 模式参数加载 modeParams : gWashModes[modeIndex]; // 模式参数加载启动时锁定防止运行中切换 IF startBtn AND state 0 AND doorClosed THEN state : 1; // 进入进水 cycleCount : 0; END_IF; // 停止按钮或门盖打开则复位 IF stopBtn OR NOT doorClosed THEN state : 0; inletValve : FALSE; drainValve : FALSE; motorFwd : FALSE; motorRev : FALSE; buzzer : FALSE; tonMain.IN : FALSE; tonMain.R : TRUE; END_IF; CASE state OF 0: // 待机只有按下启动门盖闭合才启动 inletValve : FALSE; drainValve : FALSE; motorFwd : FALSE; motorRev : FALSE; 1: // 进水 inletValve : TRUE; // 达到目标水位就停止进水 IF (modeParams.waterLevel 0 AND lowLevel) OR (modeParams.waterLevel 1 AND highLevel) OR (modeParams.waterLevel 2 AND highLevel) THEN inletValve : FALSE; state : 2; // 进入洗涤 tonMain.IN : TRUE; tonMain.PT : INT_TO_TIME(modeParams.washTimeSec * 1000); END_IF; 2: // 洗涤 tonMain.IN : TRUE; // 调用电机节奏子程序 runMotorSequence(modeParams.fwdTimeMs, modeParams.stopTimeMs, modeParams.revTimeMs); IF tonMain.Q THEN tonMain.IN : FALSE; state : 3; // 洗涤结束进入排水 END_IF; 3: // 排水 drainValve : TRUE; // 低水位开关断开 延时30秒确保排空 IF NOT lowLevel THEN drainDelayTimer.IN : TRUE; drainDelayTimer.PT : T#30S; IF drainDelayTimer.Q THEN drainValve : FALSE; drainDelayTimer.IN : FALSE; state : 4; // 进入脱水 tonMain.IN : TRUE; tonMain.PT : INT_TO_TIME(modeParams.spinTimeSec * 1000); motorPhase : 1; // 脱水时强制正转高速 END_IF; ELSE drainDelayTimer.IN : FALSE; END_IF; 4: // 脱水 motorFwd : TRUE; // 脱水时电机始终正转 IF tonMain.Q THEN tonMain.IN : FALSE; motorFwd : FALSE; // 判断漂洗是否完成 cycleCount : cycleCount 1; IF cycleCount modeParams.rinseCycles THEN state : 5; // 还有漂洗轮次进入进水漂洗 ELSE state : 8; // 全部完成 END_IF; END_IF; 5: // 进水漂洗 inletValve : TRUE; IF highLevel THEN inletValve : FALSE; state : 6; tonMain.IN : TRUE; tonMain.PT : T#3M; // 漂洗默认3分钟 END_IF; 6: // 漂洗 tonMain.IN : TRUE; runMotorSequence(modeParams.fwdTimeMs, modeParams.stopTimeMs, modeParams.revTimeMs); IF tonMain.Q THEN tonMain.IN : FALSE; state : 7; // 进入排水漂洗 END_IF; 7: // 排水漂洗 drainValve : TRUE; IF NOT lowLevel THEN drainDelayTimer.IN : TRUE; drainDelayTimer.PT : T#30S; IF drainDelayTimer.Q THEN drainValve : FALSE; drainDelayTimer.IN : FALSE; state : 4; // 再次脱水 tonMain.IN : TRUE; tonMain.PT : INT_TO_TIME(modeParams.spinTimeSec * 1000); motorPhase : 1; END_IF; ELSE drainDelayTimer.IN : FALSE; END_IF; 8: // 完成 buzzer : TRUE; // 蜂鸣器响3秒后自动停或按下停止键复位 tonMain.IN : TRUE; tonMain.PT : T#3S; IF tonMain.Q THEN buzzer : FALSE; state : 0; END_IF; END_CASE;5.2 电机节奏子程序正反转互锁与暂停电机节奏的逻辑单独封装成一个子程序好处是整个状态机里不用反复写电机控制细节。核心是用一个小的内部定时器在正转、停止、反转三个相位间循环切换FUNCTION runMotorSequence : BOOL VAR_INPUT fwdTimeMs : INT; stopTimeMs : INT; revTimeMs : INT; END_VAR VAR_OUTPUT motorFwd : BOOL; motorRev : BOOL; END_VAR CASE motorPhase OF 0: // 停止相位 motorFwd : FALSE; motorRev : FALSE; motorSeqTimer.IN : TRUE; motorSeqTimer.PT : INT_TO_TIME(stopTimeMs); IF motorSeqTimer.Q THEN motorSeqTimer.IN : FALSE; motorPhase : 1; END_IF; 1: // 正转相位 motorFwd : TRUE; motorRev : FALSE; motorSeqTimer.IN : TRUE; motorSeqTimer.PT : INT_TO_TIME(fwdTimeMs); IF motorSeqTimer.Q THEN motorSeqTimer.IN : FALSE; motorPhase : 0; // 先回停止相位再切反转 END_IF; 2: // 反转相位 motorFwd : FALSE; motorRev : TRUE; motorSeqTimer.IN : TRUE; motorSeqTimer.PT : INT_TO_TIME(revTimeMs); IF motorSeqTimer.Q THEN motorSeqTimer.IN : FALSE; motorPhase : 0; END_IF; END_CASE;注意我是从正转相位退出后先回到停止相位再在下一个扫描周期进入反转相位。这样即使PLC程序层面的互锁失效至少时间上隔了一个相位周期给了接触器充分的机械释放时间。这个设计思路在所有电机正反转场景里都适用。5.3 梯形图互锁与输出驱动SCL写状态机梯形图写输出驱动。在梯形图里我对Q0.2和Q0.3做双重重保护第一个网络是软件互锁Q0.2(正转输出) ---|/|--- Q0.3(反转输出) Q0.3(反转输出) ---|/|--- Q0.2(正转输出)第二个网络是通过辅助继电器把SCL里的motorFwd和motorRev信号汇集到实际输出同时加入急停停止按钮的常闭触点。这样无论程序状态机怎么走只要停止按钮被拍下电机输出必然被切断。如果你用的是三菱FX系列思路完全一样——状态机可以用ST程序写输出驱动放到梯形图里用SET/RST配合互锁触点。不同品牌PLC的语言差异不会改变控制逻辑的本质。6. VMware虚拟调试要点网络模式选对仿真才不坑这个项目我并没有一开始就接真实洗衣机而是在博途里完成程序后用PLCSIM做了软件仿真然后在VMware虚拟机里跑了整机虚拟验证最后才动硬件。这里要专门说一下虚拟机连PLC的问题因为很多人在这一步卡住。6.1 虚拟机网络连接模式选择VMware给虚拟机提供了三种常用网络模式桥接模式、NAT模式、仅主机模式。和PLC仿真通信相关的核心原则是虚拟机必须能和宿主机处于同一局域网且能收发广播包。桥接模式是最佳选择。在桥接模式下虚拟机网卡直接连接物理网络虚拟机和真实PLC、真实电脑都处在同一网段博途的在线访问功能可以正常扫描到设备IP。NAT模式本质是虚拟机背后有一台虚拟路由器做地址转换虚拟机能访问外网但外部设备主动访问虚拟机、或者收到虚拟机发出的广播帧都异常缓慢甚至丢失这会导致博途可访问的设备列表里扫不到S7-1200。仅主机模式就更不用提了它只能和宿主机通信连PLC的物理网段都进不去。具体操作上VMware里选中虚拟机 → 编辑设置 → 网络适配器 → 选择桥接模式并在复制物理网络连接状态前打勾。虚拟机里的系统我用的Windows 10专业版网络IP要手动设置成和PLC同一网段比如PLC的IP是192.168.10.1虚拟机就设192.168.10.50。宿主机也设同一个网段。只要三者同段博途基本稳定在线。6.2 仿真验证中的几个实用技巧首先博途的PLCSIM在连接虚拟机里的TIA时要注意PLCSIM是一个独立的仿真进程不依赖网卡所以虚拟机网络模式对PLCSIM本身的连接影响不大。真正依赖网络的是你从虚拟机里访问真实PLC——如果你手里有实体S7-1200想在虚拟机里下载程序那桥接模式就是必须的。其次在没有真实PLC的情况下你可以用S7-PLCSIM和WinCC Runtime一起跑模拟。步骤是先在TIA里启动仿真下载完程序后在虚拟机里打开WinCC运行系统画面上的按钮对应PLC输入灯对应PLC输出。这样整个洗衣机的控制逻辑和HMI交互全部都能在虚拟机里闭环验证不需要碰任何硬件。我实际验证中发现一个比较隐蔽的问题PLCSIM仿真时I0.0到I0.5这些数字量输入默认是0你需要在仿真界面上手动强制为1来模拟按钮按下、门盖闭合、水位开关动作。很多人仿真跑不起来以为程序错了其实是没强制输入点。另一个坑是TON定时器在仿真里跑得很快PLCSIM有个减少扫描周期的选项默认开启定时器时间会加速我一开始以为代码有问题结果查了半天发现是仿真的时间压缩效应。7. 从仿真到真机实测效果与后续扩展程序在虚拟机里验证通过后我开始动真机。接线用了大约两个小时其中一半时间花在确认原机的电机、水位开关、进水阀线的颜色和功能上。第一次上电我先只给PLC供电把所有输出强制复位逐个手动强制输出继电器通断确认每个执行器动作正确后才把程序下载进去跑完整流程。实测效果符合预期标准洗从进水到结束约40分钟和原机逻辑基本一致轻柔洗明显更安静电机启停冲击小强力洗脱水转速高衣物脱水后明显更干。从用户体验角度这套改造方案已经完全替代原电脑板了。几处我实际踩过的坑在这里重点强调水位的判断逻辑必须和实际浮子开关的机械位置配合。我一开始用高水位开关作为达到目标水位的信号结果低水位模式时水还没到高水位就提前进洗涤了。后来给每个模式加了水位档位判断问题才解决。排水延时是必要的。光靠低水位开关断开判断排空不可靠因为波轮洗衣机排水管里残留的水可能让浮子开关抖动。加30秒延时后脱水前的排水彻底干净消除了脱水时进水阀带水的异响。电机正反转的换向停止时间不能设太短。我试过把停止时间改成1秒洗涤时撞击声马上变大能明显感觉到离合器受到的冲击。最终恢复为2到5秒噪音和冲击大幅下降。后续我打算再做三件事一是加一个触摸屏HMI通过MODBUS TCP连接PLC把运行状态、模式选择、故障报警都可视化二是用变频器替换原来的机械式电机控制实现无级调速——这样洗涤转速、脱水转速都可以精确设定衣服磨损会更小三是在进水管上加一个流量计把进水量精确量化代替水位开关的粗略判断。最后说点个人体会。这个项目给我的收获远超花钱买一台新洗衣机。它让我更深刻地理解了顺序控制的本质——不管工艺多复杂最终都可以拆成状态×参数的组合。你把状态机写得干净了参数做成可配置的数据结构那么以后不管面对什么设备改造都能快速套用这套方法论。洗衣机的四重模式只是个开始同样的思路拿来控制注塑机、包装线、小型机械手只是换了一组输入输出和一套参数表而已。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价