简介

文章介绍了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 );

参考
《ESP8266_用户手册_V0.3.pdf》
《ESP8266 Non-OS SDK AT 指令集.pdf》
《野火YH-ESP8266模块用户手册.pdf》
《野火提供的esp8266源码》