当前位置: 首页 > news >正文

ESP32 + 传感器:手把手教你做土壤监测终端

ESP32 + 传感器:手把手教你做土壤监测终端

上一篇给了硬件清单,这篇直接上代码。从 GPIO 初始化到传感器读数,再到 MQTT 上发,最后低功耗优化——每一行都有注释,复制到 Arduino IDE 里就能跑。


前置准备

软件环境:

  • Arduino IDE 2.x(装好 ESP32 开发板支持)
  • 库:WiFiPubSubClientDHT sensor libraryOneWireDallasTemperatureBH1750ModbusMaster

硬件接线:按上一篇的引脚表接好,USB 线插电脑。


第一步:基础采集——五个传感器一把梭

#include<WiFi.h>#include<DHT.h>#include<OneWire.h>#include<DallasTemperature.h>#include<BH1750.h>#include<Wire.h>#include<ModbusMaster.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);// SDA=21, SCL=22lightMeter.begin();// RS485 (Serial2: RX=16, TX=17)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_tresult=modbus.readHoldingRegisters(0x0000,1);// 切回接收模式digitalWrite(RS485_DE_RE,LOW);if(result==modbus.ku8MBSuccess){returnmodbus.getResponseBuffer(0)/10.0;// 传感器返回 0-1000,除以 10}return-1.0;// 读取失败}// ==================== 读土壤温度(DS18B20) ====================floatreadSoilTemp(){soilTempSensor.requestTemperatures();floattemp=soilTempSensor.getTempCByIndex(0);// DS18B20 在 -127 时表示读取异常if(temp==DEVICE_DISCONNECTED_C)return-127;returntemp;}// ==================== 采集全部数据 ====================SensorDatacollectAll(){SensorData data;// DHT22 空气温湿度data.airTemp=dht.readTemperature();data.airHumidity=dht.readHumidity();// DS18B20 土壤温度data.soilTemp=readSoilTemp();// RS485 土壤湿度data.soilMoisture=readSoilMoistureRS485();// BH1750 光照data.lightLux=lightMeter.readLightLevel();returndata;}voidloop(){SensorData data=collectAll();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 出去。

#include<PubSubClient.h>// ==================== WiFi & MQTT 配置 ====================constchar*WIFI_SSID="你的WiFi名";constchar*WIFI_PASS="你的WiFi密码";constchar*MQTT_BROKER="你的服务器IP";constintMQTT_PORT=1883;constchar*MQTT_CLIENT_ID="esp32_greenhouse_01";constchar*MQTT_TOPIC="farm/greenhouse/01/data";WiFiClient espClient;PubSubClientmqtt(espClient);// 连接 WiFivoidconnectWiFi(){WiFi.begin(WIFI_SSID,WIFI_PASS);Serial.print("连接 WiFi");intretry=0;while(WiFi.status()!=WL_CONNECTED&&retry<40){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 data=collectAll();publishData(data);delay(300000);// 5 分钟上报一次}

到这里,你的 ESP32 已经能做到:每 5 分钟采集一组数据 → JSON 格式化 → MQTT 上发到 EMQX。


第三步:低功耗优化——一节电池用半年

ESP32 全速跑起来大约 150-200mA,18650 一节 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 data=collectAll();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-10mA
  • WiFi 快速连接:提前存 WiFi 信道,连接时间从 3 秒降到 1 秒
  • 静态 IP:DHCP 握手省 0.5 秒
  • MQTT QoS 0:不等待服务器确认,发完就走

优化后平均电流可以压到 1.5mA 以下,一节 18650 撑 90+ 天。


常见问题

Q: RS485 读数总是 -1(失败)?
A: 检查 DE/RE 引脚电平——发送时拉高、接收时拉低。时序:拉高后要 delay(10) 再发指令。另外确认 MAX485 的 RO/DI 交叉接对。

Q: DHT22 偶尔返回 NaN?
A: DHT22 的单总线时序很敏感,读取间隔不能短于 2 秒。如果连续读太快,加delay(2500)或者换 DHT22 库里带超时处理的版本。

Q: 太阳能板阴天能充进去吗?
A: 能,但很慢。5V 1W 的多晶硅在阴天输出只有 0.1-0.3W。如果你在四川、贵州这种阴天多的地区,建议上 2W 的板子或者两片并联。


下一篇:《MQTT 物联网通信:100 个传感器的数据怎么传到云端?》——部署 EMQX、设计 topic 规范、设备上下线监控、断网重连机制。

http://www.jsqmd.com/news/1099641/

相关文章:

  • Windows本地实时语音转文字:TMSpeech让你的电脑变身智能会议助手
  • 大模型技术之深度学习
  • Java 26 发布了, 我人麻了。。
  • AI Agent 新概念: Loop Engineering 是什么? 一篇文章讲清楚定义、组成、应用场景
  • Redis缓存实战:彻底解决缓存穿透、击穿、雪崩三大难题
  • 软件工程从业所需的技能:正确认识行业,并走出可持续的职业生涯
  • 整群随机抽样
  • 可视化学科发展脉络浅梳(学习笔记)
  • 京东开源实时视频视觉语言交互模型:全栈方案解析与落地实践
  • sdfsfds
  • 2026 年本地部署的 AI 数字人直播系统到底有多省钱?
  • 开源模型技术总结-3————FireRed(小红书)开源模型
  • 北京心商科技发布GEO优化产品 助力企业合规营销
  • 从Prompt到Loop,拆解Agent 进化的底层逻辑
  • Agent推理快到API成瓶颈:Responses API WebSocket如何提速40%
  • 51单片机数码管电压表
  • 大模型评测与AI产品质量保障:第3篇 用 Python 调用 模型API
  • OpenAI SDK 环境搭建教程
  • Xshell+Xftp使用教程
  • 主流三维光学轮廓仪国产品牌与技术解析
  • 操作简便吗?8款AI写作辅助网站综合榜,毕业答辩稳了!
  • TactiX实测:星际2战术训练神器,支持离线REP解析与MOD扩展
  • 2026 在上海如何找一家专业又靠谱的小程序定制开发公司
  • 告别命令行!用JGit在Java项目里优雅地操作Git(附完整API使用示例)
  • SpringBoot(springboot的类加载和传统的双亲委派有什么区别、如何按顺序实例化Bean)
  • 】[SampleVirtualTexture节点]原理解析与实际应用
  • 只看光明的一面:当机器学习失去“反面教材“时 | Positive-Only Learning深度解读
  • MySQL8-Windows安装教程
  • 【第 8 篇:数据接口管理——从模拟到真实与企业级接口治理】
  • 2026最新年版Java八股文,7天背完通过面试