【stm32简单外设篇】- ESP8266 Wi-Fi 模块(ESP-01系列)

一、适用场景

适用场景:给 STM32 或其它 MCU 添加 Wi-Fi(数据上报、OTA、远程控制、MQTT、HTTP/REST、Web 控制面板);或将 ESP8266 作为独立微控制器(NodeMCU/Arduino 栈)快速做物联网原型、Wi-Fi 网关、局域网 Web 服务器与 Wi-Fi → 串口透传桥。

二、器材清单

ESP8266 模块(ESP-01)×1

若干杜邦线(母对母/母对公)×1组

stm32f103(或其它 STM32)开发板 ×1

三、工作原理(要点)

ESP8266 是集成了 Wi-Fi 协议栈的低成本 SoC,既可作 Wi-Fi 外围(通过 AT 固件用串口控制),也可单独作为主 MCU(烧入 NodeMCU/Arduino/ESP-IDF 程序运行)。常见和稳定的交互方式有:

AT 固件 + STM32 UART:STM32 用串口发 AT 指令控制 ESP8266 做 STA/AP、TCP/UDP、MQTT 等。

设备模式指令

AP模式指令

ESP 自主运行(Arduino/ESP-IDF/NodeMCU):直接在 ESP8266 上编写逻辑并连接传感器/执行器(适合快速原型)。

四、接线示意(以 ESP-01 为例)

VCC → 3.3V 稳定电源(注意不是 5V)

GND → GND(与 MCU 共地)

HAL库/标准库

PB10 → TX(模块)

PB11 → RX(模块)

  • 示例代码

标准库

设备模式

cpp 复制代码
/**
  ******************************************************************************
  * @file    bsp_usart.c
  * @author  fire
  * @version V1.0
  * @date    2013-xx-xx
  * @brief   重定向c库printf函数到usart端口
  ******************************************************************************
  * @attention
  *
  * 实验平台:野火STM32 F103-指南者 开发板  
  * 论坛    :http://www.firebbs.cn
  * 淘宝    :https://fire-stm32.taobao.com
  *
  ******************************************************************************
  */ 
	
#include "bsp_usart.h"
#include "bsp_SysTick.h"
#include "stdio.h"
#include "stm32f10x.h"
#include <string.h>

#define newRESET "AT+RST\r\n"//重启模块指令

int oknum=0,flagnum=0,lednum=0;
char buffer[12],buffer1[12],show1[20];
 
int AT_OK_Flag = 0; //OK返回值的标志位
int AT_Connect_Net_Flag = 0; //WIFI GOT IP返回值的标志位
 /**
  * @brief  配置嵌套向量中断控制器NVIC
  * @param  无
  * @retval 无
  */
static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /* 嵌套向量中断控制器组选择 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  /* 配置USART为中断源 */
  NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
  /* 抢断优先级*/
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  /* 子优先级 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  /* 使能中断 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  /* 初始化配置NVIC */
  NVIC_Init(&NVIC_InitStructure);
}


static void NVIC_Configuration1(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /* 嵌套向量中断控制器组选择 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  /* 配置USART为中断源 */
  NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ1;
  /* 抢断优先级*/
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 子优先级 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中断 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  /* 初始化配置NVIC */
  NVIC_Init(&NVIC_InitStructure);
}


 /**
  * @brief  USART GPIO 配置,工作参数配置
  * @param  无
  * @retval 无
  */
void USART_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

	// 打开串口GPIO的时钟
	DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
	// 打开串口外设的时钟
	DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);

	// 将USART Tx的GPIO配置为推挽复用模式
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);

  // 将USART Rx的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
	
	// 配置串口的工作参数
	// 配置波特率
	USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
	// 配置 针数据字长
	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(DEBUG_USARTx, &USART_InitStructure);
	
	// 串口中断优先级配置
	NVIC_Configuration();
	
	// 使能串口接收中断
	USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);	
	
	// 使能串口
	USART_Cmd(DEBUG_USARTx, ENABLE);	    
}

void USART_Config1(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

	// 打开串口GPIO的时钟
	DEBUG_USART_GPIO_APBxClkCmd1(DEBUG_USART_GPIO_CLK1, ENABLE);
	// 打开串口外设的时钟
	DEBUG_USART_APBxClkCmd1(DEBUG_USART_CLK1, ENABLE);

	// 将USART Tx的GPIO配置为推挽复用模式
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(DEBUG_USART_TX_GPIO_PORT1, &GPIO_InitStructure);

  // 将USART Rx的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(DEBUG_USART_RX_GPIO_PORT1, &GPIO_InitStructure);
	
	
	// 配置串口的工作参数
	// 配置波特率
	USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE1;
	// 配置 针数据字长
	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(DEBUG_USARTx1, &USART_InitStructure);
	
	// 串口中断优先级配置
	NVIC_Configuration1();
	
	// 使能串口接收中断
	USART_ITConfig(DEBUG_USARTx1, USART_IT_RXNE, ENABLE);	
	
	// 使能串口
	USART_Cmd(DEBUG_USARTx1, ENABLE);	    
}

/*****************  发送一个字节 **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
	/* 发送一个字节数据到USART */
	USART_SendData(pUSARTx,ch);
		
	/* 等待发送数据寄存器为空 */
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}

/****************** 发送8位的数组 ************************/
void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
{
  uint8_t i;
	
	for(i=0; i<num; i++)
  {
	    /* 发送一个字节数据到USART */
	    Usart_SendByte(pUSARTx,array[i]);	
  
  }
	/* 等待发送完成 */
	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}

/*****************  发送字符串 **********************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
	unsigned int k=0;
  do 
  {
      Usart_SendByte( pUSARTx, *(str + k) );
      k++;
  } while(*(str + k)!='\0');
  
  /* 等待发送完成 */
  while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
  {}
}

/*****************  发送一个16位数 **********************/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{
	uint8_t temp_h, temp_l;
	
	/* 取出高八位 */
	temp_h = (ch&0XFF00)>>8;
	/* 取出低八位 */
	temp_l = ch&0XFF;
	
	/* 发送高八位 */
	USART_SendData(pUSARTx,temp_h);	
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
	
	/* 发送低八位 */
	USART_SendData(pUSARTx,temp_l);	
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}

void USART2_IRQHandler( void )
{	
	static int i = 0;//静态变量,被初始化一次
	uint8_t tmp;
	char *ret,*ret2,*ret3;
	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) 
	{
		tmp  = USART_ReceiveData(USART2);
		Usart_SendByte(USART1,tmp);//打印从esp-01s接收到的数据
//		if((tmp == 'W' || tmp == 'O' || tmp == 'L')&& first==1){
		if(tmp == 'W' || tmp == 'O'|| tmp == 'L'){
			ret = strchr(buffer,'W');
			ret2 = strchr(buffer,'O');
			ret3 = strchr(buffer,'L');
			if((ret!=NULL)||(ret2!=NULL)||(ret3!=NULL))//防止前面有识别到时后面有出现关键字符,如WOFI_G,因为它识别到关键字符时会清零,所以要避开这种情况
			{
				
			}else
				i = 0;
			
		}
		buffer[i++] = tmp;
		
		if(i>=3)//判断是否是ok
		{
			if(buffer[0] == 'O' && buffer[1] == 'K'){
				AT_OK_Flag = 1;
				oknum=flagnum=lednum=0;//如果出现关键字符,清除其标志位
				memset(buffer, '\0', 12);
				i = 0; 
			}else
				oknum=1;//非ok标志位
			
			//灯控指令
			if(buffer[0] == 'L' && buffer[2] == '1'){
				GPIO_ResetBits(GPIOE,GPIO_Pin_1);//点亮D5
				oknum=flagnum=lednum=0;
				memset(buffer, '\0', 12);
			}else if(buffer[0] == 'L' && buffer[2] == '0'){
				GPIO_SetBits(GPIOE,GPIO_Pin_1);//熄灭D5
				oknum=flagnum=lednum=0;
				memset(buffer, '\0', 12);
			}else{
				lednum=1;
			}
		}
		if(i>=7)
		{
			if(buffer[0] == 'W' && buffer[5] == 'G'){//入网成功的判断依据WIFI GOT IP
				AT_Connect_Net_Flag = 1;
				oknum=flagnum=lednum=0;
				memset(buffer, '\0', 12);
				i = 0; 
			}else
				flagnum=1;//非WIFI GOT IP标志位
		}
		if(oknum==1 && flagnum==1 && lednum==1)//非关键字符串处理
		{
			i = 0; 
			oknum=flagnum=lednum=0;
			memset(buffer, '\0', 12);
		}

		//联网失败出现FAIL字样捕获
//		if(buffer[0] == 'F' && buffer[1] == 'A'){
//			for(i=0;i<5;i++){
//			GPIO_ResetBits(GPIOD,GPIO_Pin_3);
//			Delay_us(1000000);
//			GPIO_SetBits(GPIOD,GPIO_Pin_3);
//			Delay_us(1000000);
//		}
//			Usart_SendString(USART1,newRESET);
//			memset(buffer, '\0', 12);
//		}
		
		if(i == 12)//超出缓冲区上限处理,虽然实际上不太可能出现这种情况
		{		
			i = 0; 
			oknum=flagnum=lednum=0;
			memset(buffer, '\0', 12);
		}

	}
}



void USART1_IRQHandler( void )
{	
	static int j = 0;//静态变量,被初始化一次
	uint8_t tmp;
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) 
	{
	}
}
#include "stm32f10x.h"
#include "bsp_SysTick.h"
#include "bsp_usart.h"

extern char buffer[12];
#define LJWL "AT+CWJAP=\"ART\",\"19181716\"\r\n" //联网指令
#define LRST "AT+RST\r\n" //重启指令
#define LJFWQ "AT+CIPSTART=\"TCP\",\"192.168.43.17\",8880\r\n" //连接服务器指令
#define TCMS "AT+CIPMODE=1\r\n" //透传指令
#define SJCS "AT+CIPSEND\r\n" //数据传输开始指令


extern int AT_OK_Flag; //OK返回值的标志位
extern int AT_Connect_Net_Flag; //WIFI GOT IP返回值的标志位


int main()
{
	int i;
	SysTick_Init();
	USART_Config();
	USART_Config1();
	Usart_SendString(USART1,"TIMEWAIT\r\n");//等待esp-01s上电的初始化
	Delay_us(10000000);
	Usart_SendString(USART1,"TIMEWAITOK\r\n");
//	Usart_SendString(USART1,LJWL);//发送联网AT指令并等待成功,由于已经连过网了,所以这里指令就算发出去受到的也是error,没什么意义
	AT_Connect_Net_Flag=0;//提前清除标志位,因为本身上电后就会有很多初始化的数据过来,防止这些数据误触发了标志位
	Usart_SendString(USART2,LRST);
	while(!AT_Connect_Net_Flag);
	Delay_us(500000);//最好加上防止指令过快
	Usart_SendString(USART1,"20%\r\n");//查看当前联网进度

	AT_OK_Flag=0;
	Usart_SendString(USART2,LJFWQ);//发送连服务器指令并等待成功
	while(!AT_OK_Flag);
	AT_OK_Flag = 0;
	Delay_us(500000);
	Usart_SendString(USART1,"40%\r\n");
	
	AT_OK_Flag=0;
	Usart_SendString(USART2,TCMS);//发送透传模式指令并等待成功
	while(!AT_OK_Flag);
	AT_OK_Flag = 0;
	Delay_us(500000);
	Usart_SendString(USART1,"60%\r\n");
	
	AT_OK_Flag=0;
	Usart_SendString(USART2,SJCS);//发送数据传输指令并等待成功
	Delay_us(500000);
	while(!AT_OK_Flag);
	
	if(AT_Connect_Net_Flag){
		GPIO_ResetBits(GPIOD,GPIO_Pin_3);
	}
	if(AT_OK_Flag){
		GPIO_ResetBits(GPIOD,GPIO_Pin_2);//点亮D6,代表连接服务器并打开透传模式成功
	}
	Usart_SendString(USART1,"85%\r\n");
	Usart_SendString(USART1,"100%\r\n");
	while(1){
		Delay_us(1500000);
		//"心跳包"
		Usart_SendString(USART2,"xiaoliu shuai\r\n");		
	}
}

AP模式

cpp 复制代码
#include "stm32f10x.h"
#include "bsp_SysTick.h"
#include "bsp_usart.h"

extern char buffer[12];
#define LJWL "AT+CWMODE=3\r\n" //工作在路由模式
#define LRST "AT+CIPMUX=1\r\n" //使能多链接
#define LJFWQ "AT+CIPSERVER=1\r\n" //建立tcp服务器
#define TCMS "AT+CIPSEND=0,6\r\n" //发送数据
//#define SJCS "AT+CIPSEND\r\n" //数据传输开始指令

extern int AT_OK_Flag; //OK返回值的标志位
extern int AT_Clicent; //WIFI GOT IP返回值的标志位


int main()
{
	int i;
	SysTick_Init();
	USART_Config();
	USART_Config1();
	Usart_SendString(USART1,"TIMEWAIT\r\n");//等待esp-01s上电的初始化
	Delay_us(10000000);
	Usart_SendString(USART1,"20%\r\n");

	
	AT_OK_Flag=0;
	Usart_SendString(USART2,LJWL);//发送透传模式指令并等待成功
	while(!AT_OK_Flag);
	AT_OK_Flag = 0;
	Delay_us(500000);
	Usart_SendString(USART1,"40%\r\n");
	
	AT_OK_Flag=0;
	Usart_SendString(USART2,LRST);//发送透传模式指令并等待成功
	while(!AT_OK_Flag);
	AT_OK_Flag = 0;
	Delay_us(500000);
	Usart_SendString(USART1,"60%\r\n");
	
	AT_OK_Flag=0;
	Usart_SendString(USART2,LJFWQ);//发送数据传输指令并等待成功
	while(!AT_OK_Flag);
	AT_OK_Flag = 0;
	Delay_us(500000);
	Usart_SendString(USART1,"85%\r\n");
	
	AT_Clicent=0;
	while(!AT_Clicent);
	AT_Clicent=0;
	Usart_SendString(USART1,"100%\r\n");
	while(1){
		Usart_SendString(USART2,TCMS);	
		Delay_us(2000000);
		//"心跳包"
		Usart_SendString(USART2,"helloC");
		Delay_us(2000000);		
	}
}
/**
  ******************************************************************************
  * @file    bsp_usart.c
  * @author  fire
  * @version V1.0
  * @date    2013-xx-xx
  * @brief   重定向c库printf函数到usart端口
  ******************************************************************************
  * @attention
  *
  * 实验平台:野火STM32 F103-指南者 开发板  
  * 论坛    :http://www.firebbs.cn
  * 淘宝    :https://fire-stm32.taobao.com
  *
  ******************************************************************************
  */ 
	
#include "bsp_usart.h"
#include "bsp_SysTick.h"
#include "stdio.h"
#include "stm32f10x.h"
#include <string.h>

#define newRESET "AT+RST\r\n"//重启模块指令

int oknum=0,flagnum=0;
char buffer[12],buffer1[12],show1[20];
 
int AT_OK_Flag = 0; //OK返回值的标志位
int AT_Clicent = 0; //WIFI GOT IP返回值的标志位
 /**
  * @brief  配置嵌套向量中断控制器NVIC
  * @param  无
  * @retval 无
  */
static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /* 嵌套向量中断控制器组选择 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  /* 配置USART为中断源 */
  NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
  /* 抢断优先级*/
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  /* 子优先级 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  /* 使能中断 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  /* 初始化配置NVIC */
  NVIC_Init(&NVIC_InitStructure);
}


static void NVIC_Configuration1(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /* 嵌套向量中断控制器组选择 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  /* 配置USART为中断源 */
  NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ1;
  /* 抢断优先级*/
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 子优先级 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中断 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  /* 初始化配置NVIC */
  NVIC_Init(&NVIC_InitStructure);
}


 /**
  * @brief  USART GPIO 配置,工作参数配置
  * @param  无
  * @retval 无
  */
void USART_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

	// 打开串口GPIO的时钟
	DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
	// 打开串口外设的时钟
	DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);

	// 将USART Tx的GPIO配置为推挽复用模式
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);

  // 将USART Rx的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
	
	// 配置串口的工作参数
	// 配置波特率
	USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
	// 配置 针数据字长
	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(DEBUG_USARTx, &USART_InitStructure);
	
	// 串口中断优先级配置
	NVIC_Configuration();
	
	// 使能串口接收中断
	USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);	
	
	// 使能串口
	USART_Cmd(DEBUG_USARTx, ENABLE);	    
}

void USART_Config1(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

	// 打开串口GPIO的时钟
	DEBUG_USART_GPIO_APBxClkCmd1(DEBUG_USART_GPIO_CLK1, ENABLE);
	// 打开串口外设的时钟
	DEBUG_USART_APBxClkCmd1(DEBUG_USART_CLK1, ENABLE);

	// 将USART Tx的GPIO配置为推挽复用模式
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(DEBUG_USART_TX_GPIO_PORT1, &GPIO_InitStructure);

  // 将USART Rx的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(DEBUG_USART_RX_GPIO_PORT1, &GPIO_InitStructure);
	
	
	// 配置串口的工作参数
	// 配置波特率
	USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE1;
	// 配置 针数据字长
	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(DEBUG_USARTx1, &USART_InitStructure);
	
	// 串口中断优先级配置
	NVIC_Configuration1();
	
	// 使能串口接收中断
	USART_ITConfig(DEBUG_USARTx1, USART_IT_RXNE, ENABLE);	
	
	// 使能串口
	USART_Cmd(DEBUG_USARTx1, ENABLE);	    
}

/*****************  发送一个字节 **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
	/* 发送一个字节数据到USART */
	USART_SendData(pUSARTx,ch);
		
	/* 等待发送数据寄存器为空 */
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}

/****************** 发送8位的数组 ************************/
void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
{
  uint8_t i;
	
	for(i=0; i<num; i++)
  {
	    /* 发送一个字节数据到USART */
	    Usart_SendByte(pUSARTx,array[i]);	
  
  }
	/* 等待发送完成 */
	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}

/*****************  发送字符串 **********************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
	unsigned int k=0;
  do 
  {
      Usart_SendByte( pUSARTx, *(str + k) );
      k++;
  } while(*(str + k)!='\0');
  
  /* 等待发送完成 */
  while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
  {}
}

/*****************  发送一个16位数 **********************/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{
	uint8_t temp_h, temp_l;
	
	/* 取出高八位 */
	temp_h = (ch&0XFF00)>>8;
	/* 取出低八位 */
	temp_l = ch&0XFF;
	
	/* 发送高八位 */
	USART_SendData(pUSARTx,temp_h);	
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
	
	/* 发送低八位 */
	USART_SendData(pUSARTx,temp_l);	
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}

void USART2_IRQHandler( void )
{	
	static int i = 0;//静态变量,被初始化一次
	uint8_t tmp;
	char *ret,*ret2,*ret3,*ret4;
	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) 
	{
		tmp  = USART_ReceiveData(USART2);
		Usart_SendByte(USART1,tmp);//打印从esp-01s接收到的数据
		if(tmp == 'W' || tmp == 'O'|| tmp == 'L' || tmp == '0'){
			ret = strchr(buffer,'W');
			ret2 = strchr(buffer,'O');
			ret3 = strchr(buffer,'L');
			ret4 = strchr(buffer,'0');
			if((ret!=NULL)||(ret2!=NULL)||(ret3!=NULL)||(ret4!=NULL))//防止前面有识别到时后面有出现关键字符,如WOFI_G,因为它识别到关键字符时会清零,所以要避开这种情况
			{
				
			}else
				i = 0;
			
		}
		buffer[i++] = tmp;
		
		if(i>=3)//判断是否是ok
		{
			if(buffer[0] == 'O' && buffer[1] == 'K'){
				AT_OK_Flag = 1;
				oknum=flagnum=0;//如果出现关键字符,清除其标志位
				memset(buffer, '\0', 12);
				i = 0; 
			}else
				oknum=1;//非ok标志位
			
		}
		if(i>=7)
		{
			if(buffer[0] == '0' && buffer[4] == 'N'){//入网成功的判断依据WIFI GOT IP
				AT_Clicent = 1;
				oknum=flagnum=0;
				memset(buffer, '\0', 12);
				i = 0; 
			}else
				flagnum=1;//非WIFI GOT IP标志位
		}
		if(oknum==1 && flagnum==1)//非关键字符串处理
		{
			i = 0; 
			oknum=flagnum=0;
			memset(buffer, '\0', 12);
		}

		//联网失败出现FAIL字样捕获
//		if(buffer[0] == 'F' && buffer[1] == 'A'){
//			for(i=0;i<5;i++){
//			GPIO_ResetBits(GPIOD,GPIO_Pin_3);
//			Delay_us(1000000);
//			GPIO_SetBits(GPIOD,GPIO_Pin_3);
//			Delay_us(1000000);
//		}
//			Usart_SendString(USART1,newRESET);
//			memset(buffer, '\0', 12);
//		}
		
		if(i == 12)//超出缓冲区上限处理,虽然实际上不太可能出现这种情况
		{		
			i = 0; 
			oknum=flagnum=0;
			memset(buffer, '\0', 12);
		}

	}
}



void USART1_IRQHandler( void )
{	
	static int j = 0;//静态变量,被初始化一次
	uint8_t tmp;
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) 
	{
	}
}

HAL库

设备模式

cpp 复制代码
#include "bsp_esp8266.h"
#include "common.h"
#include <stdio.h>  
#include <string.h>  
#include <stdbool.h>
#include "cJSON.h"
#include <stdlib.h>

#define NET_TIME "GET http://api.k780.com:88/?app=life.time&appkey=70087&sign=b68078fc7206f646d911624cd3e1ad6d&format=json\r\n\r\n"
char * netstr;
uint32_t start;
void realtime()
{
//	while(ESP8266_Link_Server(enumTCP,"45.76.213.158","88",Single_ID_0) == 0);
//	ESP8266_SendString(DISABLE,NET_TIME,strlen(NET_TIME),Single_ID_0);
//	netstr = ESP8266_ReceiveString(DISABLE,5000);
//	if(netstr){
//		cJSON * root = cJSON_Parse(netstr);
//		if(root){
//			cJSON * item = cJSON_GetObjectItem(root,"result");
//			if(item){
//				item = cJSON_GetObjectItem(item,"timestamp");
//				if(item){
//					RTC_WaitForLastTask();
//					RTC_SetCounter(atoi(item->valuestring));
//					RTC_WaitForLastTask();
//				}
//			}
//			cJSON_Delete(root);
//		}
//	}
}

void macESP8266_USART_IDE_FUN(void)
{
  if (__HAL_UART_GET_FLAG(&macESP8266_USARTx, UART_FLAG_IDLE) != RESET)
  {
    __HAL_UART_CLEAR_IDLEFLAG(&macESP8266_USARTx);  // 清除IDLE标志
    strEsp8266_Fram_Record.InfBit.FramFinishFlag = 1;
    
    // 可选:重启接收(如果用 HAL_UART_Receive_IT 或 HAL_UART_Receive_DMA)
    // HAL_UART_Receive_IT(&huart3, (uint8_t *)strEsp8266_Fram_Record.Data_RX_BUF, RX_BUF_MAX_LEN);
  }
}

void macESP8266_USART_INT_FUN(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART3)
  {
    uint8_t ucCh = uart3_rx_temp;  // 临时变量接收

    if (strEsp8266_Fram_Record.InfBit.FramLength < RX_BUF_MAX_LEN - 1)
    {
      strEsp8266_Fram_Record.Data_RX_BUF[strEsp8266_Fram_Record.InfBit.FramLength++] = ucCh;
    }

    // 继续接收下一字节
    HAL_UART_Receive_IT(&huart3, &uart3_rx_temp, 1);
  }
}

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 };
struct  STRUCT_USARTx_Fram strUSART_Fram_Record = { 0 };


/**
  * @brief  ESP8266初始化函数
  * @param  无
  * @retval 无
  */
void ESP8266_Init ( void )
{
	ESP8266_GPIO_Config (); 
	
//	ESP8266_USART_Config (); 
	
	
	macESP8266_RST_HIGH_LEVEL();

	macESP8266_CH_ENABLE();
	
	 // 启动第一次接收,让 HAL_UART_RxCpltCallback/IDLE 触发
    HAL_UART_Receive_IT(&huart3, (uint8_t *)&uart3_rx_temp, 1);
}


/**
  * @brief  初始化ESP8266用到的GPIO引脚
  * @param  无
  * @retval 无
  */
static void ESP8266_GPIO_Config ( void )
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	/* 配置 CH 引脚*/
  __HAL_RCC_GPIOB_CLK_ENABLE();
	GPIO_InitStruct.Pin = macESP8266_CH_PD_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
	
	/* 配置 RST 引脚*/
	__HAL_RCC_GPIOB_CLK_ENABLE();
	GPIO_InitStruct.Pin = macESP8266_RST_PIN;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}


///**
//  * @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 = 1;
//	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();
	 HAL_Delay ( 500 ); 
	 macESP8266_RST_HIGH_LEVEL();
	#endif

}


/*
 * 函数名:ESP8266_Cmd
 * 描述  :对WF-ESP8266模块发送AT指令
 * 输入  :cmd,待发送的指令
 *         reply1,reply2,期待的响应,为NULL表不需响应,两者为或逻辑关系
 *         waittime,等待响应的时间
 * 返回  : 1,指令发送成功
 *         0,指令发送失败
 * 调用  :被外部调用
ESP8266_Cmd ( "AT", "OK", NULL, 500 ) 
 */
bool ESP8266_Cmd ( char * cmd, char * reply1, char * reply2, u32 waittime )
{
	bool res = false;
	strEsp8266_Fram_Record .InfBit .FramLength = 0;               //从新开始接收新的数据包
	macESP8266_Usart ( "%s\r\n", cmd );
	if ( ( reply1 == 0 ) && ( reply2 == 0 ) )                      //不需要接收数据
		return true;
	
	while(1){
		//HAL_Delay ( waittime );                 //延时
		HAL_Delay ( 1 );                 //延时
		waittime--;
		if(waittime==0) break;
		if(strEsp8266_Fram_Record .InfBit .FramFinishFlag==0)continue;
		
		strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ]  = '\0';

//		macPC_Usart ( "%s", strEsp8266_Fram_Record .Data_RX_BUF );
		
		//strEsp8266_Fram_Record .InfBit .FramLength = 0;         //清除接收标志
		strEsp8266_Fram_Record .InfBit .FramFinishFlag = 0;
		if ( ( reply1 != 0 ) && ( reply2 != 0 ) ){
			res = ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply1 ) || 
							 ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply2 ) ); 
		}
		
		else if ( reply1 != 0 ){
			res = ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply1 ) );
		}else{
			res = ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply2 ) );
		}
		if(res) break;
	}
	return res;
}


/*
 * 函数名:ESP8266_AT_Test
 * 描述  :对WF-ESP8266模块进行AT测试启动
 * 输入  :无
 * 返回  : 无
 * 调用  :被外部调用
 */
//void ESP8266_AT_Test ( void )
//{
//	macESP8266_RST_HIGH_LEVEL();
//	
//	HAL_Delay ( 1000 ); 
//	
//	while ( ! ESP8266_Cmd ( "AT", "OK", NULL, 500 ) ) ESP8266_Rst ();  	

//}
void ESP8266_AT_Test ( void )
{
	char count=0;
	
	macESP8266_RST_HIGH_LEVEL();	
	HAL_Delay ( 2000 );
	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, 1000 );
	
}


/*
 * 函数名: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 )
{
	char cStr [20];
	
	sprintf ( cStr, "AT+CIPMUX=%d", ( enumEnUnvarnishTx ? 1 : 0 ) );
	
	return ESP8266_Cmd ( cStr, "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 )
{
	if ( ! ESP8266_Cmd ( "AT+CIPMODE=1", "OK", 0, 500 ) )
		return false;
	
	return 
	  ESP8266_Cmd ( "AT+CIPSEND", "OK", ">", 500 );
	
}


/*
 * 函数名:ESP8266_ExitUnvarnishSend
 * 描述  :配置WF-ESP8266模块退出透传模式
 * 输入  :无
 * 返回  : 无
 * 调用  :被外部调用
 */
void ESP8266_ExitUnvarnishSend ( void )
{
	HAL_Delay ( 1000 );
	
	macESP8266_Usart ( "+++" );
	
	HAL_Delay ( 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 [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;

}


/*
 * 函数名:ESP8266_ReceiveString
 * 描述  :WF-ESP8266模块接收字符串
 * 输入  :enumEnUnvarnishTx,声明是否已使能了透传模式
 * 返回  : 接收到的字符串首地址
 * 调用  :被外部调用
 */
char * ESP8266_ReceiveString ( FunctionalState enumEnUnvarnishTx, u32 waittime  )
{
	char * pRecStr = 0;
	
	/* 先清理旧标志、未清则前面已做 */
    while (!strEsp8266_Fram_Record.InfBit.FramFinishFlag && waittime--) {
        HAL_Delay(10);
    }

    /* 加个尾 '\0' */
    strEsp8266_Fram_Record.Data_RX_BUF[strEsp8266_Fram_Record.InfBit.FramLength] = '\0';
	
	pRecStr = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+IPD" );
	if ( pRecStr ){
		char *end;
		pRecStr = strstr(pRecStr, ":") + 1;
		end = strstr(pRecStr, "CLOSED");
		if(end){
			*end = 0;
		}
		return pRecStr;
	}
	strEsp8266_Fram_Record .InfBit .FramLength = 0;
	strEsp8266_Fram_Record .InfBit .FramFinishFlag = 0;
	
//	while ( ! strEsp8266_Fram_Record .InfBit .FramFinishFlag ){
//		waittime--;
//		HAL_Delay(10);
//		if(waittime==0){
//			return 0;
//		}
//	}
	start = HAL_GetTick();
	while (!strEsp8266_Fram_Record.InfBit.FramFinishFlag) {
    if ((HAL_GetTick() - start) >= waittime) {
        return 0;
    }
    // 不要再放 HAL_Delay,这里让中断随时进来处理
	}
	
	strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ] = '\0';
	
	if ( enumEnUnvarnishTx )
		pRecStr = strEsp8266_Fram_Record .Data_RX_BUF;
	else 
	{
		pRecStr = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+IPD" );
		if ( pRecStr ){
			char *end;
			pRecStr = strstr(pRecStr, ":") + 1;
			end = strstr(pRecStr, "CLOSED");
			if(end){
				*end = 0;
			}
		}

	}

	return pRecStr;
	
}
uint8_t uart3_rx_temp;
char usart[100]={0};
extern struct  STRUCT_USARTx_Fram strEsp8266_Fram_Record;
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_USART3_UART_Init();
  /* USER CODE BEGIN 2 */
	// 启动接收中断
	HAL_Delay(6000);
	ESP8266_Init();
  // 启动接收

	// 手动启用 IDLE 中断(必须)
	__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
	HAL_Delay(6000);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	HAL_UART_Transmit(&huart1, "ESP8266 AT Test...\r\n", strlen("ESP8266 AT Test...\r\n"), HAL_MAX_DELAY);
  ESP8266_AT_Test();
	if (!strstr(strEsp8266_Fram_Record.Data_RX_BUF, "OK"))
  {
		HAL_UART_Transmit(&huart1, "AT Test Failed!\r\n", strlen("AT Test Failed!\r\n"), HAL_MAX_DELAY);
      while (1);
  }
	HAL_UART_Transmit(&huart1, "OK\r\n", strlen("OK\r\n"), HAL_MAX_DELAY);
	HAL_UART_Transmit(&huart1, "Joining AP...\r\n", strlen("Joining AP...\r\n"), HAL_MAX_DELAY);
  if (ESP8266_JoinAP("yzzl", "yzzl2021"))
  {
		HAL_UART_Transmit(&huart1, "Join AP OK\r\n", strlen("Join AP OK\r\n"), HAL_MAX_DELAY);
  }
  else
  {
		HAL_UART_Transmit(&huart1, "Join AP Failed!\r\n", strlen("Join AP Failed!\r\n"), HAL_MAX_DELAY);
  }
	
	if (ESP8266_JoinAP("yzzl", "yzzl2021"))
  {
		HAL_UART_Transmit(&huart1, "Join AP OK\r\n", strlen("Join AP OK\r\n"), HAL_MAX_DELAY);
  }
  else
  {
		HAL_UART_Transmit(&huart1, "Join AP Failed!\r\n", strlen("Join AP Failed!\r\n"), HAL_MAX_DELAY);
  }
	
	if (ESP8266_JoinAP("yzzl", "yzzl2021"))
  {
		HAL_UART_Transmit(&huart1, "Join AP OK\r\n", strlen("Join AP OK\r\n"), HAL_MAX_DELAY);
  }
  else
  {
		HAL_UART_Transmit(&huart1, "Join AP Failed!\r\n", strlen("Join AP Failed!\r\n"), HAL_MAX_DELAY);
  }
		
		
		
		/* 6. 连接远程服务器测试 */ 
	HAL_UART_Transmit(&huart1, "Link to server...\r\n", strlen("Link to server...\r\n"), HAL_MAX_DELAY);
	if (ESP8266_Link_Server(enumTCP, "192.168.31.39", "8080", Single_ID_0)) 
	    HAL_UART_Transmit(&huart1, "CIPSTART OK\r\n", strlen("CIPSTART OK\r\n"), HAL_MAX_DELAY);
	else    
			HAL_UART_Transmit(&huart1, "CIPSTART Failed!\r\n", strlen("CIPSTART Failed!\r\n"), HAL_MAX_DELAY); 
	/* 7. 发送测试数据 */ 
	const char *testMsg = "Hello from STM32!";
	HAL_UART_Transmit(&huart1, "Send data...\r\n", strlen("Send data...\r\n"), HAL_MAX_DELAY);
	if (ESP8266_SendString(DISABLE, (char *)testMsg, strlen(testMsg), Single_ID_0)) 
		HAL_UART_Transmit(&huart1, "SEND OK\r\n", strlen("SEND OK\r\n"), HAL_MAX_DELAY);
	else 
	  HAL_UART_Transmit(&huart1, "SEND Failed!\r\n", strlen("SEND Failed!\r\n"), HAL_MAX_DELAY); 
	/* 8. 接收服务器响应 */
	HAL_UART_Transmit(&huart1, "Waiting response...\r\n", strlen("Waiting response...\r\n"), HAL_MAX_DELAY);
	
	ESP8266_PrepareReceive();
	char *rec = ESP8266_ReceiveString(DISABLE, 5000); 
	if (rec) {     
		sprintf(usart,"Received: %s\r\n", rec);
		HAL_UART_Transmit(&huart1, usart, strlen(usart), HAL_MAX_DELAY);
	}
	else
		HAL_UART_Transmit(&huart1, "No response or timeout\r\n", strlen("No response or timeout\r\n"), HAL_MAX_DELAY);  
  while (1)
  {
		ESP8266_PrepareReceive();
		HAL_Delay(1000);
    if (ESP8266_Cmd("AT+CIFSR", "OK", NULL, 500))
    {
			/* 假定 usart[64] */
			snprintf(usart, sizeof(usart), "IP: %s\r\n", strEsp8266_Fram_Record.Data_RX_BUF);

			HAL_UART_Transmit(&huart1, usart, strlen(usart), HAL_MAX_DELAY);
    }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
/**
  * @brief This function handles USART3 global interrupt.
  */
void USART3_IRQHandler(void)
{
  /* USER CODE BEGIN USART3_IRQn 0 */

  /* USER CODE END USART3_IRQn 0 */
  /* USER CODE BEGIN USART3_IRQn 1 */
	USART3_IDLE_IRQHandler();
	HAL_UART_IRQHandler(&huart3);  // HAL库处理通用中断
  USART3_IDLE_IRQHandler();      // 手动处理IDLE中断
  /* USER CODE END USART3_IRQn 1 */
}

六、讲解视频

https://www.bilibili.com/video/BV1enmcByE4N/?spm_id_from=333.1387.upload.video_card.click&vd_source=f7dfe1b14f260b9cc3a146d2dbfd0719

https://www.bilibili.com/video/BV1aWmcBkEsD/?spm_id_from=333.1387.upload.video_card.click\&vd_source=f7dfe1b14f260b9cc3a146d2dbfd0719

相关推荐
点灯master2 小时前
miniOTA:32位mcu平台OTA升级
单片机·嵌入式硬件
qqssss121dfd2 小时前
计算机网络(第8版,谢希仁)第四章习题解答
服务器·c语言·网络·单片机·计算机网络
byte轻骑兵2 小时前
【安全函数】memmove_s ():C 语言内存安全迁移的守护者与 memmove 深度对比
c语言·开发语言·安全
HarrySunCn2 小时前
大夏龙雀DX-CT511N-B实战之路-第1步
前端·单片机·物联网·iot
田甲2 小时前
STM32L051实现RTC低功耗唤醒
stm32·嵌入式硬件·实时音视频
清月电子11 小时前
杰理AC109N系列AC1082 AC1074 AC1090 芯片停产替代及资料说明
人工智能·单片机·嵌入式硬件·物联网
sevenez11 小时前
Vibe Coding 实战笔记:从“修好了C坏了AB”到企业级数据库架构重构
c语言·笔记·数据库架构
智嵌电子11 小时前
【笔记篇】【硬件基础篇】模拟电子技术基础 (童诗白) 第10章 模拟电子电路读图
笔记·单片机·嵌入式硬件