STM32 进阶封神之路二十六ESP8266 实战全攻略 ——TCP 通信 数据上传 远程控制 透传模式库函数 代码落地上一篇我们吃透了 ESP8266 的底层原理、AT 指令集和 STM32 硬件连接这一篇聚焦实战落地 —— 基于 STM32F103ESP8266实现 “TCP 客户端连接、温湿度数据上传、手机远程控制 LED、透传模式通信” 四大核心功能所有代码基于 AT 指令开发可直接编译运行覆盖物联网设备的核心应用场景本文结合实战场景从 TCP 连接建立、传感器数据上传、远程控制指令解析到透传模式配置手把手带你搭建完整的 WiFi 通信系统让你真正掌握 ESP8266 的工程应用一、实战准备硬件环境与核心需求1. 硬件清单主控STM32F103C8T6 最小系统板无线模块ESP8266-12F 模块已刷 AT 指令固件传感器DHT11 温湿度传感器单总线外设LEDPB0远程控制、1KΩ 限流电阻、4.7KΩ 上拉电阻DHT11辅助硬件3.3V 电源模块ESP8266 供电、USB-TTL 模块调试、杜邦线、面包板服务器电脑运行网络调试助手模拟 TCP 服务器或手机TCP 客户端 APP。2. 核心实战需求功能 1TCP 客户端连接→ESP8266 作为 TCP 客户端连接电脑网络调试助手的 TCP 服务器功能 2数据上传→STM32 采集 DHT11 温湿度数据通过 ESP8266 上传到 TCP 服务器功能 3远程控制→TCP 服务器电脑 / 手机发送控制指令如 “LED_ON”“LED_OFF”STM32 解析后控制 LED功能 4透传模式→配置 ESP8266 为透传模式实现 STM32 与 TCP 服务器的双向透明通信无需 AT 指令直接收发数据。3. 关键硬件连接1核心连接表STM32 ↔ ESP8266 ↔ 其他模块表格模块引脚STM32 引脚连接说明ESP8266VCC3.3V外部电源3.3V 供电避免 STM32 直接供电电流不足ESP8266GNDGND共地STM32、ESP8266、DHT11 必须共地ESP8266TXPA10USART1_RX交叉连接ESP8266→STM32 数据传输ESP8266RXPA9USART1_TX交叉连接STM32→ESP8266 数据传输ESP8266CH_PD3.3V高电平使能模块不可悬空DHT11VCC3.3V传感器供电DHT11GNDGND共地DHT11DATAPB1单总线数据引脚外接 4.7KΩ 上拉电阻LED正极串 1KΩ 电阻PB0推挽输出低电平点亮LED负极GND2网络拓扑plaintextSTM32 ESP8266TCP客户端 ↔ WiFi路由器 ↔ 电脑TCP服务器网络调试助手关键前提ESP8266 和电脑需连接同一 WiFi 路由器确保局域网通信电脑 IP 查询通过 “ipconfig” 查询本地 IP如 192.168.1.105TCP 服务器端口设为 8080。二、核心代码实现四大功能全流程1. 头文件与全局变量定义c运行#include stm32f10x.h #include stdio.h #include string.h #include stdlib.h // 串口1与ESP8266通信配置 #define USART1_RECV_BUF_LEN 512 uint8_t USART1_Recv_Buf[USART1_RECV_BUF_LEN]; uint16_t USART1_Recv_Cnt 0; uint8_t USART1_Recv_Idle 0; // 接收完成标志位 // DHT11相关定义 typedef struct { uint8_t humidity_int; // 湿度整数部分 uint8_t humidity_dec; // 湿度小数部分DHT11恒为0 uint8_t temp_int; // 温度整数部分 uint8_t temp_dec; // 温度小数部分 uint8_t data_valid; // 数据有效性标志1有效 } DHT11_Data_TypeDef; DHT11_Data_TypeDef dht11_data; // TCP服务器配置替换为你的电脑IP和端口 #define TCP_SERVER_IP 192.168.1.105 #define TCP_SERVER_PORT 8080 // 控制指令定义 #define LED_ON_CMD LED_ON #define LED_OFF_CMD LED_OFF // 延时函数声明 void Delay_ms(uint32_t ms); void DHT11_DelayUs(uint32_t us); // 串口1函数声明 void USART1_Init_ESP8266(void); void USART1_SendByte(uint8_t data); void USART1_SendString(uint8_t *str); uint8_t ESP8266_SendCmd(uint8_t *cmd, uint8_t *resp, uint32_t timeout); uint8_t ESP8266_Init_STA(uint8_t *ssid, uint8_t *pwd); uint8_t ESP8266_Connect_TCP(uint8_t *ip, uint16_t port); void ESP8266_Enter_TransparentMode(void); // DHT11函数声明 void DHT11_Init(void); uint8_t DHT11_ReadData(DHT11_Data_TypeDef *data); // 外设函数声明 void LED_Init(void); void LED_On(void); void LED_Off(void); void Cmd_Parse(uint8_t *cmd_buf);2. 基础模块初始化串口 1LEDDHT111串口 1 初始化与 ESP8266 通信c运行// 串口1发送字节 void USART1_SendByte(uint8_t data) { while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET); USART_SendData(USART1, data); } // 串口1发送字符串 void USART1_SendString(uint8_t *str) { while(*str ! \0) { USART1_SendByte(*str); str; } } // printf重定向 int fputc(int ch, FILE *f) { USART1_SendByte((uint8_t)ch); return ch; } // 串口1中断服务函数接收ESP8266数据 void USART1_IRQHandler(void) { uint8_t recv_data; // 接收非空中断字节接收 if(USART_GetITStatus(USART1, USART_IT_RXNE) ! RESET) { recv_data (uint8_t)USART_ReceiveData(USART1); if(USART1_Recv_Cnt USART1_RECV_BUF_LEN - 1) { USART1_Recv_Buf[USART1_Recv_Cnt] recv_data; } USART_ClearITPendingBit(USART1, USART_IT_RXNE); } // 空闲中断数据接收完成 if(USART_GetITStatus(USART1, USART_IT_IDLE) ! RESET) { USART1_Recv_Buf[USART1_Recv_Cnt] \0; USART1_Recv_Idle 1; // 清除空闲中断标志 recv_data (uint8_t)USART_ReceiveData(USART1); (void)recv_data; } } // 串口1初始化115200bps8N1中断接收 void USART1_Init_ESP8266(void) { GPIO_InitTypeDef GPIO_InitStruct; USART_InitTypeDef USART_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE); // PA9TX复用推挽输出 GPIO_InitStruct.GPIO_Pin GPIO_Pin_9; GPIO_InitStruct.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStruct); // PA10RX浮空输入 GPIO_InitStruct.GPIO_Pin GPIO_Pin_10; GPIO_InitStruct.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStruct); // 串口参数配置 USART_InitStruct.USART_BaudRate 115200; USART_InitStruct.USART_WordLength USART_WordLength_8b; USART_InitStruct.USART_StopBits USART_StopBits_1; USART_InitStruct.USART_Parity USART_Parity_No; USART_InitStruct.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStruct.USART_Mode USART_Mode_Tx | USART_Mode_Rx; USART_Init(USART1, USART_InitStruct); // 使能接收中断和空闲中断 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); // 配置NVIC优先级 NVIC_InitStruct.NVIC_IRQChannel USART1_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority 1; NVIC_InitStruct.NVIC_IRQChannelSubPriority 0; NVIC_InitStruct.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStruct); USART_Cmd(USART1, ENABLE); } // 清空串口1接收缓冲区 void USART1_Clear_Recv_Buf(void) { memset(USART1_Recv_Buf, 0, USART1_RECV_BUF_LEN); USART1_Recv_Cnt 0; USART1_Recv_Idle 0; }2LED 初始化c运行void LED_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStruct.GPIO_Pin GPIO_Pin_0; GPIO_InitStruct.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOB, GPIO_InitStruct); GPIO_SetBits(GPIOB, GPIO_Pin_0); // 初始熄灭 } void LED_On(void) { GPIO_ResetBits(GPIOB, GPIO_Pin_0); printf(LED已点亮\r\n); } void LED_Off(void) { GPIO_SetBits(GPIOB, GPIO_Pin_0); printf(LED已熄灭\r\n); }3DHT11 初始化与数据采集c运行// DHT11 GPIO模式切换 void DHT11_SetOutputMode(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStruct.GPIO_Pin GPIO_Pin_1; GPIO_InitStruct.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed GPIO_Speed_2MHz; GPIO_Init(GPIOB, GPIO_InitStruct); } void DHT11_SetInputMode(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStruct.GPIO_Pin GPIO_Pin_1; GPIO_InitStruct.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOB, GPIO_InitStruct); } // 微秒级延时 void DHT11_DelayUs(uint32_t us) { uint32_t i; for(i 0; i us * 9; i); // 72MHz主频下校准 } // 毫秒级延时 void Delay_ms(uint32_t ms) { uint32_t i, j; for(i 0; i ms; i) { for(j 0; j 1000; j); } } // DHT11发送起始信号 uint8_t DHT11_SendStart(void) { DHT11_SetOutputMode(); GPIO_ResetBits(GPIOB, GPIO_Pin_1); Delay_ms(20); // 拉低≥18ms GPIO_SetBits(GPIOB, GPIO_Pin_1); DHT11_DelayUs(30); // 拉高20~40us DHT11_SetInputMode(); // 等待DHT11响应 if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) 0) { // 检测响应低电平 while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) 0); // 检测响应高电平 while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) 1); return 1; // 响应成功 } return 0; // 响应失败 } // DHT11读取1位数据 uint8_t DHT11_ReadBit(void) { uint8_t bit_val 0; // 低电平起始50us while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) 0); // 高电平持续时间决定数据026~28us170us DHT11_DelayUs(40); if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) 1) { bit_val 1; while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) 1); } return bit_val; } // DHT11读取1字节数据 uint8_t DHT11_ReadByte(void) { uint8_t byte_val 0; for(uint8_t i 0; i 8; i) { byte_val 1; byte_val | DHT11_ReadBit(); } return byte_val; } // DHT11读取温湿度数据 uint8_t DHT11_ReadData(DHT11_Data_TypeDef *data) { uint8_t humidity_int, humidity_dec, temp_int, temp_dec, check_sum; if(DHT11_SendStart() 0) { data-data_valid 0; return 0; } // 读取40位数据 humidity_int DHT11_ReadByte(); humidity_dec DHT11_ReadByte(); temp_int DHT11_ReadByte(); temp_dec DHT11_ReadByte(); check_sum DHT11_ReadByte(); // 校验数据 if(check_sum (humidity_int humidity_dec temp_int temp_dec)) { data-humidity_int humidity_int; data-humidity_dec humidity_dec; data-temp_int temp_int; data-temp_dec temp_dec; data-data_valid 1; return 1; } else { data-data_valid 0; return 0; } }3. ESP8266 核心功能实现TCP 连接 数据上传 透传1AT 指令发送与响应判断c运行uint8_t ESP8266_SendCmd(uint8_t *cmd, uint8_t *resp, uint32_t timeout) { USART1_Clear_Recv_Buf(); USART1_SendString(cmd); USART1_SendByte(\r); USART1_SendByte(\n); uint32_t start_time SystemCoreClock / 1000 * timeout; while(start_time--) { if(USART1_Recv_Idle 1) { if(strstr((char*)USART1_Recv_Buf, (char*)resp) ! NULL) { printf(发送指令%s 响应%s\r\n, cmd, USART1_Recv_Buf); USART1_Clear_Recv_Buf(); return 1; } else { printf(发送指令%s 响应异常%s\r\n, cmd, USART1_Recv_Buf); USART1_Clear_Recv_Buf(); return 0; } } Delay_ms(1); } printf(发送指令%s 超时无响应\r\n, cmd); USART1_Clear_Recv_Buf(); return 0; }2ESP8266 STA 模式初始化连接 WiFic运行uint8_t ESP8266_Init_STA(uint8_t *ssid, uint8_t *pwd) { uint8_t ret 0; // 测试模块是否在线 ret ESP8266_SendCmd((uint8_t*)AT, (uint8_t*)OK, 1000); if(ret 0) return 0; // 重启模块 ret ESP8266_SendCmd((uint8_t*)ATRST, (uint8_t*)OK, 3000); if(ret 0) return 0; Delay_ms(2000); // 设置为STA模式 ret ESP8266_SendCmd((uint8_t*)ATCWMODE1, (uint8_t*)OK, 1000); if(ret 0) return 0; // 连接WiFi uint8_t cwjap_cmd[64]; sprintf((char*)cwjap_cmd, ATCWJAP\%s\,\%s\, ssid, pwd); ret ESP8266_SendCmd(cwjap_cmd, (uint8_t*)OK, 10000); if(ret 0) return 0; printf(ESP8266已连接WiFi%s\r\n, ssid); return 1; }3TCP 客户端连接连接电脑服务器c运行uint8_t ESP8266_Connect_TCP(uint8_t *ip, uint16_t port) { uint8_t ret 0; uint8_t cipstart_cmd[64]; // 关闭之前的TCP连接 ESP8266_SendCmd((uint8_t*)ATCIPCLOSE, (uint8_t*)OK, 1000); // 建立TCP连接格式ATCIPSTARTTCP,IP,端口 sprintf((char*)cipstart_cmd, ATCIPSTART\TCP\,\%s\,%d, ip, port); ret ESP8266_SendCmd(cipstart_cmd, (uint8_t*)CONNECT, 5000); if(ret 0) return 0; // 查询连接状态 ret ESP8266_SendCmd((uint8_t*)ATCIPSTATUS, (uint8_t*)STATUS:3, 1000); if(ret 0) return 0; printf(TCP连接成功服务器IP%s端口%d\r\n, ip, port); return 1; }4数据上传到 TCP 服务器c运行/** * brief 发送数据到TCP服务器 * param data要发送的数据 * param len数据长度 * retval 1成功0失败 */ uint8_t ESP8266_SendData_TCP(uint8_t *data, uint16_t len) { uint8_t ret 0; uint8_t cipsend_cmd[32]; // 发送数据指令ATCIPSEND长度 sprintf((char*)cipsend_cmd, ATCIPSEND%d, len); ret ESP8266_SendCmd(cipsend_cmd, (uint8_t*), 1000); if(ret 0) return 0; // 发送实际数据 USART1_Clear_Recv_Buf(); USART1_SendString(data); Delay_ms(500); // 等待发送完成 // 检查发送结果 if(strstr((char*)USART1_Recv_Buf, SEND OK) ! NULL) { printf(TCP数据发送成功%s\r\n, data); USART1_Clear_Recv_Buf(); return 1; } else { printf(TCP数据发送失败%s\r\n, USART1_Recv_Buf); USART1_Clear_Recv_Buf(); return 0; } } // 温湿度数据上传封装为JSON格式 void DHT11_Data_Upload(void) { if(DHT11_ReadData(dht11_data) 1) { uint8_t upload_data[64]; // 封装为JSON格式便于服务器解析 sprintf((char*)upload_data, {\temp\:\%d.%d\,\humidity\:\%d.%d\}, dht11_data.temp_int, dht11_data.temp_dec, dht11_data.humidity_int, dht11_data.humidity_dec); ESP8266_SendData_TCP(upload_data, strlen((char*)upload_data)); } else { printf(DHT11数据采集失败\r\n); } }5远程控制指令解析c运行void Cmd_Parse(uint8_t *cmd_buf) { // 解析LED控制指令 if(strstr((char*)cmd_buf, LED_ON_CMD) ! NULL) { LED_On(); // 回复服务器指令执行结果 ESP8266_SendData_TCP((uint8_t*)LED已点亮, strlen(LED已点亮)); } else if(strstr((char*)cmd_buf, LED_OFF_CMD) ! NULL) { LED_Off(); ESP8266_SendData_TCP((uint8_t*)LED已熄灭, strlen(LED已熄灭)); } else { // 未知指令 ESP8266_SendData_TCP((uint8_t*)未知指令, strlen(未知指令)); } } // 处理ESP8266接收的TCP数据 void ESP8266_RecvData_Handle(void) { if(USART1_Recv_Idle 1) { // 普通模式下TCP数据格式为IPD,长度:数据需提取有效数据 uint8_t *ipd_start strstr((char*)USART1_Recv_Buf, IPD,); if(ipd_start ! NULL) { // 提取数据部分跳过IPD,len: uint8_t *data_start strchr(ipd_start, :) 1; printf(收到TCP服务器数据%s\r\n, data_start); // 解析指令 Cmd_Parse(data_start); } USART1_Clear_Recv_Buf(); } }6透传模式配置与通信c运行// 进入透传模式 void ESP8266_Enter_TransparentMode(void) { uint8_t ret 0; // 1. 确保TCP连接已建立 ret ESP8266_SendCmd((uint8_t*)ATCIPSTATUS, (uint8_t*)STATUS:3, 1000); if(ret 0) { printf(TCP未连接无法进入透传模式\r\n); return; } // 2. 设置为透传模式 ret ESP8266_SendCmd((uint8_t*)ATCIPMODE1, (uint8_t*)OK, 1000); if(ret 0) return; // 3. 启动透传发送ATCIPSEND无参数 ret ESP8266_SendCmd((uint8_t*)ATCIPSEND, (uint8_t*), 1000); if(ret 0) return; printf(已进入透传模式数据将直接收发退出请发送无回车换行\r\n); } // 透传模式数据收发主循环中调用 void ESP8266_Transparent_Comm(void) { // 接收TCP数据并转发到串口电脑调试 if(USART1_Recv_Idle 1) { printf(透传接收%s\r\n, USART1_Recv_Buf); USART1_Clear_Recv_Buf(); } // 采集DHT11数据并透传发送 if(DHT11_ReadData(dht11_data) 1) { uint8_t send_data[64]; sprintf((char*)send_data, 透传数据温度%d.%d℃湿度%d.%d%%RH, dht11_data.temp_int, dht11_data.temp_dec, dht11_data.humidity_int, dht11_data.humidity_dec); USART1_SendString(send_data); printf(透传发送%s\r\n, send_data); Delay_ms(5000); // 每5秒发送一次 } }4. 主函数整合四大功能c运行int main(void) { // 初始化系统时钟 SystemInit(); // 初始化基础模块 USART1_Init_ESP8266(); LED_Init(); printf(STM32ESP8266 WiFi实战系统初始化成功\r\n); printf(\r\n\r\n); // 1. ESP8266连接WiFi替换为你的WiFi名称和密码 uint8_t wifi_ssid[] MyWiFi; uint8_t wifi_pwd[] 12345678; uint8_t esp_init_ret ESP8266_Init_STA(wifi_ssid, wifi_pwd); if(esp_init_ret 0) { printf(ESP8266 WiFi连接失败请检查配置\r\n); while(1); } // 2. 连接TCP服务器 uint8_t tcp_connect_ret ESP8266_Connect_TCP((uint8_t*)TCP_SERVER_IP, TCP_SERVER_PORT); if(tcp_connect_ret 0) { printf(TCP连接失败请检查服务器IP和端口\r\n); while(1); } // 选择工作模式0普通模式数据上传远程控制1透传模式 #define WORK_MODE 0 if(WORK_MODE 0) { // 普通模式数据上传远程控制 printf(进入普通模式每5秒上传温湿度支持LED_ON/LED_OFF指令控制\r\n); while(1) { // 每5秒上传一次温湿度数据 static uint32_t upload_cnt 0; if(upload_cnt 5000) { upload_cnt 0; DHT11_Data_Upload(); } // 处理远程控制指令 ESP8266_RecvData_Handle(); Delay_ms(1); } } else { // 透传模式双向透明通信 ESP8266_Enter_TransparentMode(); while(1) { ESP8266_Transparent_Comm(); } } }三、实战步骤与运行效果1. 前期准备1电脑端配置安装网络调试助手如 SSCOM、TCPUDP 测试工具确保电脑与 ESP8266 连接同一 WiFi 路由器打开网络调试助手选择 “TCP 服务器” 模式设置端口为 8080点击 “开启监听”。2代码配置替换代码中的wifi_ssid和wifi_pwd为你的 WiFi 名称和密码替换TCP_SERVER_IP为你的电脑本地 IP通过ipconfig查询选择工作模式WORK_MODE0为普通模式WORK_MODE1为透传模式。2. 普通模式运行效果数据上传 远程控制1数据上传效果STM32 每 5 秒采集一次 DHT11 数据通过 ESP8266 上传到 TCP 服务器网络调试助手接收如下plaintext{temp:25.0,humidity:60.0} {temp:25.1,humidity:60.2}2远程控制效果在网络调试助手发送指令 “LED_ON”STM32 解析后点亮 LED同时回复plaintextLED已点亮发送指令 “LED_OFF”LED 熄灭回复plaintextLED已熄灭3. 透传模式运行效果配置WORK_MODE1系统进入透传模式网络调试助手与 STM32 可直接收发数据STM32 每 5 秒发送透传数据透传数据温度25.0℃湿度60.0%RH网络调试助手发送 “Hello ESP8266”STM32 串口打印透传接收Hello ESP8266无需 AT 指令数据直接透明传输适合高频数据通信。四、ESP8266 实战避坑指南10 高频错误1. TCP 连接失败返回 CONNECT FAIL原因 1ESP8266 与电脑未连接同一 WiFi 路由器解决确保两者在同一局域网重新检查 WiFi 名称和密码原因 2电脑防火墙阻止了 TCP 端口如 8080解决关闭电脑防火墙或在防火墙中放行 8080 端口原因 3服务器 IP 或端口错误解决通过ipconfig重新查询电脑 IP确保端口与网络调试助手一致原因 4ESP8266 已建立其他 TCP 连接解决连接前发送ATCIPCLOSE关闭现有连接。2. 数据发送失败返回 ERROR 或无响应原因 1未建立 TCP 连接解决先调用ESP8266_Connect_TCP建立连接再发送数据原因 2发送数据长度超过 ESP8266 限制单次最大 1460 字节解决分多次发送每次长度≤1460 字节原因 3发送数据前未等待提示符解决发送ATCIPSENDlen后必须等待 ESP8266 返回再发送实际数据。3. 接收不到 TCP 服务器数据原因 1普通模式下未解析IPD格式数据解决在ESP8266_RecvData_Handle中提取IPD,len:后的有效数据原因 2透传模式下未启动透传未发送ATCIPSEND解决进入透传模式后必须发送ATCIPSEND无参数等待后再通信原因 3串口接收缓冲区溢出解决增大USART1_RECV_BUF_LEN如从 256 改为 512 字节。4. 透传模式无法退出原因退出透传模式需发送无回车换行且发送间隔≥1 秒解决在网络调试助手发送不勾选 “自动回车”等待 ESP8266 返回OK即可退出透传模式。5. DHT11 数据采集失败原因 1DHT11 DATA 引脚未接 4.7KΩ 上拉电阻解决添加 4.7KΩ 上拉电阻确保数据传输稳定原因 2延时函数不精准导致起始信号或数据读取错误解决根据 STM32 主频校准DHT11_DelayUs函数。五、总结ESP8266 实战核心要点与进阶方向1. 核心要点回顾ESP8266 实战核心流程硬件连接→WiFi 连接→TCP 连接→数据收发 / 透传普通模式适合低频率数据上传和控制需通过ATCIPSEND发送数据解析IPD格式接收数据透传模式适合高频数据通信无需 AT 指令直接透明传输退出需发送避坑核心供电充足、WiFi 同网、TCP 连接前置、数据格式解析正确。2. 进阶学习方向云平台对接将数据上传到阿里云、腾讯云或 OneNet实现远程监控MQTT 协议通信基于 MQTT 协议轻量级物联网协议实现低功耗、可靠的数据传输手机 APP 开发通过 Android/iOS APP 作为 TCP 客户端实现手机远程控制多设备通信配置 ESP8266 为 AP 模式实现多个 STM32 设备的局域网通信低功耗优化ESP8266 进入休眠模式定时唤醒上传数据延长电池续航。掌握 ESP8266 实战后你已具备物联网设备的无线通信能力可应用于智能家居、远程监控、数据记录仪等场景。下一篇我们将学习 STM32 的 CAN 总线通信实现工业级设备间的高可靠性数据传输
STM32 进阶封神之路(二十六):ESP8266 实战全攻略 ——TCP 通信 + 数据上传 + 远程控制 + 透传模式(库函数 + 代码落地)
STM32 进阶封神之路二十六ESP8266 实战全攻略 ——TCP 通信 数据上传 远程控制 透传模式库函数 代码落地上一篇我们吃透了 ESP8266 的底层原理、AT 指令集和 STM32 硬件连接这一篇聚焦实战落地 —— 基于 STM32F103ESP8266实现 “TCP 客户端连接、温湿度数据上传、手机远程控制 LED、透传模式通信” 四大核心功能所有代码基于 AT 指令开发可直接编译运行覆盖物联网设备的核心应用场景本文结合实战场景从 TCP 连接建立、传感器数据上传、远程控制指令解析到透传模式配置手把手带你搭建完整的 WiFi 通信系统让你真正掌握 ESP8266 的工程应用一、实战准备硬件环境与核心需求1. 硬件清单主控STM32F103C8T6 最小系统板无线模块ESP8266-12F 模块已刷 AT 指令固件传感器DHT11 温湿度传感器单总线外设LEDPB0远程控制、1KΩ 限流电阻、4.7KΩ 上拉电阻DHT11辅助硬件3.3V 电源模块ESP8266 供电、USB-TTL 模块调试、杜邦线、面包板服务器电脑运行网络调试助手模拟 TCP 服务器或手机TCP 客户端 APP。2. 核心实战需求功能 1TCP 客户端连接→ESP8266 作为 TCP 客户端连接电脑网络调试助手的 TCP 服务器功能 2数据上传→STM32 采集 DHT11 温湿度数据通过 ESP8266 上传到 TCP 服务器功能 3远程控制→TCP 服务器电脑 / 手机发送控制指令如 “LED_ON”“LED_OFF”STM32 解析后控制 LED功能 4透传模式→配置 ESP8266 为透传模式实现 STM32 与 TCP 服务器的双向透明通信无需 AT 指令直接收发数据。3. 关键硬件连接1核心连接表STM32 ↔ ESP8266 ↔ 其他模块表格模块引脚STM32 引脚连接说明ESP8266VCC3.3V外部电源3.3V 供电避免 STM32 直接供电电流不足ESP8266GNDGND共地STM32、ESP8266、DHT11 必须共地ESP8266TXPA10USART1_RX交叉连接ESP8266→STM32 数据传输ESP8266RXPA9USART1_TX交叉连接STM32→ESP8266 数据传输ESP8266CH_PD3.3V高电平使能模块不可悬空DHT11VCC3.3V传感器供电DHT11GNDGND共地DHT11DATAPB1单总线数据引脚外接 4.7KΩ 上拉电阻LED正极串 1KΩ 电阻PB0推挽输出低电平点亮LED负极GND2网络拓扑plaintextSTM32 ESP8266TCP客户端 ↔ WiFi路由器 ↔ 电脑TCP服务器网络调试助手关键前提ESP8266 和电脑需连接同一 WiFi 路由器确保局域网通信电脑 IP 查询通过 “ipconfig” 查询本地 IP如 192.168.1.105TCP 服务器端口设为 8080。二、核心代码实现四大功能全流程1. 头文件与全局变量定义c运行#include stm32f10x.h #include stdio.h #include string.h #include stdlib.h // 串口1与ESP8266通信配置 #define USART1_RECV_BUF_LEN 512 uint8_t USART1_Recv_Buf[USART1_RECV_BUF_LEN]; uint16_t USART1_Recv_Cnt 0; uint8_t USART1_Recv_Idle 0; // 接收完成标志位 // DHT11相关定义 typedef struct { uint8_t humidity_int; // 湿度整数部分 uint8_t humidity_dec; // 湿度小数部分DHT11恒为0 uint8_t temp_int; // 温度整数部分 uint8_t temp_dec; // 温度小数部分 uint8_t data_valid; // 数据有效性标志1有效 } DHT11_Data_TypeDef; DHT11_Data_TypeDef dht11_data; // TCP服务器配置替换为你的电脑IP和端口 #define TCP_SERVER_IP 192.168.1.105 #define TCP_SERVER_PORT 8080 // 控制指令定义 #define LED_ON_CMD LED_ON #define LED_OFF_CMD LED_OFF // 延时函数声明 void Delay_ms(uint32_t ms); void DHT11_DelayUs(uint32_t us); // 串口1函数声明 void USART1_Init_ESP8266(void); void USART1_SendByte(uint8_t data); void USART1_SendString(uint8_t *str); uint8_t ESP8266_SendCmd(uint8_t *cmd, uint8_t *resp, uint32_t timeout); uint8_t ESP8266_Init_STA(uint8_t *ssid, uint8_t *pwd); uint8_t ESP8266_Connect_TCP(uint8_t *ip, uint16_t port); void ESP8266_Enter_TransparentMode(void); // DHT11函数声明 void DHT11_Init(void); uint8_t DHT11_ReadData(DHT11_Data_TypeDef *data); // 外设函数声明 void LED_Init(void); void LED_On(void); void LED_Off(void); void Cmd_Parse(uint8_t *cmd_buf);2. 基础模块初始化串口 1LEDDHT111串口 1 初始化与 ESP8266 通信c运行// 串口1发送字节 void USART1_SendByte(uint8_t data) { while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET); USART_SendData(USART1, data); } // 串口1发送字符串 void USART1_SendString(uint8_t *str) { while(*str ! \0) { USART1_SendByte(*str); str; } } // printf重定向 int fputc(int ch, FILE *f) { USART1_SendByte((uint8_t)ch); return ch; } // 串口1中断服务函数接收ESP8266数据 void USART1_IRQHandler(void) { uint8_t recv_data; // 接收非空中断字节接收 if(USART_GetITStatus(USART1, USART_IT_RXNE) ! RESET) { recv_data (uint8_t)USART_ReceiveData(USART1); if(USART1_Recv_Cnt USART1_RECV_BUF_LEN - 1) { USART1_Recv_Buf[USART1_Recv_Cnt] recv_data; } USART_ClearITPendingBit(USART1, USART_IT_RXNE); } // 空闲中断数据接收完成 if(USART_GetITStatus(USART1, USART_IT_IDLE) ! RESET) { USART1_Recv_Buf[USART1_Recv_Cnt] \0; USART1_Recv_Idle 1; // 清除空闲中断标志 recv_data (uint8_t)USART_ReceiveData(USART1); (void)recv_data; } } // 串口1初始化115200bps8N1中断接收 void USART1_Init_ESP8266(void) { GPIO_InitTypeDef GPIO_InitStruct; USART_InitTypeDef USART_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE); // PA9TX复用推挽输出 GPIO_InitStruct.GPIO_Pin GPIO_Pin_9; GPIO_InitStruct.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStruct); // PA10RX浮空输入 GPIO_InitStruct.GPIO_Pin GPIO_Pin_10; GPIO_InitStruct.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStruct); // 串口参数配置 USART_InitStruct.USART_BaudRate 115200; USART_InitStruct.USART_WordLength USART_WordLength_8b; USART_InitStruct.USART_StopBits USART_StopBits_1; USART_InitStruct.USART_Parity USART_Parity_No; USART_InitStruct.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStruct.USART_Mode USART_Mode_Tx | USART_Mode_Rx; USART_Init(USART1, USART_InitStruct); // 使能接收中断和空闲中断 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); // 配置NVIC优先级 NVIC_InitStruct.NVIC_IRQChannel USART1_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority 1; NVIC_InitStruct.NVIC_IRQChannelSubPriority 0; NVIC_InitStruct.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStruct); USART_Cmd(USART1, ENABLE); } // 清空串口1接收缓冲区 void USART1_Clear_Recv_Buf(void) { memset(USART1_Recv_Buf, 0, USART1_RECV_BUF_LEN); USART1_Recv_Cnt 0; USART1_Recv_Idle 0; }2LED 初始化c运行void LED_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStruct.GPIO_Pin GPIO_Pin_0; GPIO_InitStruct.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOB, GPIO_InitStruct); GPIO_SetBits(GPIOB, GPIO_Pin_0); // 初始熄灭 } void LED_On(void) { GPIO_ResetBits(GPIOB, GPIO_Pin_0); printf(LED已点亮\r\n); } void LED_Off(void) { GPIO_SetBits(GPIOB, GPIO_Pin_0); printf(LED已熄灭\r\n); }3DHT11 初始化与数据采集c运行// DHT11 GPIO模式切换 void DHT11_SetOutputMode(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStruct.GPIO_Pin GPIO_Pin_1; GPIO_InitStruct.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed GPIO_Speed_2MHz; GPIO_Init(GPIOB, GPIO_InitStruct); } void DHT11_SetInputMode(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStruct.GPIO_Pin GPIO_Pin_1; GPIO_InitStruct.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOB, GPIO_InitStruct); } // 微秒级延时 void DHT11_DelayUs(uint32_t us) { uint32_t i; for(i 0; i us * 9; i); // 72MHz主频下校准 } // 毫秒级延时 void Delay_ms(uint32_t ms) { uint32_t i, j; for(i 0; i ms; i) { for(j 0; j 1000; j); } } // DHT11发送起始信号 uint8_t DHT11_SendStart(void) { DHT11_SetOutputMode(); GPIO_ResetBits(GPIOB, GPIO_Pin_1); Delay_ms(20); // 拉低≥18ms GPIO_SetBits(GPIOB, GPIO_Pin_1); DHT11_DelayUs(30); // 拉高20~40us DHT11_SetInputMode(); // 等待DHT11响应 if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) 0) { // 检测响应低电平 while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) 0); // 检测响应高电平 while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) 1); return 1; // 响应成功 } return 0; // 响应失败 } // DHT11读取1位数据 uint8_t DHT11_ReadBit(void) { uint8_t bit_val 0; // 低电平起始50us while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) 0); // 高电平持续时间决定数据026~28us170us DHT11_DelayUs(40); if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) 1) { bit_val 1; while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) 1); } return bit_val; } // DHT11读取1字节数据 uint8_t DHT11_ReadByte(void) { uint8_t byte_val 0; for(uint8_t i 0; i 8; i) { byte_val 1; byte_val | DHT11_ReadBit(); } return byte_val; } // DHT11读取温湿度数据 uint8_t DHT11_ReadData(DHT11_Data_TypeDef *data) { uint8_t humidity_int, humidity_dec, temp_int, temp_dec, check_sum; if(DHT11_SendStart() 0) { data-data_valid 0; return 0; } // 读取40位数据 humidity_int DHT11_ReadByte(); humidity_dec DHT11_ReadByte(); temp_int DHT11_ReadByte(); temp_dec DHT11_ReadByte(); check_sum DHT11_ReadByte(); // 校验数据 if(check_sum (humidity_int humidity_dec temp_int temp_dec)) { data-humidity_int humidity_int; data-humidity_dec humidity_dec; data-temp_int temp_int; data-temp_dec temp_dec; data-data_valid 1; return 1; } else { data-data_valid 0; return 0; } }3. ESP8266 核心功能实现TCP 连接 数据上传 透传1AT 指令发送与响应判断c运行uint8_t ESP8266_SendCmd(uint8_t *cmd, uint8_t *resp, uint32_t timeout) { USART1_Clear_Recv_Buf(); USART1_SendString(cmd); USART1_SendByte(\r); USART1_SendByte(\n); uint32_t start_time SystemCoreClock / 1000 * timeout; while(start_time--) { if(USART1_Recv_Idle 1) { if(strstr((char*)USART1_Recv_Buf, (char*)resp) ! NULL) { printf(发送指令%s 响应%s\r\n, cmd, USART1_Recv_Buf); USART1_Clear_Recv_Buf(); return 1; } else { printf(发送指令%s 响应异常%s\r\n, cmd, USART1_Recv_Buf); USART1_Clear_Recv_Buf(); return 0; } } Delay_ms(1); } printf(发送指令%s 超时无响应\r\n, cmd); USART1_Clear_Recv_Buf(); return 0; }2ESP8266 STA 模式初始化连接 WiFic运行uint8_t ESP8266_Init_STA(uint8_t *ssid, uint8_t *pwd) { uint8_t ret 0; // 测试模块是否在线 ret ESP8266_SendCmd((uint8_t*)AT, (uint8_t*)OK, 1000); if(ret 0) return 0; // 重启模块 ret ESP8266_SendCmd((uint8_t*)ATRST, (uint8_t*)OK, 3000); if(ret 0) return 0; Delay_ms(2000); // 设置为STA模式 ret ESP8266_SendCmd((uint8_t*)ATCWMODE1, (uint8_t*)OK, 1000); if(ret 0) return 0; // 连接WiFi uint8_t cwjap_cmd[64]; sprintf((char*)cwjap_cmd, ATCWJAP\%s\,\%s\, ssid, pwd); ret ESP8266_SendCmd(cwjap_cmd, (uint8_t*)OK, 10000); if(ret 0) return 0; printf(ESP8266已连接WiFi%s\r\n, ssid); return 1; }3TCP 客户端连接连接电脑服务器c运行uint8_t ESP8266_Connect_TCP(uint8_t *ip, uint16_t port) { uint8_t ret 0; uint8_t cipstart_cmd[64]; // 关闭之前的TCP连接 ESP8266_SendCmd((uint8_t*)ATCIPCLOSE, (uint8_t*)OK, 1000); // 建立TCP连接格式ATCIPSTARTTCP,IP,端口 sprintf((char*)cipstart_cmd, ATCIPSTART\TCP\,\%s\,%d, ip, port); ret ESP8266_SendCmd(cipstart_cmd, (uint8_t*)CONNECT, 5000); if(ret 0) return 0; // 查询连接状态 ret ESP8266_SendCmd((uint8_t*)ATCIPSTATUS, (uint8_t*)STATUS:3, 1000); if(ret 0) return 0; printf(TCP连接成功服务器IP%s端口%d\r\n, ip, port); return 1; }4数据上传到 TCP 服务器c运行/** * brief 发送数据到TCP服务器 * param data要发送的数据 * param len数据长度 * retval 1成功0失败 */ uint8_t ESP8266_SendData_TCP(uint8_t *data, uint16_t len) { uint8_t ret 0; uint8_t cipsend_cmd[32]; // 发送数据指令ATCIPSEND长度 sprintf((char*)cipsend_cmd, ATCIPSEND%d, len); ret ESP8266_SendCmd(cipsend_cmd, (uint8_t*), 1000); if(ret 0) return 0; // 发送实际数据 USART1_Clear_Recv_Buf(); USART1_SendString(data); Delay_ms(500); // 等待发送完成 // 检查发送结果 if(strstr((char*)USART1_Recv_Buf, SEND OK) ! NULL) { printf(TCP数据发送成功%s\r\n, data); USART1_Clear_Recv_Buf(); return 1; } else { printf(TCP数据发送失败%s\r\n, USART1_Recv_Buf); USART1_Clear_Recv_Buf(); return 0; } } // 温湿度数据上传封装为JSON格式 void DHT11_Data_Upload(void) { if(DHT11_ReadData(dht11_data) 1) { uint8_t upload_data[64]; // 封装为JSON格式便于服务器解析 sprintf((char*)upload_data, {\temp\:\%d.%d\,\humidity\:\%d.%d\}, dht11_data.temp_int, dht11_data.temp_dec, dht11_data.humidity_int, dht11_data.humidity_dec); ESP8266_SendData_TCP(upload_data, strlen((char*)upload_data)); } else { printf(DHT11数据采集失败\r\n); } }5远程控制指令解析c运行void Cmd_Parse(uint8_t *cmd_buf) { // 解析LED控制指令 if(strstr((char*)cmd_buf, LED_ON_CMD) ! NULL) { LED_On(); // 回复服务器指令执行结果 ESP8266_SendData_TCP((uint8_t*)LED已点亮, strlen(LED已点亮)); } else if(strstr((char*)cmd_buf, LED_OFF_CMD) ! NULL) { LED_Off(); ESP8266_SendData_TCP((uint8_t*)LED已熄灭, strlen(LED已熄灭)); } else { // 未知指令 ESP8266_SendData_TCP((uint8_t*)未知指令, strlen(未知指令)); } } // 处理ESP8266接收的TCP数据 void ESP8266_RecvData_Handle(void) { if(USART1_Recv_Idle 1) { // 普通模式下TCP数据格式为IPD,长度:数据需提取有效数据 uint8_t *ipd_start strstr((char*)USART1_Recv_Buf, IPD,); if(ipd_start ! NULL) { // 提取数据部分跳过IPD,len: uint8_t *data_start strchr(ipd_start, :) 1; printf(收到TCP服务器数据%s\r\n, data_start); // 解析指令 Cmd_Parse(data_start); } USART1_Clear_Recv_Buf(); } }6透传模式配置与通信c运行// 进入透传模式 void ESP8266_Enter_TransparentMode(void) { uint8_t ret 0; // 1. 确保TCP连接已建立 ret ESP8266_SendCmd((uint8_t*)ATCIPSTATUS, (uint8_t*)STATUS:3, 1000); if(ret 0) { printf(TCP未连接无法进入透传模式\r\n); return; } // 2. 设置为透传模式 ret ESP8266_SendCmd((uint8_t*)ATCIPMODE1, (uint8_t*)OK, 1000); if(ret 0) return; // 3. 启动透传发送ATCIPSEND无参数 ret ESP8266_SendCmd((uint8_t*)ATCIPSEND, (uint8_t*), 1000); if(ret 0) return; printf(已进入透传模式数据将直接收发退出请发送无回车换行\r\n); } // 透传模式数据收发主循环中调用 void ESP8266_Transparent_Comm(void) { // 接收TCP数据并转发到串口电脑调试 if(USART1_Recv_Idle 1) { printf(透传接收%s\r\n, USART1_Recv_Buf); USART1_Clear_Recv_Buf(); } // 采集DHT11数据并透传发送 if(DHT11_ReadData(dht11_data) 1) { uint8_t send_data[64]; sprintf((char*)send_data, 透传数据温度%d.%d℃湿度%d.%d%%RH, dht11_data.temp_int, dht11_data.temp_dec, dht11_data.humidity_int, dht11_data.humidity_dec); USART1_SendString(send_data); printf(透传发送%s\r\n, send_data); Delay_ms(5000); // 每5秒发送一次 } }4. 主函数整合四大功能c运行int main(void) { // 初始化系统时钟 SystemInit(); // 初始化基础模块 USART1_Init_ESP8266(); LED_Init(); printf(STM32ESP8266 WiFi实战系统初始化成功\r\n); printf(\r\n\r\n); // 1. ESP8266连接WiFi替换为你的WiFi名称和密码 uint8_t wifi_ssid[] MyWiFi; uint8_t wifi_pwd[] 12345678; uint8_t esp_init_ret ESP8266_Init_STA(wifi_ssid, wifi_pwd); if(esp_init_ret 0) { printf(ESP8266 WiFi连接失败请检查配置\r\n); while(1); } // 2. 连接TCP服务器 uint8_t tcp_connect_ret ESP8266_Connect_TCP((uint8_t*)TCP_SERVER_IP, TCP_SERVER_PORT); if(tcp_connect_ret 0) { printf(TCP连接失败请检查服务器IP和端口\r\n); while(1); } // 选择工作模式0普通模式数据上传远程控制1透传模式 #define WORK_MODE 0 if(WORK_MODE 0) { // 普通模式数据上传远程控制 printf(进入普通模式每5秒上传温湿度支持LED_ON/LED_OFF指令控制\r\n); while(1) { // 每5秒上传一次温湿度数据 static uint32_t upload_cnt 0; if(upload_cnt 5000) { upload_cnt 0; DHT11_Data_Upload(); } // 处理远程控制指令 ESP8266_RecvData_Handle(); Delay_ms(1); } } else { // 透传模式双向透明通信 ESP8266_Enter_TransparentMode(); while(1) { ESP8266_Transparent_Comm(); } } }三、实战步骤与运行效果1. 前期准备1电脑端配置安装网络调试助手如 SSCOM、TCPUDP 测试工具确保电脑与 ESP8266 连接同一 WiFi 路由器打开网络调试助手选择 “TCP 服务器” 模式设置端口为 8080点击 “开启监听”。2代码配置替换代码中的wifi_ssid和wifi_pwd为你的 WiFi 名称和密码替换TCP_SERVER_IP为你的电脑本地 IP通过ipconfig查询选择工作模式WORK_MODE0为普通模式WORK_MODE1为透传模式。2. 普通模式运行效果数据上传 远程控制1数据上传效果STM32 每 5 秒采集一次 DHT11 数据通过 ESP8266 上传到 TCP 服务器网络调试助手接收如下plaintext{temp:25.0,humidity:60.0} {temp:25.1,humidity:60.2}2远程控制效果在网络调试助手发送指令 “LED_ON”STM32 解析后点亮 LED同时回复plaintextLED已点亮发送指令 “LED_OFF”LED 熄灭回复plaintextLED已熄灭3. 透传模式运行效果配置WORK_MODE1系统进入透传模式网络调试助手与 STM32 可直接收发数据STM32 每 5 秒发送透传数据透传数据温度25.0℃湿度60.0%RH网络调试助手发送 “Hello ESP8266”STM32 串口打印透传接收Hello ESP8266无需 AT 指令数据直接透明传输适合高频数据通信。四、ESP8266 实战避坑指南10 高频错误1. TCP 连接失败返回 CONNECT FAIL原因 1ESP8266 与电脑未连接同一 WiFi 路由器解决确保两者在同一局域网重新检查 WiFi 名称和密码原因 2电脑防火墙阻止了 TCP 端口如 8080解决关闭电脑防火墙或在防火墙中放行 8080 端口原因 3服务器 IP 或端口错误解决通过ipconfig重新查询电脑 IP确保端口与网络调试助手一致原因 4ESP8266 已建立其他 TCP 连接解决连接前发送ATCIPCLOSE关闭现有连接。2. 数据发送失败返回 ERROR 或无响应原因 1未建立 TCP 连接解决先调用ESP8266_Connect_TCP建立连接再发送数据原因 2发送数据长度超过 ESP8266 限制单次最大 1460 字节解决分多次发送每次长度≤1460 字节原因 3发送数据前未等待提示符解决发送ATCIPSENDlen后必须等待 ESP8266 返回再发送实际数据。3. 接收不到 TCP 服务器数据原因 1普通模式下未解析IPD格式数据解决在ESP8266_RecvData_Handle中提取IPD,len:后的有效数据原因 2透传模式下未启动透传未发送ATCIPSEND解决进入透传模式后必须发送ATCIPSEND无参数等待后再通信原因 3串口接收缓冲区溢出解决增大USART1_RECV_BUF_LEN如从 256 改为 512 字节。4. 透传模式无法退出原因退出透传模式需发送无回车换行且发送间隔≥1 秒解决在网络调试助手发送不勾选 “自动回车”等待 ESP8266 返回OK即可退出透传模式。5. DHT11 数据采集失败原因 1DHT11 DATA 引脚未接 4.7KΩ 上拉电阻解决添加 4.7KΩ 上拉电阻确保数据传输稳定原因 2延时函数不精准导致起始信号或数据读取错误解决根据 STM32 主频校准DHT11_DelayUs函数。五、总结ESP8266 实战核心要点与进阶方向1. 核心要点回顾ESP8266 实战核心流程硬件连接→WiFi 连接→TCP 连接→数据收发 / 透传普通模式适合低频率数据上传和控制需通过ATCIPSEND发送数据解析IPD格式接收数据透传模式适合高频数据通信无需 AT 指令直接透明传输退出需发送避坑核心供电充足、WiFi 同网、TCP 连接前置、数据格式解析正确。2. 进阶学习方向云平台对接将数据上传到阿里云、腾讯云或 OneNet实现远程监控MQTT 协议通信基于 MQTT 协议轻量级物联网协议实现低功耗、可靠的数据传输手机 APP 开发通过 Android/iOS APP 作为 TCP 客户端实现手机远程控制多设备通信配置 ESP8266 为 AP 模式实现多个 STM32 设备的局域网通信低功耗优化ESP8266 进入休眠模式定时唤醒上传数据延长电池续航。掌握 ESP8266 实战后你已具备物联网设备的无线通信能力可应用于智能家居、远程监控、数据记录仪等场景。下一篇我们将学习 STM32 的 CAN 总线通信实现工业级设备间的高可靠性数据传输