想知道屋顶水塔几时快见底?把 JSN-SR04T 的 probe 装在水塔盖上、朝下对着水面——它测出到水面的距离,Arduino Uno 把距离换算成百分比,显示在小小的 OLED 上,水位跌破 20% 就响 buzzer 提醒你。只有黑色 probe 防水,蓝色驱动板必须放在水塔外保持干燥。
为什么要用 JSN-SR04T,不用普通的 HC-SR04?
JSN-SR04T 传感器分成两部分:一个完全密封的黑色圆柱形 probe(IP67 防护等级),接在一条带白色 2-pin 插头的长线上;另一块是独立的蓝色驱动板,带 4 pin header。普通 HC-SR04 有两颗外露的「眼睛」,在水塔里潮湿的空气中很快就坏——做水位监测这种活,全密封的 probe 才是正解。
按 Manorshi 原厂 datasheet,这个模块在 DC 3.0–5.5V 供电下测量 21 cm 到 600 cm,trigger 和 echo 的用法与 HC-SR04 相同——超声波测距的基本原理,我们在 HC-SR04 教程里已经讲过。
元件清单
长期安装用
| Item | Price | Qty | |
|---|---|---|---|
Power Supply Adapter DC Universal AC to DC Converter PSU 5V2A 5V3A 9V2A 12V2A - P.S. ADAPTOR (12V2A)PSA1202 | RM15.95 |
12V 适配器直接插 Uno 的 DC 插座——不用接电脑,监控器 24 小时运行。
probe 装在水塔哪个位置最合适?
JSN-SR04T 有一个重要限制:盲区。太近的东西它测不到——Manorshi 3.0 版 datasheet 写最小 21 cm,旧版 datasheet 写 25 cm。这个数字随板子版本而不同,所以按更安全的那个来设计:把盲区当作 25 cm。
实际安装时,probe 至少要装在满水位上方 30 cm——水塔满的时候,水面仍在盲区之外,这个 offset 之后会算进代码的公式里。probe 的波束是约 75 度的宽锥形,所以要装在盖子正中,远离塔壁和进水口,免得壁面回波和进水的波纹干扰读数。
别让 probe 吊在线上——它会晃、会歪。在盖子中央按 probe 头的尺寸钻一个孔,把 probe 嵌进去,让它的面正对垂直向下,四周用 silicone sealant 或 cable gland 封好。驱动板、Uno 和 buzzer 放在水塔外阴凉干燥的盒子里;只有 probe 头穿过盖子。上屋顶作业有规矩:别一个人爬,线缆沿现有水管或结构扎牢,市电电线远离水塔。长期安装的话,用 12V 适配器从 Uno 的 DC 插座供电——插座留在屋里,只有低压 DC 线上到电子盒。

JSN-SR04T、OLED 和 buzzer 怎么接到 Uno?
JSN-SR04T 的驱动板用四个 pin——Vcc、GND、Trig、Echo——probe 线上的白色 2-pin 插头直接插到驱动板上的插座。0.91 寸 128×32 OLED 则走 I2C:在 Arduino Uno 上,I2C 引脚是 A4(SDA)和 A5(SCL)。留意这块 OLED 排针的丝印顺序:GND、VCC、SCK、SDA——这里的 SCK 就是 I2C 时钟线 SCL,只是印字不同。
| 元件 / 引脚 | 接到 |
|---|---|
| JSN-SR04T Vcc | Uno 5V |
| JSN-SR04T GND | Uno GND |
| JSN-SR04T Trig | Uno D9 |
| JSN-SR04T Echo | Uno D8 |
| probe 线(白色 2-pin 插头) | 驱动板上的插座 |
| OLED GND | Uno GND |
| OLED VCC | Uno 5V |
| OLED SCK(即 SCL 线) | Uno A5 |
| OLED SDA | Uno A4 |
| Buzzer 红线(+) | Uno D7 |
| Buzzer 黑线(−) | Uno GND |
SFM-20B buzzer 是有源 piezo 型——规格标明最大 10 mA(在额定 12V 下,5V 时电流更低)——远低于 Uno 每个引脚 20 mA 的上限,所以可以直接用数字 pin 驱动,不需要三极管(不像电磁式 buzzer 那么吃电流)。它也够响,大约 95 dB——所以之后的代码响的是间歇短哔声,不是长鸣。

开工之前想看看这颗传感器配 OLED 的实际安装过程,这条短片一步一步示范:
距离怎么换算成水位百分比?
Arduino Uno 只知道一件事:probe 面到水面的距离。要把距离换成水位,需要从你自己的水塔量两个固定数字——满水距离(probe 到满水位,例如 30 cm)和空塔距离(probe 到塔底,例如 150 cm)。水深 = 空塔距离 − 读数;百分比 = 水深 ÷(空塔距离 − 满水距离)× 100。
举个例子:上面那个水塔,传感器读到 90 cm。水深 = 150 − 90 = 60 cm,百分比 = 60 ÷ (150 − 30) × 100 = 50%。安装时用卷尺量好这两个固定数字——整个系统的准确度全靠它们。
为什么读数在水塔里跳来跳去?怎么稳定它?
JSN-SR04T 在真实水塔里的读数很少安安静静。进水管一冲水面就晃,细小的波纹会把回波打散,75 度的波束锥可能扫到塔壁,水汽还会在 probe 面上结露——每一样都可能触发乱跳的读数。
最有效的解法:连取几个读数,用中位数(median),不是平均值。七个样本里混进一个 400 cm 的野值,平均值会被拉得老远;中位数只取排序后的中间值——野值直接被丢掉。对这种爱突跳的超声波数据,median 几乎稳赢。
温度也会影响声速:0°C 时约 331.5 m/s,每升高 1°C 增加约 0.6 m/s。代码按 343 m/s(约 20°C)计算;大热天水塔里的空气可以去到 40°C,读数会偏差接近 4%——每米距离大约 3 到 4 cm。对百分比显示和警报来说可以忽略;想要厘米级精度,就挑中午时分在现场校准空塔距离。

这个监控器的完整代码是什么?
这个 sketch 需要在 Arduino IDE 的 Library Manager 装两个 library:Adafruit GFX Library 和 Adafruit SSD1306(Wire 是内置的)。这块 0.91 寸模块的 I2C 地址是 0x3C。按你的水塔改好 JARAK_PENUH(满水距离)和 JARAK_KOSONG(空塔距离),sketch 就能直接用;屏幕上的提示文字维持拉丁字母字符串——SSD1306 的默认字体显示不了中文。
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
Adafruit_SSD1306 oled(128, 32, &Wire, -1);
const int PIN_TRIG = 9;
const int PIN_ECHO = 8;
const int PIN_BUZZER = 7;
// 你的水塔尺寸——按实际改这两个值
const float JARAK_PENUH = 30.0; // cm:probe 到满水位(保持在 25 cm 盲区之外)
const float JARAK_KOSONG = 150.0; // cm:probe 到塔底
const int AMBANG_ALARM = 20; // 低于 20% buzzer 开始响
const int AMBANG_RESET = 30; // 回升超过 30% 才重新安静(迟滞)
const int BIL_SAMPEL = 7; // 取中位数的采样次数
bool alarmAktif = false;
float bacaJarakSekali() {
digitalWrite(PIN_TRIG, LOW);
delayMicroseconds(2);
digitalWrite(PIN_TRIG, HIGH);
delayMicroseconds(10); // 按 datasheet 给 10us 触发脉冲
digitalWrite(PIN_TRIG, LOW);
unsigned long tempoh = pulseIn(PIN_ECHO, HIGH, 40000UL);
if (tempoh == 0) return -1.0; // 没收到回波
return tempoh * 0.0343 / 2.0; // 343 m/s(约 20°C)
}
float bacaJarakMedian() {
float sampel[BIL_SAMPEL];
int n = 0;
for (int i = 0; i < BIL_SAMPEL; i++) {
float j = bacaJarakSekali();
if (j > 0) {
int k = n; // 升序插入排序
while (k > 0 && sampel[k - 1] > j) {
sampel[k] = sampel[k - 1];
k--;
}
sampel[k] = j;
n++;
}
delay(60); // 等旧回波先消散
}
if (n == 0) return -1.0;
return sampel[n / 2]; // 中间值 = 中位数
}
void setup() {
pinMode(PIN_TRIG, OUTPUT);
pinMode(PIN_ECHO, INPUT);
pinMode(PIN_BUZZER, OUTPUT);
oled.begin(SSD1306_SWITCHCAPVCC, 0x3C); // 0.91 寸模块的 I2C 地址
oled.clearDisplay();
oled.display();
}
void loop() {
float jarak = bacaJarakMedian();
oled.clearDisplay();
oled.setTextColor(SSD1306_WHITE);
if (jarak < 0) {
oled.setTextSize(1);
oled.setCursor(0, 12);
oled.print(F("Tiada bacaan sensor")); // 无读数——检查 probe 插头和接线
oled.display();
return;
}
// 把距离换算成水深和百分比
float julat = JARAK_KOSONG - JARAK_PENUH;
float dalamAir = JARAK_KOSONG - jarak;
dalamAir = constrain(dalamAir, 0.0, julat);
int peratus = round(dalamAir / julat * 100.0);
oled.setTextSize(2); // 左边大字显示百分比
oled.setCursor(0, 9);
oled.print(peratus);
oled.print(F("%"));
oled.setTextSize(1); // 右边小字显示水深
oled.setCursor(72, 6);
oled.print(F("Dalam:"));
oled.setCursor(72, 18);
oled.print(dalamAir, 0);
oled.print(F(" cm"));
oled.display();
// 迟滞:低于 20% 响起,只有回升超过 30% 才停
if (!alarmAktif && peratus < AMBANG_ALARM) alarmAktif = true;
if (alarmAktif && peratus > AMBANG_RESET) alarmAktif = false;
if (alarmAktif) { // 短哔声,不是持续长鸣
digitalWrite(PIN_BUZZER, HIGH);
delay(150);
digitalWrite(PIN_BUZZER, LOW);
}
delay(1000);
}
留意那两个警报门槛:水位跌破 20% buzzer 开始响,但要等水位回升超过 30% 才会停。没有这种迟滞处理,水面在 20% 附近晃来晃去,buzzer 就会响响停停闹个没完。下一步很多人都会做:加 relay 和水泵,让水塔自己补水——概念和我们的 Arduino 自动浇花系统一样。
我们常看到的错误
读数一直是 0 或卡在同一个数字。多半是 probe 的白色插头没插紧在驱动板上,或者 Trig 和 Echo 接反了。把 probe 插头重新插稳,对照上表检查 Trig 接 D9、Echo 接 D8。
读数疯狂乱跳。通常是 probe 离塔壁太近,或正对着进水口的水流——移到盖子正中。如果水装太满、水面进了 25 cm 盲区,读数也会变乱码:把 probe 的位置抬高。
在桌上好好的,进了水塔就乱讲。在桌上,probe 对着又平又静的地板——理想条件。在水塔里,要确保 probe 正对垂直向下;歪几度回波就打到塔壁,不再回到 probe——所以 probe 必须稳稳嵌在盖子钻的孔里,不能吊在线上晃。
装在外面几个星期后系统就死了。几乎都是驱动板或 Uno 淋了雨、沾了露水。再说一次:只有 probe 防水——所有板子都要装在密封盒里,走线孔也要封好。
关于水塔水位传感器的常见问题
多高的水塔可以用?
JSN-SR04T 最远测到 600 cm,扣掉 30 cm 的安装 offset,5 米深的水塔也还在量程内。马来西亚住家常见的 poly 水塔多是 1 到 2 米——对这颗传感器绰绰有余。
水面晃动的话,读数会不会乱?
一般的晃动已经被代码里 7 次读数取中位数吸收掉了。如果你的水塔长期晃得厉害,把 BIL_SAMPEL 提高到 11,或在 probe 下方垂一根竖直的 PVC 管当「稳流井」(stilling well)——管里的水面比开放水面平静得多。
probe 顶得住屋顶的太阳吗?
probe 是 IP67 等级,datasheet 标明工作温度 -20°C 到 +70°C,马来西亚屋顶的热度还在范围内。真正要保护的是电子部分:驱动板和 Uno 要装在阴凉处的密封盒里,不要直接暴晒。
可以把警报发到手机吗?
Arduino Uno 没有 WiFi,所以只有 OLED 和 buzzer。升级到 ESP32,几乎一样的代码就能把通知推送到手机——看我们的 ESP32、ESP8266 和 Uno 对比挑一块合适的板。
地下水箱适合吗?
适合——原理一样:probe 装在顶盖、朝下测。只是地下水箱的空气更潮湿,probe 面更容易结露;每次保养时擦一擦 probe 面,驱动板则要留在地面以上的干燥盒子里。
最后更新:2026年8月。有问题?WhatsApp 联系我们。



Arduino Uno Compatible SMD UNO R3 with Type B Cable - ATMEGA328P with CH340G-Microcontroller Project
Waterproof Ultrasonic Distance Sensor JSN-SR04T Module Water Level Measurement Range Finder 20-600cm Arduino
0.91' OLED Display Module I2C Communication 3.3V 5V For Arduino IOT Application
SFM-20B Active Buzzer DC 3-24V Piezoelectric Long Continous Beep
Power Supply Adapter DC Universal AC to DC Converter PSU 5V2A 5V3A 9V2A 12V2A - P.S. ADAPTOR (12V2A)