ESP8266接入STM32F103:AT指令配置、透传模式与调试实战
2026/9/14 7:12:50 网站建设 项目流程

简介:这是一套基于STM32F103与ESP8266的物联网通信实验工程,面向嵌入式初学者与物联网爱好者,重点解决Wi-Fi模块选型、接线、AT指令配置、串口收发和主控协同等问题。压缩包内共117个文件,以56个C源码文件、50个H头文件为主,辅以5个HEX固件、链接脚本、Keil工程配置和批处理脚本,便于直接导入工程编译烧录;整体压缩后仅436KB,小巧完整。目前已有976人学习浏览,尤其适合对照实验手册边看边练,理解ESP8266硬件接口、I2C通信方式以及STM32F103外设驱动开发流程。资源目录清晰,工程内集成标准外设库的定时器、串口、I2C、ADC等模块代码,可快速复现实验现象,也能作为课程设计或物联网小项目的底层参考。工程中附带链接脚本与清理脚本,可辅助完成编译下载与中间文件管理,适合作为STM32标准库项目模板复用。

1. 把ESP8266接进STM32F103,第一步不是写代码

很多人拿到ESP8266模块第一反应是打开Keil开始敲代码,但实际调试过就会发现,真正卡住进度的往往不是程序,而是模块根本没进AT模式、波特率对不上、或者供电不足导致无限重启。这个实验10的核心,其实就是把ESP8266当作一个“Wi-Fi网卡”挂在STM32F103旁边:MCU通过串口发AT指令,ESP8266负责连接路由器、建立TCP/UDP通道、收发网络数据。STM32F103不需要理解TCP/IP协议栈,所有网络逻辑都交给ESP8266的固件处理,MCU只做串口数据的搬运和解析。

这个方案适合谁?如果你在做物联网网关、远程设备监控、或者给现有STM32项目增加联网能力,ESP8266是最短路径。它支持802.11 b/g/n,工作在2.4GHz频段,成本低、资料多,而且可以直接用AT指令集控制,不需要额外写驱动。下面从硬件连接开始,把整个链路的每个环节拆开讲。

2. 硬件连接与引脚分配:UART是主线,I2C是支线

2.1 模块选型:ESP-01S还是ESP-12F

ESP8266在市面上最常见的封装是ESP-01S和ESP-12F。ESP-01S引出引脚少,GPIO0和GPIO2各一个,适合做纯透传;ESP-12F引出引脚多,有ADC、多个GPIO、完整的UART引脚,适合需要同时控制传感器或灯带的场景。

实验资源里出现了i2cwifi模块这个关键词,这里需要澄清一个概念:ESP8266本身没有硬件I2C外设,所谓的“I2C WiFi模块”通常是指用GPIO软件模拟I2C时序,或者是指某个集成了I2C接口转接板的ESP8266变体。在STM32F103这一侧,硬件I2C外设的稳定性一直有争议,很多人直接用GPIO模拟I2C。如果ESP8266需要和STM32通过I2C通信,实际上是用两根GPIO线模拟I2C协议,把AT指令响应包装成I2C读写操作。但最常见的做法仍然是UART,因为ESP8266的固件默认就是通过UART接收AT指令的。

2.2 引脚连接表与电平匹配

STM32F103是3.3V逻辑电平,ESP8266也是3.3V供电和3.3V逻辑,两者可以直接相连,不需要电平转换。但如果你的开发板上有5V的USB转TTL模块,调试时要注意跳线选择3.3V。

STM32F103引脚ESP8266引脚说明
PA9 (USART1_TX)RXDSTM32发送数据给ESP8266
PA10 (USART1_RX)TXDESP8266发送数据给STM32
GNDGND共地必须连接
3.3VVCC供电,见下文注意事项
不连接CH_PD (EN)必须拉高,否则模块不工作
不连接GPIO0悬空或拉高,进入运行模式

CH_PD引脚(也叫EN)是ESP8266的使能脚,必须接3.3V。很多初学者忘记处理这个引脚,导致模块毫无反应。GPIO0在正常运行模式下必须拉高或悬空,如果拉低则会进入固件下载模式,此时模块不会响应AT指令。

提示:ESP8266的VCC不能直接接STM32F103的3.3V引脚输出。ESP8266在Wi-Fi发射瞬间电流峰值可达300mA以上,而STM32F103的LDO输出能力通常在150mA左右。如果直接供电,模块会反复重启。建议用AMS1117-3.3或者专门的降压模块供电。

2.3 烧录模式与运行模式的切换

ESP8266支持两种启动模式,由GPIO0和GPIO15的电平决定。对于ESP-01S,只需要关注GPIO0:

GPIO0GPIO15模式
固件下载(UART烧录)
正常运行(Flash启动)

如果要用串口烧录ESP8266固件,需要把GPIO0拉低再上电。烧录完成后,断电,GPIO0悬空或拉高,重新上电进入运行模式。这个操作在实验中很容易被忽视——很多人的模块第一次能烧录,之后怎么发AT指令都没反应,就是因为GPIO0一直处于低电平。

这里还涉及到一个常见的STM32F103启动配置问题:BOOT0和BOOT1引脚决定STM32从哪启动。实验10的代码如果是通过SWD下载到Flash,BOOT0应该接地,从主Flash启动。如果BOOT0接高电平,STM32进入ISP模式,用户程序不会运行,串口自然也不会有数据。

3. 让ESP8266连上Wi-Fi:AT指令配置与联网状态验证

3.1 串口助手先验证模块

在写STM32代码之前,先用USB转TTL模块把ESP8266单独接到电脑上,用串口助手验证模块是否正常。ESP8266默认波特率通常是115200(部分固件是9600或74880),打开串口助手后发送AT,模块应该返回OK

发送: AT 接收: OK

如果没有任何响应,依次检查:VCC电压是否稳定、CH_PD是否拉高、TXD和RXD是否交叉连接、串口助手的波特率是否匹配。如果模块返回乱码,说明波特率不匹配,尝试74880——这是ESP8266上电时ROM打印信息的波特率,很多情况下固件启动后自动切换到了115200。

3.2 配置Wi-Fi工作模式

ESP8266有三种工作模式:Station(连接路由器)、SoftAP(自己开热点)、Station+SoftAP(同时工作)。实验场景中,STM32需要访问网络,所以通常设置为Station模式或Station+SoftAP模式。

AT+CWMODE=1 // 设置为Station模式 AT+CWMODE=3 // 设置为Station+SoftAP混合模式

参数说明:

  • 1:Station模式,ESP8266连接现有路由器
  • 2:SoftAP模式,ESP8266自己创建热点,其它设备连接它
  • 3:混合模式,同时连接路由器和创建热点

实验调试阶段推荐用Station模式,行为最简单,不会出现热点信号干扰。

3.3 连接路由器并查看IP

配置完模式后,发送连接路由器的指令。以SSID为"MyWiFi"、密码为"12345678"为例:

AT+CWJAP="MyWiFi","12345678"

返回WIFI CONNECTED后再返回WIFI GOT IP,表示关联成功并且DHCP获取到了IP地址。如果返回FAIL,检查SSID和密码是否包含不可见字符、路由器是否开启了MAC过滤、路由器信号频道是否为2.4GHz(ESP8266不支持5GHz)。

连接成功后,用下面两条指令确认状态:

AT+CWJAP? // 查询当前连接的路由器 AT+CIFSR // 查询模块IP地址

AT+CIFSR返回结果类似:

+CIFSR:STAIP,"192.168.1.100" +CIFSR:STAMAC,"5c:cf:7f:xx:xx:xx"

这个IP地址后面会用到——如果STM32作为TCP客户端连接局域网内的服务器,需要知道服务器的IP;如果ESP8266作为TCP服务器,客户端需要连接这个IP。

3.4 TCP透传模式与波特率设置

实验10的核心任务通常是让STM32通过ESP8266实现TCP通信。ESP8266支持AT指令直接收发TCP数据,也支持透传模式(Transparent Transmission)。透传模式下,串口收到的所有数据都会直接发往TCP连接对端,不再解析AT指令,这对MCU来说最省事。

先建立TCP连接,以连接TCP服务器192.168.1.50的端口8080为例:

AT+CIPSTART="TCP","192.168.1.50",8080

返回CONNECTOK后,开启透传模式:

AT+CIPMODE=1

然后发送以下指令进入透传状态:

AT+CIPSEND

此时模块返回>,之后串口发送的任何数据都会直接通过TCP连接发出去。如果要退出透传模式,发送+++(不带回车换行),模块会返回OK,回到AT指令模式。

这里有一个很容易踩的坑:进入透传模式后,STM32发的AT指令会被当成数据处理,直接发到TCP服务器。所以透传模式必须放在所有配置完成之后、正式通信之前才开启。而且要记住,退出透传的唯一方式是+++,这就要求STM32的代码里预留一个“退出透传”的控制逻辑,否则一旦需要重新配置就得重启模块。

4. STM32F103端程序设计:串口驱动、状态解析与数据转发

4.1 STM32F103的串口资源分配

实验10的源码涉及stm32f10x_usart.cstm32f10x_tim.c,说明工程里同时启用了串口和定时器。STM32F103有多个串口,常用的分配方案是:

串口引脚用途
USART1PA9/PA10ESP8266通信(默认)
USART2PA2/PA3调试日志输出
USART3PB10/PB11备用或传感器数据接入

USART1是STM32F103上最常用的串口,因为它的引脚在SWD调试接口附近,方便接线。USART2的PA2/PA3往往被占用,因为PA2也可能是DAC输出引脚。如果实验板上有其它外设占用PA9/PA10,可以改用USART2,但注意修改中断向量和时钟使能代码。

4.2 串口中断接收与环形缓冲区

ESP8266返回的数据是异步到达的,STM32串口必须用中断接收,否则会丢数据。最简单的方案是每接收到一个字节就触发中断,把数据写入环形缓冲区。下面是一个典型的环形缓冲区实现:

#define RX_BUFFER_SIZE 512 volatile uint8_t rx_buffer[RX_BUFFER_SIZE]; volatile uint16_t rx_head = 0; volatile uint16_t rx_tail = 0; void USART1_IRQHandler(void) { if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { uint8_t data = USART_ReceiveData(USART1); uint16_t next_head = (rx_head + 1) % RX_BUFFER_SIZE; if (next_head != rx_tail) // 缓冲区未满 { rx_buffer[rx_head] = data; rx_head = next_head; } else { // 缓冲区溢出,丢弃新数据,可在此加调试计数 } } } uint16_t RX_GetData(uint8_t *data, uint16_t max_len) { uint16_t len = 0; while (rx_tail != rx_head && len < max_len) { data[len++] = rx_buffer[rx_tail]; rx_tail = (rx_tail + 1) % RX_BUFFER_SIZE; } return len; }

逻辑说明:

  • 环形缓冲区的核心是head和tail两个指针,head指向下一个写入位置,tail指向下一个读取位置
  • RXNE中断标志位为1时,表示接收数据寄存器非空,此时读取数据寄存器就会自动清除标志
  • 缓冲区满时丢弃新数据,避免覆盖未读取的旧数据
  • 中断服务函数要尽量短,只做数据搬运,不做字符串解析

参数说明:

  • RX_BUFFER_SIZE:缓冲区大小,512字节足够应对AT指令响应,如果透传数据量大可以调到1024或2048
  • USART_IT_RXNE:接收中断使能标志,需要在主程序中调用USART_ITConfig开启

这段代码是ST官方标准库的常用写法,不依赖操作系统,中断延迟极低。如果用的是HAL库,对应的是HAL_UART_RxCpltCallback回调函数。

4.3 AT指令的“发送-等待响应”状态机

ESP8266的AT指令响应时间不固定,连接路由器时可能耗时数秒,所以STM32不能简单地发送指令后死等。正确做法是用一个状态机:主循环发送指令,串口中断接收数据,然后在主循环中检查是否收到了预期的响应字符串。

typedef enum { STATE_IDLE, STATE_WAIT_OK, STATE_WAIT_CONNECT, STATE_WAIT_GOT_IP, STATE_TRANSPARENT } esp_state_t; esp_state_t esp_state = STATE_IDLE; uint8_t at_cmd[64]; void ESP_SendCommand(const char *cmd) { // 清空接收缓冲区,确保之前残留的数据不影响新一轮匹配 rx_head = rx_tail = 0; // 发送AT指令字符串 while (*cmd) { while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); USART_SendData(USART1, *cmd++); } // 自动补回车换行 USART_SendData(USART1, '\r'); } void ESP_HandleResponse(void) { char buf[128]; uint16_t len = RX_GetData((uint8_t *)buf, sizeof(buf) - 1); if (len == 0) return; buf[len] = '\0'; switch (esp_state) { case STATE_WAIT_OK: if (strstr(buf, "OK")) { esp_state = STATE_IDLE; } break; case STATE_WAIT_CONNECT: if (strstr(buf, "WIFI CONNECTED") && strstr(buf, "WIFI GOT IP")) { esp_state = STATE_IDLE; } else if (strstr(buf, "FAIL")) { // 连接失败,可以重试或报警 esp_state = STATE_IDLE; } break; default: break; } }

逻辑说明:

  • 发送AT指令前先清空缓冲区,避免上一次的残留响应干扰当前匹配
  • 使用strstr而不是strcmp,因为AT响应在不可见字符后可能附带其它信息,只要包含目标字符串即可认为匹配
  • 连接路由器时,响应是分两行返回的,需要同时匹配WIFI CONNECTEDWIFI GOT IP

参数说明:

  • USART_FLAG_TXE:发送数据寄存器空标志,为1时才能写入新数据
  • AT响应超时:建议用定时器实现超时重发机制,例如每500ms检查一次状态,超过3秒没有匹配到目标字符串就重新发送指令

4.4 透传模式下的数据转发

进入透传模式后,STM32不再解析ESP8266返回的内容,而是直接把串口收到的数据转发给用户逻辑。此时状态机切换到STATE_TRANSPARENT,主循环中定期消费缓冲区数据:

void Loop_ProcessTansparentData(void) { uint8_t buf[256]; uint16_t len = RX_GetData(buf, sizeof(buf)); if (len > 0) { // 转发到日志串口或用户处理函数 // 注意:透传模式下,数据不做任何过滤和解析 ProcessNetworkData(buf, len); } }

这里有一个关键点:SPI和I2C可以按寄存器或字节精确读写,但串口数据是流式的,没有帧边界。如果网络协议里定义了帧头、帧尾或长度字段,STM32必须在ProcessNetworkData中自行做拆包处理。常见做法是:用一个接收状态机,搜索帧头,累计长度,接收完成后触发一帧数据的处理。

5. 进阶:离线数据缓存、WS2812灯带控制与常见故障排查

5.1 掉线自动重连

ESP8266在运行过程中可能因为路由器重启、信号干扰等原因掉线。AT固件提供了一个命令可以自动重连:

AT+CWJAP="MyWiFi","12345678" // 主动连接 AT+CIPSTART="TCP","192.168.1.50",8080 // 建立连接

掉线检测有两种思路。第一种是TCP连接层面:定期发送心跳包,如果在N秒内没有收到对端响应,判定为掉线,执行重连流程。第二种是AT响应层面:在透传模式下向对端发送数据时,如果ESP8266的TCP连接已断开,模块会返回CLOSEDERROR,此时退出透传模式,重新执行AT指令建立连接。

具体的重连序列是:+++退出透传,等待返回OK,然后发送AT+CIPSTART重新建立TCP连接,再发送AT+CIPMODE=1AT+CIPSEND重新进入透传。整个流程耗时约1-2秒。

5.2 用ESP8266控制WS2812灯带的特殊方案

最新网络热词里出现了“esp8266无线控制ws2812灯带源码包,含渐变/海浪/滚动等10+灯光效果”。这个场景下,ESP8266可以作为独立的主控直接驱动WS2812灯带,不经过STM32。WS2812是单线归零码协议,需要微秒级精度的时序,ESP8266可以用RMT外设或者GPIO模拟的方式实现。

如果你的系统里STM32F103需要控制WS2812,有两种路线:一是STM32用定时器PWM+中断模拟WS2812时序,生成颜色数据后通过串口发给ESP8266转发;二是ESP8266运行独立的固件,监听UDP端口,STM32只发送颜色值到指定IP和端口,ESP8266收到后更新灯带。第二种路线更常见,因为WS2812时序要求高,ESP8266的RMT外设天然适合。

STM32用UDP广播颜色值的示例:

AT+CIPSTART="UDP","192.168.1.255",7000,7000,2

参数说明:

  • 目标IP填255.255.255.255192.168.1.255实现局域网广播
  • 目标端口和本地端口都填7000
  • 最后一个2表示UDP连接固定对端地址

然后发送:AT+CIPSEND,再发送RGB数据包头+灯珠数量+颜色序列。ESP8266端固件解析后直接驱动灯带。这比通过STM32 GPIO硬编码WS2812时序更灵活,因为效果算法都跑在ESP8266上,STM32只负责业务逻辑。

5.3 常见故障速查表与排查技巧

现象可能原因排查步骤
ESP8266上电后反复重启供电不足万用表量VCC电压,发射时若跌到3.0V以下,换独立电源
AT指令无响应CH_PD未拉高检查CH_PD引脚电平,必须为3.3V
串口输出乱码波特率不匹配依次尝试115200/9600/74880
连不上路由器路由器5GHz频道确认路由器开启了2.4GHz频段
透传模式退出不了发送的+++带了回车退出用+++,后面不加任何字符
STM32发送AT无响应TX/RX接反交叉检查接线,TX接RXD,RX接TXD

还有一个调试技巧值得分享:在STM32代码里加一个“AT指令回显测试”功能,开机长按按键时,把STM32串口接收到的所有数据原样丢弃,同时把调试串口收到的任何字符串直接转发给ESP8266。这样就不需要反复烧录固件,直接用串口助手发AT指令调试ESP8266,确认配置没问题后再烧入正式程序。这个技巧在调试阶段能节省大量时间,尤其是当你的代码里状态机逻辑和AT指令响应纠缠在一起时,先用裸模块确定Wi-Fi环境没问题,再回到STM32侧排错,效率高得多。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询