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

ESP32多传感器数据采集与传输系统

IOT——VIP

    • 系统概述
    • 硬件介绍
      • 主要组件清单
      • 硬件连接原理
    • 软件介绍
      • 开发环境配置
      • 项目结构
      • 核心代码实现
    • 示例演示
      • Web界面访问
      • RS485数据格式示例
      • API接口调用
    • 优化建议
      • 1. 硬件优化
      • 2. 软件优化
      • 3. 功能扩展
      • 4. 部署建议


系统概述

本项目基于ESP32开发板,集成温湿度、气压和GPS传感器,实现环境数据的实时采集。系统支持两种数据传输方式:通过WiFi在局域网内分享数据,以及通过RS485有线接口传输给其他单片机设备。采用模块化设计,便于维护和扩展。

硬件介绍

主要组件清单

组件型号说明
主控芯片ESP32-WROOM-32双核处理器,集成WiFi和蓝牙
环境传感器BME280集成温度、湿度、气压测量
GPS模块NEO-6M提供地理位置和时间信息
RS485模块MAX485TTL转RS485电平转换
电源模块LM25965V/3A降压模块

硬件连接原理

ESP32 (3.3V) --- BME280 (VCC)
ESP32 (GND)  --- BME280 (GND)
ESP32 (GPIO21) --- BME280 (SDA)
ESP32 (GPIO22) --- BME280 (SCL)ESP32 (3.3V) --- NEO-6M (VCC)
ESP32 (GND)  --- NEO-6M (GND)
ESP32 (GPIO16) --- NEO-6M (TX)
ESP32 (GPIO17) --- NEO-6M (RX)ESP32 (5V)   --- MAX485 (VCC)
ESP32 (GND)  --- MAX485 (GND)
ESP32 (GPIO4)  --- MAX485 (RO)
ESP32 (GPIO5)  --- MAX485 (DI)
ESP32 (GPIO15) --- MAX485 (DE+RE)

软件介绍

开发环境配置

platformio.ini 配置文件

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200lib_deps = adafruit/Adafruit BME280 Library@^2.2.2mikem/Arduino-TinyGPSPlus@^1.0.3bblanchon/ArduinoJson@^6.21.3

项目结构

src/
├── main.cpp
├── sensors/
│   ├── BME280Sensor.h
│   ├── GPSSensor.h
│   └── SensorManager.h
├── communication/
│   ├── WebServerManager.h
│   ├── RS485Manager.h
│   └── DataProtocol.h
└── config/└── Config.h

核心代码实现

Config.h - 配置文件

#ifndef CONFIG_H
#define CONFIG_H// WiFi配置
const char* WIFI_SSID = "Your_WiFi_SSID";
const char* WIFI_PASSWORD = "Your_WiFi_Password";// 引脚定义
const uint8_t BME280_SDA_PIN = 21;
const uint8_t BME280_SCL_PIN = 22;
const uint8_t GPS_RX_PIN = 16;
const uint8_t GPS_TX_PIN = 17;
const uint8_t RS485_RO_PIN = 4;
const uint8_t RS485_DI_PIN = 5;
const uint8_t RS485_DE_RE_PIN = 15;// 串口配置
const uint32_t GPS_BAUDRATE = 9600;
const uint32_t RS485_BAUDRATE = 9600;// 数据更新间隔(ms)
const uint32_t SENSOR_UPDATE_INTERVAL = 2000;
const uint32_t RS485_SEND_INTERVAL = 1000;#endif

DataProtocol.h - 数据结构定义

#ifndef DATA_PROTOCOL_H
#define DATA_PROTOCOL_H#include <Arduino.h>struct SensorData {float temperature;float humidity;float pressure;double latitude;double longitude;String time;int satellites;bool gpsValid;String toJSON() {String json = "{";json += "\"temperature\":" + String(temperature, 1) + ",";json += "\"humidity\":" + String(humidity, 1) + ",";json += "\"pressure\":" + String(pressure, 2) + ",";json += "\"latitude\":" + String(latitude, 6) + ",";json += "\"longitude\":" + String(longitude, 6) + ",";json += "\"time\":\"" + time + "\",";json += "\"satellites\":" + String(satellites) + ",";json += "\"gpsValid\":" + String(gpsValid ? "true" : "false");json += "}";return json;}
};#endif

BME280Sensor.h - 环境传感器类

#ifndef BME280_SENSOR_H
#define BME280_SENSOR_H#include <Adafruit_BME280.h>
#include "DataProtocol.h"class BME280Sensor {
private:Adafruit_BME280 bme;bool sensorFound = false;public:bool begin(uint8_t sdaPin, uint8_t sclPin) {Wire.begin(sdaPin, sclPin);sensorFound = bme.begin(0x76);if (!sensorFound) {sensorFound = bme.begin(0x77);}return sensorFound;}bool readData(SensorData& data) {if (!sensorFound) return false;data.temperature = bme.readTemperature();data.humidity = bme.readHumidity();data.pressure = bme.readPressure() / 100.0F;return !isnan(data.temperature) && !isnan(data.humidity) && !isnan(data.pressure);}
};#endif

GPSSensor.h - GPS传感器类

#ifndef GPS_SENSOR_H
#define GPS_SENSOR_H#include <TinyGPSPlus.h>
#include <HardwareSerial.h>
#include "DataProtocol.h"class GPSSensor {
private:TinyGPSPlus gps;HardwareSerial& gpsSerial;public:GPSSensor(HardwareSerial& serial) : gpsSerial(serial) {}void begin(unsigned long baudrate) {gpsSerial.begin(baudrate);}void update() {while (gpsSerial.available() > 0) {gps.encode(gpsSerial.read());}}void readData(SensorData& data) {data.gpsValid = gps.location.isValid() && gps.location.isUpdated();if (data.gpsValid) {data.latitude = gps.location.lat();data.longitude = gps.location.lng();} else {data.latitude = 0.0;data.longitude = 0.0;}if (gps.time.isValid() && gps.time.isUpdated()) {char timeStr[9];snprintf(timeStr, sizeof(timeStr), "%02d:%02d:%02d", gps.time.hour(), gps.time.minute(), gps.time.second());data.time = String(timeStr);}data.satellites = gps.satellites.value();}bool isGPSValid() {return gps.location.isValid();}
};#endif

RS485Manager.h - RS485通信管理

#ifndef RS485_MANAGER_H
#define RS485_MANAGER_H#include <HardwareSerial.h>
#include "DataProtocol.h"class RS485Manager {
private:HardwareSerial& rs485Serial;uint8_t deRePin;String createDataPacket(const SensorData& data) {String packet = "$SENSOR,";packet += String(data.temperature, 1) + ",";packet += String(data.humidity, 1) + ",";packet += String(data.pressure, 2) + ",";packet += String(data.latitude, 6) + ",";packet += String(data.longitude, 6) + ",";packet += data.time + ",";packet += String(data.satellites) + ",";packet += String(data.gpsValid ? "1" : "0");packet += "*";// 计算校验和char checksum = 0;for (size_t i = 0; i < packet.length(); i++) {checksum ^= packet[i];}packet += String(checksum, HEX);packet += "\r\n";return packet;}public:RS485Manager(HardwareSerial& serial, uint8_t pin) : rs485Serial(serial), deRePin(pin) {}void begin(unsigned long baudrate) {pinMode(deRePin, OUTPUT);digitalWrite(deRePin, LOW); // 初始化为接收模式rs485Serial.begin(baudrate);}void sendData(const SensorData& data) {digitalWrite(deRePin, HIGH); // 切换到发送模式delay(2);String packet = createDataPacket(data);rs485Serial.print(packet);rs485Serial.flush();delay(2);digitalWrite(deRePin, LOW); // 切换回接收模式Serial.println("[RS485] Sent: " + packet);}
};#endif

WebServerManager.h - Web服务器管理

#ifndef WEB_SERVER_MANAGER_H
#define WEB_SERVER_MANAGER_H#include <WebServer.h>
#include <ArduinoJson.h>
#include "DataProtocol.h"class WebServerManager {
private:WebServer server;SensorData* currentData;void handleRoot() {String html = R"(
<!DOCTYPE html>
<html>
<head><title>ESP32 Sensor Data</title><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><style>body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }.container { max-width: 800px; margin: 0 auto; background: white; padding: 20px; border-radius: 10px; }.card { background: #e3f2fd; padding: 15px; margin: 10px 0; border-radius: 5px; }.gps-valid { color: green; }.gps-invalid { color: red; }</style>
</head>
<body><div class="container"><h1>📊 ESP32 传感器数据监控</h1><div class="card"><h2>🌡️ 环境数据</h2><p><b>温度:</b> <span id="temp">--</span> °C</p><p><b>湿度:</b> <span id="humi">--</span> %</p><p><b>气压:</b> <span id="pres">--</span> hPa</p></div><div class="card"><h2>📍 GPS 数据</h2><p><b>纬度:</b> <span id="lat">--</span></p><p><b>经度:</b> <span id="lng">--</span></p><p><b>时间:</b> <span id="time">--</span></p><p><b>卫星数:</b> <span id="sats">--</span></p><p><b>状态:</b> <span id="gpsStatus">--</span></p></div><button onclick="refreshData()">🔄 刷新数据</button><p>最后更新: <span id="lastUpdate">--</span></p></div><script>function refreshData() {fetch('/data').then(response => response.json()).then(data => {document.getElementById('temp').textContent = data.temperature;document.getElementById('humi').textContent = data.humidity;document.getElementById('pres').textContent = data.pressure;document.getElementById('lat').textContent = data.latitude;document.getElementById('lng').textContent = data.longitude;document.getElementById('time').textContent = data.time;document.getElementById('sats').textContent = data.satellites;const gpsStatus = document.getElementById('gpsStatus');if (data.gpsValid) {gpsStatus.textContent = '✅ 定位有效';gpsStatus.className = 'gps-valid';} else {gpsStatus.textContent = '❌ 等待定位';gpsStatus.className = 'gps-invalid';}document.getElementById('lastUpdate').textContent = new Date().toLocaleString();});}// 页面加载时自动刷新,之后每5秒刷新一次document.addEventListener('DOMContentLoaded', function() {refreshData();setInterval(refreshData, 5000);});</script>
</body>
</html>)";server.send(200, "text/html", html);}void handleData() {String json = currentData->toJSON();server.send(200, "application/json", json);}public:WebServerManager() : server(80) {}void begin(SensorData* data) {currentData = data;server.on("/", [this]() { handleRoot(); });server.on("/data", [this]() { handleData(); });server.begin();Serial.println("[WebServer] HTTP server started");}void handleClient() {server.handleClient();}String getIPAddress() {return WiFi.localIP().toString();}
};#endif

main.cpp - 主程序

#include <Arduino.h>
#include <WiFi.h>
#include "config/Config.h"
#include "sensors/BME280Sensor.h"
#include "sensors/GPSSensor.h"
#include "communication/WebServerManager.h"
#include "communication/RS485Manager.h"
#include "communication/DataProtocol.h"// 传感器和管理器对象
BME280Sensor bmeSensor;
GPSSensor gpsSensor(GPSSerial);
WebServerManager webServer;
RS485Manager rs485(RS485Serial, RS485_DE_RE_PIN);// 传感器数据
SensorData sensorData;// 定时器变量
unsigned long lastSensorUpdate = 0;
unsigned long lastRS485Send = 0;void setup() {Serial.begin(115200);// 初始化传感器Serial.println("[System] Initializing sensors...");if (!bmeSensor.begin(BME280_SDA_PIN, BME280_SCL_PIN)) {Serial.println("[BME280] Error: Sensor not found!");} else {Serial.println("[BME280] Sensor initialized successfully");}gpsSensor.begin(GPS_BAUDRATE);Serial.println("[GPS] Sensor initialized successfully");// 初始化RS485rs485.begin(RS485_BAUDRATE);Serial.println("[RS485] Communication initialized");// 连接WiFiSerial.println("[WiFi] Connecting to: " + String(WIFI_SSID));WiFi.begin(WIFI_SSID, WIFI_PASSWORD);while (WiFi.status() != WL_CONNECTED) {delay(1000);Serial.print(".");}Serial.println("\n[WiFi] Connected! IP address: " + WiFi.localIP().toString());// 启动Web服务器webServer.begin(&sensorData);Serial.println("[System] All systems ready!");
}void loop() {// 处理Web客户端请求webServer.handleClient();// 更新GPS数据gpsSensor.update();unsigned long currentMillis = millis();// 定期更新传感器数据if (currentMillis - lastSensorUpdate >= SENSOR_UPDATE_INTERVAL) {lastSensorUpdate = currentMillis;// 读取BME280数据bool envDataValid = bmeSensor.readData(sensorData);// 读取GPS数据gpsSensor.readData(sensorData);if (envDataValid) {Serial.println("[Sensors] Environment data updated");}if (sensorData.gpsValid) {Serial.println("[GPS] GPS data updated - Lat: " + String(sensorData.latitude, 6) + ", Lng: " + String(sensorData.longitude, 6));}}// 定期通过RS485发送数据if (currentMillis - lastRS485Send >= RS485_SEND_INTERVAL) {lastRS485Send = currentMillis;rs485.sendData(sensorData);}
}

示例演示

Web界面访问

  1. 将程序上传到ESP32后,打开串口监视器查看IP地址
  2. 在浏览器中输入 http://[ESP32-IP] 访问监控界面
  3. 界面将显示实时传感器数据并每5秒自动更新

RS485数据格式示例

$SENSOR,25.3,60.1,1013.25,22.123456,114.123456,12:34:56,8,1*1A\r\n

字段说明:温度,湿度,气压,纬度,经度,时间,卫星数,GPS状态*校验和

API接口调用

# 获取JSON格式数据
curl http://192.168.1.100/data# 返回示例
{"temperature": 25.3,"humidity": 60.1,"pressure": 1013.25,"latitude": 22.123456,"longitude": 114.123456,"time": "12:34:56","satellites": 8,"gpsValid": true
}

优化建议

1. 硬件优化

  • 电源管理:添加锂电池和充放电管理电路,实现便携使用
  • 信号稳定性:在RS485总线两端添加120Ω终端电阻
  • 防干扰:为GPS模块使用有源天线,提高定位精度

2. 软件优化

// 添加数据滤波处理
class DataFilter {
public:static float movingAverage(float newValue, float previousAverage, int count) {return (previousAverage * (count - 1) + newValue) / count;}
};// 添加SD卡数据存储功能
#include <SD.h>
class DataLogger {
public:bool logData(const SensorData& data) {File file = SD.open("/datalog.txt", FILE_APPEND);if (file) {file.println(data.toJSON());file.close();return true;}return false;}
};

3. 功能扩展

  • MQTT支持:添加物联网平台接入能力
  • OTA更新:支持无线固件更新
  • 数据告警:设置阈值触发通知
  • 历史数据:添加数据趋势图表显示

4. 部署建议

  • 使用防水外壳保护电子元件
  • 为天线预留合适的位置
  • 考虑散热设计,避免阳光直射
  • 使用工业级连接器提高可靠性

这个项目提供了完整的传感器数据采集和传输解决方案,具有良好的可扩展性和稳定性,适合各种物联网应用场景。

http://www.dtcms.com/a/566635.html

相关文章:

  • 中小企仓储数字化转型的破局之道
  • 邢台移动网站建设报价seo外包
  • 损失函数系列:focal-Dice-vgg
  • 网站建设的技巧下载的网站模板怎么改
  • 桔子seo网邢台快照优化
  • 做网站 杭州建设美团网站
  • 网站太花哨icp备案后要建网站吗
  • VTK教程-VTK-9.5源码编译详细教程
  • 西安网站建设公司排行榜用wordpress制作表单
  • 用阿里云服务器做盗版小说网站吗管理网站模板下载
  • 英飞凌 LITIX™ Interior:汽车内饰氛围灯解决方案
  • 美团网站网站建设发展网站定制一般价格多少
  • 网站公司图片wordpress 评论双击
  • C 标准库 - <errno.h>
  • 劳务公司网站建设WordPress前端分离
  • 杭州网站做的好公司哪家好wordpress登录页名
  • 合肥网站制作开发旅游网站名称设计
  • 郑州做网站 汉狮网络怎样推广自己的app
  • 西安做网站程序泉州做网站的公司
  • 前端Tabs切换导致的数据问题
  • 中专旅游管理专业职业发展指南
  • 微网站管理平台wordpress 主题 最简单
  • 彩票网站是怎么做的南宁做网站开发的公司有哪些
  • 网站为什么开发appc mvc制作网站开发
  • 做服装招聘的网站有哪些群辉怎么做视频网站
  • 佛山顺德容桂网站制作asp网站建设案例
  • 解决Grid布局下el-table自适应缩小失败的问题
  • 企业做网站应该注意的问题北京排名seo
  • 基础展示营销型型网站网站建设中 英语
  • Javascript运算符之一元运算符