文章目录
- 简介
- ESP8266介绍
- 模块参数
- 无线组网方式
- AT指令
- STM32连接模块与配置
- GPIO配置
- USART配置
- 中断函数
- ESP8266使用流程
简介
文章介绍了ESP8266的特性以及连网模式(AP,station),使用串口(USART)接入STM32,实现连网功能。
ESP8266介绍
esp8266 内置超低功耗 Tensilica L106 32 位 RISC 处理器,CPU 时钟速度最高可达 160 MHz,支持实时操作系统 (RTOS) 和 Wi-Fi 协议栈。标准数字外设接口、天线开关、射频 balun、功率放大器、低噪放大器、过滤器和电源管理模块等。低功耗
模块参数
无线参数 | 值 |
无线标准 | 802.11 b/g/n |
频率范围 | 2.4G-2.5G(2400M-2483.5M) |
发射功率 | 802.11 b: 20 dBm;802.11 g: 17 dBm;802.11 n: 14 dBm |
接收灵敏度 | 802.11 b: (11Mbps) -91db;802.11 g: (54Mbps) -75db;802.11 n: (MCS7) -72db |
硬件参数 | 值 |
数据接口 | UART、PWM、 GPIO |
工作电压 | 3.3V |
工作电流 | 平均电流 80mA |
工作温度 | -40° ~125° |
软件参数 | 值 |
无线网络模式 | station/softAP/SoftAP+station |
安全机制 | WPA/WPA2 |
加密类型 | WEP/TKIP/AES |
UART成帧
ESP8266 判断 UART 传来的数据时间间隔,若时间间隔大于 20ms, 则认为一帧结束;否则, 一直接收数据到上限值 2KB, 认为一帧结束。 ESP8266 模块判断UART 来的数据一帧结束后, 通过 WIFI 接口将数据转发出去。
成帧时间间隔为 20ms, 一帧上限值为 2KB。
无线组网方式
ESP8266 支持 softAP 模式, station 模式, softAP + station 共存模式三种。
SoftAP: 即无线接入点, 是一个无线网络的中心节点,类似于无线路由器。手机 用户设备、 其他 ESP8266 station 接口等均可以作为 station 连入ESP8266, 组建成一个局域网。(透传)
Station:即无线终端, 是一个无线网络的终端。
通过连接路由器(AP) 连入 internet ,可向云端服务器上传、 下载数据。用户可随时使用移动终端(手机、 笔记本等) ,通过云端连接ESP8266。
网络相关的模块,比如4G、lora等模块都有AT指令,使用AT指令配置模块,ESP8266的AT指令如下
AT指令
分类 | 指令格式 | 指令功能 |
测试命令 | AT+=? | 该命令用于查询设置命令或内部程序设置的 |
查询命令 | AT+? | 该命令用于返回参数的当前值 |
设置命令 | AT+=<…> | 该命令用于设置用户自定义的参数值 |
执行命令 | AT+ | 该命令用于执行受模块内部程序控制的变参 |
基础指令
命令 | 说明 |
AT | 测试 AT 启动 |
AT+RST | 重启模块 |
AT+GMR | 查看版本信息 |
wifi 功能指令
命令 | 说明 |
AT+CWMODE | 选择 WIFI 应用模式 |
AT+CWJAP | 加入 AP |
AT+CWLAP | 列出当前可用 AP |
AT+CWQAP | 退出与 AP 的连接 |
AT+CWSAP | 设置 AP 模式下的参数 |
AT+ CWLIF | 查看已接入设备的 IP |
TCP/IP 指令
命令 | 说明 |
AT+CIPSTATUS | 获得连接状态 |
AT+CIPSTART | 建立 TCP 连接或注册 UDP 端口号 |
AT+CIPSEND | 发送数据 |
AT+CIPCLOSE | 关闭 TCP 或 UDP |
AT+CIFSR | 获取本地 IP 地址 |
AT+CIPMUX | 启动多连接 |
AT+CIPSERVER | 配置为服务器 |
AT+CIPMODE | 设置模块传输模式 |
AT+CIPSTO | 设置服务器超时时间 |
STM32连接模块与配置
RST复位引脚,与CH_PD片选引脚,在模式初始化阶段使用。RST拉高,CH_PD先复位 再置位,模块正常工作。采用串口方式与STM32进行通信,使用串口中断,有数据时,去读取数据。
GPIO配置
// CH_PD引脚
// Enables or disables the High Speed APB (APB2) peripheral clock
#define macESP8266_CH_PD_APBxClock_FUN RCC_APB2PeriphClockCmd
//RCC_APB2Periph: specifies the APB2 peripheral to gates its clock
#define macESP8266_CH_PD_CLK RCC_APB2Periph_GPIOB
//PORT
#define macESP8266_CH_PD_PORT GPIOB
//PIN
#define macESP8266_CH_PD_PIN GPIO_Pin_8
RST引脚
#define macESP8266_RST_APBxClock_FUN RCC_APB2PeriphClockCmd
#define macESP8266_RST_CLK RCC_APB2Periph_GPIOB
#define macESP8266_RST_PORT GPIOB
#define macESP8266_RST_PIN GPIO_Pin_9
//
static void ESP8266_GPIO_Config ( void )
{
GPIO_InitTypeDef GPIO_InitStructure;
macESP8266_CH_PD_APBxClock_FUN ( macESP8266_CH_PD_CLK, ENABLE );
//CH_PD引脚
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 );
}
USART配置
#define macESP8266_USART_BAUD_RATE 115200
#define macESP8266_USARTx USART3
#define macESP8266_USART_APBxClock_FUN RCC_APB1PeriphClockCmd
#define macESP8266_USART_CLK RCC_APB1Periph_USART3
#define macESP8266_USART_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd
#define macESP8266_USART_GPIO_CLK RCC_APB2Periph_GPIOB
//发送TX
#define macESP8266_USART_TX_PORT GPIOB
#define macESP8266_USART_TX_PIN GPIO_Pin_10
//接受RX
#define macESP8266_USART_RX_PORT GPIOB
#define macESP8266_USART_RX_PIN GPIO_Pin_11
//中断
#define macESP8266_USART_IRQ USART3_IRQn
#define macESP8266_USART_INT_FUN USART3_IRQHandler
extern struct STRUCT_USARTx_Fram //´®¿ÚÊý¾ÝÖ¡µÄ´¦Àí½á¹¹Ìå
{
char Data_RX_BUF [ RX_BUF_MAX_LEN ];
union {
__IO u16 InfAll;
struct {
__IO u16 FramLength :15; // 14:0
__IO u16 FramFinishFlag :1; // 15
} InfBit;
};
} strEsp8266_Fram_Record;
struct STRUCT_USARTx_Fram strEsp8266_Fram_Record = { 0 };
//USART 的 NVIC中断
static void ESP8266_USART_NVIC_Configuration ( void )
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure the NVIC Preemption Priority Bits */
NVIC_PriorityGroupConfig ( macNVIC_PriorityGroup_x );
/* Enable the USART3 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);
}
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);
}
中断函数
void macESP8266_USART_INT_FUN ( void )
{
uint8_t ucCh;
//获取RX中断状态
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 ) ) //长度判断
//向BUF缓冲区中写入数据ucCh,FramLength 在不断增加
strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ++ ] = ucCh;
}
//获取IDEL中断状态 ,数据帧接收完毕
if ( USART_GetITStatus( macESP8266_USARTx, USART_IT_IDLE ) == SET )
{
strEsp8266_Fram_Record .InfBit .FramFinishFlag = 1;//条件置位
ucCh = USART_ReceiveData( macESP8266_USARTx );
ucTcpClosedFlag = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "CLOSED\r\n" ) ? 1 : 0;
}
}
ESP8266使用流程
ESP8266的一般使用顺序,ESP8266连接当前环境的热点,与服务器建立TCP连接,传输数据。
AT+CWMODE=1:设置工作模式(STA模式)
AT+RST:模块重启(生效工作模式)
AT+CWJAP=“111”,“11111111”:连接当前环境的WIFI热点(热点名,密码)
AT+CIPMUX=0:设置单路连接模式
AT+CIPSTART=“TCP”,“xxx.xxx.xxx.xxx”,xxxx:建立TCP连接
AT+CIPMODE=1:开启透传模式
AT+CIPSEND:透传模式下,传输数据
+++:退出透传模式
程序的主处理流程
void ESP8266_StaTcpClient_UnvarnishTest ( void )
{
uint8_t ucStatus;
char cStr [ 100 ] = { 0 };
//使能PD_CH
macESP8266_CH_ENABLE();
//AT测试
ESP8266_AT_Test ();
//选择网络模式
ESP8266_Net_Mode_Choose ( STA );
//连接AP
while ( ! ESP8266_JoinAP ( macUser_ESP8266_ApSsid, macUser_ESP8266_ApPwd ) );
//启动多连接关闭
ESP8266_Enable_MultipleId ( DISABLE );
//连接服务器IP 端口号
while ( ! ESP8266_Link_Server ( enumTCP, macUser_ESP8266_TcpServer_IP, macUser_ESP8266_TcpServer_Port, Single_ID_0 ) );
//设置模式进入透传模式
while ( ! ESP8266_UnvarnishSend () );
while ( 1 )//进入循环
{
//此处可以修改数据源,此处为一串字符串,也可以是从开发版上获取传感器数据,比如温湿度传感器
sprintf ( cStr,"ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n" );
ESP8266_SendString ( ENABLE, cStr, 0, Single_ID_0 ); //发送数据
Delay_ms ( 100 );
if ( ucTcpClosedFlag ) //检测是否丢失链接
{
ESP8266_ExitUnvarnishSend (); //如果丢失,退出透传模式
do ucStatus = ESP8266_Get_LinkStatus (); //获取链接状态
while ( ! ucStatus );
if ( ucStatus == 4 ) //失去链接后重连
{
while ( ! ESP8266_JoinAP ( macUser_ESP8266_ApSsid, macUser_ESP8266_ApPwd ) );
while ( !ESP8266_Link_Server ( enumTCP, macUser_ESP8266_TcpServer_IP, macUser_ESP8266_TcpServer_Port, Single_ID_0 ) );
}
while ( ! ESP8266_UnvarnishSend () );
}
}
发送AT指令函数
/*
cmd:待发送的命令,
reply1,reply2期待的回复
waittime 等待时间
*/
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';
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 ) );
}
选择NET模式
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;
}
}
链接wifi, AT+CWJAP
/*
pSSID用户名
pPassWord 密码
*/
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 );
}
连接外部服务器 AT+CIPSTART
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 );
}
获取链接状态AT+CIPSTATUS
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;
}
发送数据"AT+CIPSEND=
/*
返回值
1,发送成功
0,发送失败
*/
bool ESP8266_SendString ( FunctionalState enumEnUnvarnishTx, char * pStr, u32 ulStrLength, ENUM_ID_NO_TypeDef ucId )
{
char cStr [20];
bool bRet = false;
if ( enumEnUnvarnishTx )
{
macESP8266_Usart ( "%s", pStr );
bRet = true;
}
else
{
if ( ucId < 5 )
sprintf ( cStr, "AT+CIPSEND=%d,%d", ucId, ulStrLength + 2 );
else
sprintf ( cStr, "AT+CIPSEND=%d", ulStrLength + 2 );
ESP8266_Cmd ( cStr, "> ", 0, 1000 );
bRet = ESP8266_Cmd ( pStr, "SEND OK", 0, 1000 );
}
return bRet;
}
主函数
void ESP8266_Init ( void )
{
ESP8266_GPIO_Config ();
ESP8266_USART_Config ();
macESP8266_RST_HIGH_LEVEL();
macESP8266_CH_DISABLE();
}
int main ( void )
{
USARTx_Config ();//串口打印函数
SysTick_Init ();//系统时钟初始化
ESP8266_Init ();//esp8266初始化
ESP8266_StaTcpClient_UnvarnishTest ();
while ( 1 );
}
实验现象
通过网络助手,收到开发版发来的数据
模块作为AP的配置
ESP8266_AT_Test ();
ESP8266_Net_Mode_Choose ( AP );
//设置模块的IP
while ( ! ESP8266_CIPAP ( macUser_ESP8266_TcpServer_IP ) );
//创建模块热点
while ( ! ESP8266_BuildAP ( macUser_ESP8266_BulitApSsid, macUser_ESP8266_BulitApPwd, macUser_ESP8266_BulitApEcn ) );
//模块启动多连接
ESP8266_Enable_MultipleId ( ENABLE );
//模块开启或关闭服务器
while ( ! ESP8266_StartOrShutServer ( ENABLE, macUser_ESP8266_TcpServer_Port, macUser_ESP8266_TcpServer_OverTime ) );
//ESP8266 获取 AP IP
ESP8266_Inquire_ApIp ( cStr, 20 );