文章目录
- 前言
- 一、硬件准备
- 二、STM32与ESP-01S连接
- [三、ESP-01S 工作模式](#三、ESP-01S 工作模式)
- [四、STM32 工程软件结构](#四、STM32 工程软件结构)
- [五、ESP8266 初始化与测试](#五、ESP8266 初始化与测试)
- [六、连接 WiFi和开启TCP Server](#六、连接 WiFi和开启TCP Server)
- 七、USART1和USART2数据传输
- [八、main.c 处理手机数据](#八、main.c 处理手机数据)
- [九、手机 TCP 客户端连接与电脑串口传输数据](#九、手机 TCP 客户端连接与电脑串口传输数据)
- 十、代码示例
- 十一、效果展示
- 十二、常见问题
前言
上一篇介绍了ESP-01S简单测试和实现通讯常用AT指令,这一篇实现F103与ESP-01S的WiFi通讯。如果不清楚ESP-01S常用AT指令可以参考这篇文章:STM32F103C8T6连接ESP-01S实现WiFi通信:TCP客户端开发实战(一)
一、硬件准备
| 硬件 | 作用 |
|---|---|
| STM32F103C8T6 | 主控制器 |
| ESP-01S | WiFi模块 |
| USB-TTL | 用于调试ESP-01S |
| 手机开启热点 | 提供无线网络 |
ESP-01S本质上就是一个ESP8266模块。它本身已经集成了WiFi功能,并且可以运行AT固件。因此STM32不需要了解复杂的WiFi底层协议,只需要通过串口给ESP-01S发送命令即可。
二、STM32与ESP-01S连接
| STM32F103C8T6 | ESP-01S |
|---|---|
| PA2 | RX |
| PA3 | TX |
| PA9 | USB转TTL -> RX |
| PA10 | USB转TTL -> TX |
注意:我们在拿到优信的ESP01S之后可以通过他的规格书查到其工作电压为3.3V,不要直接给ESP-01S使用5V供电。另外,ESP8266在WiFi发送数据的时候电流会明显增加,所以ESP-01S的3.3V电源一定要稳定。如果使用STM32开发板上的3.3V给ESP-01S供电,建议确认一下3.3V稳压器的带载能力。
三、ESP-01S 工作模式
ESP8266 可以通过 AT 指令配置成不同工作模式。
本项目使用:
AT+CWMODE=1,即 STA 模式。
ESP-01S 连接现有 WiFi:AT+CWJAP="WiFi名称","WiFi密码"
然后获取 IP:AT+CIFSR
开启多连接:AT+CIPMUX=1
开启 TCP Server:AT+CIPSERVER=1,8288
这里使用:8288,作为 TCP Server 端口。
手机 TCP Client 连接:STM32所在局域网IP:8288
即可建立通信。
四、STM32 工程软件结构
工程主要分为:main.c,esp8266.c,esp8266.h,usart.c,usart.h
其中:
main.c 负责:系统初始化→ESP8266初始化→连接WiFi→开启TCP Server→手机数据处理→电脑数据处理
esp8266.c 负责:ESP8266 AT指令;WiFi连接;TCP Server;TCP发送;TCP接收
USART1 负责:STM32 <-> 电脑
USART2 负责:STM32 <-> ESP-01S
五、ESP8266 初始化与测试
c
首先初始化 USART2:
void ESP8266_Init(void)
{
ESP8266_USART_Config();
}
ESP8266 串口参数:
USART_InitStructure.USART_BaudRate = macESP8266_USART_BAUD_RATE;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(macESP8266_USARTx, &USART_InitStructure);
同时开启:
USART_IT_RXNE
USART_IT_IDLE
也就是:接收中断 + 空闲中断
初始化之后先发送:AT
ESP8266 正常情况下返回:OK
void ESP8266_AT_Test(void)
{
char count = 0;
macESP8266_RST_HIGH_LEVEL();
delay_ms(1000);
while(count < 10)
{
if(ESP8266_Cmd("AT", "OK", NULL, 500))
return;
ESP8266_Rst();
count++;
}
}
六、连接 WiFi和开启TCP Server
c
设置 STA:
ESP8266_Net_Mode_Choose(STA);
然后连接 WiFi:
while(!ESP8266_JoinAP(macUser_ESP8266_ApSsid,
macUser_ESP8266_ApPwd));
对应 AT 指令:
AT+CWMODE=1
AT+CWJAP="SSID","PASSWORD"
连接成功后:OK
首先设置多连接:
ESP8266_Cmd("AT+CIPMUX=1", "OK", 0, 1000);
然后开启 TCP Server:
ESP8266_Cmd("AT+CIPSERVER=1,8288", "OK", 0, 1000);
完整初始化函数:
void ESP8266_StaTcpClient(void)
{
printf("\r\n正在配置 ESP8266 ......\r\n");
macESP8266_CH_ENABLE();
ESP8266_AT_Test();
ESP8266_Net_Mode_Choose(STA);
while(!ESP8266_JoinAP(
macUser_ESP8266_ApSsid,
macUser_ESP8266_ApPwd));
ESP8266_Cmd(
"AT+CIFSR",
"OK",
0,
1000
);
ESP8266_Cmd(
"AT+CIPMUX=1",
"OK",
0,
1000
);
ESP8266_Cmd(
"AT+CIPSERVER=1,8288",
"OK",
0,
1000
);
printf("\r\n配置 ESP8266 完毕\r\n");
}
七、USART1和USART2数据传输
c
USART1 用于连接电脑。
电脑发送:abcdefg
USART1 接收中断:
volatile uint8_t PC_RX_BUF[256];
volatile uint16_t PC_RX_LEN = 0;
volatile uint8_t PC_RX_FINISH = 0;
void DEBUG_USART_IRQHandler(void)
{
uint8_t ucTemp;
if(USART_GetITStatus(
USART1,
USART_IT_RXNE) != RESET)
{
ucTemp = USART_ReceiveData(USART1);
if(PC_RX_LEN < sizeof(PC_RX_BUF) - 1)
{
PC_RX_BUF[PC_RX_LEN++] = ucTemp;
}
}
if(USART_GetITStatus(
USART1,
USART_IT_IDLE) != RESET)
{
USART_GetFlagStatus(
USART1,
USART_FLAG_IDLE
);
USART_ReceiveData(USART1);
PC_RX_BUF[PC_RX_LEN] = '\0';
PC_RX_FINISH = 1;
}
}
USART2接收 ESP8266 数据
ESP8266 的串口中断采用:
void macESP8266_USART_INT_FUN(void)
{
uint8_t ucCh;
if(USART_GetITStatus(
macESP8266_USARTx,
USART_IT_RXNE) != RESET)
{
ucCh = USART_ReceiveData(macESP8266_USARTx);
if(strEsp8266_Fram_Record.InfBit.FramLength <
(RX_BUF_MAX_LEN - 1))
{
strEsp8266_Fram_Record.Data_RX_BUF[
strEsp8266_Fram_Record.InfBit.FramLength++
] = ucCh;
}
}
if(USART_GetITStatus(
macESP8266_USARTx,
USART_IT_IDLE) == SET)
{
strEsp8266_Fram_Record.InfBit.FramFinishFlag = 1;
ucCh = USART_ReceiveData(macESP8266_USARTx);
ucTcpClosedFlag = strstr(
(char *)strEsp8266_Fram_Record.Data_RX_BUF,
"CLOSED\r\n"
) ? 1 : 0;
}
}
八、main.c 处理手机数据
c
主循环检测:FramFinishFlag,表示一帧数据接收完成。
char *pData;
while(1)
{
if(strEsp8266_Fram_Record.InfBit.FramFinishFlag)
{
strEsp8266_Fram_Record.InfBit.FramFinishFlag = 0;
strEsp8266_Fram_Record.Data_RX_BUF[
strEsp8266_Fram_Record.InfBit.FramLength
] = '\0';
if(strstr(
(char *)strEsp8266_Fram_Record.Data_RX_BUF,
"+IPD") != NULL)
{
pData = strchr(
(char *)strEsp8266_Fram_Record.Data_RX_BUF,
':'
);
if(pData != NULL)
{
pData++;
printf(
"手机 -> 电脑:%s",
pData
);
}
}
strEsp8266_Fram_Record.InfBit.FramLength = 0;
}
}
九、手机 TCP 客户端连接与电脑串口传输数据
手机安装一个 TCP 网络调试助手,设置:协议:TCP Client,IP:ESP-01S获取到的IP,端口:8288
例如 ESP-01S 获取的 IP 为:192.168.1.100
手机连接:192.168.1.100:8288
手机发送:123456,ESP8266 在普通 TCP 模式下会将接收数据通过串口发送给 STM32,电脑串口就会收到:123456
电脑串口发送:abcde,手机客户端就会收到:abcde
十、代码示例
esp8266.c
c
#include "esp8266.h"
/*****************辰哥单片机设计******************
STM32
* 项目 : ESP8266模块通信实验
* 版本 : V1.0
* 日期 : 2024.9.30
* MCU : STM32F103C8T6
* 接口 : 串口2
* IP账号 : 辰哥单片机设计(同BILIBILI|抖音|快手|小红书|CSDN|公众号|视频号等)
* 作者 : 辰哥
* 工作室 : 异方辰电子工作室
* 讲解视频 : https://www.bilibili.com/video/BV1oSxteYEZy/?share_source=copy_web
* 官方网站 : www.yfcdz.cn
**********************BEGIN***********************/
#include "esp8266.h"
#include "common.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "delay.h"
volatile uint8_t ucTcpClosedFlag = 0;
volatile uint8_t ESP8266_Silent = 0;
char cStr [ 1500 ] = { 0 };
volatile uint8_t PC_RX_BUF[256];
volatile uint16_t PC_RX_LEN = 0;
volatile uint8_t PC_RX_FINISH = 0;
static void ESP8266_GPIO_Config ( void );
static void ESP8266_USART_Config ( void );
static void ESP8266_USART_NVIC_Configuration ( void );
struct STRUCT_USARTx_Fram strEsp8266_Fram_Record = { 0 };
/**
* @brief ESP8266 (Sta Tcp Client)透传
* @param 无
* @retval 无
*/
void ESP8266_StaTcpClient ( void )
{
// uint8_t ucStatus;
// char cStr [ 100 ] = { 0 };
printf ( "\r\n正在配置 ESP8266 ......\r\n" );
macESP8266_CH_ENABLE();
ESP8266_AT_Test ();
ESP8266_Net_Mode_Choose ( STA );
while ( ! ESP8266_JoinAP ( macUser_ESP8266_ApSsid, macUser_ESP8266_ApPwd ) );
ESP8266_Cmd ( "AT+CIFSR", "OK", 0, 1000 );
ESP8266_Cmd ( "AT+CIPMUX=1", "OK", 0, 1000 );
ESP8266_Cmd ( "AT+CIPSERVER=1,8288", "OK", 0, 1000 );
//ESP8266_Cmd("AT+CIPSTART="TCP",192.168.1.1,8000","OK",0,1000);
printf( "\r\n配置 ESP8266 完毕\r\n" );
}
/**
* @brief ESP8266初始化函数
* @param 无
* @retval 无
*/
void ESP8266_Init ( void )
{
// ESP8266_GPIO_Config ();
ESP8266_USART_Config ();
// macESP8266_RST_HIGH_LEVEL();
// macESP8266_CH_DISABLE();
}
/**
* @brief 初始化ESP8266用到的GPIO引脚
* @param 无
* @retval 无
*/
static void ESP8266_GPIO_Config ( void )
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
/* 配置 CH_PD 引脚*/
macESP8266_CH_PD_APBxClock_FUN ( macESP8266_CH_PD_CLK, ENABLE );
GPIO_InitStructure.GPIO_Pin = macESP8266_CH_PD_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init ( macESP8266_CH_PD_PORT, & GPIO_InitStructure );
/* 配置 RST 引脚*/
macESP8266_RST_APBxClock_FUN ( macESP8266_RST_CLK, ENABLE );
GPIO_InitStructure.GPIO_Pin = macESP8266_RST_PIN;
GPIO_Init ( macESP8266_RST_PORT, & GPIO_InitStructure );
}
/**
* @brief 初始化ESP8266用到的 USART
* @param 无
* @retval 无
*/
static void ESP8266_USART_Config ( void )
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
/* config USART clock */
macESP8266_USART_APBxClock_FUN ( macESP8266_USART_CLK, ENABLE );
macESP8266_USART_GPIO_APBxClock_FUN ( macESP8266_USART_GPIO_CLK, ENABLE );
/* USART GPIO config */
/* Configure USART Tx as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = macESP8266_USART_TX_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(macESP8266_USART_TX_PORT, &GPIO_InitStructure);
/* Configure USART Rx as input floating */
GPIO_InitStructure.GPIO_Pin = macESP8266_USART_RX_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(macESP8266_USART_RX_PORT, &GPIO_InitStructure);
/* USART1 mode config */
USART_InitStructure.USART_BaudRate = macESP8266_USART_BAUD_RATE;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(macESP8266_USARTx, &USART_InitStructure);
/* 中断配置 */
USART_ITConfig ( macESP8266_USARTx, USART_IT_RXNE, ENABLE ); //使能串口接收中断
USART_ITConfig ( macESP8266_USARTx, USART_IT_IDLE, ENABLE ); //使能串口总线空闲中断
ESP8266_USART_NVIC_Configuration ();
USART_Cmd(macESP8266_USARTx, ENABLE);
}
/**
* @brief 配置 ESP8266 USART 的 NVIC 中断
* @param 无
* @retval 无
*/
static void ESP8266_USART_NVIC_Configuration ( void )
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure the NVIC Preemption Priority Bits */
NVIC_PriorityGroupConfig ( macNVIC_PriorityGroup_x );
/* Enable the USART2 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = macESP8266_USART_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/*
* 函数名:ESP8266_Rst
* 描述 :重启WF-ESP8266模块
* 输入 :无
* 返回 : 无
* 调用 :被 ESP8266_AT_Test 调用
*/
void ESP8266_Rst ( void )
{
#if 0
ESP8266_Cmd ( "AT+RST", "OK", "ready", 2500 );
#else
macESP8266_RST_LOW_LEVEL();
delay_ms ( 500 );
macESP8266_RST_HIGH_LEVEL();
#endif
}
/*
* 函数名:ESP8266_Cmd
* 描述 :对WF-ESP8266模块发送AT指令
* 输入 :cmd,待发送的指令
* reply1,reply2,期待的响应,为NULL表不需响应,两者为或逻辑关系
* waittime,等待响应的时间
* 返回 : 1,指令发送成功
* 0,指令发送失败
* 调用 :被外部调用
*/
bool ESP8266_Cmd ( char * cmd, char * reply1, char * reply2, u32 waittime )
{
strEsp8266_Fram_Record .InfBit .FramLength = 0; //从新开始接收新的数据包
macESP8266_Usart ( "%s\r\n", cmd );
if ( ( reply1 == 0 ) && ( reply2 == 0 ) ) //不需要接收数据
return true;
delay_ms( waittime ); //延时
strEsp8266_Fram_Record.Data_RX_BUF[strEsp8266_Fram_Record.InfBit.FramLength] = '\0';
if (!ESP8266_Silent)
{
macPC_Usart("%s", strEsp8266_Fram_Record.Data_RX_BUF);
}
if ( ( reply1 != 0 ) && ( reply2 != 0 ) )
return ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply1 ) ||
( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply2 ) );
else if ( reply1 != 0 )
return ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply1 ) );
else
return ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply2 ) );
}
/*
* 函数名:ESP8266_AT_Test
* 描述 :对WF-ESP8266模块进行AT测试启动
* 输入 :无
* 返回 : 无
* 调用 :被外部调用
*/
void ESP8266_AT_Test ( void )
{
char count=0;
macESP8266_RST_HIGH_LEVEL();
delay_ms( 1000 );
while ( count < 10 )
{
if( ESP8266_Cmd ( "AT", "OK", NULL, 500 ) ) return;
ESP8266_Rst();
++ count;
}
}
/*
* 函数名:ESP8266_Net_Mode_Choose
* 描述 :选择WF-ESP8266模块的工作模式
* 输入 :enumMode,工作模式
* 返回 : 1,选择成功
* 0,选择失败
* 调用 :被外部调用
*/
bool ESP8266_Net_Mode_Choose ( ENUM_Net_ModeTypeDef enumMode )
{
switch ( enumMode )
{
case STA:
return ESP8266_Cmd ( "AT+CWMODE=1", "OK", "no change", 2500 );
case AP:
return ESP8266_Cmd ( "AT+CWMODE=2", "OK", "no change", 2500 );
case STA_AP:
return ESP8266_Cmd ( "AT+CWMODE=3", "OK", "no change", 2500 );
default:
return false;
}
}
/*
* 函数名:ESP8266_JoinAP
* 描述 :WF-ESP8266模块连接外部WiFi
* 输入 :pSSID,WiFi名称字符串
* :pPassWord,WiFi密码字符串
* 返回 : 1,连接成功
* 0,连接失败
* 调用 :被外部调用
*/
bool ESP8266_JoinAP ( char * pSSID, char * pPassWord )
{
char cCmd [120];
sprintf ( cCmd, "AT+CWJAP=\"%s\",\"%s\"", pSSID, pPassWord );
return ESP8266_Cmd ( cCmd, "OK", NULL, 5000 );
}
/*
* 函数名:ESP8266_BuildAP
* 描述 :WF-ESP8266模块创建WiFi热点
* 输入 :pSSID,WiFi名称字符串
* :pPassWord,WiFi密码字符串
* :enunPsdMode,WiFi加密方式代号字符串
* 返回 : 1,创建成功
* 0,创建失败
* 调用 :被外部调用
*/
bool ESP8266_BuildAP ( char * pSSID, char * pPassWord, ENUM_AP_PsdMode_TypeDef enunPsdMode )
{
char cCmd [120];
sprintf ( cCmd, "AT+CWSAP=\"%s\",\"%s\",1,%d", pSSID, pPassWord, enunPsdMode );
return ESP8266_Cmd ( cCmd, "OK", 0, 1000 );
}
/*
* 函数名:ESP8266_Enable_MultipleId
* 描述 :WF-ESP8266模块启动多连接
* 输入 :enumEnUnvarnishTx,配置是否多连接
* 返回 : 1,配置成功
* 0,配置失败
* 调用 :被外部调用
*/
bool ESP8266_Enable_MultipleId ( FunctionalState enumEnUnvarnishTx )
{
return ESP8266_Cmd ( "AT+CIPMUX=%d", "OK", 0, 500 );
}
/*
* 函数名:ESP8266_Link_Server
* 描述 :WF-ESP8266模块连接外部服务器
* 输入 :enumE,网络协议
* :ip,服务器IP字符串
* :ComNum,服务器端口字符串
* :id,模块连接服务器的ID
* 返回 : 1,连接成功
* 0,连接失败
* 调用 :被外部调用
*/
bool ESP8266_Link_Server ( ENUM_NetPro_TypeDef enumE, char * ip, char * ComNum, ENUM_ID_NO_TypeDef id)
{
char cStr [100] = { 0 }, cCmd [120];
switch ( enumE )
{
case enumTCP:
sprintf ( cStr, "\"%s\",\"%s\",%s", "TCP", ip, ComNum );
break;
case enumUDP:
sprintf ( cStr, "\"%s\",\"%s\",%s", "UDP", ip, ComNum );
break;
default:
break;
}
if ( id < 5 )
sprintf ( cCmd, "AT+CIPSTART=%d,%s", id, cStr);
else
sprintf ( cCmd, "AT+CIPSTART=%s", cStr );
return ESP8266_Cmd ( cCmd, "OK", "ALREAY CONNECT", 4000 );
}
/*
* 函数名:ESP8266_StartOrShutServer
* 描述 :WF-ESP8266模块开启或关闭服务器模式
* 输入 :enumMode,开启/关闭
* :pPortNum,服务器端口号字符串
* :pTimeOver,服务器超时时间字符串,单位:秒
* 返回 : 1,操作成功
* 0,操作失败
* 调用 :被外部调用
*/
bool ESP8266_StartOrShutServer ( FunctionalState enumMode, char * pPortNum, char * pTimeOver )
{
char cCmd1 [120], cCmd2 [120];
if ( enumMode )
{
sprintf ( cCmd1, "AT+CIPSERVER=%d,%s", 1, pPortNum );
sprintf ( cCmd2, "AT+CIPSTO=%s", pTimeOver );
return ( ESP8266_Cmd ( cCmd1, "OK", 0, 500 ) &&
ESP8266_Cmd ( cCmd2, "OK", 0, 500 ) );
}
else
{
sprintf ( cCmd1, "AT+CIPSERVER=%d,%s", 0, pPortNum );
return ESP8266_Cmd ( cCmd1, "OK", 0, 500 );
}
}
/*
* 函数名:ESP8266_Get_LinkStatus
* 描述 :获取 WF-ESP8266 的连接状态,较适合单端口时使用
* 输入 :无
* 返回 : 2,获得ip
* 3,建立连接
* 3,失去连接
* 0,获取状态失败
* 调用 :被外部调用
*/
uint8_t ESP8266_Get_LinkStatus ( void )
{
if ( ESP8266_Cmd ( "AT+CIPSTATUS", "OK", 0, 500 ) )
{
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "STATUS:2\r\n" ) )
return 2;
else if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "STATUS:3\r\n" ) )
return 3;
else if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "STATUS:4\r\n" ) )
return 4;
}
return 0;
}
/*
* 函数名:ESP8266_Get_IdLinkStatus
* 描述 :获取 WF-ESP8266 的端口(Id)连接状态,较适合多端口时使用
* 输入 :无
* 返回 : 端口(Id)的连接状态,低5位为有效位,分别对应Id5~0,某位若置1表该Id建立了连接,若被清0表该Id未建立连接
* 调用 :被外部调用
*/
uint8_t ESP8266_Get_IdLinkStatus ( void )
{
uint8_t ucIdLinkStatus = 0x00;
if ( ESP8266_Cmd ( "AT+CIPSTATUS", "OK", 0, 500 ) )
{
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:0," ) )
ucIdLinkStatus |= 0x01;
else
ucIdLinkStatus &= ~ 0x01;
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:1," ) )
ucIdLinkStatus |= 0x02;
else
ucIdLinkStatus &= ~ 0x02;
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:2," ) )
ucIdLinkStatus |= 0x04;
else
ucIdLinkStatus &= ~ 0x04;
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:3," ) )
ucIdLinkStatus |= 0x08;
else
ucIdLinkStatus &= ~ 0x08;
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:4," ) )
ucIdLinkStatus |= 0x10;
else
ucIdLinkStatus &= ~ 0x10;
}
return ucIdLinkStatus;
}
/*
* 函数名:ESP8266_Inquire_ApIp
* 描述 :获取 F-ESP8266 的 AP IP
* 输入 :pApIp,存放 AP IP 的数组的首地址
* ucArrayLength,存放 AP IP 的数组的长度
* 返回 : 0,获取失败
* 1,获取成功
* 调用 :被外部调用
*/
uint8_t ESP8266_Inquire_ApIp ( char * pApIp, uint8_t ucArrayLength )
{
char uc;
char * pCh;
ESP8266_Cmd ( "AT+CIFSR", "OK", 0, 500 );
pCh = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "APIP,\"" );
if ( pCh )
pCh += 6;
else
return 0;
for ( uc = 0; uc < ucArrayLength; uc ++ )
{
pApIp [ uc ] = * ( pCh + uc);
if ( pApIp [ uc ] == '\"' )
{
pApIp [ uc ] = '\0';
break;
}
}
return 1;
}
/*
* 函数名:ESP8266_UnvarnishSend
* 描述 :配置WF-ESP8266模块进入透传发送
* 输入 :无
* 返回 : 1,配置成功
* 0,配置失败
* 调用 :被外部调用
*/
bool ESP8266_UnvarnishSend ( void )
{
ESP8266_Cmd ( "AT+CIPMODE=1", "OK", 0, 500 );
}
/*
* 函数名:ESP8266_ExitUnvarnishSend
* 描述 :配置WF-ESP8266模块退出透传模式
* 输入 :无
* 返回 : 无
* 调用 :被外部调用
*/
void ESP8266_ExitUnvarnishSend ( void )
{
delay_ms( 1000 );
macESP8266_Usart ( "+++" );
delay_ms( 500 );
}
/*
* 函数名:ESP8266_SendString
* 描述 :WF-ESP8266模块发送字符串
* 输入 :enumEnUnvarnishTx,声明是否已使能了透传模式
* :pStr,要发送的字符串
* :ulStrLength,要发送的字符串的字节数
* :ucId,哪个ID发送的字符串
* 返回 : 1,发送成功
* 0,发送失败
* 调用 :被外部调用
*/
bool ESP8266_SendString(
FunctionalState enumEnUnvarnishTx,
char *pStr,
u32 ulStrLength,
ENUM_ID_NO_TypeDef ucId
)
{
char cStr[32];
if(pStr == NULL || ulStrLength == 0)
{
return false;
}
/* 透传模式 */
if(enumEnUnvarnishTx)
{
macESP8266_Usart("%s", pStr);
return true;
}
if(ucId < 5)
{
sprintf(cStr,"AT+CIPSEND=%d,%lu",ucId,(unsigned long)ulStrLength);
}
else
{
return false;
}
ESP8266_Silent = 1;
if(!ESP8266_Cmd(cStr, ">", NULL, 1000))
{
ESP8266_Silent = 0;
return false;
}
ESP8266_Silent = 0;
macESP8266_Usart("%s", pStr);
delay_ms(500);
return true;
}
/*
* 函数名:ESP8266_ReceiveString
* 描述 :WF-ESP8266模块接收字符串
* 输入 :enumEnUnvarnishTx,声明是否已使能了透传模式
* 返回 : 接收到的字符串首地址
* 调用 :被外部调用
*/
char * ESP8266_ReceiveString ( FunctionalState enumEnUnvarnishTx )
{
char * pRecStr = 0;
strEsp8266_Fram_Record .InfBit .FramLength = 0;
strEsp8266_Fram_Record .InfBit .FramFinishFlag = 0;
while ( ! strEsp8266_Fram_Record .InfBit .FramFinishFlag );
strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ] = '\0';
if ( enumEnUnvarnishTx )
pRecStr = strEsp8266_Fram_Record .Data_RX_BUF;
else
{
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+IPD" ) )
pRecStr = strEsp8266_Fram_Record .Data_RX_BUF;
}
return pRecStr;
}
main.c
c
#include "stm32f10x.h"
#include "led.h"
#include "usart.h"
#include "delay.h"
#include "esp8266.h"
#include <stdio.h>
#include <string.h>
/*****************辰哥单片机设计******************
STM32
* 项目 : ESP8266模块通信实验
* 版本 : V1.0
* 日期 : 2024.9.30
* MCU : STM32F103C8T6
* 接口 : 参看usart2.h
* IP账号 : 辰哥单片机设计(同BILIBILI|抖音|快手|小红书|CSDN|公众号|视频号等)
* 作者 : 辰哥
* 工作室 : 异方辰电子工作室
* 讲解视频 : https://www.bilibili.com/video/BV1oSxteYEZy/?share_source=copy_web
* 官方网站 : www.yfcdz.cn
**********************BEGIN***********************/
uint8_t flag;
char *pData;
int main(void)
{
SystemInit();//配置系统时钟为72M
delay_init(72);
LED_Init();
LED_On();
USART_Config();
ESP8266_Init (); //初始化WiFi模块使用的接口和外设(使用串口2)
ESP8266_StaTcpClient ();//WiFi模块设置
printf("Start \n");
delay_ms(1000);
while (1)
{
/* 手机 -> 电脑 */
if (strEsp8266_Fram_Record.InfBit.FramFinishFlag)
{
strEsp8266_Fram_Record.InfBit.FramFinishFlag = 0;
strEsp8266_Fram_Record.Data_RX_BUF[strEsp8266_Fram_Record.InfBit.FramLength] = '\0';
if (strstr((char *)strEsp8266_Fram_Record.Data_RX_BUF,"+IPD") != NULL)
{
pData = strchr((char *)strEsp8266_Fram_Record.Data_RX_BUF,':');
if (pData != NULL)
{
pData++;
printf("手机 -> 电脑:%s\r\n", pData);
}
}
strEsp8266_Fram_Record.InfBit.FramLength = 0;
}
/* 电脑 -> 手机 */
if (PC_RX_FINISH)
{
PC_RX_FINISH = 0;
if (PC_RX_LEN < sizeof(PC_RX_BUF))
{
PC_RX_BUF[PC_RX_LEN] = '\0';
}
printf("电脑 -> 手机:%s", PC_RX_BUF);
ESP8266_SendString(DISABLE,(char *)PC_RX_BUF,PC_RX_LEN,Multiple_ID_0
);
PC_RX_LEN = 0;
memset((void *)PC_RX_BUF,0,sizeof(PC_RX_BUF));
}
}
}
十一、效果展示

十二、常见问题
-
TCP连接不上?
答:检查IP地址和TCP端口是否正确;设备与ESP是否处在同一个局域网内;ESP连接2.4GHz WiFi,不要连接5GHz WiFi。
-
STM32 能收到手机数据,但电脑显示乱码?
答:检查:USART1和USART2波特率,以及:8位数据,1位停止位,无校验,同时检查 STM32 与 ESP-01S 是否共地。
-
手机收到的数据长度不正确?
答:检查:AT+CIPSEND=0,数据长度,这里的数据长度必须和实际发送字节数一致。