单片机污水控制:4-20mA采集、Modbus与级联PID整定

发布时间:2026/9/19 2:25:17
单片机污水控制:4-20mA采集、Modbus与级联PID整定 简介围绕单片机在污水处理中的自动化控制这份文档资料面向自动化、环境工程及电子类专业的学生与技术人员尤其适合课程设计、毕业设计或方案调研阶段参考。内容以MCS-51单片机为控制核心讲解如何用流量传感器与pH值传感器采集废水参数再由电动调节阀调节电石渣液流量使中和后的pH值稳定在排放要求附近。针对中和剂浓度波动大、反应滞后等问题文档引入串级调节系统内环控制电石渣液流量外环控制pH值并配有报警和显示功能同时讨论传感器精度、抗干扰能力、实时性以及PID、模糊逻辑等控制策略的取舍也提到电石渣作为中和液实现“以废治废”的经济与环保意义。包内共1个doc文件约42KB属于文档资料型资源结构完整便于摘录控制回路与设计思路。已有64人学习适合需要搭建控制系统框架或补充污水处理案例的读者查阅。1. 单片机控制污水处理控的其实不是水很多人接这类题目的第一反应是测 pH超了就开加药泵。真装到一体化设备上问题立刻变样——探头三天长满生物膜读数从 7.0 缓慢爬到 7.8加药泵在设定值附近一分钟启停五六次接触器烧触点液位变送器被泡沫顶到假高报提升泵空转。单片机在这一环里做的不是把水处理干净而是把工艺人员给的几个设定值——溶解氧、pH、液位、浊度——稳定地维持在一个带死区的区间内并且在传感器断线、通信超时、执行器反馈缺失时退回到一个已知的安全状态。这件事拆开就是五步把工艺回路翻译成 IO 点位表、选一颗匹配现场的主控、把 4-20mA 信号干净地送进 ADC、把单环或级联 PID 调到不振荡、最后做现场加固与在线升级。下面按我实际做控制柜的顺序推进代码给到能直接改了用的颗粒度。2. 污水处理点位表拆解与单片机选型2.1 一个小型一体化设备到底要接哪些点位污水处理的传感器和执行器不是孤立存在的任何一个控制回路都至少包含一个测点 一个执行器 一条安全联锁。做点位表的价值在于它决定了主控要几个 ADC 通道、几路继电器、几路 PWM也决定了采样周期和滤波窗口该取多大。测点典型传感器信号形式建议采样周期控制用途调节池液位投入式压力变送器4-20mA500 ms提升泵启停、防干转保护溶解氧 DO荧光法 DO 电极4-20mA / RS4851 s曝气风机变频调节pH玻璃电极 变送器4-20mA / RS4851 s加酸 / 加碱计量泵浊度90° 散射式浊度计4-20mA1 s加药 PAC/PAM、排泥阀ORP铂电极 变送器4-20mA2 s厌氧段与消毒段判断出水流量电磁流量计4-20mA / 脉冲1 s加药前馈、回流比计算曝气风机变频器0-10V / RS485200 msDO 内环执行器加药泵隔膜计量泵继电器 / 4-20mA1 spH、浊度执行器排泥阀、回流泵电磁阀、离心泵继电器 接触器事件触发时序控制、联锁一个常见的误判是把 pH 电极直接接到 ADC 上。玻璃电极输出阻抗在 10^8 Ω 量级必须经过高输入阻抗运放缓冲CA3140、AD8605 这类输入级再进变送器转成 4-20mA。市售工业 pH 变送器基本已经做了这一步直接用探头接 MCU 是必坑。2.2 51、STC、STM32、ESP32 在污水现场的取舍热搜里 51 单片机和 stc 单片机常年挂着但现场选型不是按我会哪颗来定的而是按通道数、隔离需求、通信接口数来定。主控内核 / 主频ADC串口现场适配性典型用途STC89C528051 / 12-35MHz无需外挂 ADC08091×UART便宜抗干扰看布板51 单片机课程设计、单点位演示STC8A8K64S4A128051 / 24MHz12 位 15 通道4×UART3.3-5V带 PWM 与比较器小型控制柜、成本敏感量产STM32F103C8T6Cortex-M3 / 72MHz12 位 10 通道3×USART外设完整生态成熟多回路 Modbus 主站ESP32-S3Xtensa LX7 / 240MHz12 位 20 通道3×UART带 WiFi需注意现场 EMC远程监视、手机端调试我一般的判断线是控制回路超过 3 个、需要做 Modbus 主站轮询在线仪表的直接上 STM32F103C8T6只有单路液位 单路继电器、成本压到极致的用 STC8A8K 系列就够省掉外挂 ADC 这点在批量上很明显。带无线的主控放在污水池边要谨慎变频器与接触器动作时的共模干扰很容易把 WiFi 打到掉线无线部分更适合放在配电箱外的网关侧。2.3 4-20mA 进 ADC采样电阻与量程换算工业变送器绝大多数是 4-20mA 两线制标准做法是串一个 250Ω 精密采样电阻0.1% 以上低温漂把电流转成 1-5V 电压再进 ADC。250Ω 的好处是压降小、功耗低同时 1-5V 能覆盖大多数 3.3V 或 5V 参考的 ADC 输入范围的下半段。#include math.h #define VREF_MV 3300.0f /* STM32F103 的 ADC 参考电压 3.3V */ #define ADC_FULL 4095.0f /* 12 位 ADC 满量程 */ #define R_SAMPLE 250.0f /* 采样电阻 250Ω1-5V 对应 4-20mA */ /* 返回工程量返回 NAN 表示断线或短路 */ float read_4_20ma(uint16_t raw, float range_lo, float range_hi) { float v raw / ADC_FULL * VREF_MV; /* ADC 码值 - 电压 mV */ float i v / R_SAMPLE; /* 电压 - 电流 mA */ if (i 3.6f || i 21.5f) /* 3.6mA 以下判断线21.5mA 以上判短路 */ return NAN; /* 线性映射到工程量例如 pH 4.0 ~ 10.0 */ return range_lo (i - 4.0f) / 16.0f * (range_hi - range_lo); }三个参数必须对着数据手册确认VREF_MV用 MCU 的 VDDA 实测值而不是标称 3.3V否则满量程有 1%-2% 的系统误差R_SAMPLE的精度直接决定整条链路的精度用 5% 碳膜电阻是浪费 ADC断线判据的上下限要留出变送器自身的输出误差带一般取 3.6mA 和 21.5mA 比取 3.9/20.1 更稳。硬件上再串一个 100nF 到地的 RC 低通截止约 1kHz能把变频器传导过来的高频噪声压掉一大截。3. 最小系统跑通采集滤波与执行器输出3.1 采样通道的中值 滑动平均写法现场 ADC 读数跳变有两个来源一是探头本身的电化学噪声二是变频器、接触器动作时的传导干扰。单纯调大滑动平均窗口会让控制变迟钝正确做法是先中值滤波去尖峰再掐头去尾求平均去白噪声。#include string.h #include stdint.h #define WIN 16 static uint16_t buf[WIN]; static uint8_t idx 0; uint16_t filter_adc(uint16_t raw) { uint16_t tmp[WIN]; buf[idx % WIN] raw; /* 环形缓冲写入最新采样 */ memcpy(tmp, buf, sizeof(buf)); /* 冒泡排序把尖峰挤到两端 */ for (int i 0; i WIN - 1; i) for (int j 0; j WIN - 1 - i; j) if (tmp[j] tmp[j 1]) { uint16_t t tmp[j]; tmp[j] tmp[j 1]; tmp[j 1] t; } uint32_t sum 0; for (int i WIN / 4; i WIN * 3 / 4; i) /* 掐掉两端各 25%抑制野值 */ sum tmp[i]; return (uint16_t)(sum / (WIN / 2)); }WIN取 16 是采样周期 100ms、对应 1.6s 的窗口对液位、pH 这类缓变量足够对流量这种快变量要降到 8。掐头去尾的比例按现场干扰强度调25% 是保守值干扰特别重的场合可以放到 1/3但窗口本身要相应加长否则有效样本太少、输出会重新抖起来。排序用冒泡在 16 点规模下开销完全可接受如果换成 64 点窗口就该上插入排序或直接调用现成的中值滤波库。3.2 三类执行器继电器、可控硅、变频器执行器怎么驱动取决于这个回路的调节频率。开关量动作一天几十次的排泥阀、回流泵用继电器 中间继电器 交流接触器的三级结构MCU 的 IO 只驱动光耦绝不直接带继电器线圈。调节频繁的加药泵、加热棒用可控硅过零触发调功MCU 输出过零同步的脉冲串控制导通周波数避免移相触发带来的谐波。调速类的曝气风机用变频器接口要么 0-10V 模拟量要么 RS485 Modbus RTU。模拟量接口简单但抗干扰弱长线必须用屏蔽双绞线且屏蔽层单端接地RS485 走数字量抗干扰好还能回读变频器的电流、频率、故障码做闭环更完整。/* 用 PWM RC 滤波输出 0-10V 给变频器控制曝气风机转速 */ void set_fan_speed(float percent) /* percent: 0.0 ~ 100.0 */ { if (percent 0.0f) percent 0.0f; if (percent 100.0f) percent 100.0f; /* TIM3_CH1PWM 频率 20kHz避免变频器侧听到啸叫 */ uint16_t ccr (uint16_t)(percent / 100.0f * 1000.0f); TIM3-CCR1 ccr; /* ARR 设为 1000 */ }percent的下限不要设成 0风机在极低频下长时间运行散热不良一般设 20% 作为最低转速低于这个值直接停机。PWM 频率取 20kHz 是折中太低会被变频器输入级的采样电路拾取太高会让 RC 滤波后的纹波压不下来。ARR 取 1000 是为了分辨率够用同时让CCR1的整数运算不至于丢精度。3.3 Modbus RTU 读在线仪表的最小实现在线 DO 仪、流量计、变频器基本都是 Modbus RTU 从机。STM32 上用 USART MAX485 或者隔离型的 ADM2483DE/RE 用一个 IO 控制收发切换。下面这条请求帧读的是从机地址 0x01 的 0x0000 起两个保持寄存器。/* 读保持寄存器 03H地址 0x01起始 0x0000数量 0x0002 */ static const uint8_t req[] {0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0xC4, 0x0B}; uint16_t modbus_crc16(const uint8_t *p, uint8_t len) { uint16_t crc 0xFFFF; while (len--) { crc ^ *p; for (int i 0; i 8; i) crc (crc 1) ? (crc 1) ^ 0xA001 : (crc 1); } return crc; /* 发送时低字节在前 */ } void modbus_send(const uint8_t *frame, uint8_t len) { RS485_DE_HIGH(); /* 拉高 DE切到发送 */ for (uint8_t i 0; i len; i) { while (!(USART1-SR USART_SR_TXE)); USART1-DR frame[i]; } while (!(USART1-SR USART_SR_TC)); RS485_DE_LOW(); /* 拉低 DE切回接收 */ }req最后两字节是 CRC 低字节在前、高字节在后写死帧只适合验证链路正式代码里应该用modbus_crc16()现算。RS485_DE_HIGH()之后的TC发送完成等待不能省否则最后一个字节还没移出移位寄存器就切回接收帧尾会被自己吃掉。从机响应超时一般设 300ms连续 3 次超时就把该通道标记为无效对应的控制回路转手动或安全默认态不要在数据无效的情况下继续跑 PID。4. 级联 PID 整定溶解氧外环 风量内环4.1 曝气控制为什么推荐级联而不是单环单环 PID 直接拿 DO 偏差算风机频率在小型池体上能凑合用但有两个绕不开的问题。第一DO 探头响应时间在 30-90 秒量级单环要把积分时间拉到很长风机频率变化滞后严重第二曝气管路压力波动、风机本身的转速环不响应会让实际风量与给定值之间产生不确定的增益变化。级联控制把结构改成两层外环输入 DO 偏差输出的是目标风量或者目标风压内环以风量 / 风压为反馈快速跟踪外环给出的目标值。内环的采样周期可以做到 200ms外环保持 1-2s两个时间尺度差一个数量级这是级联能稳的前提。DO 探头的慢响应被挡在内环之外风机的快速调节能力被充分利用。热搜里的级联 PID 控制多半说的是这类结构工业上在曝气、加药、温度串级里都常见。要注意内环必须先单独整定好内环没调稳外环参数怎么改都白搭。4.2 增量式 PID 的 C 实现与抗积分饱和位置式 PID 的输出会随时间累加到一个大数一旦执行器饱和积分项继续累积退饱和时输出严重过冲。增量式只算增量配合输出限幅天然带抗饱和能力也是现场最常用的形式。typedef struct { float Kp, Ki, Kd; float err, err_last, err_prev; float out, out_min, out_max; float dead_zone; /* 死区单位与反馈一致 */ } IncPID; float pid_inc(IncPID *p, float sv, float pv) { float e sv - pv; if (e -p-dead_zone e p-dead_zone) return p-out; /* 死区内保持输出抑制执行器频繁动作 */ p-err_prev p-err_last; p-err_last p-err; p-err e; float du p-Kp * (p-err - p-err_last) p-Ki * p-err p-Kd * (p-err - 2 * p-err_last p-err_prev); p-out du; if (p-out p-out_max) p-out p-out_max; /* 上限幅防积分饱和 */ if (p-out p-out_min) p-out p-out_min; /* 下限幅防负输出 */ return p-out; }dead_zone是污水控制里最实用的一个参数。DO 的设定值 2.0 mg/L如果死区设 0探头噪声会让风机频率每秒都动变频器和风机都受不了设 0.1 mg/L 以后实际波动带在 1.9-2.1工艺上完全可接受。out_min和out_max对应风机的 20%-100% 转速区间要和set_fan_speed()里的限幅保持一致两处不一致会出现PID 算出 15% 但执行器给 20%的静差。Ki的量纲要特别注意这里的Ki已经含了采样周期实际工程换算中它等于Kp * T / Ti。改采样周期的时候Ki必须同步改否则同一组参数换周期就振荡。4.3 参数整定顺序与现场记录整定按先内环后外环、先比例后积分再微分的顺序走。内环只有风量反馈比例配一个较大的值先让它快速跟得上目标再慢慢加积分消静差。外环 DO 的整定可以从临界比例度法起步也可以按经验值先粗调再细修。参数内环风量外环DO说明采样周期200 ms1 s内外环差 5 倍以上才稳Kp1.5 - 3.00.6 - 1.2外环偏小避免响应过冲Ki0.05 - 0.150.01 - 0.03外环积分时间通常在分钟级Kd0或极小0.02 - 0.05反馈噪声大时加微分要先滤波输出限幅20% - 100%0 - 100%与执行器物理范围对齐死区00.1 mg/L只在最终稳定环节设死区整定过程中一定要做记录记录格式比参数本身重要时间、DO 实测、设定值、风机频率、进水流量。这三五列数据在事后分析时能直接告诉你振荡是增益过高的等幅振荡周期固定、幅度不衰减还是进水量突变引起的强迫振荡周期随进水变化。前者调小Kp或Ki后者要靠前馈解决不是 PID 参数的事。4.4 pH 加药回路死区、最小启停间隔与前馈pH 控制用计量泵情况和风机完全不同。计量泵的输出是离散的要么按固定流量运行要么停而且加药点混合需要时间。这里的三个技巧第一死区必须设pH 设 7.0 附近 ±0.15 是常见值具体看排放标准第二加最小启停间隔两次启停之间至少 30 秒避免泵频繁启动烧电机第三加前馈用进水流量作为前馈信号流量大就提前把加药量往上抬一个基础值PID 只负责修正偏差这样 pH 波动幅度能明显收窄。/* pH 加药前馈 PID 修正 最小启停间隔 */ #define PUMP_MIN_INTERVAL_S 30 static uint32_t last_pump_tick 0; void ph_dose_control(float ph_now, float ph_sv, float flow_lpm) { /* 前馈按流量给出基础加药占空比0.5 ml/L 为例 */ float ff flow_lpm * 0.5f; /* PID 只修正偏差部分 */ IncPID *loop ph_pid; float pid_out pid_inc(loop, ph_sv, ph_now); float total ff (pid_out - 50.0f); /* pid_out 以 50% 为中性点 */ if (total 100.0f) total 100.0f; if (total 0.0f) total 0.0f; uint32_t now HAL_GetTick() / 1000; if (now - last_pump_tick PUMP_MIN_INTERVAL_S) return; /* 未到最小间隔保持当前输出 */ set_dosing_pump(total); last_pump_tick now; }ff的系数要按药剂浓度和小试结果标定不是拍脑袋给的。pid_out - 50.0f这种以中性点为基准的写法是为了让前馈和反馈在同一量纲上叠加如果 PID 直接从 0 输出前馈加进去会整体偏移、标定全部作废。PUMP_MIN_INTERVAL_S是硬约束宁可让 pH 在短时间内略微超差也不能让泵进入一分钟启停十次的状态。5. ADC 跳变排查、看门狗与串口在线升级5.1 ADC 跳变引起误动作的三条排查线现场出现阀门莫名开启或者风机频率乱跳八成是采集链路的问题不是程序逻辑。按顺序查三条线。第一条是地线。变频器、接触器、MCU、传感器如果共用一个地平面而不是单点接地变频器开关瞬间的共模电流会全部灌进 ADC 参考地。做法是把模拟地和数字地在 ADC 下方单点汇合采样电阻的地就近回到 MCU 的 AGND。第二条是屏蔽层。4-20mA 信号线用屏蔽双绞线屏蔽层只在变送器端或控制柜端单端接地两端都接会形成地环流反而把干扰放大。第三条才是软件。在filter_adc()之后加一个变化率限幅相邻两次有效采样之间的跳变超过量程的 10%直接丢弃该次采样并沿用上一次的值同时计数一分钟内计数超过 20 次就报信号异常告警。#define RATE_LIMIT 0.10f /* 相邻采样最大变化率 10% 量程 */ float adc_with_rate_limit(uint16_t raw, float range_lo, float range_hi) { static float last 0.0f, last_valid 0.0f; static uint16_t bad_cnt 0; float now read_4_20ma(raw, range_lo, range_hi); if (isnan(now)) return last_valid; /* 断线沿用上次 */ float span range_hi - range_lo; if (fabsf(now - last) span * RATE_LIMIT last ! 0.0f) { if (bad_cnt 20) { alarm_raise(ALM_SIGNAL_BAD); } /* 频繁跳变告警 */ return last_valid; /* 丢弃本次 */ } last now; last_valid now; return now; }RATE_LIMIT取 10% 量程是经验值对液位、pH、DO 都够用流量这种本身就快的信号要放宽到 30%。bad_cnt只增不减所以要在一个正常的采样周期里把它清掉否则误告警会一直挂着。5.2 看门狗与安全默认态的定义污水现场的 MCU 一旦跑飞最怕的是输出保持在上一次的状态。STM32 用独立看门狗 IWDG独立时钟源喂狗放在主循环末尾而不是定时器中断里——放中断里等于没喂狗主循环卡死中断照样跑。安全默认态要按回路逐个定义清楚别只写一句全部停止曝气风机降到最低 20% 而不是全停因为池内 DO 掉太快会死菌提升泵停加药泵停排泥阀保持关闭。这些状态在watchdog_init()里就要写好复位后的初始输出让 MCU 一上电或一复位就落到安全态再等通信恢复后逐步接管。5.3 串口在线升级在现场的实际价值控制柜装在池边每次改一个 PID 参数都要带笔记本、开柜门、接下载器这个成本高得离谱而且污水现场开柜门本身就有安全风险。带 bootloader 的串口升级是这类设备的标准配置Flash 里分 Boot 区和 App 区上电先跑 Boot检测到升级标志或收到特定握手帧就进入接收模式接收完整固件、校验 CRC、写完切换。常见的做法是用双区备份新固件先写到备份区校验通过后再把标志位切过去App 里再擦除旧区。这样升级中途断电也不会变成砖头回滚只需要改一个标志字节。51 单片机受限于 Flash 容量和寻址方式做串口升级一般用 STC 官方的 ISP 协议或者精简的 XMODEM 传输STM32 上直接写 IAP 例程改一改更省事。升级帧的握手建议用固定魔术字 版本号 总长度 分片序号 CRC主机每发一包等一个 ACK超时重传三次。这不是为了好看而是污水现场的 485 总线在变频器工作时误码率确实不低没有重传的裸写基本会失败在半途。真到现场把升级工具做成一个上位机小脚本操作工也能点一下完成比带一堆工具下池子实用得多。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询