物联网场景中,温湿度实时监测与云端管理需求日益广泛,但传统方案常存硬件兼容差、传输不稳定、开发门槛高的问题。搭配SHT2X高精度温湿度传感器与ESP-01 WiFi模块,将数据上传至Thingspeak云平台,实现低成本、易开发、高可靠的温湿度监测方案
目录
[1.1 硬件清单](#1.1 硬件清单)
[1.2 接线方案](#1.2 接线方案)
[1.3 具体接线图](#1.3 具体接线图)
[1.4 连接实物图](#1.4 连接实物图)
[2.1 初始化和数据读取](#2.1 初始化和数据读取)
[2.2 ESP-01初始化配置](#2.2 ESP-01初始化配置)
[2.3 数据上传功能](#2.3 数据上传功能)
[2.4 指令发送与响应检测](#2.4 指令发送与响应检测)
[2.5 完整代码](#2.5 完整代码)
[3.1 ESP-01 AT配置步骤](#3.1 ESP-01 AT配置步骤)
[3.2 Thingspeak云平台配置](#3.2 Thingspeak云平台配置)
[3.3 SHT2X温湿度传感器操作流程](#3.3 SHT2X温湿度传感器操作流程)
[3.4 视频演示](#3.4 视频演示)
[4.1 SHT2X温湿度传感器工作原理](#4.1 SHT2X温湿度传感器工作原理)
[4.2 ESP-01 WIFI模块工作原理](#4.2 ESP-01 WIFI模块工作原理)
(1)项目概述
本项目基于零知增强板(主控芯片STM32F407VET6),结合SHT2X高精度数字温湿度传感器和ESP-01 WIFI模块,实现了一套完整的物联网环境监测系统。系统能够实时采集环境温湿度数据,通过ESP-01模块将数据上传至Thingspeak云平台,实现数据的远程监控和可视化展示
(2)项目难点及解决方案
问题描述:ESP-01模块通过AT指令进行控制,容易出现响应超时或指令执行失败
**解决方案:**实现带超时机制的指令发送函数、添加指令重试和错误恢复逻辑、采用状态机模式管理连接流程
一、硬件系统设计
1.1 硬件清单
组件名称 | 型号/规格 | 数量 | 备注 |
---|---|---|---|
主控板 | 零知增强板(STM32F407VET6) | 1 | STM32F407VET6主控芯片 |
温湿度传感器 | SHT2X | 1 | I2C接口,3.3V供电 |
WiFi模块 | ESP-01 | 1 | ESP8266核心,支持AT指令 |
连接线 | 杜邦线 | 若干 | 建议使用不同颜色 |
1.2 接线方案
零知增强板引脚 | 连接组件 | 引脚功能 |
---|---|---|
3.3V | SHT2X VCC | 电源正极 |
GND | SHT2X GND | 电源地 |
20/SDA | SHT2X SDA | I2C数据线 |
21/SCL | SHT2X SCL | I2C时钟线 |
3.3V | ESP-01 VCC | 电源正极 |
GND | ESP-01 GND | 电源地 |
7 | ESP-01 TX | 软件串口RX |
6 | ESP-01 RX | 软件串口TX |
3.3V | ESP-01 CH_PD | 使能引脚 |
1.3 具体接线图

1.4 连接实物图

二、代码架构部分
2.1 初始化和数据读取
cpp
#include "Wire.h"
#include "SHT2x.h"
#include "SoftwareSerial.h"
// SHT2x传感器初始化
SHT2x sht;
// ESP-01软件串口初始化
SoftwareSerial esp01(6, 7); // RX, TX
// Thingspeak配置
const char* SSID = "Your_WiFi_SSID";
const char* PASSWORD = "Your_WiFi_Password";
const char* API_KEY = "Your_Thingspeak_API_Key";
// 定时上传变量
unsigned long previousMillis = 0;
const long interval = 30000; // 上传间隔30秒
void loop() {
// 读取传感器数据
sht.read();
float temperature = sht.getTemperature();
float humidity = sht.getHumidity();
// 串口显示数据
Serial.print("温度: ");
Serial.print(temperature, 1);
Serial.print("°C, 湿度: ");
Serial.print(humidity, 1);
Serial.println("%");
}
SoftwareSerial esp01(6, 7):创建软件串口对象,Pin6为RX,Pin7为TX
2.2 ESP-01初始化配置
cpp
void setupESP01() {
Serial.println("初始化ESP-01...");
// 重置ESP-01
sendCommand("AT+RST", "Ready", 5000);
delay(2000);
// 设置Station模式
if (!sendCommand("AT+CWMODE=1", "OK", 3000)) {
Serial.println("设置模式失败");
return;
}
// 连接WiFi
String connectCmd = "AT+CWJAP=\"" + String(SSID) + "\",\"" + String(PASSWORD) + "\"";
if (!sendCommand(connectCmd.c_str(), "GOT IP", 10000)) {
Serial.println("WiFi连接失败");
return;
}
}
AT+CWMODE=1:设置为Station模式(作为WiFi客户端)
2.3 数据上传功能
cpp
bool uploadToThingspeak(float temp, float humidity) {
// 建立TCP连接
if (!sendCommand("AT+CIPSTART=\"TCP\",\"api.thingspeak.com\",80", "CONNECT", 10000)) {
Serial.println("TCP连接失败");
return false;
}
// 构建HTTP GET请求
String getRequest = "GET /update?api_key=" + String(API_KEY) +
"&field1=" + String(temp, 1) +
"&field2=" + String(humidity, 1) +
" HTTP/1.1\r\nHost: api.thingspeak.com\r\n\r\n";
// 发送数据
String sendCmd = "AT+CIPSEND=" + String(getRequest.length());
if (!sendCommand(sendCmd.c_str(), ">", 5000)) {
Serial.println("准备发送失败");
sendCommand("AT+CIPCLOSE", "OK", 3000);
return false;
}
// 发送HTTP请求
if (!sendCommand(getRequest.c_str(), "CLOSED", 10000)) {
Serial.println("等待响应超时,但数据可能已发送");
}
// 关闭连接
sendCommand("AT+CIPCLOSE", "OK", 3000);
return true;
}
Thingspeak API进行HTTP GET请求:传入field1和field2数据字段
2.4 指令发送与响应检测
cpp
bool sendCommand(const char* command, const char* expectedResponse, unsigned int timeout) {
Serial.print("发送: ");
Serial.println(command);
esp01.println(command);
unsigned long startTime = millis();
String response = "";
while (millis() - startTime < timeout) {
if (esp01.available()) {
char c = esp01.read();
response += c;
Serial.write(c);
if (response.indexOf(expectedResponse) != -1) {
Serial.println();
return true;
}
}
}
Serial.println();
Serial.print("超时,未收到预期响应: ");
Serial.println(expectedResponse);
return false;
}
每个AT指令设置独立的超时时间、实时监控串口接收数据并匹配预期响应
2.5 完整代码
cpp
#include "Wire.h"
#include "SHT2x.h"
#include "SoftwareSerial.h"
// SHT2x传感器
SHT2x sht;
// ESP-01软件串口
SoftwareSerial esp01(7, 6); // RX, TX
// Thingspeak配置
const char* SSID = "zaixinjian"; // 替换为您的WiFi名称
const char* PASSWORD = "2020zaixinjian"; // 替换为您的WiFi密码
const char* API_KEY = "ZZSS7WI0AHOOP8H6"; // 替换为您的Thingspeak API Key
// 定时变量
unsigned long previousMillis = 0;
const long interval = 30000; // 30秒上传一次
void setup() {
Serial.begin(115200);
esp01.begin(115200);
Serial.println();
Serial.println("SHT2x + ESP-01 Thingspeak Demo");
Serial.print("SHT2x_LIB_VERSION: ");
Serial.println(SHT2x_LIB_VERSION);
// 初始化I2C和传感器
Wire.begin();
if (!sht.begin()) {
Serial.println("SHT2x传感器初始化失败!");
while(1);
}
Serial.println("SHT2x传感器初始化成功");
// 初始化ESP-01
setupESP01();
}
void loop() {
// 读取传感器数据
sht.read();
float temperature = sht.getTemperature();
float humidity = sht.getHumidity();
// 串口显示数据
Serial.print("温度: ");
Serial.print(temperature, 1);
Serial.print("°C, 湿度: ");
Serial.print(humidity, 1);
Serial.println("%");
// 定时上传到Thingspeak
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
if (uploadToThingspeak(temperature, humidity)) {
Serial.println("数据上传成功!");
} else {
Serial.println("数据上传失败!");
}
}
delay(2000); // 2秒读取一次
}
void setupESP01() {
Serial.println("初始化ESP-01...");
// 重置ESP-01
sendCommand("AT+RST", "Ready", 5000);
delay(2000);
// 设置模式
if (!sendCommand("AT+CWMODE=1", "OK", 3000)) {
Serial.println("设置模式失败");
return;
}
// 连接WiFi
String connectCmd = "AT+CWJAP=\"" + String(SSID) + "\",\"" + String(PASSWORD) + "\"";
if (!sendCommand(connectCmd.c_str(), "GOT IP", 10000)) {
Serial.println("WiFi连接失败");
return;
}
Serial.println("ESP-01初始化完成");
}
bool uploadToThingspeak(float temp, float humidity) {
Serial.println("准备上传数据到Thingspeak...");
// 建立TCP连接
if (!sendCommand("AT+CIPSTART=\"TCP\",\"api.thingspeak.com\",80", "CONNECT", 10000)) {
Serial.println("TCP连接失败");
return false;
}
// 构建HTTP GET请求
String getRequest = "GET /update?api_key=" + String(API_KEY) +
"&field1=" + String(temp, 1) +
"&field2=" + String(humidity, 1) +
" HTTP/1.1\r\nHost: api.thingspeak.com\r\n\r\n";
// 发送数据长度
String sendCmd = "AT+CIPSEND=" + String(getRequest.length());
if (!sendCommand(sendCmd.c_str(), ">", 5000)) {
Serial.println("准备发送失败");
sendCommand("AT+CIPCLOSE", "OK", 3000);
return false;
}
// 发送数据
if (!sendCommand(getRequest.c_str(), "CLOSED", 10000)) {
// 即使没有收到CLOSED,也可能上传成功
Serial.println("等待响应超时,但数据可能已发送");
}
// 关闭连接
sendCommand("AT+CIPCLOSE", "OK", 3000);
return true;
}
bool sendCommand(const char* command, const char* expectedResponse, unsigned int timeout) {
Serial.print("发送: ");
Serial.println(command);
esp01.println(command);
unsigned long startTime = millis();
String response = "";
while (millis() - startTime < timeout) {
if (esp01.available()) {
char c = esp01.read();
response += c;
Serial.write(c); // 在串口监视器显示响应
if (response.indexOf(expectedResponse) != -1) {
Serial.println();
return true;
}
}
}
Serial.println();
Serial.print("超时,未收到预期响应: ");
Serial.println(expectedResponse);
return false;
}
系统工作流程图

三、项目结果演示
3.1 ESP-01 AT配置步骤
(1)模块检测
通过串口发送AT指令,检查模块响应
(2)WIFI模式设置
打开串口助手查看AT指令操作的对应结果
(3)连接WiFi网络
发送
AT+CWJAP="SSID","PASSWORD"
连接路由器

显示连接到的局域网IP地址表示WIFI连接成功
(4)串口打印连接状态
设置Station模式并连接到WIFI网络

3.2 Thingspeak云平台配置
(1)账户注册与登录
访问Thingspeak官网注册免费账户、完成邮箱验证

访问ThingSpeak官网:https://thingspeak.mathworks.com/
(2)创建新Channel
点击"New Channel"按钮、设置Channel名称和描述、创建Field 1(温度)和Field 2(湿度)

(3)获取API密钥
进入"API Keys"标签页、记录"Write API Key"

将密钥填入代码的API_KEY
变量
(4)系统发送HTTP请求
发送: GET /update?api_key=8J39CZBWM7MTQODU&field1=31.2&field2=62.0 HTTP/1.1 Host: api.thingspeak.com

(5)上传温湿度数据
打开ThingSpeak云平台,将手放到SHT2X温湿度传感器上观察数据波形变化

3.3 SHT2X温湿度传感器操作流程
(1)传感器初始化
发送测量指令(0xF3为温度,0xF5为湿度)
cpp
bool SHT2x::requestTemperature()
{
if (! writeCmd(SHT2x_GET_TEMPERATURE_NO_HOLD))
{
_requestType = SHT2x_REQ_FAIL;
return false; // error is registered in writeCmd()
}
_lastRequest = millis();
_requestType = SHT2x_REQ_TEMPERATURE;
return true;
}
bool SHT2x::requestHumidity()
{
if (! writeCmd(SHT2x_GET_HUMIDITY_NO_HOLD))
{
_requestType = SHT2x_REQ_FAIL;
return false;
}
_lastRequest = millis();
_requestType = SHT2x_REQ_HUMIDITY;
return true;
}
等待测量完成(典型时间12-15ms)、读取测量结果并计算实际值
(2)数据精度控制
SHT2X支持可配置的分辨率,默认分辨率:湿度12位,温度14位
cpp
bool SHT2x::setResolution(uint8_t res)
{
if (res > 3) return false;
uint8_t userReg = 0x00;
writeCmd(SHT2x_READ_USER_REGISTER);
if (readBytes(1, (uint8_t *) &userReg, 5) == false)
{
_error = SHT2x_ERR_READBYTES;
return false;
}
// clear old resolution and set new
userReg &= ~SHT2x_USRREG_RESOLUTION;
// resolution is bit 7 and bit 0.
userReg |= ((res & 0x02) << 6);
userReg |= (res & 0x01);
if (writeCmd(SHT2x_WRITE_USER_REGISTER, userReg) == false)
{
_error = SHT2x_ERR_RESOLUTION;
return false;
}
_resolution = res;
return true;
}
通过指令调整精度和功耗
(3)温湿度数据上传

3.4 视频演示
基于STM32F407VET6的物联网温湿度监测系统
SHT2X传感器采集环境温湿度数据,到ESP-01模块连接WiFi网络并将数据成功上传至Thingspeak云平台
四、系统传感器工作原理
4.1 SHT2X温湿度传感器工作原理
SHT2x 系列传感器包含一个电容式湿度传感器、一个带隙温度传感器以及专用的模拟和数字集成电路

SHT2x 温湿度传感器的供电范围为 2.1-3.6V,推荐电压为 3.0V
(1)I2C串行通信
SHT2x温湿度传感器采用标准的I2C协议进行通信。启动传输后,后续传输的第一个I2C字节包含7位I2C设备地址(二进制范例地址为"1000'000")和1位SDA方向位(读操作R对应"1",写操作W对应"0")。在第8个SCL时钟的下降沿之后,传感器会通过拉低SDA引脚(即ACK位)来指示数据已正常接收。

在发出测量命令之后("1110'0011" 代表温度测量,"1110'0101" 代表相对湿度测量),微控制器(MCU)需等待测量操作完成,基本的命令列表如下:

读取SHT2x温湿度传感器数据有两种不同的方式可选,主机模式或非主机模式
(2)数据转换
默认分辨率设置为 12 位相对湿度和 14 位温度读数。测量数据以两字节数据包的形式传输,即 8 位长度的帧,其中最高有效位(MSB)先传输(左对齐)。每个字节后都跟有一个确认位
无论选择哪种分辨率,都可通过以下公式得到相对湿度 RH:

对于冰面上方的相对湿度 RHi,其数值需要由温度 t 下水面上方的相对湿度 RHw 转换而来:

相对湿度的单位是%RH,温度的单位是°C。相应的系数定义如下:
βw = 17.62, λw = 243.12°C, βi = 22.46, λi = 272.62°C.
无论选择哪种分辨率,温度 T 都是通过将温度信号输出 ST 代入以下公式(结果以 °C 为单位)计算得出的:

4.2 ESP-01 WIFI模块工作原理
ESP8266芯片集成Tensilica L106 32位微处理器、SPI Flash存储固件和配置数据、2.4GHz WiFi射频模块,支持802.11 b/g/n协议

ESP-01管脚定义:
脚序 | 名称 | 功能说明 |
---|---|---|
1 | GND | 接地 |
2 | IO2 | GPIO2/UART1_TXD |
3 | IO0 | GPIO0; 下载模式:外部拉低;运行模式:悬空或外部拉高 |
4 | RXD | UART0_RXD/GPIO3 |
5 | TXD | UART0_TXD/GPIO1 |
6 | EN | 芯片使能端,高电平有效 |
7 | RST | 复位 |
8 | VCC | 3.3V供电(VDD); 外部供电电源输入电流建议在500mA以上 |
(1)工作模式
AT 指令要求以新行 (CR LF) 结尾 、 AT 指令必须为大写英文字母 、 AT指令默认响应为OK 、 一般而言,当我们用USB转TTL模块与Esp8266连接之后,波特率默认为115200 、 用串口软件输入指令时,每条AT指令后面都要加一个回车键再发送,即串口助手记得勾选"发送新行"
Station模式:
bash
AT+CWMODE=1 # 指令原型为:AT+CWMODE=<mode>;其中<mode>:1-Station模式,2-AP模式,3-AP兼Station模式。
AT+RST # 配置好模式后需要重启生效。
AT+CWMODE? # 这条指令可以不要,这是查询当前模式的指令,模式返回是1,说明是Station模式。
AT+CWLAP # 可以让模块搜索周围的信号了,列出可以连接的热点(中文显示为乱码)。
AT+CWJAP="HOTPOINT","1234" # 指令原型为:AT+CWJAP=<ssid>,<pwd>),ssid就是wifi的名字,pwd就是wifi的密码。
AT+CWJAP? # 查询一下当前连接的AP。
AT+CIFSR # 查看下模块的IP地址。
# 在通过路由器查看下模块的IP地址时。如果模块之前我们设置成了AP和Station共存模式,则会出现两个IP,
# 上面的APIP是作为无线AP的IP地址。
# 下面的STAIP是它作为客户端从路由器获取到的IP 地址。
AT+CIPSTA_CUR="192.168.6.100","192.168.6.1","255.255.255.0" # 这条指令可以不要,这是分配固定ip。
AT+CIPSTART="TCP","192.168.1.100",8080 # 连接到服务器,/192.168.1.100为服务器IP地址;8080为端口。
AT+CIPSEND=4 # 发送四个字节的数据。
通过路由器管理界面查看到模块的MAC地址
AP模式:
bash
AT+CWMODE=2 # 指令原型为:AT+CWMODE=<mode>;其中<mode>:1-Station模式,2-AP模式,3-AP兼Station模式。
AT+RST # 配置好模式后需要重启生效。
AT+CWMODE? # 这是查询当前模式的指令,模式返回是2,说明是AP模式。
AT+CWSAP="ESP8266","0123456789",11,0
# 指令原型为:AT+ CWSAP=<ssid>,<pwd>,<chl>, <ecn>;
# 其中<ssid>:字符串参数,接入点名称;
# <pwd>:字符串参数,密码最长64字节,ASCII;
# <chl>:通道号;
# < ecn >:0-OPEN,1-WEP,2-WPA_PSK,3-WPA2_PSK,4-WPA_WPA2_PSK。
# 然后现在就可以在你的手机或者是电脑通过无线网卡连接到ESP8266上了。
AT+CWLIF # 查看已接入设备的 IP
# AT+CIFSR # 查看本模块的 IP 地址,AP 模式下无效!会造成死机现象!
AT+CIPMUX=1
# 开启多连接模式,因为只有在开启多连接模式的时候才能开启服务器模式。注意:透传只能在单连接模式下进行。
# 模块最多允许5个客户端连接(每个客户端对应一个id号,0--4)
AT+CIPSERVER=1,8080 # 建立SERVER(0关闭,1开启),设置端口为8080
# AT+CIPSERVER=1 # 默认的端口333
AT+CIPSEND=0,10 # 下一次输入字符串,0是通道号,10是数据长度。
# 每个连接进来的TCPClient都会有一个ID,默认从0开始增加
# 多连接模式下,第一个参数指明第几个Client(客户端),第二个参数指明发送几个字节,这个用的10,超过后只发送前20字节。
# 单路连接时,只指定发送长度即可。
作为接入点,允许其他设备连接
混合模式:
bash
AT+CWMODE=3 # 指令原型为:AT+CWMODE=<mode>;其中<mode>:1-Station模式,2-AP模式,3-AP兼Station模式。
AT+RST # 配置好模式后需要重启生效。
AT+CWSAP="ESP8266","0123456789",11,0
# 指令原型为:AT+ CWSAP=<ssid>,<pwd>,<chl>, <ecn>;
# <ssid>:字符串参数,接入点名称;
# <pwd>:字符串参数,密码最长64字节,ASCII;
# <chl>:通道号;
# < ecn >:0-OPEN,1-WEP,2-WPA_PSK,3-WPA2_PSK,4-WPA_WPA2_PSK。
# 然后现在就可以在你的手机或者是电脑通过无线网卡连接到ESP8266上了。
# 打开手机上的有人网络助手,TCP server→配置→激活→能看到此时手机的IP和端口号,要记下,下面要用。
AT+CIPMODE=1 # 开启透传模式。
AT+CIPMUX=0 # 开启单路模式。
AT+CIPSTART="TCP","192.168.4.2",8080
# 192.168.4.2为服务器IP地址;8080为端口。填刚才记下的手机IP和端口号
# 这时手机已经能向模块发信息了,但模块不能发。
AT+CIPSEND=4 # AT+CIPSEND=(要发送的字节长度)
# AT+CIPSEND # ESP8266发送数据至手机。
同时支持Station和AP模式
(2)TCP/IP协议栈
TCP透传:
注意只有在单连接的时候才可以设置为透传模式:就是串口的数据直接发送到网络,网络的数据直接发送到串口
bash
AT+CWMODE=3
AT+CWJAP="SSID","PASSWD"
AT+CIFSR # 查询自己的IP地址
AT+CIPSTART="TCP","192.168.xxx.xxx",8000 # 作为 TCP client 链接到上述服务器
AT+CIPMODE=1 # 使能透传模式
AT+CIPSEND # 向服务器发送数据
多连接模式:
每次上电后只要输入AT+CIPMUX=1和AT+CIPSERVER=1,8080即可
cpp
AT+CWMODE=3
AT+RST # 重启生效
AT+CWSAP="ESP8266_TEST","1234",1,3 # 名字,密码,通道和密码模式
AT+CIPMUX=1 # 启动多连接
AT+CIPSERVER=1,8000 # 建立SERVER(0关闭,1开启), 端口8000,
五、常见问题解答
Q1:ESP-01模块无法连接WiFi
A:可能原因及解决方案:
检查代码中SSID和密码是否正确、确保模块与路由器距离适中、使用独立的3.3V电源为ESP-01供电,避免电流不足、尝试更新AT固件到最新版本
Q2:SHT2X传感器读取数据失败
A:排查步骤:
检查I2C线路连接是否正确(SDA、SCL)、确认电源电压在2.1-3.6V范围使用I2C扫描程序检测设备地址(应为0x40)、检查上拉电阻(通常需要4.7kΩ上拉)
Q3:Thingspeak平台无法接收数据
A:诊断方法:
检查API密钥是否正确配置、确认网络连接正常,能够访问互联网、查看串口输出的HTTP请求和响应信息、验证字段名称与Channel中设置的一致性
项目资源整合
SHT2x库: SHT2x-master
SHT2x数据手册:SHT2x datasheet
ESP-01数据手册:ESP-01 WIFI Module
此项目由 Lingzhi Lab 开源:https://www.lingzhilab.com/