土壤湿度传感器
| 器材 | 数量 | 参考 |
|---|---|---|
| 电容式土壤湿度传感器 | 1 | — |
价格随渠道波动,以购买页实时为准。
想做一个自动浇花的小盒子,第一步不是接水泵,而是让板子先知道一件事:现在土到底干没干。人凭手指插进去捏一捏就有数,板子要靠一根插进土里的探头,把"湿度"变成一个能读的电压。这块传感器干的就是这件事——把土壤里看不见的含水状态,翻译成 ESP32 的 ADC 能读的数字。
它属于模拟类传感器,多数模块同时给出两个输出脚:AO(模拟)和 DO(数字)。AO 是连续变化的电压,干湿之间平滑过渡;DO 是模块板上自带一个比较器,超过你拧电位器设定的阈值就翻转高低电平。做"看具体湿了多少"用 AO,做"干到一定程度就报警/浇水"可以直接用 DO。本页主讲 AO 接 ADC 这条路,因为它信息全、可标定,配合 ADC 原理 一看就透。
工作原理
市面上的土壤湿度传感器分两大流派,原理完全不同,寿命差出十倍,买之前必须分清。
电阻式(叉子状两个金属电极):靠测量两电极之间土壤的电阻来判断湿度。土里水分越多、溶解的离子越多,电阻越小,导电越好;土越干,电阻越大。模块把这个电阻变化经过分压(原理见 分压)变成 AO 电压输出。问题出在"两根裸金属一直插在湿土里通电"——这其实就是一个微型电解槽,长期通直流电会让电极发生电化学腐蚀,金属一点点被电解掉,表面氧化、长绿锈。新买时读数还准,埋土里浇几周水,电极烂了读数就飘了,再过段时间直接报废。它便宜,但本质上是个消耗品。
电容式(一整块覆了防腐涂层的板子,常见黑色或绿色):它不靠土壤导电,而是把探头当成电容器的一极,测探头周围介质介电常数的变化。水的介电常数(约 80)远高于干土和空气(约 1~4),周围水分越多,等效电容越大,模块内部把电容变化转成频率再转成 AO 电压。关键点是:电容式的导电部分被涂层封住了,不直接和土壤里的水、离子接触,不参与电解,所以基本不腐蚀,寿命长得多。 这就是为什么但凡要长期埋在土里、放户外、想用一两年的场景,都直接选电容式。
一句话结论:长期用、户外、认真做项目 → 电容式;只是接出来玩两天、图便宜 → 电阻式也行,但心里要清楚它会坏。
接线
电容式模块一般 3.3V 供电就够,ESP32 也是 3.3V 体系,直接对接,不用电平转换。
| 传感器 | ESP32 | 说明 |
|---|---|---|
| VCC | 3.3V | 供电 |
| GND | GND | 共地 |
| AO(AOUT) | GPIO34 | 模拟输出,接 ADC1 引脚 |
| DO(可选) | 任意 GPIO | 比较器数字输出,超阈值翻转,用不上可以不接 |
注意 ESP32 的 ADC2 在 WiFi 开启时不可用,做联网项目时 AO 务必接 ADC1 的脚(GPIO32~39 这一组),GPIO34 是常用选择。GPIO34~39 这几个还是只输入引脚,正好拿来读传感器。
完整代码
读 AO 的原始 ADC 值,再把它映射成 0~100% 的湿度百分比。注意一个反直觉的点:很多电容式模块数值越小代表越湿(干土读数高、湿土读数低),具体方向以你实测为准,下面代码按"越小越湿"写,方向反了把 map 的两个端点调换即可。
const int PIN_SOIL = 34; // AO 接 GPIO34(ADC1)
// 标定得到的两个端点(见下文“标定”一节,先填占位,标定后改)
const int RAW_DRY = 3200; // 完全干(空气中或干透的土)读到的原始值
const int RAW_WET = 1300; // 刚浇透的湿土读到的原始值
void setup() {
Serial.begin(115200);
// ESP32 ADC 默认量程偏小,加大衰减让 0~3.3V 都能读到
analogSetPinAttenuation(PIN_SOIL, ADC_11db);
}
void loop() {
int raw = analogRead(PIN_SOIL); // 0~4095 的原始值
// 越干读数越大、越湿越小 → 映射成 0~100% 湿度
int pct = map(raw, RAW_DRY, RAW_WET, 0, 100);
pct = constrain(pct, 0, 100); // 夹在 0~100,防止越界
Serial.print("raw="); Serial.print(raw);
Serial.print(" 湿度="); Serial.print(pct); Serial.println("%");
delay(1000);
}
analogSetPinAttenuation(..., ADC_11db) 这一句很关键。ESP32 的 ADC 默认衰减下满量程只到约 1.1V,传感器输出可能到 2~3V,不加衰减会发现读数早早就顶到 4095 一动不动。加上 11db 衰减,0~3.3V 才都落进可测范围。模拟与数字输出的区别,可参考 数字与模拟。
你应该看到什么
烧录后打开串口监视器(115200),做两个动作对照:
- 探头悬空 / 插进干透的土:raw 偏大(比如 3000~3300),映射后湿度接近 0%。
- 把探头插进刚浇透的湿土,或直接插进一杯水到标记线:raw 明显变小(比如 1200~1500),湿度跳到 80%~100%。
只要插干和插湿时数字朝两个方向明显变化,传感器和接线就没问题了。如果数字纹丝不动,往下看故障排查。
标定
土壤湿度传感器读出来的是相对值,不同模块、不同土质、不同插入深度,原始值都不一样,所以不能照搬别人的数字,必须自己做两点标定:
- 取"全干"点:探头放空气中,或插进彻底干透的土,记下稳定后的 raw,填进代码的
RAW_DRY。 - 取"刚浇透"点:把同一盆土浇透(或把探头插进水里到正常埋入深度),等读数稳定,记下 raw,填进
RAW_WET。 - 这两个值就是 0% 和 100% 的端点,
map()会把中间的读数线性映射成百分比。
标定后再插半湿的土试试,百分比应该落在中间且符合直觉。换了一盆土质差很多的土(沙土 vs 营养土),最好重新标定一次。
选型 / 避坑
① 优先电容式:电阻式两极长期通电会电解腐蚀,埋土里几周就锈烂、读数飘,长期项目别用。 ② 供电方式影响寿命:哪怕电容式,也不建议 24 小时常通电。做电池供电的花盆时,让传感器平时断电、要测时才用 GPIO 上电几秒再读,既省电又减少老化。 ③ 换土要重标:不同土壤介电/导电特性不同,干湿两点的原始值会变,换盆、换土质后重新标定一次。 ④ 插入深度固定:插得深浅不同读数也不同,标定和日常使用保持同一深度。
故障排查
| 现象 | 可能原因 | 怎么办 |
|---|---|---|
| 读数恒定不变 / 一直 0 或 4095 | AO 没接 ADC 脚,或接到了只输出脚 | 确认 AO 接到 GPIO34 等 ADC1 输入脚,VCC/GND 接好 |
| 读数顶到 4095 不动 | 没设 ADC 衰减 | 加 analogSetPinAttenuation(pin, ADC_11db) |
| 湿度方向反了(越湿数字越大) | 该模块"越干读数越小" | 把代码里 RAW_DRY 和 RAW_WET 两个值对调 |
| 干湿都差不多、区分不开 | 没标定 / 插入深度太浅 | 做两点标定,探头插够深度 |
| 用了一段时间读数越来越飘 | 电阻式电极被腐蚀 | 换成电容式 |
| WiFi 开启后读数乱跳 | AO 接到了 ADC2 引脚 | 改接 ADC1(GPIO32~39) |
进阶 / 变体
把湿度判断接上执行器,就从"监测"变成"自动浇花"。最常见的做法:湿度低于设定阈值时,用一个 继电器 控制水泵开一段时间浇水,浇完延时一会儿再检测,避免水还没渗匀就反复触发。
const int PIN_RELAY = 26;
const int THRESHOLD = 30; // 低于 30% 就浇水
void waterIfDry() {
int raw = analogRead(PIN_SOIL);
int pct = constrain(map(raw, RAW_DRY, RAW_WET, 0, 100), 0, 100);
if (pct < THRESHOLD) {
digitalWrite(PIN_RELAY, HIGH); // 开泵
delay(3000); // 浇 3 秒(按盆大小调)
digitalWrite(PIN_RELAY, LOW); // 关泵
delay(60000); // 等水渗匀再测,避免连续触发
}
}
想更聪明一点,可以把湿度曲线传上云端,结合天气、植物种类做更细的浇水策略,这就进入了 传感器 + AI 的玩法:让模型根据历史湿度变化预测什么时候该浇、浇多少。
典型应用
- 自动浇花 / 智能花盆:阈值触发水泵,出门一周也不怕花渴死。
- 大棚 / 农田土壤监测:多点埋设,回传湿度曲线指导灌溉。
- 植物养护提醒:不接水泵,只在土太干时推送一条提醒到手机。
- 科学小实验:观察不同浇水量下土壤湿度的变化与回落速度。
小结 · 相关
土壤湿度传感器把"土干没干"变成可读的数字,是自动浇花、植物监测的核心。记住三件事就够用:选电容式(电阻式会腐蚀报废)、AO 接 ADC1 并设好衰减、用前必须做干湿两点标定。把它和继电器、水泵串起来,一个全自动浇花系统就成型了。
参数以 datasheet 为准;本页公开资料整理,接线与代码请结合实物验证。