STM32与ESP8266连接:实现WiFi功能

目录

1. ESP8266模块介绍

1.1. 系统结构图

1.2. 功能介绍

 1.3. AT指令说明

 2. STM32连接ESP8266

3. ESP8266示例

3.1. ESP8266透传模式

 3.2. ESP8266上传数据例程


1. ESP8266模块介绍

1.1. 系统结构图

乐鑫智能互联平台——ESP8266 拥有高性能无线 SOC,是一个完整且自成体系的 WiFi 网络解决方案,能够独立运行,也可以作为 slave 搭载于其他 Host 运行。

装有ESP8266的系统表现出来的领先特征有:节能VoIP在睡眠/唤醒模式之间的快速切换、配合低功率操作的自适应无线电偏置、前端信号的处理功能、故障排除和无线电系统共存特性为消除蜂窝/蓝牙/DDR/LVDS/LCD干扰。

 

 管脚定义:

1.2. 功能介绍

ESP8266 支持 softAP 模式,station 模式,softAP + station 共存模式三种。
利用 ESP8266 可以实现十分灵活的组网方式和网络拓扑。
注,
SoftAP:即无线接入点,是一个无线网络的中心节点。通常使用的无线路
由器就是一个无线接入点。
Station:即无线终端,是一个无线网络的终端端。 

提供三种省电模式:

 1.3. AT指令说明

AT指令分类: 

指令集:

 2. STM32连接ESP8266

用STM32F103的USART3(PB10、PB11)连接ESP8266的URXD、UTXD,PB8连接CH-PD,PB9连接RST。

3. ESP8266示例

3.1. ESP8266透传模式

打开CubeMX, 配置USART1和USART3,并且NVIC处Enable打√,USART1用于与电脑的串口调试助手连接,USART3用于与ESP8266的串口连接:

在main.c定义变量,并且配置非阻塞接收:

//main.c:

uint8_t revData[100];
uint8_t esp8266RevData[200];
int main(void)
{
	HAL_UARTEx_ReceiveToIdle_IT(&huart1, revData, 100);
	HAL_UARTEx_ReceiveToIdle_IT(&huart3, esp8266RevData, 200);
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

在usart.c文件中重写HAL_UARTEx_RxEventCallback函数:

//usart.c:

#include <stdio.h>

extern uint8_t revData[100];
extern uint8_t esp8266RevData[200];

/* USER CODE BEGIN 1 */
int fputc(int ch,FILE *f)
{
	HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,1000);
	return ch;
}


void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{

	if(huart->Instance==USART1)
	{
//		HAL_UART_Transmit(&huart1,revData,Size,10);
		HAL_UART_Transmit(&huart3,revData,Size,10);	
		
		while(HAL_UARTEx_ReceiveToIdle_IT(&huart1, revData, 100) != HAL_OK);
	}
	else if(huart->Instance==USART3)
	{
		HAL_UART_Transmit(&huart1,esp8266RevData,Size,10);	
		while(HAL_UARTEx_ReceiveToIdle_IT(&huart3, esp8266RevData, 200) != HAL_OK);
	}
}


/* USER CODE END 1 */

编译并且烧录至单片机,可以看到串口助手输入指令后正确的得到反馈:

 3.2. ESP8266上传数据例程

新增接收数据大小的变量:

//usart.c
uint16_t *esp8266Size;

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{

	if(huart->Instance==USART1)
	{
//		HAL_UART_Transmit(&huart1,revData,Size,10);
		HAL_UART_Transmit(&huart3,revData,Size,10);	
		
		while(HAL_UARTEx_ReceiveToIdle_IT(&huart1, revData, 100) != HAL_OK);
	}
	else if(huart->Instance==USART3)
	{
		HAL_UART_Transmit(&huart1,esp8266RevData,Size,10);	
		esp8266Size=&Size;
		while(HAL_UARTEx_ReceiveToIdle_IT(&huart3, esp8266RevData, 200) != HAL_OK);
	}
}

编写wifi AT指令的操作函数:

//usart.c

/*
 * 函数名:cmdAT
 * 描述  :对WF-ESP8266模块发送AT指令
 * 输入  :cmdData,待发送的指令
 *         expReturn1,expReturn2,期待的响应,为NULL表不需响应,两者为或逻辑关系
 * 返回  : 1,指令发送成功
 *         0,指令发送失败
 * 调用  :被外部调用
 */
_Bool cmdAT(char *cmdData,char *expReturn1,char *expReturn2)
{
	char cmdDataTmp[40];
	sprintf(cmdDataTmp,"%s\r\n",cmdData);
	HAL_UART_Transmit(&huart3,(uint8_t *)cmdDataTmp,strlen(cmdDataTmp),10);	
//	printf("cmdDataTmp:%s\r\nlenth:%d",cmdDataTmp,sizeof((char *)cmdDataTmp)/sizeof(char));
	if(expReturn1==NULL && expReturn2==NULL)
		return 1;
	HAL_Delay(100);
	uint8_t count=0;
	if(esp8266Size==0 || count<40)
	{
		HAL_Delay(200);
		count++;
	}
	esp8266RevData[*esp8266Size]='\0';
	esp8266Size=0;
	if(expReturn2!=NULL)
		return (((_Bool)strstr((const char *)esp8266RevData,expReturn1))||((_Bool)strstr((const char *)esp8266RevData,expReturn2)));
	else
		return ((_Bool)strstr((const char *)esp8266RevData,expReturn1));
}

_Bool testAT( void )
{
	char count=0;

//	ESP8266_RST_H;	
  printf("\r\n测试AT启动\r\n");
	HAL_Delay ( 100 );
	while ( count < 5 )
	{
    printf("\r\n第%d次尝试连接AT\r\n", count);
		if( cmdAT ( "AT", "OK",NULL) )
    {
      printf("\r\nAT成功启动\r\n");
      return 1;
    }
		ESP8266_RST_L;
		HAL_Delay(500);
		ESP8266_RST_H;
		HAL_Delay(1000);
		++ count;
	}
  return 0;
}

_Bool ESP8266_DHCP_CUR (void)
{
	return cmdAT( "AT+CWDHCP_CUR=1,1", "OK",NULL);
}

/*
 * 函数名:ESP8266_Net_Mode_Choose
 * 描述  :选择WF-ESP8266模块的工作模式
 * 输入  :enumMode,工作模式
 * 返回  : 1,选择成功
 *         0,选择失败
 * 调用  :被外部调用
 */
_Bool ESP8266_Net_Mode_Choose ( ENUM_Net_ModeTypeDef enumMode )
{
	switch ( enumMode )
	{
		case STA:
			return cmdAT ( "AT+CWMODE=1", "OK",NULL); 
		
	  case AP:
		  return cmdAT ( "AT+CWMODE=2", "OK",NULL); 
		
		case STA_AP:
		  return cmdAT ( "AT+CWMODE=3", "OK",NULL); 
		
	  default:
		  return 0;
  }
	
}

/*
 * 函数名: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 cmdAT ( cCmd, "OK",NULL);
	
}

/*
 * 函数名:ESP8266_Enable_MultipleId
 * 描述  :WF-ESP8266模块启动多连接
 * 输入  :enumEnUnvarnishTx,配置是否多连接
 * 返回  : 1,配置成功
 *         0,配置失败
 * 调用  :被外部调用
 */
_Bool ESP8266_Enable_MultipleId ( FunctionalState enumEnUnvarnishTx )
{
	char cStr [20];
	
	sprintf ( cStr, "AT+CIPMUX=%d", ( enumEnUnvarnishTx ? 1 : 0 ) );
	
	return cmdAT ( cStr, "OK",NULL);
	
}

/*
 * 函数名: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 cmdAT ( cCmd, "OK","ALREADY CONNECTED");
	
}

/*
 * 函数名:ESP8266_UnvarnishSend
 * 描述  :配置WF-ESP8266模块进入透传发送
 * 输入  :无
 * 返回  : 1,配置成功
 *         0,配置失败
 * 调用  :被外部调用
 */
_Bool ESP8266_UnvarnishSend ( void )
{
	if ( ! cmdAT ( "AT+CIPMODE=1", "OK", NULL ) )
		return 0;
	
	return 
	  cmdAT ( "AT+CIPSEND", "OK", ">" );
	
}

在usart.h配置宏定义和函数声明:

/* USER CODE BEGIN Private defines */
typedef enum{
	STA,
  AP,
  STA_AP  
} ENUM_Net_ModeTypeDef;

typedef enum{
	 enumTCP,
	 enumUDP,
} ENUM_NetPro_TypeDef;
	

typedef enum{
	Multiple_ID_0 = 0,
	Multiple_ID_1 = 1,
	Multiple_ID_2 = 2,
	Multiple_ID_3 = 3,
	Multiple_ID_4 = 4,
	Single_ID_0 = 5,
} ENUM_ID_NO_TypeDef;
	
/* USER CODE END Private defines */

void MX_USART1_UART_Init(void);
void MX_USART3_UART_Init(void);

/* USER CODE BEGIN Prototypes */
_Bool cmdAT(char *cmdData,char *expReturn1,char *expReturn2);
_Bool testAT( void );
_Bool ESP8266_DHCP_CUR (void);
_Bool ESP8266_Net_Mode_Choose ( ENUM_Net_ModeTypeDef enumMode );
_Bool ESP8266_JoinAP ( char * pSSID, char * pPassWord );
_Bool ESP8266_Enable_MultipleId ( FunctionalState enumEnUnvarnishTx );
_Bool ESP8266_Link_Server ( ENUM_NetPro_TypeDef enumE, char * ip, char * ComNum, ENUM_ID_NO_TypeDef id);
_Bool ESP8266_UnvarnishSend ( void );

/* USER CODE END Prototypes */

编写初始化函数:

//esp8266_test.h

#ifndef __ESP8266_TEST_H__
#define __ESP8266_TEST_H__

#ifdef __cplusplus
extern "C" {
#endif

#define WIFI_SSID                "nomi"                //要连接的热点的名称
#define WIFI_PASSWORD            "fdhgtdhrt"           //要连接的热点的密钥

#define SERVER_IP                "192.168.64.74"      //要连接的服务器的 IP
#define SERVER_PORT              "8000"               //要连接的服务器的端口


void initEsp8266(void);

#ifdef __cplusplus
}
#endif

#endif /* __ESP8266_TEST_H__ */
//esp8266_test.c

#include "esp8266_test.h"
#include <stdio.h>
#include "usart.h"

void initEsp8266(void)
{
	printf("\r\n开始测试AT启动:\r\n");
	if(testAT()==0)
	{
		printf("AT连接不上!");
		return;
	}
	
	printf("\r\n设置DHCP获取:\r\n");
	_Bool dhcpreturn=ESP8266_DHCP_CUR();
	printf("testdhcpreturn:%d",dhcpreturn);
	if(ESP8266_DHCP_CUR()==0)
	{
		printf("设置DHCP获取失败!\r\n");
	}
	printf("\r\n选择WF-ESP8266模块的工作模式为STA:\r\n");
	if(ESP8266_Net_Mode_Choose(STA)==0)
	{
		printf("选择WF-ESP8266模块的工作模式失败!\r\n");
	}
	printf("\r\n连接WiFi:\r\n");
	if(ESP8266_JoinAP (WIFI_SSID,WIFI_PASSWORD)==0)
	{
		printf("WiFi连接不上!\r\n");
		return;
	}
	printf("\r\nESP8266模块启动单连接:\r\n");
	if(ESP8266_Enable_MultipleId (DISABLE)==0)
	{
		printf("ESP8266模块启动单连接失败!\r\n");
		return;
	}
	
	HAL_Delay(2000);
	printf("\r\n连接外部服务器:\r\n");
	while(ESP8266_Link_Server (enumTCP,SERVER_IP,SERVER_PORT,Single_ID_0)==0)
	{
		printf("服务器连接不上!\r\n");
		HAL_Delay(1000);
	}
	printf("\r\n进入透传发送:\r\n");
	if(ESP8266_UnvarnishSend()==0)
	{
		printf("进入透传发送失败!\r\n");
		return;
	}
	
	printf( "\r\n配置 ESP8266 完毕\r\n" );
	printf ( "\r\n开始透传......\r\n" );
  
}

在main.c写初始化测试语句:

//main.c

	HAL_UARTEx_ReceiveToIdle_IT(&huart1, revData, 100);
	HAL_UARTEx_ReceiveToIdle_IT(&huart3, esp8266RevData, 200);
	HAL_Delay(1000);
	initEsp8266();
	HAL_Delay(100);
	HAL_UART_Transmit(&huart3,(uint8_t *)"wendu",5,10);

网络助手打开监听模式。

运行程序,在串口助手中看到提示正常:

网络助手正常收到消息:

 

 

物联沃分享整理
物联沃-IOTWORD物联网 » STM32与ESP8266连接:实现WiFi功能

发表评论