STM32+ESP8266 WiFi 远程环境监测平台|本地 OLED 显示 + TCP 上传电脑 / 手机

一、项目整体方案与功能介绍

1.1 实现全部功能

传感器采集:DHT11 温湿度 + ADC 模拟量(土壤湿度 / 光敏 / 电压);

本地可视化:IIC-OLED 实时刷新温湿度、电压、WiFi 连接状态;

ESP8266 AT 指令驱动:上电自动连 WiFi,断线自动重连 TCP 服务端;

远程数据上传:格式化报文 TCP 透传发送,电脑 / 手机远程实时查看;

容错机制:WiFi 断开自动重试,采集失败填充默认值避免界面乱码。

1.2 硬件接线分配

STM32 USART1(PA9/PA10):ESP8266 通信,波特率 115200。

DHT11 DATA:PA0。

ADC 模拟输入:PA1。

OLED IIC:PB6 SCL、PB7 SDA。

3.3V 统一供电,所有模块共地,ESP8266 禁止 5V 直供。

1.3 整体数据流

传感器采集 → 数据缓存结构体 → OLED 本地刷新 + ESP8266 TCP 远程上传

ESP8266 工作逻辑:上电检测模块 → 连接路由器 WiFi → 连接电脑 TCP 服务端 → 持续透传上报数据,掉线全程自动重试,不阻塞采集业务。

二、核心原理深度解析

2.1 ESP8266 AT 透传核心逻辑

ESP8266 出厂默认 AT 固件无需二次开发,仅靠串口指令完成全部联网操作:

AT 检测模块是否上电正常;

AT+CWJAP="wifi名","密码" 连接局域网 WiFi;

AT+CIPSTART="TCP","服务器IP",端口 建立 TCP 客户端连接;

AT+CIPMODE=1 + AT+CIPSEND 开启透传,串口数据直接转发至网络;

一旦收到模块返回CLOSED代表 TCP 断开,程序自动重置 WiFi 状态机重新走联网流程。

2.2 多外设时序冲突解决方案

采集、屏幕刷新、WiFi 串口上报共用主循环,若不加时间分片会出现:OLED 刷屏卡顿、WiFi 指令发送截断、温湿度读取校验失败。

本项目采用时分轮询机制:不同业务设置独立计时阈值,错峰执行,互不抢占 CPU。

2.3 远程通信防乱码设计

环境数据统一封装固定格式字符串,带换行分隔帧尾;

WiFi 发送操作加简易互斥保护,避免采集与上报同时抢占串口;

断线暂停上报,只保留本地采集显示,保证基础功能不瘫痪。

三、极简模块化完整源码(STM32 标准库)

3.1 env_data.h 统一数据管理

#ifndef __ENV_DATA_H

#define __ENV_DATA_H

#include "stm32f10x.h"

//环境数据结构体

typedef struct

{

uint8_t temp;

uint8_t hum;

float adc_vol;

uint8_t wifi_link; //1=WiFi已连上TCP,0=离线

}EnvData_t;

extern EnvData_t env_data;

void Env_Scan(void);

#endif

3.2 esp8266_wifi.h WiFi 驱动头文件

#ifndef __ESP8266_WIFI_H

#define __ESP8266_WIFI_H

#include "stm32f10x.h"

#include "env_data.h"

//WiFi配置,直接修改此处参数

#define WIFI_NAME "MyWiFi"

#define WIFI_PWD "12345678"

#define TCP_SERVER_IP "192.168.1.105"

#define TCP_PORT 8080

//WiFi状态枚举

typedef enum

{

WIFI_IDLE,

WIFI_CHECK_MODULE,

WIFI_CONNECT_AP,

WIFI_CONNECT_TCP,

WIFI_TRANS_OK

}WiFiState_t;

void ESP8266_Init(void);

void ESP8266_StateTask(void);

void ESP8266_SendTcpData(uint8_t *buf);

#endif

3.3 esp8266_wifi.c 非阻塞状态机 WiFi 驱动

#include "esp8266_wifi.h"

#include "usart.h"

#include "string.h"

static WiFiState_t wifi_state = WIFI_IDLE;

static uint32_t wifi_tick = 0;

extern uint8_t usart_rx_buf128;

static void ESP_SendAT(char cmd)
{
USART_SendString((uint8_t
)cmd);

}

void ESP8266_Init(void)

{

wifi_state = WIFI_CHECK_MODULE;

wifi_tick = 0;

env_data.wifi_link = 0;

memset(usart_rx_buf,0,sizeof(usart_rx_buf));

}

//WiFi主状态机,10ms调用一次,非阻塞不卡采集

void ESP8266_StateTask(void)

{

wifi_tick++;

switch(wifi_state)

{

case WIFI_CHECK_MODULE:

if(wifi_tick >= 20)

{

wifi_tick = 0;

ESP_SendAT("AT\r\n");

if(strstr((char*)usart_rx_buf,"OK"))

{

memset(usart_rx_buf,0,128);

wifi_state = WIFI_CONNECT_AP;

}

}

break;

case WIFI_CONNECT_AP:

if(wifi_tick >= 30)

{

wifi_tick = 0;

ESP_SendAT("AT+CWJAP=""WIFI_NAME"",""WIFI_PWD""\r\n");

if(strstr((char*)usart_rx_buf,"OK"))

{

memset(usart_rx_buf,0,128);

wifi_state = WIFI_CONNECT_TCP;

}

}

break;

case WIFI_CONNECT_TCP:

if(wifi_tick >= 30)

{

wifi_tick = 0;

ESP_SendAT("AT+CIPSTART="TCP",""TCP_SERVER_IP"","#TCP_PORT"\r\n");

if(strstr((char*)usart_rx_buf,"CONNECT"))

{

ESP_SendAT("AT+CIPMODE=1\r\n");

ESP_SendAT("AT+CIPSEND\r\n");

wifi_state = WIFI_TRANS_OK;

env_data.wifi_link = 1;

memset(usart_rx_buf,0,128);

}

}

break;

case WIFI_TRANS_OK:

env_data.wifi_link = 1;

//检测TCP断开标志

if(strstr((char*)usart_rx_buf,"CLOSED"))

{

env_data.wifi_link = 0;

wifi_state = WIFI_CHECK_MODULE;

memset(usart_rx_buf,0,128);

}

break;

default:

wifi_state = WIFI_CHECK_MODULE;

break;

}

}

//TCP远程发送环境数据

void ESP8266_SendTcpData(uint8_t *buf)

{

if(wifi_state == WIFI_TRANS_OK)

{

USART_SendString(buf);

}

}

3.4 env_scan.c 传感器采集业务

#include "env_data.h"

#include "dht11.h"

#include "adc.h"

EnvData_t env_data;

void Env_Scan(void)

{

//读取温湿度

if(DHT11_Read(&env_data.hum,&env_data.temp) != 0)

{

env_data.temp = 0;

env_data.hum = 0;

}

//读取ADC电压均值

env_data.adc_vol = ADC_GetFilterVolt();

}

3.5 main.c 主循环时分调度

#include "stm32f10x.h"

#include "usart.h"

#include "oled.h"

#include "esp8266_wifi.h"

#include "env_data.h"

uint32_t scan_tick = 0;

uint32_t oled_tick = 0;

uint32_t upload_tick = 0;

void delay_ms(uint32_t ms)

{

uint32_t i,j;

for(i=0;i<ms;i++)

for(j=0;j<7200;j++);

}

int main(void)

{

USART1_Init();

OLED_Init();

DHT11_Init();

ADC_Init();

ESP8266_Init();

复制代码
while(1)
{
    delay_ms(10);
    scan_tick += 10;
    oled_tick += 10;
    upload_tick += 10;

    //WiFi状态机持续运行
    ESP8266_StateTask();

    //500ms采集一次环境数据
    if(scan_tick >= 500)
    {
        scan_tick = 0;
        Env_Scan();
    }

    //800ms刷新OLED本地界面
    if(oled_tick >= 800)
    {
        oled_tick = 0;
        OLED_Clear();
        OLED_ShowString(0,0,"WiFi Env Monitor");
        OLED_ShowString(0,16,"T:");
        OLED_ShowNum(20,16,env_data.temp,2,16);
        OLED_ShowString(40,16,"C");
        OLED_ShowString(0,32,"H:");
        OLED_ShowNum(20,32,env_data.hum,2,16);
        OLED_ShowString(40,32,"%");
        OLED_ShowString(0,48,"V:");
        OLED_ShowFloat(20,48,env_data.adc_vol,2,16);
        //WiFi在线状态提示
        if(env_data.wifi_link)
            OLED_ShowString(0,64,"WiFi:Online");
        else
            OLED_ShowString(0,64,"WiFi:Offline");
    }

    //1s远程TCP上传一次数据
    if(upload_tick >= 1000)
    {
        upload_tick = 0;
        char send_buf[64];
        sprintf(send_buf,"Temp:%dC,Hum:%d%%,Vol:%.2fV\r\n",
                env_data.temp,env_data.hum,env_data.adc_vol);
        ESP8266_SendTcpData((uint8_t*)send_buf);
    }
}

}

四、电脑上位机操作步骤

电脑连接与 ESP8266 相同局域网 WiFi;

打开网络调试助手,创建 TCP 服务端,端口填写 8080;

查看电脑本机 IPv4,修改代码内TCP_SERVER_IP;

下载程序,模块自动联网,成功后 OLED 显示 WiFi:Online,调试助手持续接收环境报文。

五、本项目原创核心优势(区别网上通用代码)

1、非阻塞 WiFi 状态机

全程无长延时等待,WiFi 重连不会阻塞传感器采集与 OLED 显示,工业设备必备;

2、时分轮询业务隔离

采集、屏幕、远程上传错峰执行,彻底解决多外设串口时序冲突;

3、断线全自动容错

TCP 断开自动重置联网流程,无需手动重启单片机,7×24 小时稳定运行;

4、分层完全解耦

WiFi 驱动、传感器采集、显示业务独立拆分,替换传感器 / 更换 WiFi 参数只需修改配置宏;

5、本地离线可用

WiFi 掉线仅停止远程上报,本地 OLED 依旧正常显示环境数据,基础监测功能不丢失;

6、代码零冗余轻量化

剔除多余 AT 指令、无效缓存、重复初始化,F103 最小容量芯片可流畅运行。

六、高频踩坑深度解决

坑 1:ESP8266 能收到 AT 应答,但始终连不上 TCP

电脑防火墙拦截端口,关闭防火墙或放行 8080 端口;

IP 地址填写错误,单片机与电脑不在同一局域网;

先启动电脑 TCP 服务端,再上电单片机。

坑 2:WiFi 偶尔掉线,长时间运行离线

ESP8266 供电电流不足,建议外部 3.3V 稳压电源独立供电,缩短杜邦线。

坑 3:OLED 闪烁、采集数据偶尔为 0

各业务执行间隔时间设置过小,增加时分轮询计时阈值,降低刷新频率。

坑 4:TCP 收到数据分段、乱码

统一使用\r\n作为报文分隔符,上位机按换行分割单条环境数据。

七、项目拓展升级方案

1、升级 SHT30 高精度温湿度传感器,提升监测精度;

2、增加阈值判断,WiFi 远程推送超标报警报文;

3、移植 FreeRTOS,WiFi、采集、显示拆分为独立任务;

4、更换 TCP 为 MQTT 协议,对接阿里云 / ESP 云平台实现外网远程监控;

5、增加按键切换 WiFi 账号,无需重新烧录程序修改参数;

6、搭配继电器,远程下发指令控制通风、喷淋设备。

八、全文总结

STM32+ESP8266 AT 透传是低成本远程物联网监测最优方案,无需复杂网络协议栈;

远程监测设备开发核心要点:非阻塞 WiFi 重连、多业务时分调度、离线基础功能保活;

本平台兼顾本地现场查看与远程电脑 / 手机监控,适用于农业大棚、机房、仓储环境监测;

模块化极简工程可直接复用至本专栏所有传感器、无线通信综合项目,拓展性极强。


相关推荐
GeekArch2 小时前
第8讲:裸机单片机项目——Vibe快速迭代的最优边界
c语言·stm32·单片机·嵌入式硬件·mcu·物联网·ai编程
其实防守也摸鱼2 小时前
运维--ip单日获取去重数据量超过500条
运维·学习·tcp/ip·安全·web安全·安全威胁分析·工具
Xxtaoaooo2 小时前
远程协助修电脑用什么软件?2026 主流跨端远控工具深度横评
电脑·远程工具·远程协助·uu远程·远程游戏
专注_每天进步一点点14 小时前
SLB(绑定弹性公网ip)-gateway-业务pod,gateway上出现reset by peer,业务pod上没有reset by peer
服务器·tcp/ip·gateway
CHANG_THE_WORLD15 小时前
TCP 三次握手彻底解析:SYN、ACK、SEQ、确认号与状态迁移
网络·网络协议·tcp/ip
Bobolink_17 小时前
手机端和电脑端的网络环境配置有什么不同?
网络·智能手机·电脑·网络环境
辰哥单片机设计18 小时前
STM32音乐播放器
stm32·单片机·嵌入式硬件
周洲083018 小时前
STM32 串口指令控制系统|上位机下发命令控制 LED、继电器,通用指令解析框架
stm32·嵌入式硬件·mongodb
qingmiaozhuan19 小时前
电脑录屏没有声音还能补救吗?音频采集链路详解及4种技术方案
前端·电脑·音视频·开发工具·电脑录屏·电脑录屏软件