[i=s] 本帖最后由 大猫的鱼 于 2025-10-19 21:58 编辑 [/i]
一 引言
上期DIY活动中做了一个智能家居相关的通断器,这次做了一款工业上用的电极式水位计。在工业场景中,电极式水位计常被用于锅炉、压力容器、水箱等设备,实现水位的实时监测与高低水位报警,保障设备安全运行。当然在民用场景里应用也较为广泛,像咱们日常可见的热水器、加湿器、饮水机等家电,内部都有水位监测装置。这些装置往往不需要精准的水位距离,只需要知道水位是否在上下限中,避免干烧或溢水问题即可。
二 功能介绍
本模块采用工业上常用的DC24V供电(6V~30V都可),板载运行指示灯与配网按钮。使用RS485总线与外部设备通讯。主机使用标准的MODBUS RTU协议便可设备进行查询与控制。在水位采集上,为了避免电极极化同时也是延长电极使用寿命,没有使用直接通直流电源方案转而使用公共电极发射PWM脉冲,在三个副电极(采样电极)上产生电压变化,单片机使用AD口采样电压的方案。在不用的水质、气压、温度等环境下,同一水位采样回来的电压值不尽相同,所以在本模块中可以对每个通道的触发阈值进行设置,从而适应不同的生产/生活环境。既然使用了咱们Ai-WB2模组作为主控,设备不联网的话我就觉得太过可惜了,因此我便加入了网络功能。用户在对设备配网后,设备便连接上对应的MQTT服务器订阅了相关主题(可在代码中更改)。这样使得模块的拓展性大大增加。我们可以通过MQTT协议将设备连接至小程序、网站或公司内部使用的服务器等,使得多设备联动,会更加智能化。
三 硬件设计
硬件部分较为简单,主要在于软件。主控采用咱们的Ai-WB2-12F模组。模组内置低功耗的32位RISC CPU,276KB RAM和丰富的外围接口,包括 SDIO,SPI,UART,I2C, IR remote,PWM,ADC,DAC,PIR 和 GPIO等。本次项目的硬件需求为:
1、一路LED
2、一路按键检测
3、一路PWM输出
4、三路ADC采样
5、一路485通讯
使用Ai-WB2-12F模组作为主控才好,完美适配。
电源部分分两级,输入24V转5V部分采用L7805芯片进行降压(建议采用DCDC,手头有这个芯片才采用这颗LDO),随后通过经典的AMS1117-3.3将5V降压至3.3V作为主控芯片的供电。众所周知485为半双工通讯,相较于UART的RX 、TX多了一个控制接收和发送的控制引脚,为了图方便直接搭了一个自动收发电路,在9600波特率的低速场合下运行是完全没有问题的,这样对于软件层面上来讲和UART就没什么不同了。下面是本项目的原理图与PCB图。

图1 原理图

图2 PCB二维图
四 软件设计
4.1 主控软件设计
本项目的单片机软件方面主要使用了GPIO、PWM、ADC、UART、MQTT等。整体软件工作流程为:
①设备上电,检测配网按键是否按下。
②如果配网按键按下,则进入配网模式;设备会先开启STA模式连接存储的配网信息,连接不上wifi则会发出一个AP热点重新配网。用户手机输入密码12345678连接SSID为ai-think的热点(热点名和密码可改)。随后打开浏览器输入192.168.169.1进入配网页面进行配网。
③如果配网按键未按下,或网络连接成功后,设备在公共电极上产生PWM脉冲,通过三通道ADC实时采样副电极电压,与触发阈值进行比较从而判断水位状态。
④设备实时的通过MODBUS和MQTT协议与外部设备进行交互,将水位状态、采样值、阈值等信息传输出去。具体软件流程图如下:

图3 系统软件流程图
4.2 Modbus通讯协议
4.2.1寄存器地址表
| 地址 |
功能 |
数值类型 |
读/写 |
| 0x0100 ~ 0x0102 |
三路水位状态寄存器 |
Bool |
R |
| 0x0200 ~ 0x0202 |
三路通道采样值寄存器 |
Uint16 |
R |
| 0x0300 ~ 0x0302 |
三路触发阈值寄存器 |
Uint16 |
R/W |
| 0x0400 |
设备站号寄存器(0站号作为广播地址) |
Uint8 |
R/W |
4.2.2 指令简介
目前本模块支持的功能码有01、03、06三个功能码,如修改站号相关指令使用广播地址00即可。
01-读线圈状态
发送查询三路水位状态:
| 01 |
01 |
01 |
00 |
00 |
03 |
7D |
F7 |
| 站号 |
功能码 |
寄存器地址H |
寄存器地址L |
读取数量H |
读取数量L |
CRC16H |
CRC16L |
返回:
| 01 |
01 |
01 |
04 |
50 |
4B |
| 站号 |
功能码 |
数据字节数 |
低三位代表水位状态 |
CRC16H |
CRC16L |
03-读保持寄存器
发送查询通道1采样值命令:
| 01 |
03 |
02 |
00 |
00 |
01 |
85 |
B2 |
| 站号 |
功能码 |
寄存器地址H |
寄存器地址L |
读取数量H |
读取数量L |
CRC16H |
CRC16L |
返回:
| 01 |
03 |
02 |
00 |
0F |
F8 |
40 |
| 站号 |
功能码 |
数据字节数 |
通道1采样值H |
通道1采样值L |
CRC16H |
CRC16L |
06-设置单个保持寄存器值
发送设置通道1触发阈值为命令:
| 01 |
06 |
03 |
00 |
0B |
B8 |
8E |
CC |
| 站号 |
功能码 |
寄存器地址H |
寄存器地址L |
设置阈值H |
设置阈值L |
CRC16H |
CRC16L |
返回:(与发送指令相同)
| 01 |
06 |
03 |
00 |
0B |
B8 |
8E |
CC |
| 站号 |
功能码 |
寄存器地址H |
寄存器地址L |
设置阈值H |
设置阈值L |
CRC16H |
CRC16L |
4.3 MQTT通讯协议设计
当给模块配网成功后,模块便将配网WIFI的ssid和password存至内部flash中了。下次再上电便会直接直接WIFI。模块成功连接网络后便会进行连接设定的MQTT服务器并订阅相关主题。给模块添加这个功能主要就是为了增加模块拓展性与智能性,让它不再单单是个连接PLC的485模块。
模块订阅:waterLevel/cmd 主题,接收其他端(小程序,网站等)发送的控制命令。并在 waterLevel/res 主题中发送响应消息。
其他端订阅: waterLevel/res 接收模块的响应消息,在 waterLevel/cmd 发布控制消息。
通讯协议为:
//查询水位命令格式
{
"id":1, //设备的485站号
"cmd":0, //查询命令 0:查询水位状态与采样值,1:查询/设置阈值
}
//查询阈值命令格式
{
"id":1, //设备的485站号
"cmd":1, //查询命令 0:查询水位状态与采样值,1:查询/设置阈值
}
//设置阈值命令格式
{
"id":1, //设备的485站号
"cmd":1, //查询命令 0:查询水位状态与采样值,1:查询/设置阈值
"TH1":100, //通道1 要设置的阈值
"TH2":100, //通道2 要设置的阈值
"TH3":100, //通道3 要设置的阈值
}
五 实物演示
还是先来几张实物图:

图4 PCB焊接后图 图5 模块实物图
模块的对外接口主要有3种:首先是DC 6V~30V的电源输入,使用工业上常用的24V开关电源接上就行了;其次是485通讯接口的A B线;最后是电极接口,模块标的SCOM作为电极公共端连接设备外壳(一定要是导电的如蒸气锅炉等)或单独连接一根最长的电极,剩下三个S1、S2、S3连接三根不同长度的电极即可。在视频演示中,由于没有找到电极就直接使用了长短不一的铜柱代替了,就这样做了一个简易的测试装置,在蒸汽锅炉中也是能正常使用的,原理都是相同的。具体演示视频如下:
六 总结
这次活动做的这个电极式水位计模块各种的功能我觉得还是很适用于工控场合的。因为个人不太喜欢只做功能上的堆叠不去考虑现实应用,我认为仅是为了做东西而去不断堆砌的做是毫无意义的。当然这个小项目还有些不足,受限于Ai-WB2的引脚数量,没有再做对应三个通道的DO有些可惜,虽然有些遗憾,但哪有完全完美的事物呢?
这次的小项目就到这啦!!!下次再见吧
附件:
附件:电极式水位计_s.zip