目录
(资料分享见文末)
一、传感器介绍
漏水传感器主要用于检测地面、管道或设备周围是否出现积水、渗漏等情况。当探头接触到水后,模块会立即切换为报警状态,并通过 RS485接口将检测结果发送给STM32、PLC或上位机。模块采用Modbus-RTU通信协议,具有通信距离远、抗干扰能力强、便于多设备组网等特点。它适用于机房、仓库、地下室、配电柜、水泵房、厨房、卫生间、智能家居及工业自动化系统,可配合蜂鸣器、水泵、电磁阀或云平台,实现漏水报警、自动断水和远程监控。

以下是模块的参数:
|------|-------------|
| 型号 | EYK-JSK930 |
| 供电 | 9-30V |
| 波特率 | 9600 |
| 设备地址 | 0x01 |
| 检测对象 | 自来水、纯净水 |
| 检测距离 | 1000米 |
| 输出地址 | 继电器输出/RS485 |
二、传感器原理
漏水传感器通过探头上的金属电极检测水的导电性。正常干燥时,电极之间电阻较大,传感器输出正常状态;当水接触探头后,水中的离子使电极之间形成导电通路,电阻降低,内部检测电路判断发生漏水并切换为报警状态。模块随后把检测结果转换为数字数据,通过RS485接口按照Modbus-RTU协议发送给STM32。主控发送查询指令后,传感器返回状态数据,其中00表示正常,01表示漏水报警。系统可根据报警结果启动蜂鸣器、关闭电磁阀、停止水泵或上传远程平台,实现实时检测和自动联动控制。

以下是引脚描述:

|------|-------------|
| 漏水传感器 ||
| 485+ | RS485差分信号正端 |
| VCC | 模块正极 |
| GND | 模块负极 |
| 485- | RS485差分信号负端 |
| S1 | 漏水探头正极 |
| S2 | 漏水探头负极 |

|-----|-------------|
| 485转TTL模块 ||
| VCC | 电源正极 |
| TXD | 发送端 |
| RDX | 接收端 |
| GND | 电源负极 |
| A+ | RS485差分信号正端 |
| B- | RS485差分信号负端 |
三、RS485指令
查询指令:01 02 00 00 00 01 B9 CA
返回指令:01 02 01 00 A1 88
四、程序设计
1.使用STM32F103C8T6接收漏水传感器发送的采集数据
2.将解析后的漏水结果在OLED上显示
|----------|------|
| PA2 | TXD |
| PA3 | RXD |
| 5V | VCC |
| GND | GND |
| OLED_SCL | PB8 |
| OLED_SDA | PB9 |
| 调试 | 串口1 |
| A+ | 485+ |
| B- | 485- |
main.c文件
cpp
#include "stm32f10x.h"
#include "delay.h"
#include "usart.h"
#include "OLED.h"
#include "water485.h"
#include <stdio.h>
/*****************辰哥单片机设计******************
STM32
* 文件 : 漏水传感器实验
* 版本 : V1.0
* 日期 : 2026.7.31
* MCU : STM32F103C8T6
* 接口 : 见usart2.h文件
* IP账号 : 辰哥单片机设计(同BILIBILI|抖音|快手|小红书|CSDN|公众号|视频号等)
* 作者 : 辰哥
* 工作室 : 异方辰电子工作室
* 官方网站 : www.yfcdz.cn
**********************BEGIN***********************/
int main(void)
{
SystemInit();
delay_init(72);
USART1_Config();
Water485_Init();
OLED_Init();
OLED_Clear();
while(1)
{
//当前状态
OLED_ShowChinese(8,24,0,16,1);
OLED_ShowChinese(24,24,1,16,1);
OLED_ShowChinese(40,24,2,16,1);
OLED_ShowChinese(56,24,3,16,1);
OLED_ShowChar(72,24,':',16,1);
/*
* 查询一次漏水传感器状态
*
* 最长等待200ms。
*/
if(Water485_ReadState(200))
{
if(Water485_State == WATER485_NORMAL)
{
//正常
OLED_ShowChinese(88,24,4,16,1);
OLED_ShowChinese(104,24,5,16,1);
}
else if(Water485_State == WATER485_ALARM)
{
//漏水
OLED_ShowChinese(88,24,6,16,1);
OLED_ShowChinese(104,24,7,16,1);
}
}
delay_ms(500);
}
}
water485.h文件
cpp
#ifndef __WATER485_H
#define __WATER485_H
#include "stm32f10x.h"
/*****************辰哥单片机设计******************
STM32
* 文件 : 漏水传感器.h文件
* 版本 : V1.0
* 日期 : 2026.7.31
* MCU : STM32F103C8T6
* 接口 : 见usart2.h文件
* IP账号 : 辰哥单片机设计(同BILIBILI|抖音|快手|小红书|CSDN|公众号|视频号等)
* 作者 : 辰哥
* 工作室 : 异方辰电子工作室
* 官方网站 : www.yfcdz.cn
**********************BEGIN***********************/
/*
* 漏水传感器状态
*/
typedef enum
{
/*
* 通信错误或没有收到正确数据
*/
WATER485_ERROR = 0,
/*
* 传感器正常,没有检测到漏水
*/
WATER485_NORMAL,
/*
* 检测到漏水
*/
WATER485_ALARM
} Water485_State_t;
/*
* 当前漏水传感器状态
*/
extern volatile Water485_State_t Water485_State;
/**
* @brief 漏水传感器初始化
* @param 无
* @retval 无
*/
void Water485_Init(void);
/**
* @brief 向漏水传感器发送状态查询指令
* @param 无
* @retval 无
*/
void Water485_SendQuery(void);
/**
* @brief 处理漏水传感器返回数据
* @param 无
* @retval 1:收到并解析到正确数据
* 0:没有数据或数据错误
*/
uint8_t Water485_Process(void);
/**
* @brief 阻塞方式读取一次漏水状态
* @param timeout_ms:等待超时时间,单位毫秒
* @retval 1:读取成功
* 0:读取失败
*/
uint8_t Water485_ReadState(uint16_t timeout_ms);
/**
* @brief 获取状态对应的字符串
* @param 无
* @retval 状态字符串
*/
const char *Water485_GetStateString(void);
#endif
water485.c文件
cpp
#include "water485.h"
#include "usart2.h"
#include "delay.h"
#include "usart.h"
/*****************辰哥单片机设计******************
STM32
* 文件 : 漏水传感器.c文件
* 版本 : V1.0
* 日期 : 2026.7.31
* MCU : STM32F103C8T6
* 接口 : 见usart2.h文件
* IP账号 : 辰哥单片机设计(同BILIBILI|抖音|快手|小红书|CSDN|公众号|视频号等)
* 作者 : 辰哥
* 工作室 : 异方辰电子工作室
* 官方网站 : www.yfcdz.cn
**********************BEGIN***********************/
/*
* 当前漏水传感器状态
*
* 上电默认设置为通信错误,
* 成功读取传感器后再更新状态。
*/
volatile Water485_State_t Water485_State = WATER485_ERROR;
/*
* 读取地址为0x01的漏水传感器状态
*
* Modbus-RTU查询指令:
*
* 01:设备地址
* 02:读取离散输入功能码
* 00 00:起始地址
* 00 01:读取1个状态
* B9 CA:CRC16校验码,低字节在前
*/
static const uint8_t Water485_QueryCmd[8] =
{
//查询指令:01 02 00 00 00 01 B9 CA
0x01,0x02,0x00,0x00,0x00,0x01,0xB9,0xCA
};
/**
* @brief 计算Modbus-RTU CRC16校验值
* @param data:需要校验的数据地址
* @param len:需要校验的数据长度
* @retval CRC16校验值
*
* 返回值低8位是CRC低字节,
* 返回值高8位是CRC高字节。
*/
static uint16_t Water485_CRC16(const uint8_t *data, uint16_t len)
{
uint16_t crc;
uint16_t i;
uint8_t j;
crc = 0xFFFF;
for(i = 0; i < len; i++)
{
crc ^= data[i];
for(j = 0; j < 8; j++)
{
if(crc & 0x0001)
{
crc >>= 1;
crc ^= 0xA001;
}
else
{
crc >>= 1;
}
}
}
return crc;
}
/**
* @brief 漏水传感器初始化
* @param 无
* @retval 无
*/
void Water485_Init(void)
{
/*
* 漏水传感器默认波特率为9600
*/
USART2_Init(9600);
USART2_ClearRx();
/*
* 初始状态设置为通信错误
*/
Water485_State = WATER485_ERROR;
}
/**
* @brief 发送漏水状态查询指令
* @param 无
* @retval 无
*/
void Water485_SendQuery(void)
{
/*
* 每次发送查询指令前,
* 先清空上一次接收的数据。
*/
USART2_ClearRx();
/*
* 发送Modbus-RTU查询指令
*/
USART2_SendArray(Water485_QueryCmd, sizeof(Water485_QueryCmd));
}
/**
* @brief 处理漏水传感器返回的数据
* @param 无
* @retval 1:收到并解析到正确数据
* 0:没有数据或数据错误
*
* 正常返回:
* 01 02 01 00 A1 88
*
* 漏水报警返回:
* 01 02 01 01 60 48
*/
uint8_t Water485_Process(void)
{
uint8_t rx_data[USART2_RX_BUF_SIZE];
uint16_t rx_len;
uint16_t i;
uint16_t crc;
/*
* 没有接收到完整的一帧数据
*/
if(USART2_RX_Flag == 0)
{
return 0;
}
/*
* 临时关闭总中断,
* 防止复制数据时USART2中断修改缓冲区。
*/
__disable_irq();
//读取接收长度
rx_len = USART2_RX_CNT;
if(rx_len > USART2_RX_BUF_SIZE)
{
rx_len = USART2_RX_BUF_SIZE;
}
for(i = 0; i < rx_len; i++)
{
//复制到局部数组
rx_data[i] = USART2_RX_BUF[i];
}
//清空接收状态
USART2_RX_CNT = 0;
USART2_RX_Flag = 0;
//重新开启接收中断
__enable_irq();
//检查数据长度
if(rx_len < 6)
{
Water485_State = WATER485_ERROR;
return 0;
}
/*
* 从接收缓冲区中查找正确的6字节数据帧。
*
* 这样即使数据前面存在少量干扰字节,
* 也能够找到真正的返回数据。
*/
for(i = 0; i + 6 <= rx_len; i++)
{
/*
* 判断设备地址、功能码和数据长度
*/
if((rx_data[i] == 0x01) &&
(rx_data[i + 1] == 0x02) &&
(rx_data[i + 2] == 0x01))
{
/*
* 对前4个字节计算CRC16
*/
crc = Water485_CRC16(&rx_data[i], 4);
/*
* Modbus-RTU发送CRC时低字节在前
*/
if(((uint8_t)(crc & 0xFF) == rx_data[i + 4]) &&
((uint8_t)(crc >> 8) == rx_data[i + 5]))
{
/*
* 第4个字节为漏水状态:
*
* 0x00:正常
* 0x01:漏水报警
*/
if(rx_data[i + 3] == 0x00)
{
Water485_State = WATER485_NORMAL;
return 1;
}
else if(rx_data[i + 3] == 0x01)
{
Water485_State = WATER485_ALARM;
return 1;
}
else
{
Water485_State = WATER485_ERROR;
return 0;
}
}
}
}
/*
* 没有找到正确的返回帧
*/
Water485_State = WATER485_ERROR;
return 0;
}
/**
* @brief 阻塞方式读取一次漏水状态
* @param timeout_ms:等待超时时间,单位毫秒
* @retval 1:读取成功
* 0:读取超时或数据错误
*/
uint8_t Water485_ReadState(uint16_t timeout_ms)
{
/*
* 发送查询指令
*/
Water485_SendQuery();
/*
* 在规定时间内等待传感器返回数据
*/
while(timeout_ms > 0)
{
/*
* 检查并处理接收数据
*/
if(Water485_Process())
{
return 1;
}
delay_ms(1);
timeout_ms--;
}
/*
* 等待超时,没有收到正确返回数据
*/
Water485_State = WATER485_ERROR;
return 0;
}
/**
* @brief 获取漏水状态字符串
* @param 无
* @retval 状态对应的字符串
*/
const char *Water485_GetStateString(void)
{
switch(Water485_State)
{
case WATER485_NORMAL:
return "NORMAL";
case WATER485_ALARM:
return "WATER ALARM";
case WATER485_ERROR:
default:
return "COMM ERROR";
}
}
四、实验演示
