简介:基于PLC与MCGS的智能灌溉系统毕业设计文档,面向自动化、电气工程及农业工程专业学生,用于参考完整的控制系统设计流程。文档以西门子PLC为下位机、MCGS组态软件为上位机,围绕节水灌溉目标,给出土壤湿度阈值判断、异常自动报警及水源故障保护等控制逻辑的梯形图与结构文本实现,并比较MODBUS、PROFIBUS、Ethernet/IP等通信方式的适用性。同时介绍了人机界面中实时数据、参数设置、报警提示等模块的组态方法。资源包为1个docx文档,压缩后大小仅317KB,篇幅紧凑。已有1911人浏览学习,适合作为课程设计或毕业设计的直接参考。读者可从中获取系统总体架构、硬件选型依据、软件编程思路、界面设计步骤及实验验证方案,为快速搭建智能灌溉系统原型提供完整技术路径;对于同类课题的毕设论文,也能提供关键内容框架与设计细节参考。
1. 基于PLC的智能灌溉系统设计:为什么先算IO再想算法
很多刚接触这个方向的人,一听到“智能灌溉”就想着上位机、云平台、各种算法,真正到现场却被最基本的东西绊住:电磁阀线圈带不动、模拟量模块少了两路、湿度信号大晴天往下漂。基于PLC的智能灌溉系统设计,本质上不是写一段多复杂的程序,而是把“传感器采集—PLC判断—阀门执行”这条链路做成可靠、可调、可修的系统。
这篇笔记按完整落地顺序展开:先算IO点,再选型,再写控制逻辑,然后接HMI和远程监控,最后把现场最容易翻车的几个问题摆出来。适合已经会PLC基本指令、但第一次做灌溉项目的人;照这个顺序走,你能得到一套能下装运行的最小系统,也能在选型和接线阶段就避开几个日后让人头疼的坑。
我不会去讲那些看上去很美的空框架,只讲自己实际会用到的方案。你照着搭,至少不会出现“程序写完了,模块不够用”这种最尴尬的事。
2. 系统架构与IO规划:先定传感器和阀,再定PLC
2.1 先分清灌溉对象:大田、温室和园林的控制逻辑不一样
同样的PLC方案,放在大田、温室和园林里,IO类型和程序结构差别很大。大田灌溉通常是大面积轮灌,阀门数量多、敷设距离远,单个阀门动作频率不高,对输出响应速度要求低,但要求输出能带动阀线圈,还要能承受一定过载。温室大棚更关注土壤湿度和空气温湿度联动,模拟量通道多,控制逻辑相对密集,经常需要把灌溉、风机、遮阳网都放在同一台PLC里。园林景观项目则常见阀箱分散,PLC控制柜放在中心,每个阀箱到主柜的距离可能上百米,这时候要考虑的不是PLC程序,而是现场总线或远程IO箱。
先问清楚对象,是因为后续点表、模块、供电方案都跟着它走。我见过一个项目,按大田方案配了集中式控制柜,结果现场是几片分散的园林绿地,信号线拉出去全乱套,最后不得不返工加远程IO。所以控制对象这一条,决定了系统边界,也决定了预算分布。
2.2 IO点表:把每一路信号按数字量、模拟量、计数形式落表
定系统架构的第一步不是选PLC,是先把IO点表列出来。灌溉系统里最常见的信号无非几类:土壤湿度传感器输出4-20mA或0-10V,属于模拟量输入;流量计可能是脉冲计数,也可能是模拟量,视仪表类型而定;电磁阀是数字量输出;水泵和报警器也是数字量输出;低液位浮球、手动按钮、手自动转换开关是数字量输入。逐个信号走一遍,点数就不会漏。
下面是一个中等规模项目的典型点表,可作为自己列点时的参考模板:
| 信号名称 | 信号类型 | IO类型 | 数量 | 备注 |
|---|---|---|---|---|
| 土壤湿度传感器 | 4-20mA两线制 | AI | 10 | 每路单独隔离供电 |
| 流量计 | 脉冲信号 | DI计数 | 1 | 用高速计数器或普通DI扫描 |
| 低液位开关 | 干接点 | DI | 1 | 故障停泵用 |
| 电磁阀 | 220VAC线圈 | DO | 12 | 经中间继电器驱动 |
| 水泵接触器 | 220VAC线圈 | DO | 1 | 必须与阀门互锁 |
| 手动/自动转换开关 | 干接点 | DI | 1 | 每台设备可增加单独手动按钮 |
按这张表,AI约10点、DI约2点、DO约13点。实际选型时我不会直接拿“CPU自带IO”去凑,因为灌溉项目往往后续要加一路压力变送器、加一个阀,所以预留空间要给足。一般做法是CPU本身带一部分DI/DO,再扩展一块4通道或8通道模拟量模块;模拟量每通道成本高,所以先在点表里再确认一次,避免“为了一个信号多买一块模块”的尴尬。
2.3 选型五个约束:点数、扩展、通信、输出类型、供电
确定了点表,PLC选型基本就框死了。我一般按五个约束逐个过:首先是CPU的点数和扩展能力,点数接近上限时直接选大一号CPU,或者加扩展模块,不要卡着临界值;第二是模拟量模块的通道数量和输入规格,灌溉传感器常用两线制4-20mA,模块必须提供相应的接线端子和供电方式,共地输入和差分输入对现场抗干扰影响很大,尽量选差分输入;第三是通信口,触摸屏、上位机、远程模块都要占用通信口,至少留一个RS485,支持Modbus RTU或Modbus TCP最佳;第四是输出类型,继电器输出适合驱动电磁阀这类交流负载,晶体管输出动作快但带载能力弱,不能直接控制阀线圈,除非外接中间继电器;第五是供电,传感器、PLC输入、通信模块通常用DC24V,电磁阀用AC220V,两套电源在控制柜内就要分开布置,屏蔽层的接地也要独立处理。
这里有一个经常被忽视的点:电磁阀是感性负载,每次关断都会产生反向电动势。如果PLC输出直接带阀线圈,触点寿命会明显下降,甚至拉弧粘连。我习惯的做法是PLC的DO先驱动中间继电器,再由中间继电器触点去控制阀线圈,中间继电器的线圈侧并联续流二极管,触点侧按阀的实际工作电压接入。虽然多了一排继电器,但后期更换阀时不用动PLC端子,现场维护会省很多事。
3. 控制逻辑实现:从状态表到可下装的ST代码
3.1 控制需求状态表:自动轮灌、手动检修和故障停车的边界
写梯形图或ST之前,先把控制需求转成状态表。灌溉系统至少要有三个状态:自动运行、手动检修、故障停车。自动运行下,系统按设定时间或湿度条件逐个开启阀门;手动检修时,操作人员在HMI或机旁按钮箱上单独开某个阀,此时自动逻辑必须让位;故障状态则由低液位、泵过载、传感器断线等条件触发,一旦触发立即停相应的泵或阀。状态表里还要写明状态切换条件和动作结果。
状态表可以控制逻辑的核心:状态转换条件是布尔量,动作结果是输出量。比如“手动检修”状态下,即使湿度信号低于设定值,自动轮灌也不能启动;“故障停车”状态下,所有自动输出被封锁,但HMI报警要持续显示。把这些条件提前写在表格里,比直接写程序更容易发现逻辑漏洞。
3.2 单路电磁阀的最小控制功能块:互锁、延时、手动优先
单路阀控制是所有灌溉逻辑的基础。我用结构化文本(ST)写一个功能块,包含手动、自动、反馈三部分。这个功能块可以直接在主流PLC软件里编译,也容易改回梯形图。
FUNCTION_BLOCK FB_Valve VAR_INPUT AutoReq : BOOL; (* 自动模式信号 *) ManReq : BOOL; (* 手动开阀请求 *) HmiOpen : BOOL; (* 上位机/触摸屏开阀命令 *) SensorOk : BOOL; (* 传感器正常,无断线 *) LevelOk : BOOL; (* 液位正常 *) DryRun : BOOL; (* 泵运行信号,作为阀开允许 *) HysteresisT : TON; (* 防抖延时 *) END_VAR VAR_OUTPUT ValveOut : BOOL; (* 阀输出 *) Status : BYTE; (* 状态字:Bit0运行,Bit1故障 *) END_VAR VAR RunReq : BOOL; (* 综合运行请求 *) END_VAR逻辑段如下:
// 自动请求只有在非手动、无故障时有效 RunReq := (AutoReq AND SensorOk AND LevelOk) OR ManReq OR HmiOpen; // 手动或上位机命令优先,互锁条件为液位正常和泵运行状态 IF RunReq AND DryRun THEN ValveOut := TRUE; ELSE ValveOut := FALSE; END_IF; // 状态字记录输出和故障 Status.0 := ValveOut; Status.1 := NOT LevelOk;这段代码的核心逻辑是:阀输出的最终条件是“运行请求”和“泵运行状态”同时成立。DryRun来自泵接触器的辅助触点,不是来自程序内部变量,这样即使PLC程序跑飞,泵没转,阀也开不了,避免干转损坏水泵。手动请求ManReq和上位机命令HmiOpen在自动请求之外,目的是让检修时能单独开阀,但要受LevelOk和DryRun约束。
参数说明:HysteresisT在这里没有展开,实际使用时要加一个3到5秒的延时,避免传感器抖动导致阀频繁动作。现场我常把它设为5秒,既不会太迟钝,也能滤掉大部分瞬时干扰。如果把这个延时去掉,你就会看到电磁阀“咔哒咔哒”不停吸合,那是最常见的翻车现场之一。
3.3 模拟量处理:4-20mA转湿度百分比,还要能识别断线
模拟量输入在PLC中通常被读成0~27648或0~4095的原始值。不要直接在程序里用原始值做比较,先做工程值转换,再判断传感器状态。下面是一个典型的4-20mA两线制传感器处理方法:
// 输入量程 4mA~20mA,对应 0~100% rawValue : INT; (* AI模块原始值 *) humidity : REAL; (* 换算后湿度百分比 *) filteredH : REAL; (* 滤波后湿度 *) brokenWire : BOOL; (* 断线诊断 *) sampleSum : REAL; (* 移动平均求和 *)换算公式:
// 4mA对应0%,20mA对应100% humidity := (rawValue - rawAt4mA) * 100.0 / (rawAt20mA - rawAt4mA); // 如果电流低于2mA,判定为断线 IF rawValue < rawAt2mA THEN brokenWire := TRUE; ELSE brokenWire := FALSE; END_IF;rawAt4mA和rawAt20mA要填模块实际的量程下限和上限原始值,不同PLC不太一样。有的AI模块有断线诊断位,直接用模块状态位更准,没有就按电流下限判断。断线识别很重要,如果传感器断了,程序还在按0%湿度灌溉,地块会被浇成水塘。
滤波我一般用简单移动平均,取最近5次采样做平均,放在一个循环里:
// 每100ms采集一次,取5次平均值 FOR i := 4 DOWNTO 1 DO sampleBuf[i] := sampleBuf[i-1]; END_FOR; sampleBuf[0] := humidity; sum := 0; FOR i := 0 TO 4 DO sum := sum + sampleBuf[i]; END_FOR; filteredH := sum / 5.0;这个滤波思路简单、参数直观。采样间隔和滑动窗口大小要匹配:100ms采一次,取5次,代表500ms内的平均湿度;窗口太大响应变慢,窗口太小滤不掉瞬时波动。湿度传感器埋在土里,本身响应就慢,500ms窗口足够。如果你发现湿度值还是跳,可以先查供电和屏蔽,而不是继续加滤波深度。
3.4 轮灌顺序与分时:避免十几路阀同时开启撑爆管网压力
灌溉系统里最隐蔽的问题是同时打开很多阀,导致管道压力骤降。肉眼看上去每路逻辑都正常,但水泵出口压力跌到设定值以下,远端阀根本喷不出水。解决方法是把轮灌改成时间错开,同一时间只允许开一部分阀。
我常用的轮灌功能块是队列式分配:把所有自动阀的编号放进数组,按顺序轮询,每路阀设定一个持续时间和间隔时间,到达间隔后切到下一路。下面是一个简化版本:
// 轮灌参数 actIndex : INT; (* 当前执行阀索引 *) valveCnt : INT; (* 参与轮灌的阀总数 *) timerFlow : TON; (* 当前阀的持续计时 *) interval : TON; (* 两轮之间的间隔计时 *) valveOpen : ARRAY[0..31] OF BOOL; (* 各阀输出 *)// 当前阀输出为真,其余为假 FOR i := 0 TO valveCnt-1 DO IF i = actIndex AND NOT faultStop THEN valveOpen[i] := TRUE; ELSE valveOpen[i] := FALSE; END_IF; END_FOR; // 持续时间结束,换下一路 IF valveOpen[actIndex] AND timerFlow.Q THEN actIndex := actIndex + 1; IF actIndex >= valveCnt THEN actIndex := 0; END_IF; timerFlow.IN := FALSE; END_IF;这段代码的逻辑很容易理解:同一时刻只让actIndex指向的那一路阀输出,其余全部关闭。timerFlow控制每一路阀的灌水时长,到点即切换。faultStop是全局故障封锁,只要有泵过载或断线,整个轮灌停住。
关键参数是timerFlow的设定时间和interval的间隔时间。比如每路灌水10分钟,两路间隔30秒,管网压力就不会瞬间被拉垮。参数不要写死在程序里,要放到HMI可改的保持型变量区;土壤干燥程度、季节不同,灌水时长变化很大,现场人员必须有权限调整。这个功能块和单阀控制功能块要配合使用:轮灌给出AutoReq,单阀功能块再根据液位和泵状态做最终输出,两层逻辑互不干扰。
4. HMI组态与远程监控:参数可调、状态可看、报警可查
4.1 触摸屏画面结构:运行页、参数页、报警页和阀组页
灌溉系统的HMI没必要做得很花哨,但要保证操作人员能在现场完成三件事:看状态、改参数、查报警。我一般把画面分成四页:
第一页是运行总览,显示泵运行状态、当前轮灌阀号、湿度趋势、流量瞬时值和累计值,所有关键数值一屏放下;第二页是参数设置,包括土壤湿度下限、上限、每路阀灌水时长、间隔时间、巡检时间;第三页是阀组控制,每路阀要有手动按钮、当前状态指示、参与/不参与自动轮灌的使能开关,方便现场单独检修;第四页是报警记录,显示故障列表、发生时间和确认按钮。
HMI地址要和PLC变量一一对应,不要直接在画面上写数值,用内部变量做一次映射。原因是在HMI上改数值时,很容易误触到相邻的IO地址;映射出一层后,参数页改的是“设定值”,运行页显示的是“实际值”,逻辑上更清晰,也不容易出现“改了一个参数,另一个阀跟着乱开”的诡异问题。
4.2 保持型变量与掉电保存:参数不丢是最低要求
很多PLC默认变量在断电后恢复初始值,如果灌水时长、轮灌顺序这类参数存在普通变量里,现场一停电就全回到默认设置。解决办法是在PLC程序里把这些参数声明为保持型变量,或者在某块保持寄存器地址区建立参数结构。
参数区我建议单独建一个结构体,包含所有现场可调参数,把结构体整体分配到保持区:
(* 参数结构体 *) TYPE TYPE_Param : STRUCT HumidLow : REAL; (* 湿度下限,单位%RH *) HumidHigh : REAL; (* 湿度上限,单位%RH *) ValveTimeMin : ARRAY[0..31] OF TIME; (* 每路灌水时长 *) IntervalSec : TIME; (* 轮灌间隔 *) PumpStartDelay : TIME; (* 启泵延时 *) END_STRUCT END_TYPE参数结构体映射到保持区后,HMI直接读写结构体成员即可。不要图省事把参数和中间变量混在一起,否则一旦程序临时增加一个计时器,参数地址整体偏移,HMI上的旧参数就可能全部错位。这是现场调试里最常见的“黑匣子”问题:程序看着没问题,HMI显示的却是另一组数。
4.3 通过Modbus RTU把数据送到上位机或DTU
如果项目需要远程监控,PLC至少要走一条标准通信协议。灌溉系统数据量不大,Modbus RTU是最常见的选择,几乎所有上位机、组态软件和DTU都支持。以Modbus从站为例,规划一个寄存器映射表,把关键数据放到连续的保持寄存器里:
| Modbus地址 | 数据类型 | 内容 | 读写属性 |
|---|---|---|---|
| 40001 | 16位无符号 | 当前系统状态 | 只读 |
| 40002 | 16位无符号 | 当前轮灌阀号 | 只读 |
| 40003 | 浮点数 | 泵出口压力 | 只读 |
| 40005 | 浮点数 | 当前土壤湿度 | 只读 |
| 40007 | 浮点数 | 流量累积值 | 只读 |
| 40009 | 16位无符号 | 手动/自动切换标志 | 读写 |
| 40010 | 浮点数 | 湿度下限设定值 | 读写 |
寄存器规划原则是每一条数据固定地址,不要随意挪。浮点数在Modbus里通常占两个字,顺序可能高字节在前或低字节在前,上位机配置时要注意字节序。我吃过这个亏:上位机显示湿度300%,一看是两个字顺序反了。建议在HMI或上位机软件里提供一个字节序测试开关,连接后用已知固定值抓包验证。
4.4 报警处理:什么时候只提示,什么时候必须停车
报警不能一律“弹窗了事”,要分等级。灌溉系统里我通常分两级:提示级和停车级。提示级包括传感器断线、单路阀反馈异常、流量偏低,这些不需要立即停机,但要记录并提醒操作人员检查;停车级包括低液位、泵过载、主管道压力超限,这些一旦触发必须立即停泵或关阀,不能等操作员确认。
PLC程序里要把停车级故障做成硬逻辑,最好不经过HMI确认直接动作。比如低液位浮球接入PLC的DI点后,无论手自动状态如何,只要液位消失,泵输出必须立刻断开。不要把这个条件只放在ST程序里的一个普通IF语句中,要让它进入硬互锁回路,或者直接在泵接触器的控制回路里串入液位继电器触点。这样即使PLC本身出现问题,泵也不会在缺水状态空转,这套双保险是现场检修时最值钱的设计。
5. 现场调试与常见问题排查:五个典型坑
5.1 电磁阀“咔哒”响但不动作,水也出不来
现象:HMI显示阀已打开,PLC输出指示灯也亮,电磁阀有吸合声,但喷头不出水或出水量很小。
原因大多是阀前压力不足,或者阀芯被杂质卡住。电磁阀虽然线圈有电,但只要阀前后压差不够,膜片就不会完全打开。轮灌时多路阀同时启动,管道压降过大,远端阀就会处于“半开不开”状态,声音响但流量极小。另一种情况是管网里有焊渣、泥沙,阀芯被卡在中间位置。
解决:先看压力表,确认阀前压力是否在电磁阀标称的最低工作压力以上。如果是压力不足,就在程序里减少同时开启的阀数或增加间隔时间;如果压力正常但阀还是不出水,拆开阀芯清洗,并在管道末端加装滤网。这里要提醒,电磁阀选型时最低工作压力是硬指标,不要只看通径。
5.2 湿度值一开机就显示满量程,甚至超过100%
现象:土壤湿度传感器刚通电时读数就跳到20mA对应的最大值,用万用表量电流确实偏大。
原因通常是传感器供电电压过高或接线错误。很多两线制传感器要求DC24V供电,但实际允许范围是10~30V;现场如果用了开关电源,输出纹波大或电压偏高,传感器内部电路会饱和,电流直接顶到上限。另外,传感器探头埋在很干的土里,探头电极与土壤接触不良,也可能让电路开路,开路表现为电流接近20mA。
解决:先确认供电电压在传感器手册规定范围内,再看接线端子有没有氧化。把探头插到湿润土壤里,如果数值马上回落,说明是土壤太干导致测量失真,不是传感器坏了。湿度传感器读数异常时,第一反应不是换传感器,而是先用万用表串量回路电流,确认信号源是否在合理范围内。
5.3 水泵频繁启停,阀门还跟着一振一振
现象:自动模式下,湿度值在设定点附近来回摆动,泵和阀每隔几分钟就启停一次,接触器触点明显发热。
原因:阈值判断没有设置“死区”和“延时”。当湿度降到下限以下时开阀,湿度升到上限时关阀,这是最常见的写法;但湿度传感器在灌溉过程中变化不是线性的,刚浇完水时探头周围湿度很高,几分钟后水分扩散,数值又掉下来,于是程序反复切换。
解决:把控制逻辑改成“下限启动、上限停止”的滞回控制,同时加入最小持续运行时间和停泵延时。比如设湿度下限30%,上限45%,湿度小于30%才启动泵,大于45%才停止;泵启动后至少运行5分钟,停止后至少等2分钟才允许再次启动。这段延时要在PLC里做成独立计时器,不被湿度值直接复位。
5.4 模拟量信号跳得像股市,HMI上湿度值来回乱闪
现象:湿度值在稳定土壤中仍然大幅度波动,相邻两次扫描之间差出20%以上。
原因:信号线没有屏蔽或屏蔽层接地错误,与动力线走在同一个线槽,开关电源纹波大,以及PLC的AI模块共地问题。灌溉现场最常见的是把模拟量信号线和电磁阀220V电源线绑在一起,阀一动作读数就跳。
解决:信号线必须用屏蔽双绞线,屏蔽层在PLC控制柜侧单端接地,传感器侧悬空;信号线与动力线分管或分槽敷设,间距至少20cm;检查AI模块是否为差分输入,如果是公用负极的模块,尽量改选差分输入,或者在传感器端加隔离配电模块。现场排查时可以先拔掉一路传感器,用标准信号发生器从端子注入4mA和20mA看读数是否稳定,这能把问题快速定位在信号源还是接线路径上。
5.5 手自动切换瞬间,阀会莫名其妙开一下
现象:转换开关从自动拨到手动时,原本不该开的阀会瞬间动作一下,然后又恢复正常;有时会喷一下水,吓人一跳。
原因:转换开关在切换过程中有中间悬空状态,PLC程序在同一扫描周期里读到“自动信号消失、手动信号还未到位”,输入端逻辑短暂处于真空,输出条件被错误满足。另一个常见原因是切换开关的触点接触电阻大,拨动瞬间产生抖动,程序没做消抖处理。
解决:切换开关选带中间挡位的三挡开关,接线时把“手动”和“自动”两路信号都接到PLC,程序只在两个信号都稳定后才切换模式;PLC扫描周期内对切换信号加50~100ms的延时滤波。更稳妥的做法是先断开输出再切换模式,也就是模式切换指令放在程序末尾执行,当模式字改变时,先把当前所有阀输出清掉,延时一个扫描周期再建立新模式输出。这样即使开关抖动,也不会造成误动作。
6. 进阶:用状态字和仿真给这套系统装上保险
最后说一个我自己的习惯,也是被现场事故教育出来的:把散落各处的故障条件汇总成一个“状态字”,一次上传给HMI和上位机。状态字的每一位代表一个具体故障,例如Bit0低液位,Bit1泵过载,Bit2传感器断线,Bit3流量不足,Bit4电磁阀反馈异常。上位机只需要读一个寄存器,通过位测试就能精确显示是哪一路故障,而不必读几十个布尔开关。
在PLC里把状态字做成一个功能块输出,每次扫描更新:
(* 汇总状态字 *) faultWord.0 := NOT LevelOk; (* 低液位 *) faultWord.1 := PumpOverload; (* 泵过载 *) faultWord.2 := SensorBroken; (* 传感器断线 *) faultWord.3 := FlowLow; (* 流量不足 *) faultWord.4 := ValveFeedbackError; (* 阀反馈异常 *)状态字里要区分“提示级”和“停车级”。我的原则是:凡是可能损坏设备的故障,比如泵过载、管压超限,除了状态字置位之外,还必须走硬接线停车回路;其他的只做提示。这样HMI上能看清原因,现场继电器又能直接断泵,双通道独立,不至于把命运全押在PLC程序上。
另外,强烈建议你花几个小时把程序放在PLC编程软件的仿真环境里跑一遍。把时间轴压缩,让10分钟轮灌缩短成10秒仿真,观察状态字切换、阀输出顺序、HMI地址映射是否正确。仿真不能替代现场调试,但能把你关在控制柜前“对着黑匣子猜”的时间省掉大半。我自己的一个教训:有一台泵因为“过载”信号接到了报警键盘而不是硬停车保护,结果上位机一直报故障但现场泵还在转,最后热保护跳了才停。从那以后,我所有停车级故障都做硬接线回路,程序里的状态字只负责记录和展示。
灌溉系统看似简单,真正能做稳需要耐心。你把IO点先算清、阀和泵互锁做牢、参数放到保持区、故障分级处理,这套基于PLC的智能灌溉系统至少能稳定运行几个灌溉季。希望帮到你。
本文还有配套的精品资源,点击获取