基于 ESP32 的冷链物流工业物联网(IIoT)监控系统|全流程实战

新晋码农一枚,小编会定期整理一些写的比较好的代码和知识点,作为自己的学习笔记,试着做一下批注和补充,转载或者参考他人文献会标明出处,非商用,如有侵权会删改!欢迎大家斧正和讨论!本章内容较多,可点击文章目录进行跳转!
小编整理和学习了机器学习的相关知识,可作为扫盲使用,后续也会更新一些技术类的文章,大家共同交流学习!

您的点赞、关注、收藏就是对小编最大的动力!

系列文章目录

机器学习---卷积神经网络【万字长文,一文搞定!】

从 SLP 到 MLP:鸢尾花分类实验全解析 ------ 神经网络入门必做实验【万字长文,一文搞定!】

基于 ESP32 的冷链物流工业物联网(IIoT)监控系统|全流程实战

四种经典降维方法全实验:SVD、PCA、LDA、ISOMAP 从原理到代码

机器学习---监督学习入门实验全攻略(小白友好版)


目录

目录

系列文章目录

目录

前言

一、项目背景与设计目标

[1.1 行业痛点](#1.1 行业痛点)

[1.2 项目目标](#1.2 项目目标)

二、系统整体架构(一主两从)

[Node A(主节点 / 数据网关)](#Node A(主节点 / 数据网关))

[Node C(从节点 1)](#Node C(从节点 1))

[Node D(从节点 2)](#Node D(从节点 2))

三、系统核心功能完整详解

[3.1 多维度数据采集](#3.1 多维度数据采集)

[3.2 I2C 主从双向通信(核心亮点)](#3.2 I2C 主从双向通信(核心亮点))

[3.3 本地显示与云端可视化](#3.3 本地显示与云端可视化)

[本地 LCD 显示(14 针并行 0802)](#本地 LCD 显示(14 针并行 0802))

云端监控(MQTT+ThingsBoard)

[3.4 三级分级报警逻辑](#3.4 三级分级报警逻辑)

四、硬件供电与总线连接设计

[4.1 供电方案(独立供电,抗干扰)](#4.1 供电方案(独立供电,抗干扰))

[4.2 I2C 标准连接(通信稳定关键)](#4.2 I2C 标准连接(通信稳定关键))

[4.3 核心元器件选型](#4.3 核心元器件选型)

五、各节点完整引脚接线

[5.1 Node A(主节点)接线表](#5.1 Node A(主节点)接线表)

[5.2 Node C(光照从节点)接线表](#5.2 Node C(光照从节点)接线表)

[5.3 Node D(倾斜从节点)接线表](#5.3 Node D(倾斜从节点)接线表)

六、系统完整代码实现

[6.1 Node A 主节点完整代码](#6.1 Node A 主节点完整代码)

[6.2 Node C 光照从节点代码](#6.2 Node C 光照从节点代码)

[6.3 Node D 倾斜从节点代码](#6.3 Node D 倾斜从节点代码)

七、系统调试与运行日志

八、项目挑战、局限与优化方向

[8.1 遇到的问题与解决](#8.1 遇到的问题与解决)

[8.2 系统现存局限](#8.2 系统现存局限)

[8.3 未来优化方案](#8.3 未来优化方案)

九、总结

总结


前言

冷链物流作为医药疫苗、生鲜食品流通的关键环节,长期面临高能耗、高损耗的行业瓶颈,其能耗占物流行业总能耗 30% 以上,全球约 20% 的温控产品在运输中因冷链失效损坏。本项目基于工业物联网理念,搭建一套室内可演示、多节点协同、云端可监控的冷链运输智能监控系统,完整实现温湿度、光照、倾斜、模拟位置的实时采集、主从通信、本地显示、云端上传与分级报警功能。

本文从项目背景、系统架构、硬件选型、接线设计、代码实现、功能测试到挑战优化,完整保留全部技术细节,以纯技术博客形式呈现,可直接作为课程设计、毕设参考与 ESP32 多节点 IIoT 实战教程。

一、项目背景与设计目标

1.1 行业痛点

  • 冷链物流能耗高、监管不透明,人工巡检无法做到实时监控。
  • 温湿度、运输姿态、箱门状态缺乏统一数字化监管手段。
  • 异常发生后无预警、无数据追溯,导致货物损耗率居高不下。

1.2 项目目标

搭建由3 个 ESP32 节点组成的工业物联网演示系统,实现以下核心能力:

  1. 多点温湿度、光照、倾斜状态数据采集
  2. I2C 主从双向非阻塞通信
  3. 本地 LCD 四页循环实时显示
  4. 模拟 GPS 轨迹与运动状态指示
  5. MQTT 协议数据上传至云端平台
  6. 三级分级异常报警
  7. 断网自动重连、异常加急上报

二、系统整体架构(一主两从)

本系统采用I2C 主从分布式架构,3 个节点分工明确、协同工作:

Node A(主节点 / 数据网关)

  • 角色:I2C 主机、数据聚合网关、本地显示与报警中心
  • 核心硬件:ESP32、DHT11、0802 LCD、交通灯、按键
  • 核心功能:
    • 采集本地温湿度,按键控制模拟 GPS 启停
    • 轮询从节点 C、D,获取光照与倾斜数据
    • 本地 LCD 实时显示所有参数
    • 控制分级报警指示灯
    • 通过 WiFi+MQTT 将数据上传云端

Node C(从节点 1)

  • 角色:环境光监测节点
  • 核心硬件:ESP32、TEMT6000 模拟光照传感器
  • 核心功能:
    • 采集环境光照强度,判断冷链箱门开闭状态
    • 响应主节点请求,回传光照模拟量数据

Node D(从节点 2)

  • 角色:运输姿态监测节点
  • 核心硬件:ESP32、KS0025 数字倾斜传感器、LED 指示灯
  • 核心功能:
    • 检测车辆倾斜 / 震动状态
    • 响应主节点查询,回传倾斜状态
    • 主动读取 GPS 运行状态,通过 LED 指示启停

三、系统核心功能完整详解

3.1 多维度数据采集

系统支持 4 类关键参数并行采集,互不阻塞:

  1. 温湿度:DHT11 采集,量程 0--50℃,精度 ±2℃
  2. 环境光照:TEMT6000 模拟量,0--4095,>2000 表示箱门打开
  3. 倾斜状态:数字量输出,低电平表示倾斜报警
  4. 模拟 GPS:软件生成固定起点,按键启停,小范围平滑偏移

3.2 I2C 主从双向通信(核心亮点)

  • 总线配置:SDA=GPIO21,SCL=GPIO22,100kHz,共地 + 4.7kΩ 上拉
  • 主节点非阻塞轮询从节点,不等待响应即可执行下一任务
  • 从节点 D 可主动作为主机读取主节点 A 的 GPS 状态,实现双向交互
  • 正常状态:每 10 秒上传云端;报警状态:每 5 秒加急上传

3.3 本地显示与云端可视化

本地 LCD 显示(14 针并行 0802)

每 2 秒自动切换一页,共 4 页:

  1. 温湿度页面
  2. 光照强度 + 门状态页面
  3. 倾斜状态 + GPS 运动状态页面
  4. GPS 经纬度坐标页面
云端监控(MQTT+ThingsBoard)
  • 协议:MQTT 1883 端口
  • 上传内容:温湿度、光照、倾斜、GPS 状态、经纬度
  • 云端能力:实时曲线、GPS 轨迹、报警历史、远程查看

3.4 三级分级报警逻辑

优先级 状态 触发条件 指示灯
最高 危险报警 倾斜 / 温度>30℃ 红灯
中等 门开提醒 光照>2000 黄灯
最低 正常运行 温度≤30℃+ 门关 + 无倾斜 绿灯

四、硬件供电与总线连接设计

4.1 供电方案(独立供电,抗干扰)

  • 3 个节点各自 5V 独立供电,I2C 总线仅传输数据,不供电
  • 避免单节点供电不足导致整体通信故障
  • 所有节点共地,保证电平参考一致

4.2 I2C 标准连接(通信稳定关键)

信号线 Node A Node C Node D 连接说明
SDA GPIO21 GPIO21 GPIO21 4.7kΩ 上拉至 3.3V
SCL GPIO22 GPIO22 GPIO22 4.7kΩ 上拉至 3.3V
GND GND GND GND 统一共地
3.3V 输出 输入 输入 外部稳压供电

4.3 核心元器件选型

器件 型号 功能
主控 ESP32-WROOM-32U 多节点互联、WiFi、MQTT
温湿度 DHT11 单总线数字温湿度采集
光照 TEMT6000 模拟量光照检测
倾斜 SW-520D/KS0025 运输姿态检测
显示 0802 LCD 14 针 本地数据轮显
报警 三色交通灯 分级状态指示

五、各节点完整引脚接线

5.1 Node A(主节点)接线表

器件 器件引脚 ESP32 引脚
0802 LCD VSS、VDD、VO、RS、RW、EN、D4--D7 GND、5V、GND、16、GND、17、2/4/13/14
DHT11 VCC、GND、DATA 5V、GND、5
交通灯 红、黄、绿、GND 25、26、27、GND
按键 信号、GND 18、GND
I2C SDA、SCL 21、22

5.2 Node C(光照从节点)接线表

器件 引脚 ESP32 引脚
TEMT6000 VCC、GND、OUT 5V、GND、34
I2C SDA、SCL 21、22

5.3 Node D(倾斜从节点)接线表

器件 引脚 ESP32 引脚
倾斜传感器 VCC、GND、DO 5V、GND、19
LED 阳极、阴极、信号 3.3V、GND、23
I2C SDA、SCL 21、22

六、系统完整代码实现

6.1 Node A 主节点完整代码

cpp 复制代码
#include <Wire.h>
#include <LiquidCrystal.h>
#include <DHT.h>
#include <WiFi.h>
#include <PubSubClient.h>

const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_PASS";
const char* MQTT_BROKER = "demo.thingsboard.io";
const uint16_t MQTT_PORT = 1883;
const char* MQTT_TOKEN = "YOUR_TOKEN";
const char* MQTT_TOPIC = "v1/devices/me/telemetry";

WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
unsigned long lastMqttUpload = 0;
long mqttUploadInterval = 10000;

#define SDA_PIN 21
#define SCL_PIN 22
#define NODE_C_ADDR 0x20
#define NODE_D_ADDR 0x21

LiquidCrystal lcd(16, 17, 2, 4, 13, 14);

#define DHTPIN 5
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

#define RED_LED 25
#define YELLOW_LED 26
#define GREEN_LED 27

#define KEY_PIN 18
volatile bool gpsMoving = false;
volatile bool keyPressed = false;
float lat = 31.2301f;
float lon = 121.4703f;
unsigned long lastGpsUpdate = 0;
const long GPS_UPDATE_INTERVAL = 500;
const float GPS_OFFSET = 0.00002f;

#define TEMP_LIMIT 30.0
#define LIGHT_THRESHOLD 2000

unsigned long lastPageTime = 0;
int pageIndex = 0;

void IRAM_ATTR handleKeyPress() {
  static unsigned long lastInterruptTime = 0;
  unsigned long interruptTime = millis();
  if (interruptTime - lastInterruptTime > 200) {
    keyPressed = true;
  }
  lastInterruptTime = interruptTime;
}

void connectWiFi() {
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(500);
}

void reconnectMQTT() {
  while (!mqttClient.connected()) {
    if (mqttClient.connect("NodeA-ColdChain", MQTT_TOKEN, "")) break;
    delay(2000);
  }
}

void uploadToThingsBoard(float temp, float humi, int lightValue, bool tiltAlarm, bool gpsMoving, float lat, float lon) {
  String jsonData = "{";
  jsonData += "\"temperature\":" + String(temp,1) + ",";
  jsonData += "\"humidity\":" + String(humi,0) + ",";
  jsonData += "\"light_value\":" + String(lightValue) + ",";
  jsonData += "\"is_tilted\":" + String(tiltAlarm?1:0) + ",";
  jsonData += "\"gps_moving\":" + String(gpsMoving?1:0) + ",";
  jsonData += "\"latitude\":" + String(lat,5) + ",";
  jsonData += "\"longitude\":" + String(lon,5);
  jsonData += "}";
  mqttClient.publish(MQTT_TOPIC, jsonData.c_str());
}

void setup() {
  Serial.begin(115200);
  Wire.begin(SDA_PIN, SCL_PIN);
  lcd.begin(8,2);
  dht.begin();
  pinMode(RED_LED,OUTPUT);
  pinMode(YELLOW_LED,OUTPUT);
  pinMode(GREEN_LED,OUTPUT);
  pinMode(KEY_PIN,INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(KEY_PIN), handleKeyPress, FALLING);
  mqttClient.setServer(MQTT_BROKER, MQTT_PORT);
  connectWiFi();
}

void loop() {
  if (keyPressed) {
    keyPressed = false;
    gpsMoving = !gpsMoving;
    Wire.beginTransmission(NODE_D_ADDR);
    Wire.write(gpsMoving?0x01:0x00);
    Wire.endTransmission();
  }

  float temp = dht.readTemperature();
  float humi = dht.readHumidity();

  int lightValue = 0;
  Wire.requestFrom(NODE_C_ADDR, (uint8_t)sizeof(lightValue));
  if (Wire.available() == sizeof(lightValue)) {
    Wire.readBytes((uint8_t*)&lightValue, sizeof(lightValue));
  }
  delay(10);

  uint8_t tiltValue = HIGH;
  Wire.requestFrom(NODE_D_ADDR, 1);
  if (Wire.available()) tiltValue = Wire.read();

  if (gpsMoving && millis()-lastGpsUpdate > GPS_UPDATE_INTERVAL) {
    lat += (random(-100,101)/100.0f)*GPS_OFFSET;
    lon += (random(-100,101)/100.0f)*GPS_OFFSET;
    lat = constrain(lat,31.2300f,31.2302f);
    lon = constrain(lon,121.4702f,121.4704f);
    lastGpsUpdate = millis();
  }

  bool tempAlarm = temp > TEMP_LIMIT;
  bool lightAlarm = lightValue > LIGHT_THRESHOLD;
  bool tiltAlarm = tiltValue == LOW;

  if (tempAlarm || tiltAlarm) {
    digitalWrite(RED_LED,HIGH);
    digitalWrite(YELLOW_LED,LOW);
    digitalWrite(GREEN_LED,LOW);
  } else if (lightAlarm) {
    digitalWrite(RED_LED,LOW);
    digitalWrite(YELLOW_LED,HIGH);
    digitalWrite(GREEN_LED,LOW);
  } else {
    digitalWrite(RED_LED,LOW);
    digitalWrite(YELLOW_LED,LOW);
    digitalWrite(GREEN_LED,HIGH);
  }

  if (millis()-lastPageTime > 2000) {
    lastPageTime = millis();
    pageIndex = (pageIndex+1)%4;
    lcd.clear();
  }

  switch(pageIndex){
    case 0:
      lcd.print("Temp:");lcd.print(temp,1);lcd.print("C");
      lcd.setCursor(0,1);lcd.print("Humi:");lcd.print(humi,0);lcd.print("%");
      break;
    case 1:
      lcd.print("Light:");lcd.print(lightValue);
      lcd.setCursor(0,1);lcd.print(lightAlarm?"BRIGHT":"DARK");
      break;
    case 2:
      lcd.print("Tilt:");lcd.print(tiltAlarm?"TILTED":"NORMAL");
      lcd.setCursor(0,1);lcd.print(gpsMoving?"MOVING":"STOP");
      break;
    case 3:
      lcd.print("Lat:");lcd.print(lat,5);
      lcd.setCursor(0,1);lcd.print("Lon:");lcd.print(lon,5);
      break;
  }

  if (!WiFi.isConnected()) connectWiFi();
  if (!mqttClient.connected()) reconnectMQTT();
  mqttClient.loop();

  bool isAlarm = tempAlarm||lightAlarm||tiltAlarm;
  mqttUploadInterval = isAlarm?5000:10000;
  if (millis()-lastMqttUpload > mqttUploadInterval) {
    uploadToThingsBoard(temp,humi,lightValue,tiltAlarm,gpsMoving,lat,lon);
    lastMqttUpload = millis();
  }
  delay(300);
}

6.2 Node C 光照从节点代码

cpp 复制代码
#include <Wire.h>
#define I2C_ADDR 0x20
#define LIGHT_PIN 34
int lightValue = 0;

void onRequest() {
  Wire.write((uint8_t*)&lightValue, sizeof(lightValue));
}

void setup() {
  Serial.begin(115200);
  pinMode(LIGHT_PIN, INPUT);
  Wire.begin(I2C_ADDR);
  Wire.onRequest(onRequest);
}

void loop() {
  lightValue = analogRead(LIGHT_PIN);
  delay(500);
}

6.3 Node D 倾斜从节点代码

cpp 复制代码
#include <Wire.h>
#define I2C_ADDR 0x21
#define TILT_PIN 19
#define LED_PIN 23
volatile uint8_t tiltState = 0;
bool gpsIsMoving = false;

void receiveEvent(int bytes) {
  if (bytes>0) {
    byte recv = Wire.read();
    gpsIsMoving = (recv == 0x01);
    digitalWrite(LED_PIN, gpsIsMoving ? HIGH : LOW);
  }
}

void onRequest() {
  Wire.write(tiltState);
}

void setup() {
  Serial.begin(115200);
  pinMode(TILT_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);
  Wire.begin(I2C_ADDR);
  Wire.onReceive(receiveEvent);
  Wire.onRequest(onRequest);
}

void loop() {
  tiltState = digitalRead(TILT_PIN);
  delay(200);
}

七、系统调试与运行日志

系统上电后运行稳定,串口输出典型日志:

  • 主节点:WiFi 连接成功 → MQTT 连接成功 → 循环采集 → 定时上云
  • 从节点 C:持续输出光照 ADC 值
  • 从节点 D:响应主节点查询,同步 GPS 状态并控制 LED

八、项目挑战、局限与优化方向

8.1 遇到的问题与解决

  1. I2C 通信不稳定、丢包
    • 原因:未共地、无上拉电阻
    • 解决:统一共地 + SDA/SCL 加 4.7kΩ 上拉
  2. 模拟 GPS 轨迹跳变
    • 解决:限制经纬度偏移范围,实现平滑移动

8.2 系统现存局限

  1. 传感器精度有限,DHT11 误差较大
  2. 网络中断时无数据缓存机制
  3. 数据传输未加密,云端权限简单
  4. 仅支持视觉报警,无声音报警

8.3 未来优化方案

  1. 升级传感器:DHT11 → DHT22/DS18B20
  2. 添加 SD 卡离线缓存,断网续传
  3. MQTT 启用 TLS 加密,增强云端安全
  4. 增加电源滤波,支持声光双报警
  5. 适配真实冷链低温场景

九、总结

本项目是一套完整、可复现、可扩展的 ESP32 多节点工业物联网冷链监控系统,覆盖传感器采集、I2C 主从通信、本地显示、MQTT 上云、分级报警全流程。硬件成本低、逻辑清晰、功能完整,非常适合课程设计、毕业设计与 IoT 入门实战,可直接迁移到智能仓储、冷链运输、环境监测等真实场景。


总结

以上就是今天要讲的内容,本文简单记录了机器学习学习内容,仅作为一份简单的笔记使用,大家根据注释理解,您的点赞关注收藏就是对小编最大的鼓励!

相关推荐
InHand云飞小白6 小时前
【工业物联网】4G/5G 工业路由器技术选型与实战部署方案
物联网·5g·工业路由器·4g路由器·工业物联网·5g路由器·数字化联网
天下财经热6 小时前
快进商店闪耀2026中国零售业博览会,远程值守全家桶独家首发,重塑云值守解决方案
大数据·人工智能·物联网
桑榆肖物6 小时前
nanoFramework 正式支持 Raspberry Pi Pico RP2040
驱动开发·嵌入式硬件·iot
BY组态7 小时前
Ricon组态系统:新一代Web可视化组态平台
前端·物联网·iot·web组态·组态
互联网推荐官8 小时前
上海物联网应用开发全解析:技术路径、架构选型与落地约束
物联网·架构·开发经验·上海
MetrixAeroCore8 小时前
英国物联网出海落地难题破解:Metrix Aero Core通信适配解决方案
物联网
国产化创客8 小时前
毫米波雷达LD2402串口调参
嵌入式硬件·物联网·智能硬件
国产化创客10 小时前
ESP32+WebServer+LD2402实现人体/宠物感知
单片机·物联网·开源·智能硬件
TDengine (老段)10 小时前
TDengine 虚拟表实现原理
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据