传感器 · 土壤湿度 · YL-38/YL-69
土壤湿度传感器 STM32F103 接线与代码
给单片机装一个「土够不够湿」的检测器:两根金属叉探头插进土里,土壤含水量越高,探头间等效电阻越小;AO 输出连续湿润程度,DO 输出「过没过阈值」一个开关量。本页是 STM32F103C8T6 + 该模块 + 0.96 OLED 的完整实机验证记录,含接线表、完整代码和 PlatformIO 工程下载。最值得看的是「探头会腐蚀」和「STATE 三档和 DO 翻转点是两回事」这两段。
Quick Facts
- 传感器:土壤湿度传感器(腐蚀式探头 + LM393 比较器小板)
- 供电:3.3V,与 STM32 共地(别接 5V)
- 接线:AO→PA0,DO→PA1,共 4 根线
- 显示:0.96 寸 OLED,SSD1306,地址 0x3C
- 实测:三档 DRY / MOIST / WET,OLED 显示 ADC + MOIST% + STATE
Verified
实机验证结果
本项目实测 下面的结果全部来自我们自己的实机测试,更新于 2026-08-18。
STM32F103C8T6 已经能读探头的 AO 模拟量并换算成 0~100% 湿度,OLED 显示 ADC 原始值 + MOIST 百分比 + STATE 三档状态,右上角一个小圆点实时显示 DO 电平。
三档湿度实测
| 探头状态 | ADC(8次平均) | STATE | DO |
|---|---|---|---|
| 干土 | ≈4000 | DRY | HIGH |
| 正常湿润土 | ≈3700 | MOIST | HIGH |
| DO 翻转点(电位器阈值) | ≈3250 | — | HIGH → LOW |
| 很湿的土 | ≈2600 | WET | LOW |
STATE 三档分界:ADC ≥ 3850 为 DRY,≥ 3150(且 < 3850)为 MOIST,否则 WET。DO 翻转点由电位器单独决定,与 STATE 三档分界是两套独立阈值。
串口输出(115200)
Soil moisture demo v1.1 starting...
OLED 0x3C: found
ADC=4008 DO=HIGH
ADC=3712 DO=HIGH
ADC=3260 DO=LOW
ADC=2610 DO=LOW
每 400ms 一行:ADC=<8次平均原始值> DO=<HIGH/LOW>。
实测环境
| 项目 | 本项目实际使用 |
|---|---|
| 主控 | STM32F103C8T6(BluePill) |
| 模块 | 土壤湿度传感器(腐蚀式探头 + LM393 比较器小板,4 针 VCC / GND / DO / AO) |
| 显示 | 0.96 寸 OLED,SSD1306,128×64,地址 0x3C |
| 状态灯 | BluePill 板载 LED,PC13(低电平点亮,DO 为 LOW 时亮) |
| 开发工具 | VS Code + PlatformIO |
| 框架 | Arduino / STM32duino |
| 烧录 | ST-Link |
| 串口 | 115200 |
| 依赖库 | Adafruit SSD1306、Adafruit GFX Library |
What it does
这个模块干什么
土壤湿度传感器就是给单片机装一个「土够不够湿」的检测器。两根金属叉探头插进土里,土壤干燥时叉齿间导电弱、等效电阻大;含水后水膜跨接叉齿,电阻下降。单片机拿到的就是一个「越湿越小」的电压,再换算成百分比。
土壤含水量改变探头两极间的电阻,探头把变化送进 LM393 控制板,控制板分成两路输出:AO 连续模拟量、DO 阈值开关量。STM32 读这两路,显示到 OLED 和串口。
AO 和 DO 到底有什么区别
| AO(模拟量) | DO(数字量) | |
|---|---|---|
| 输出 | 连续电压,反映湿润程度 | 开关量,只答「过没过阈值」 |
| 用途 | 算百分比、判三档 | 报警、触发、点灯 |
| 受电位器影响 | 基本不受 | 完全由电位器决定翻转点 |
AO/DO 的区别来自模块输出定义,由我们整理成表。资料参考
Wiring
接线
本项目实测 按下面接法实机跑通。模块 4 根线 + OLED 4 根线。
土壤湿度模块(丝印 VCC / GND / DO / AO)
| 信号 | 模块丝印 | STM32F103C8T6 |
|---|---|---|
| 电源 | VCC | 3.3V |
| 地 | GND | GND |
| 模拟输出 | AO | PA0(ADC) |
| 数字输出 | DO | PA1(内部上拉) |
OLED
| 信号 | OLED | STM32F103C8T6 |
|---|---|---|
| 电源 | VCC / VDD | 3.3V |
| 地 | GND | GND |
| 时钟 | SCL / SCK | PB8 |
| 数据 | SDA | PB9 |
烧录与串口(不接也能跑,接上方便看数据)
| 用途 | 连接 | 说明 |
|---|---|---|
| 烧录 | ST-Link → SWD 四线(3.3V / GND / SWDIO=PA13 / SWCLK=PA14) | 烧录用 |
| 串口 | PA9(TX) / PA10(RX) → CP2102 等 | 看串口数据(115200,可选) |
1. 供电用 3.3V,不要接 5V。AO 直接进 STM32 ADC,3.3V 供电能保证 AO 输出 0~3.3V 不超量程。
2. OLED 用重映射引脚 PB8/PB9,不是默认 PB7/PB6。代码里必须先
Wire.setSDA(PB9)、Wire.setSCL(PB8),再 Wire.begin(),顺序反了读不到屏幕。3. 必须共地。模块、OLED、STM32 的 GND 接一起,否则 ADC 和 I2C 都会莫名其妙失败。
Principle
工作原理
资料参考 这一节来自厂家资料和常规工程实践,不是我们实测的结论,用来帮助理解参数。实测结果只在上面「实机验证结果」一节。
| 环节 | 说明 | 来源类型 |
|---|---|---|
| 探头电极 | 两根金属叉齿插入土壤,干燥土壤颗粒间导电弱,等效电阻大,AO 电压高 | 厂家/模块资料 |
| 水膜跨接 | 土壤水分含离子,水膜跨接两根叉齿形成导电路径,含水量越高电阻越小,AO 电压越低(越湿 AO 越小) | 公开测试资料 |
| LM393 阈值比较 | 信号电压 vs 电位器设定的参考电压(门槛),越线瞬间 DO 翻转、板载 LED 点亮 | 厂家/模块资料 |
| 电位器调门槛 | 调的是 DO 的触发点;不影响 AO 连续读数 | 厂家/模块资料 |



DO 极性:不同模块可能相反
LM393 是开漏输出,DO 的「触发电平」取决于板上接法,不同厂家批次可能相反。我们实测这块板子是「干 HIGH / 湿 LOW」。若你的模块实测相反,把判断逻辑改一处,或直接调模块电位器把翻转门槛调过来。
探头会腐蚀 · 最需要提前知道的一条
腐蚀式探头是裸露金属叉齿,长期通电 + 插土会发生电化学腐蚀,金属会一点点被吃掉,直到失效。这是这种电阻式雨滴/土壤传感器的通病。
和电容式传感器比有什么区别
| 电阻式(本项目) | 电容式 | |
|---|---|---|
| 原理 | 水改变探头叉齿间电阻 | 水改变电极间电容 |
| 腐蚀 | 金属裸露,会电解腐蚀 | 电极可覆膜,耐腐蚀好很多 |
| 成本 | 很便宜 | 贵一些 |
| 精度 | 够判断干湿档位 | 更适合长期、量化记录 |
对比来自电阻式与电容式传感器的常规工程实践,由我们整理。资料参考
Code
完整代码
本项目实测 下面是实际烧录进板子、拍摄结果照片时运行的那一份(v1.1),一字未改。环境:VS Code + PlatformIO + Arduino(STM32duino)。
关键处说明
1. I2C 指到 PB8/PB9。STM32duino 默认 I2C 引脚不是 PB8/PB9,必须先 Wire.setSDA()/Wire.setSCL() 再 Wire.begin(),顺序反了读不到 OLED。
2. 8 次平均 + EMA 平滑。AO 一次读 8 次取平均,再送指数滑动平均(EMA),抗探头波动,数值才稳。
3. 按实测方向的百分比映射。map(smoothAdc, SOIL_DRY_ADC, SOIL_WET_ADC, 0, 100),按本项目实测的方向(ADC 越小越湿)线性换算,夹到 0~100。
4. STATE 三档和 DO 翻转点互不干扰。三档分界(≥3850 DRY / 3150~3849 MOIST / <3150 WET)和 DO 的电位器翻转点(≈3250)是两套独立阈值。
5. 校准值单独定义。SOIL_DRY_ADC / SOIL_WET_ADC 是干燥/湿润两个 ADC 读数,实测后只改这两行。
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define FIRMWARE_VERSION "v1.1"
// =========================
// GPIO 配置
// =========================
// 土壤湿度模块(腐蚀探头 + LM393 比较器小板,4 针:VCC / GND / DO / AO)
// AO -> PA0(模拟量,ADC1_IN0,反映探头间电阻,湿度越大读数方向「已实测:越湿越小」)
// DO -> PA1(数字量,LM393 比较器输出,超过电位器阈值时翻转)
// VCC -> 3.3V(3.3V 供电,AO 输出 0~3.3V,与 STM32 ADC 量程一致,不要接 5V)
// GND -> GND
// 注意:腐蚀式探头持续通电会电腐蚀电极。短时测试/拍视频直接接 3.3V 没问题;
// 长期插土里使用时,改成 GPIO/三极管控制供电(隔几秒上电→等几十ms→采样→断电)。
// 板载 LED -> PC13(bluepill 板载 LED,低电平点亮;DO 低电平时点亮,作观察用)
constexpr uint8_t SOIL_AO_PIN = PA0;
constexpr uint8_t SOIL_DO_PIN = PA1;
constexpr uint8_t LED_PIN = PC13;
// OLED 使用 I2C1 重映射引脚:SCL=PB8 / SDA=PB9(与 01~08 系列公共标准一致)
constexpr uint8_t I2C_SDA_PIN = PB9;
constexpr uint8_t I2C_SCL_PIN = PB8;
constexpr uint8_t OLED_ADDRESS = 0x3C;
constexpr uint8_t SCREEN_WIDTH = 128;
constexpr uint8_t SCREEN_HEIGHT = 64;
constexpr int OLED_RESET = -1;
// =========================
// 校准参数(实测数据,2026-08-18 记录)
// =========================
// ADC: 4000 STATE: DRY DO: HIGH
// ADC: 3700 STATE: MOIST DO: HIGH
// ADC: 3250 STATE: THRESHOLD DO: LOW <- DO 电位器实测翻转点,只是 DO 的阈值,不是湿度档位中点
// ADC: 2600 STATE: WET DO: LOW
// 方向:ADC 越高越干,越低越湿。MOIST% 按 DRY(0%) ~ WET(100%) 线性换算。
// STATE(土壤干湿档位)与 DO(比较器电平)是两个独立概念,分开显示,不用 HIGH/LOW 当干湿状态名。
// 注意:水中测试只作极限参考,不要把「水中 ADC」当成实际土壤的 100%;
// 且只能让金属叉形探头接触水,LM393 小板不能浸水。
constexpr uint16_t SOIL_DRY_ADC = 4000; // 干土 ADC 读数(0%)
constexpr uint16_t SOIL_WET_ADC = 2600; // 湿土 ADC 读数(100%)
// STATE 三档分界(DRY / MOIST / WET,与 DO 翻转点 3250 无关,避免把 DO 阈值当成湿度中点)
constexpr uint16_t SOIL_TH_DRY = 3850; // >= 该值 -> DRY
constexpr uint16_t SOIL_TH_MOIST = 3150; // >= 该值(且 < DRY)-> MOIST,否则 WET
// =========================
// 采样 / 滤波 / 刷新周期
// =========================
constexpr uint32_t SAMPLE_INTERVAL_MS = 20; // 采样周期
constexpr uint8_t ADC_AVG_SAMPLES = 8; // 每次读 8 次 ADC 取平均
constexpr float EMA_ALPHA = 0.08f; // 轻度指数滑动平均(越小越平滑,OLED 显示用)
constexpr uint32_t OLED_REFRESH_MS = 200; // OLED 重绘周期(约 5fps)
constexpr uint32_t SERIAL_INTERVAL_MS = 400; // 串口打印周期(200~500ms)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// 状态
bool g_hasOled = false; // OLED 是否初始化成功
uint16_t g_rawAdc = 0; // 最近一次 ADC 读数(8 次平均,串口/校准用)
float g_smoothAdc = 0; // 滑动平均后的 ADC(OLED 显示用,更稳)
bool g_smoothInit = false;
bool g_doLevel = false; // DO 原始电平:true=HIGH / false=LOW
static uint32_t g_lastSampleMs = 0;
static uint32_t g_lastOledMs = 0;
static uint32_t g_lastSerialMs = 0;
// =========================
// 读取
// =========================
// DO:LM393 开漏输出,板上一般已有上拉,这里再开内部上拉更稳。
// 本阶段只如实上报电平 HIGH/LOW,不做 DRY/WET 判断(不同模块逻辑可能相反,待实测)。
// 连续读 5 次取多数(>=3 次 HIGH 才算 HIGH),避免电位器阈值附近抖动。
static bool readDoLevelStable() {
uint8_t highCount = 0;
for (uint8_t i = 0; i < 5; i++) {
if (digitalRead(SOIL_DO_PIN) == HIGH) highCount++;
}
return highCount >= 3;
}
// =========================
// 采样(8 次平均) + 轻度滑动平均
// =========================
// 一次读 8 次 ADC 取平均,再送指数滑动平均(仅 OLED 显示用)。
// 串口保留「未经百分比转换」的 8 次平均原始 ADC 值,供校准记录。
static uint16_t readAdcAverage() {
uint32_t sum = 0;
for (uint8_t i = 0; i < ADC_AVG_SAMPLES; i++) {
sum += analogRead(SOIL_AO_PIN);
}
return (uint16_t)(sum / ADC_AVG_SAMPLES);
}
static void updateSensor() {
if (millis() - g_lastSampleMs < SAMPLE_INTERVAL_MS) return;
g_lastSampleMs = millis();
g_rawAdc = readAdcAverage();
if (!g_smoothInit) {
g_smoothAdc = (float)g_rawAdc;
g_smoothInit = true;
} else {
g_smoothAdc += ((float)g_rawAdc - g_smoothAdc) * EMA_ALPHA;
}
g_doLevel = readDoLevelStable();
digitalWrite(LED_PIN, g_doLevel ? HIGH : LOW); // DO 低电平时点亮(bluepill LED 低电平点亮)
}
static const char* getDoText() {
return g_doLevel ? "HIGH" : "LOW";
}
// ADC 越小越湿:DRY_ADC(0%) ~ WET_ADC(100%) 线性换算,并夹到 0~100
static uint8_t getMoisturePercent() {
long pct = map((long)(g_smoothAdc + 0.5f), SOIL_DRY_ADC, SOIL_WET_ADC, 0, 100);
if (pct < 0) pct = 0;
if (pct > 100) pct = 100;
return (uint8_t)pct;
}
static const char* getStateText() {
uint16_t adc = (uint16_t)(g_smoothAdc + 0.5f);
if (adc >= SOIL_TH_DRY) return "DRY";
if (adc >= SOIL_TH_MOIST) return "MOIST";
return "WET";
}
// =========================
// OLED UI 绘制
// =========================
static void drawOledUi() {
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextWrap(false);
// 顶部标题
display.setTextSize(1);
display.setCursor(0, 0);
display.print(F("SOIL MOISTURE"));
// 右上角 DO 指示点(实心 = LOW,空心 = HIGH)
if (!g_doLevel) display.fillCircle(120, 4, 3, WHITE);
else display.drawCircle(120, 4, 3, WHITE);
// 分隔线
display.drawFastHLine(0, 9, 128, WHITE);
// 右上角 DO 电平文字(与串口一致,如实上报,不做 DRY/WET 判断)
display.setTextSize(1);
display.setCursor(86, 16);
display.print(F("DO:"));
display.print(getDoText());
// ADC 原始值(平滑后,现场观察更稳;串口才是 8 平均原始值)
display.setCursor(0, 16);
display.print(F("ADC:"));
display.setTextSize(2);
display.setCursor(0, 27);
display.print((uint16_t)(g_smoothAdc + 0.5f));
// MOIST(按实测 SOIL_DRY_ADC/SOIL_WET_ADC 换算)
display.setTextSize(1);
display.setCursor(0, 48);
display.print(F("MOIST: "));
display.print(getMoisturePercent());
display.print(F(" %"));
// 状态(按实测阈值分档:DRY/NORMAL/WET/VERY WET)
display.setCursor(0, 57);
display.print(F("STATE: "));
display.print(getStateText());
display.display();
}
// =========================
// 串口输出
// =========================
static void printSerialData() {
Serial.printf("ADC=%u DO=%s\n",
(unsigned)g_rawAdc,
getDoText());
}
void setup() {
Serial.begin(115200);
delay(100);
Serial.printf("Soil moisture demo %s starting...\n", FIRMWARE_VERSION);
pinMode(SOIL_DO_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
analogReadResolution(12); // 明确 12 位 ADC,读数 0~4095
// I2C1 重映射:PB9=SDA / PB8=SCL,必须先 setSDA/setSCL 再 begin()
Wire.setSDA(I2C_SDA_PIN);
Wire.setSCL(I2C_SCL_PIN);
Wire.begin();
Wire.setClock(100000); // I2C 100kHz,与 01~08 系列公共标准一致
if (display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS)) {
g_hasOled = true;
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.display();
Serial.println(F("OLED 0x3C: found"));
} else {
Serial.println(F("OLED 0x3C: NOT found (continue with serial only)"));
}
// 首帧采样
g_rawAdc = readAdcAverage();
g_smoothAdc = (float)g_rawAdc;
g_smoothInit = true;
g_doLevel = readDoLevelStable();
digitalWrite(LED_PIN, g_doLevel ? HIGH : LOW);
g_lastSampleMs = millis();
// 串口校准提示
Serial.println(F("=== 校准(先做这步,再定最终阈值)==="));
Serial.println(F("1. 探头悬空(空气中) -> 记录 ADC 值"));
Serial.println(F("2. 探头插入干土 -> 记录 ADC 值 = 干燥值"));
Serial.println(F("3. 探头插入湿土/很湿的土 -> 记录 ADC 值 = 湿润值"));
Serial.println(F("4. 改 main.cpp 里 SOIL_DRY_ADC / SOIL_WET_ADC 后重烧(v2)"));
Serial.println(F(" 水中只作极限参考,别当土壤 100%;且只能探头叉入水,小板别浸水"));
Serial.println(F("输出格式: ADC:<原始8平均> DO:<HIGH/LOW>"));
Serial.println(F("注意: ADC 方向(越湿越大/越小)待实测,OLED 上 MOIST 暂不换算百分比"));
if (g_hasOled) drawOledUi();
}
void loop() {
updateSensor();
if (millis() - g_lastOledMs >= OLED_REFRESH_MS) {
g_lastOledMs = millis();
if (g_hasOled) drawOledUi();
}
if (millis() - g_lastSerialMs >= SERIAL_INTERVAL_MS) {
g_lastSerialMs = millis();
printSerialData();
}
}
依赖库:Adafruit SSD1306 和 Adafruit GFX Library,用 PlatformIO 打开工程会按 platformio.ini 自动下载,不用手动安装。
Video
视频演示
本项目实测 208 秒完整演示动画(1920×1080 / 60fps / 带音效)。
视频\土壤_动画_千问办公制作\成品\ 目录下,网页嵌入前需压成小体积版本再放到站点资源目录。当前先给出分段导航。
分段导航(14 段 · 共 208 秒)
| 时间 | 段落 | 内容 |
|---|---|---|
| 00:00 | 成品效果 | 盆栽+探针→加水→OLED 12%→85%,DRY→MOIST→WET |
| 00:14 | 模块认识 | 比较小板/探针/电位器/AO·DO/VCC·GND |
| 00:32 | 接线 | AO→PA0/DO→PA1/VCC→3.3V/GND→GND/OLED PB8/PB9 |
| 00:52 | 干土湿土 | 干土导电弱 → 湿土水膜导电路径 |
| 01:08 | AO 模拟量 | 电压随加水连续下降(实测干 3.2V→很湿 1.9~2.3V) |
| 01:22 | ADC 流水线 | 7 节点数据链:土壤→…→ADC→校准映射→湿度% |
| 01:40 | 湿度百分比 | OLED 大号 UI + 三档状态 + 滤波稳定 |
| 01:58 | 电位器与 DO | 调 Threshold,干 HIGH/湿 LOW 两轮对比 |
| 02:18 | AO 与 DO 对比 | DO 只有 HIGH/LOW,AO 连续变化 |
| 02:30 | 校准 | DRY ADC→0% / WET ADC→100% 三步映射 |
| 02:48 | 实际使用 | 盆栽浇水 35%→71% |
| 03:02 | 腐蚀提醒 | 1/3/7 DAYS 探针腐蚀 + 间歇供电 |
| 03:18 | 总结 | 数据链重现 + 总结 |
Download
下载
PlatformIO 工程,解压后直接打开即可编译烧录,一般不需要改代码,也不需要改 platformio.ini。
第一次使用
- 按上面接线表接好:模块 AO→PA0、DO→PA1、VCC→3.3V、GND→GND;OLED SDA→PB9、SCL→PB8、VCC→3.3V、GND→GND
- 下载 ZIP,解压,用 VS Code + PlatformIO 打开这个文件夹(第一次打开会自动下载 Adafruit SSD1306 和 GFX 库)
- 点击 Build(底部状态栏 ✓ 图标),看到 SUCCESS 就说明代码没问题
- 接上 ST-Link,点击 Upload(底部状态栏 → 图标),看到
** Verified OK **和[SUCCESS]表示烧录成功 - 看 OLED:先显示 SOIL MOISTURE 标题和 ADC 数值,把探头插进干土再插进湿土,MOIST 百分比和 STATE 会跟着变化
正常应该看到什么
| 动作 | OLED 上的表现 |
|---|---|
| 探头插干土 | ADC≈4000,MOIST≈0%,STATE: DRY |
| 换插正常湿土 | ADC 下降,MOIST 上升,STATE: MOIST |
| 插很湿的土 | ADC≈2600,MOIST≈100%,STATE: WET,DO 翻转、LED 亮 |
pio device list,找 CP2102 / CP210x / CH340 对应的那个,然后在自己电脑的 platformio.ini 里加 monitor_port = COMx 和 monitor_speed = 115200。只有需要看串口时才需要加这两行,正常烧录用 ST-Link 不需要。
Troubleshooting
常见问题排查
下面每一条都是这个模块真实会遇到的。标注「实测」的是我们自己踩过的。
供电接错、共地没接,读数乱跳
按这个顺序查:
- 供电是否 3.3V。AO 直接进 STM32 ADC,接 5V 会让 AO 超出 3.3V 量程。
- 是否共地。模块、OLED、STM32 的 GND 要接在一起,否则 ADC 和 I2C 都会莫名其妙失败。
- PA13 / PA14 别占用。这两个脚留给 ST-Link 调试,占用后可能烧不进去。
百分比方向反了:土越湿,百分比越低
校准值 SOIL_DRY_ADC / SOIL_WET_ADC 填反了。按自己模块实测重填这两行即可:map(smoothAdc, SOIL_DRY_ADC, SOIL_WET_ADC, 0, 100),本项目实测方向是「ADC 越小越湿」。
DO 极性反了:干土时 DO 是 LOW
不同厂家批次的比较器输出极性可能不同。程序默认按「干 HIGH / 湿 LOW」写。若实测相反,调模块电位器,或改 readDoLevelStable() 的判断逻辑。不要照抄别人的 DO 逻辑,先在自己板子上实测。
STATE 和 DO 对不上
这是正常现象,两者是独立的两套阈值。STATE 按 ADC 校准换算(≥3850 DRY / 3150~3849 MOIST / <3150 WET),DO 翻转点由电位器单独决定(本项目实测≈3250),不要把 DO 的 HIGH/LOW 当成干湿状态名来用。
OLED 不亮 / 串口打印 OLED 0x3C: NOT found
十有八九是 I2C 引脚或地址。按这个顺序查:
- 确认 SDA 接 PB9、SCL 接 PB8,不是默认的 PB7/PB6。
- 确认代码里
setSDA/setSCL在Wire.begin()之前,顺序反了配置不生效。 - 确认 OLED 地址。常见 0.96 寸 SSD1306 大多是
0x3C,少数是0x3D。 - 确认共地。OLED 的 GND 必须和 STM32 接在一起。
串口看不到数据
先查当前串口:
pio device list
找到 CP2102 / CP210x / CH340 对应的那个 COM,然后在自己电脑的 platformio.ini 里加:
monitor_port = COMx
monitor_speed = 115200
COMx 要换成你自己电脑实际识别到的端口号,不要直接抄。只有需要看串口时才加这两行,正常用 ST-Link 烧录不需要。
长期用探头腐蚀、失效
这是金属探头 + 通电 + 插土产生的电化学腐蚀,是这类腐蚀式探头的固有特性,不是坏了。短时间演示、拍视频完全没问题。长期部署建议改成「上电 → 稳定 → 采样 → 断电」的间歇供电,或换电容式传感器(覆膜电极,耐腐蚀好很多)。
References
资料来源
本页信息来源声明
| 内容 | 来源 |
|---|---|
| 接线、代码、OLED UI、三档阈值、滤波参数、串口输出格式 | 本项目实测 2026-08-18 实机测试 |
| 探头电极、水膜导电、LM393 比较器、电位器门槛 | 资料参考 厂家/模块资料与公开测试资料 |
| AO / DO 两类输出的对比、电阻式与电容式传感器对比 | 资料参考 常规工程实践,由我们整理成表 |
| DO 触发电平极性(干 HIGH / 湿 LOW) | 本项目实测 本块板子实测结果,不同批次可能相反 |
| 探头具体型号(YL-38/YL-69) | 待确认 图上丝印常见于该系列,淘宝批次型号可能不同 |
本页所有「资料参考」内容均由我们重新整理表述,未直接复制原文。参数以你手上模块的实际批次和卖家说明为准;本节任何一条都不代表我们实测验证过,实测结果只在「实机验证结果」一节。