ESP32 + 传感器:手把手教你做土壤监测终端 ESP32 传感器手把手教你做土壤监测终端上一篇给了硬件清单这篇直接上代码。从 GPIO 初始化到传感器读数再到 MQTT 上发最后低功耗优化——每一行都有注释复制到 Arduino IDE 里就能跑。前置准备软件环境Arduino IDE 2.x装好 ESP32 开发板支持库WiFiPubSubClientDHT sensor libraryOneWireDallasTemperatureBH1750ModbusMaster硬件接线按上一篇的引脚表接好USB 线插电脑。第一步基础采集——五个传感器一把梭#includeWiFi.h#includeDHT.h#includeOneWire.h#includeDallasTemperature.h#includeBH1750.h#includeWire.h#includeModbusMaster.h// 引脚定义 #defineDHT_PIN25#defineONE_WIRE_PIN4#defineRS485_DE_RE18// MAX485 方向控制引脚#defineSOIL_SENSOR_132// ADC1 读模拟量土壤湿度备选方案// 传感器对象 DHTdht(DHT_PIN,DHT22);OneWireoneWire(ONE_WIRE_PIN);DallasTemperaturesoilTempSensor(oneWire);BH1750 lightMeter;ModbusMaster modbus;// 数据结构 structSensorData{floatairTemp;// 空气温度 ℃floatairHumidity;// 空气湿度 %floatsoilTemp;// 土壤温度 ℃floatsoilMoisture;// 土壤湿度 %RS485 读数floatlightLux;// 光照强度 Lux};// 初始化 voidsetup(){Serial.begin(115200);// DHT22dht.begin();// DS18B20 土壤温度soilTempSensor.begin();// BH1750 光照Wire.begin(21,22);// SDA21, SCL22lightMeter.begin();// RS485 (Serial2: RX16, TX17)Serial2.begin(9600,SERIAL_8N1,16,17);modbus.begin(1,Serial2);// 从机地址 1pinMode(RS485_DE_RE,OUTPUT);Serial.println( 土壤监测终端启动 );}// RS485 读土壤湿度 floatreadSoilMoistureRS485(){// 切换到发送模式digitalWrite(RS485_DE_RE,HIGH);delay(10);// 读保持寄存器 0x0000湿度值读 1 个寄存器uint8_tresultmodbus.readHoldingRegisters(0x0000,1);// 切回接收模式digitalWrite(RS485_DE_RE,LOW);if(resultmodbus.ku8MBSuccess){returnmodbus.getResponseBuffer(0)/10.0;// 传感器返回 0-1000除以 10}return-1.0;// 读取失败}// 读土壤温度DS18B20 floatreadSoilTemp(){soilTempSensor.requestTemperatures();floattempsoilTempSensor.getTempCByIndex(0);// DS18B20 在 -127 时表示读取异常if(tempDEVICE_DISCONNECTED_C)return-127;returntemp;}// 采集全部数据 SensorDatacollectAll(){SensorData data;// DHT22 空气温湿度data.airTempdht.readTemperature();data.airHumiditydht.readHumidity();// DS18B20 土壤温度data.soilTempreadSoilTemp();// RS485 土壤湿度data.soilMoisturereadSoilMoistureRS485();// BH1750 光照data.lightLuxlightMeter.readLightLevel();returndata;}voidloop(){SensorData datacollectAll();Serial.println(════════════════════════════);Serial.printf(空气温度: %.1f ℃\n,data.airTemp);Serial.printf(空气湿度: %.1f %%\n,data.airHumidity);Serial.printf(土壤温度: %.1f ℃\n,data.soilTemp);Serial.printf(土壤湿度: %.1f %%\n,data.soilMoisture);Serial.printf(光照强度: %.0f Lux\n,data.lightLux);delay(5000);// 调试阶段 5s 一次实际部署改 5min}这段代码用 Arduino IDE 编译下载到 ESP32打开串口监视器115200 波特率你应该能看到每隔 5 秒打印一组传感器读数。第二步接上 MQTT数据上云端光串口打印没意义数据得上云。MQTT 部分只需要在setup()里连 WiFi 连 EMQX在loop()里把采集到的数据 publish 出去。#includePubSubClient.h// WiFi MQTT 配置 constchar*WIFI_SSID你的WiFi名;constchar*WIFI_PASS你的WiFi密码;constchar*MQTT_BROKER你的服务器IP;constintMQTT_PORT1883;constchar*MQTT_CLIENT_IDesp32_greenhouse_01;constchar*MQTT_TOPICfarm/greenhouse/01/data;WiFiClient espClient;PubSubClientmqtt(espClient);// 连接 WiFivoidconnectWiFi(){WiFi.begin(WIFI_SSID,WIFI_PASS);Serial.print(连接 WiFi);intretry0;while(WiFi.status()!WL_CONNECTEDretry40){delay(500);Serial.print(.);retry;}if(WiFi.status()WL_CONNECTED){Serial.println(\nWiFi 已连接);Serial.print(IP: );Serial.println(WiFi.localIP());}}// 连接 MQTTvoidconnectMQTT(){while(!mqtt.connected()){Serial.print(连接 MQTT...);if(mqtt.connect(MQTT_CLIENT_ID)){Serial.println(成功);}else{Serial.print(失败, rc);Serial.print(mqtt.state());Serial.println( 5 秒后重试);delay(5000);}}}// 发送 JSON 数据不用 ArduinoJson 库也行手动拼voidpublishData(SensorData data){charpayload[256];snprintf(payload,sizeof(payload),{\t\:\%.1f\,\h\:\%.1f\,\st\:\%.1f\,\sm\:\%.1f\,\l\:\%.0f\},data.airTemp,data.airHumidity,data.soilTemp,data.soilMoisture,data.lightLux);if(mqtt.publish(MQTT_TOPIC,payload)){Serial.println(✅ 数据已上发);}else{Serial.println(❌ 发送失败);}}voidsetup(){Serial.begin(115200);// ... 传感器初始化同上省略...connectWiFi();mqtt.setServer(MQTT_BROKER,MQTT_PORT);connectMQTT();}voidloop(){if(!mqtt.connected())connectMQTT();mqtt.loop();SensorData datacollectAll();publishData(data);delay(300000);// 5 分钟上报一次}到这里你的 ESP32 已经能做到每 5 分钟采集一组数据 → JSON 格式化 → MQTT 上发到 EMQX。第三步低功耗优化——一节电池用半年ESP32 全速跑起来大约 150-200mA18650 一节 3400mAh 撑不到 24 小时。必须做低功耗优化。思路ESP32 大部分时间在睡觉深度睡眠模式电流 ~10μA定时醒来RTC 闹钟花 5 秒采数据 连 WiFi 发 MQTT然后倒头接着睡。时间线 ┌───── 睡眠(295s) ─────┬─ 唤醒(5s) ─┐ │ 约 10μA │ WiFi采集发送 │ └───────────────────────┴──────────────┘ 平均电流 ≈ (295*0.01 5*150) / 300 2.5mA 一节 3400mAh → 约 56 天加太阳能板 TP4056 充电白天充电晚上耗电基本无限续航。#defineuS_TO_S_FACTOR1000000ULL#defineSLEEP_SECONDS300// 5 分钟voidsetup(){// ... 前面初始化 ...// 采集一次并上报SensorData datacollectAll();publishData(data);// 断开 WiFi省电WiFi.disconnect(true);WiFi.mode(WIFI_OFF);// 配置唤醒源定时器esp_sleep_enable_timer_wakeup(SLEEP_SECONDS*uS_TO_S_FACTOR);Serial.println(进入深度睡眠...);esp_deep_sleep_start();}voidloop(){// 深度睡眠模式下永远不会执行到这里// setup() 执行完后 ESP32 自动关机RTC 闹钟触发后重启 → 再次进 setup()}注意用了深度睡眠后setup()就是你的主循环——每次醒来跑一遍跑完就睡。loop()成了摆设。进一步省电技巧去掉串口打印Serial.begin()和Serial.print()在部署时全删掉能省 5-10mAWiFi 快速连接提前存 WiFi 信道连接时间从 3 秒降到 1 秒静态 IPDHCP 握手省 0.5 秒MQTT QoS 0不等待服务器确认发完就走优化后平均电流可以压到 1.5mA 以下一节 18650 撑 90 天。常见问题Q: RS485 读数总是 -1失败A: 检查 DE/RE 引脚电平——发送时拉高、接收时拉低。时序拉高后要 delay(10) 再发指令。另外确认 MAX485 的 RO/DI 交叉接对。Q: DHT22 偶尔返回 NaNA: DHT22 的单总线时序很敏感读取间隔不能短于 2 秒。如果连续读太快加delay(2500)或者换 DHT22 库里带超时处理的版本。Q: 太阳能板阴天能充进去吗A: 能但很慢。5V 1W 的多晶硅在阴天输出只有 0.1-0.3W。如果你在四川、贵州这种阴天多的地区建议上 2W 的板子或者两片并联。下一篇《MQTT 物联网通信100 个传感器的数据怎么传到云端》——部署 EMQX、设计 topic 规范、设备上下线监控、断网重连机制。