一、ESP8265概述

        官方网址:ESP8266 Wi-Fi MCU I 乐鑫科技 (espressif.com.cn)

        ESP8266模块 ---wifi 模块
        产品特点:

ESP8266 是什么?

        ESP8266 是由乐鑫科技(Espressif Systems)开发的一款低成本、高性能的 Wi-Fi 微控制器芯片 / 模块,集成了 32 位 Tensilica L106 处理器、Wi-Fi 射频(802.11 b/g/n)、TCP/IP 协议栈,以及丰富的 GPIO 引脚和外设接口(I2C、SPI、UART 等)。

        

        它的核心优势是 **“低成本实现 Wi-Fi 联网”**—— 相比传统的 “MCU + 独立 Wi-Fi 模块” 方案,ESP8266 直接将处理器和 Wi-Fi 功能集成,成本可低至几美元,且体积小巧(常见模块如 ESP-12F 尺寸仅 24mm×16mm),因此成为物联网(IoT)领域的 “明星产品”。

ESP8266 能干什么?

ESP8266 的核心功能是 **“让设备接入 Wi-Fi 网络”**,因此被广泛用于需要联网的场景,典型应用包括:

  • 物联网(IoT)设备:如智能传感器(温湿度、光照、烟雾传感器)的数据上传(发送到云端服务器或手机);
  • 智能家居:控制灯光、窗帘、空调等设备(通过 Wi-Fi 接收手机 APP 指令);
  • 远程监控:连接摄像头或传感器,实时向手机推送数据;
  • Wi-Fi 网关:将其他协议(如蓝牙、ZigBee)的设备数据转换为 Wi-Fi 信号转发;
  • 简易服务器:作为小型 Web 服务器,通过浏览器直接控制设备(例如网页按钮控制灯光开关)。

1. ESP8266中的wifi:

         ESP8266EX支持TCP/IP协议,完全遵循802.11 b/g/n WLAN MAC协议,支持分布式控制功能(DCF)下的基本服务集(BSS)STA和SoftAP操作。支持通过最小化主机交互来优化有效工作时长,以实现功耗管理。

         我们主要使用esp8266的wifi功能:

2.AT指令集的概念:

        AT指令是应用于终端设备与 PC 应用之间的连接与通信的指令。 AT Attention 。每个 AT 命令行中只能 包含一条AT 指令;对于 AT 指令的发送,除 AT 两个字符外,最多可以接收 1056 个字符的长度(包括最后的空字符)。
        格式: AT + CMD

3. ESP8266引脚:

 需要配置的引脚:

1. 复位:

2. 使能管脚:

3.  电源部分:

4.  串口

以下为单片机与ESP8266的连接方式:

启动模式:

         程序正常运行,我们需要保证使能位和RST,必须拉高

二、ESP8266的联网步骤

步骤 AT 指令(串口发送) 期望返回 作用说明
1 AT+CWMODE=1 OK 设为 STA 模式
2 AT+RST 重启日志 + ready + OK 重启生效模式
3 AT+CWJAP="MyWiFi","1234" WIFI CONNECTED
WIFI GOT IP
OK
连 Wi-Fi 成功
4 AT+CIPMUX=0 OK 设为单连接模式
5 AT+CIPSTART="TCP","192.168.1.100",8888 CONNECT OK 连 TCP 服务器成功
6 AT+CIPMODE=1 OK 开透传模式
7 AT+CIPSEND > 进入透传,可直接发数据
8 Hello Server! (无返回,直接传给服务器) 透传数据
9 +++(发之前停 1 秒) OK 退出透传,切回 AT 指令模式

1. AT+CWMODE=1:设置工作模式(STA 模式)

  • 作用:让 ESP8266 作为「Station(站点)」,即像手机、电脑一样,去连接外部 Wi-Fi 热点。
  • 模式说明
    • Station: 用作客户端,是需要连接路由器或者热点
      SoftAP: 用作服务器端,本身可以作为热点使用
      SoftAP+Station :混合模式。
  • 实操
    串口发送 AT+CWMODE=1,收到 OK 则设置成功。

2. AT+RST:模块重启(让工作模式生效)
  • 作用:ESP8266 是 “单片机思维”,改完模式后需重启才能真正切换。
  • 细节
    发送 AT+RST 后,模块会重启,串口会打印一堆启动日志(如 ready 等),最后回到可接收 AT 指令状态。

3. AT+CWJAP="SSID","PASSWORD":连接 Wi-Fi 热点

  • 作用:让 ESP8266 接入你指定的 Wi-Fi 网络。
  • 参数说明
    • SSID:你要连的 Wi-Fi 名称(字符串,必须用英文双引号包裹)
    • PASSWORD:Wi-Fi 密码(同理,英文双引号包裹,无密码则填 "" )
  • 实操
    比如连名为 MyWiFi、密码 12345678 的 Wi-Fi,发送:
    AT+CWJAP="MyWiFi","12345678"
    
    等待几秒,收到 WIFI CONNECTED(连成功) + WIFI GOT IP(分配到 IP) + OK,则联网完成。

4. AT+CIPMUX=0:设置单路连接模式

  • 作用:告诉模块,接下来要建立 1 对 1 的 TCP/UDP 连接(单连接模式)。
  • 模式说明
    • CIPMUX=0:单连接(同一时间只能连 1 个服务器)
    • CIPMUX=1:多连接(可同时连多个服务器,需配合 AT+CIPSERVER 等指令)
  • 何时用
    如果你只是想连一个服务器(比如传数据到自己的云平台),选 0 更简单。

5. AT+CIPSTART="TCP","IP地址",端口号:建立 TCP 连接

  • 作用:让 ESP8266 主动连到你指定的 TCP 服务器(比如自己电脑开的 TCP 服务、云平台)。
  • 参数说明
    • TCP:协议类型(也支持 UDP,按需换)
    • IP地址:服务器的公网 / 局域网 IP(比如本地调试填 192.168.1.100,云平台填 47.xxx.xxx.xxx )
    • 端口号:服务器监听的端口(如 8080 3333,需和服务器程序对应)
  • 实操
    比如连本地电脑(IP 192.168.1.100,端口 8888)的 TCP 服务,发送:
    AT+CIPSTART="TCP","192.168.1.100",8888
    
    收到 CONNECT OK 则连接成功,失败会返回 CONNECT FAIL(检查 IP、端口、服务器是否开启)。

6. AT+CIPMODE=1:开启透传模式

  • 作用:进入「透传」状态 —— 你从串口发的所有数据,会直接透传给 TCP/UDP 服务器,无需额外加指令头(反之,服务器发的数据也会直接返回串口)。
  • 对比普通模式
    • 普通模式(CIPMODE=0)发数据,需先 AT+CIPSEND=长度,再发内容(麻烦);
    • 透传模式(CIPMODE=1)发数据,直接敲内容就行(简单,适合持续传数据)。

7. AT+CIPSEND:进入透传数据发送

  • 作用:在透传模式下,执行这条指令后,模块进入 “数据直通” 状态。
  • 实操
    发送 AT+CIPSEND 后,串口会返回 >,此时你输入的任何内容(比如 Hello Server! ),都会直接通过 TCP 发给服务器,无需额外处理。

8. +++:退出透传模式
  • 作用:从透传状态切回 “AT 指令模式”,方便你发其他 AT 指令(比如断网、改配置)。
  • 关键细节
    发 +++ 时,必须保证串口没有其他数据同时发送(即发 +++ 前后,要等 1 秒左右无数据,否则模块可能识别成普通数据)。
    成功退出后,串口会返回 OK,此时可继续发 AT+CWQAP(断开 Wi-Fi)等指令。

 

三、具体代码案例

1.esp8266.c:

#include "esp8266.h"
#include "delay.h"
#include "stdio.h"
#include "string.h"
#include "esp_data.h"
//配置串口+ESP8266使能和复位
void usart3_Init(u32 brr)
{
	GPIO_InitTypeDef GPIOInitTypeDef;
	USART_InitTypeDef USARTInitTypeDef;
	//打开时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
	//配置PB10--TX PB11--RX
	//PB10--复用推挽输出
	GPIOInitTypeDef.GPIO_Pin=GPIO_Pin_10;
	GPIOInitTypeDef.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIOInitTypeDef.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIOInitTypeDef);
	//PB11--浮空
	GPIOInitTypeDef.GPIO_Pin=GPIO_Pin_11;
	GPIOInitTypeDef.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOB,&GPIOInitTypeDef);
	//usart3的配置
	USARTInitTypeDef.USART_BaudRate=brr;
	USARTInitTypeDef.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
	USARTInitTypeDef.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
	USARTInitTypeDef.USART_Parity=USART_Parity_No;
	USARTInitTypeDef.USART_StopBits=USART_StopBits_1;
	USARTInitTypeDef.USART_WordLength=USART_WordLength_8b;
	USART_Init(USART3,&USARTInitTypeDef);
	usart3_It_Config();
	USART_Cmd(USART3,ENABLE);
}
//配置中断 接收和空闲
void usart3_It_Config(void)
{
	//设置空闲中断和接收中断
	USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);
	USART_ITConfig(USART3,USART_IT_IDLE,ENABLE);
	
	//

	NVIC_SetPriority(USART3_IRQn,0);//占先优先级:1 次级优先级:1 
	NVIC_EnableIRQ(USART3_IRQn);
}

void ESP8266_IO_Config(void)
{
	GPIO_InitTypeDef gpio_initsources;
	//打开时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG,ENABLE);
	gpio_initsources.GPIO_Pin=GPIO_Pin_13|GPIO_Pin_14;
	gpio_initsources.GPIO_Mode=GPIO_Mode_Out_PP;
	gpio_initsources.GPIO_Speed=GPIO_Speed_2MHz;
	//配置PB5
	//void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
	GPIO_Init(GPIOG,&gpio_initsources);
}
//联网流程
u8 Esp8266_AT_test(void)
{
	//"AT\r\n"
	char count=0;
	GPIO_SetBits ( GPIOG, GPIO_Pin_13 );
	GPIO_SetBits ( GPIOG, GPIO_Pin_14 );
  printf("\r\nAT测试.....\r\n");
	delay_ms ( 2000 );
	while ( count < 10 )
	{
    printf("\r\nAT测试次数 %d......\r\n", count);
		if( ESP8266_Cmd ( "AT", "OK",NULL,500) )
    {
      printf("\r\nAT测试启动成功 %d......\r\n", count);
      return 1;
    }
		//复位以下
		GPIO_ResetBits ( GPIOG, GPIO_Pin_14 );
	  delay_ms ( 500 ); 
	  GPIO_SetBits ( GPIOG, GPIO_Pin_14 );
		++ count;
	}
  return 0;
}
//AT+CWMODE=1
bool ESP8266_SetMode(u8 mode)
{
	char esp_cmd[100];
//	switch(mode)
//	{
//		case 1:sprintf(esp_cmd,"AT+CWMODE=%d",mode);break;
//		case 2:sprintf(esp_cmd,"AT+CWMODE=%d",mode);break;
//		case 3:sprintf(esp_cmd,"AT+CWMODE=%d",mode);break
//	}
//	
	sprintf(esp_cmd,"AT+CWMODE=%d",mode);
	
	return (ESP8266_Cmd(esp_cmd,"OK",NULL,500));

}
//设置联网热点
//AT+CWJAP="111","11111111"  
bool ESP8266_SET_HotPort(void)
{
	char esp_cmd[100];
	sprintf(esp_cmd,"AT+CWJAP=\"%s\",\"%s\"",WIFI_ID,WIFI_PW);
	return (ESP8266_Cmd(esp_cmd,"OK",NULL,500));
	
}
//AT+CIPMUX=0--单链接
bool ESP8266_Set_CIPmux(u8 cipmux)
{
	char esp_cmd[100];
	sprintf(esp_cmd,"AT+CIPMUX=%d",cipmux);
	
	return (ESP8266_Cmd(esp_cmd,"OK",NULL,500));
	
}

bool ESP8266_Set_CIPSTART(u8 link_id)
{
	char esp_cmd[100];
	//整理需要发送的指令格式
	if(link_id<5)
	{
		//多链接
		
	}
	else 
	{
		//单链接
		//AT+CIPSTART="TCP","iot.espressif.cn",8000

		sprintf(esp_cmd,"AT+CIPSTART=\"%s\",\"%s\",%d","TCP",SER_IP,SER_PORT);
	}
	return (ESP8266_Cmd(esp_cmd,"OK","ALREADY	CONNECT",500));
	
}

u8 ESP8266_Send_Data(void)
{
	//设置透传模式
	if ( ! ESP8266_Cmd ( "AT+CIPMODE=1", "OK", 0, 500 ) )
		return false;
	//开始数据传输
	return   //必须接收到  “>”,然后才可以进入透传模式
	  ESP8266_Cmd ( "AT+CIPSEND", "OK", ">", 500 );
}

void ESP8266_NET_Config(void)
{
	GPIO_SetBits ( GPIOG, GPIO_Pin_13 );//使能ESP8266
	
	printf("配置ESP8266联网流程\r\n");
	//联网流程
//	Esp8266_AT_test();
	while(!Esp8266_AT_test());
	
	//
	printf("正在配置ESP8266模式\r\n");
	while(!ESP8266_SetMode(1));
	printf("正在配置WIFI热点信息\r\n");
	while(!ESP8266_SET_HotPort());
	
	printf("正在配置单链接\r\n");
	while(!ESP8266_Set_CIPmux(0));
	
	//
	printf("正在配置服务器端信息\r\n");
	while(!ESP8266_Set_CIPSTART(5));
	
	//透传模式配置
	printf("进入透传模式\r\n");
	while(!ESP8266_Send_Data());
	printf("进入透传模式成功\r\n");
	printf("开始传输数据\r\n");
	
}

对应的.h文件:

#ifndef _ESP8266_H_
#define _ESP8266_H_
#include "stm32f10x.h"
#include <stdbool.h>

//enum{
//	Station=1,
//	SoftAP,
//	SoftSta
//}Cmode;
#define WIFI_ID "iPhone010"   //热点ID
#define WIFI_PW "66666666"   //热点密码

#define SER_IP  ""  //连接的服务器的ip,建议为云服务器,因为有公网ip
#define SER_PORT  8000   //端口号


void usart3_Init(u32 brr);
void usart3_It_Config(void);
void ESP8266_IO_Config(void);
u8 Esp8266_AT_test(void);
bool ESP8266_SetMode(u8 mode);
bool ESP8266_SET_HotPort(void);
bool ESP8266_Set_CIPmux(u8 cipmux);
bool ESP8266_Set_CIPSTART(u8 link_id);
	u8 ESP8266_Send_Data(void);
void ESP8266_NET_Config(void);

#endif

2.esp_data.c:


#include "esp_data.h"
#include "stdarg.h"
#include "string.h"
#include <stdbool.h>
#include <delay.h>
#include <stdio.h>
#include "esp8266.h"


struct  STRUCT_USARTx_Fram strEsp8266_Fram_Record = { 0 };
struct  STRUCT_USARTx_Fram strUSART_Fram_Record = { 0 };

static char *itoa( int value, char * string, int radix );

void USART_printf ( USART_TypeDef * USARTx, char * Data, ... )
{
	const char *s;
	int d;   
	char buf[16];

	
	va_list ap;
	va_start(ap, Data);

	while ( * Data != 0 )     // 判断是否到达字符串结束符
	{				                          
		if ( * Data == 0x5c )  //'\'
		{									  
			switch ( *++Data )
			{
				case 'r':							          //回车符
				USART_SendData(USARTx, 0x0d);
				Data ++;
				break;

				case 'n':							          //换行符
				USART_SendData(USARTx, 0x0a);	
				Data ++;
				break;

				default:
				Data ++;
				break;
			}			 
		}
		
		else if ( * Data == '%')
		{									  //
			switch ( *++Data )
			{				
				case 's':										  //字符串
				s = va_arg(ap, const char *);
				
				for ( ; *s; s++) 
				{
					USART_SendData(USARTx,*s);
					while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );
				}
				
				Data++;
				
				break;

				case 'd':			
					//十进制
				d = va_arg(ap, int);
				
				itoa(d, buf, 10);
				
				for (s = buf; *s; s++) 
				{
					USART_SendData(USARTx,*s);
					while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );
				}
				
				Data++;
				
				break;
				
				default:
				Data++;
				
				break;
				
			}		 
		}
		
		else USART_SendData(USARTx, *Data++);
		
		while ( USART_GetFlagStatus ( USARTx, USART_FLAG_TXE ) == RESET );
		
	}
}
/*
 * 函数名:itoa
 * 描述  :将整形数据转换成字符串
 * 输入  :-radix =10 表示10进制,其他结果为0
 *         -value 要转换的整形数
 *         -buf 转换后的字符串
 *         -radix = 10
 * 输出  :无
 * 返回  :无
 * 调用  :被USART2_printf()调用
 */
static char * itoa( int value, char *string, int radix )
{
	int     i, d;
	int     flag = 0;
	char    *ptr = string;

	/* This implementation only works for decimal numbers. */
	if (radix != 10)
	{
		*ptr = 0;
		return string;
	}

	if (!value)
	{
		*ptr++ = 0x30;
		*ptr = 0;
		return string;
	}

	/* if this is a negative value insert the minus sign. */
	if (value < 0)
	{
		*ptr++ = '-';

		/* Make the value positive. */
		value *= -1;
		
	}

	for (i = 10000; i > 0; i /= 10)
	{
		d = value / i;

		if (d || flag)
		{
			*ptr++ = (char)(d + 0x30);
			value -= (d * i);
			flag = 1;
		}
	}

	/* Null terminate the string. */
	*ptr = 0;

	return string;

} /* NCL_Itoa */


//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';
	printf("000\r\n");
	macPC_Usart ( "00%s", strEsp8266_Fram_Record .Data_RX_BUF );
  strEsp8266_Fram_Record .InfBit .FramLength = 0;                             //清除接收标志
	strEsp8266_Fram_Record.InfBit.FramFinishFlag = 0;                             
	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 ) );
	
}


u8 ucTcpClosedFlag=0;
void USART1_IRQHandler(void)
{
  uint8_t ucCh;
	if ( USART_GetITStatus ( USART1, USART_IT_RXNE ) != RESET )
	{
		ucCh  = USART_ReceiveData( USART1 );
		
		if ( strUSART_Fram_Record .InfBit .FramLength < ( RX_BUF_MAX_LEN - 1 ) )                       //预留1个字节写结束符
			   strUSART_Fram_Record .Data_RX_BUF [ strUSART_Fram_Record .InfBit .FramLength ++ ]  = ucCh;

	}
	 	 
	if ( USART_GetITStatus( USART1, USART_IT_IDLE ) == SET )                                         //数据帧接收完毕
	{
    strUSART_Fram_Record .InfBit .FramFinishFlag = 1;		
		
		ucCh = USART_ReceiveData( USART1 );                                                              //由软件序列清除中断标志位(先读USART_SR,然后读USART_DR)	
  }	
}

/**
  * @brief  This function handles macESP8266_USARTx Handler.
  * @param  None
  * @retval None
  */
void USART3_IRQHandler ( void )
{	
	uint8_t ucCh;
	
	if ( USART_GetITStatus ( USART3, USART_IT_RXNE ) != RESET )
	{
		ucCh  = USART_ReceiveData( USART3 );
		
		if ( strEsp8266_Fram_Record .InfBit .FramLength < ( RX_BUF_MAX_LEN - 1 ) )                       //预留1个字节写结束符
			strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ++ ]  = ucCh;

	}
	 	 
	if ( USART_GetITStatus( USART3, USART_IT_IDLE ) == SET )                                         //数据帧接收完毕
	{
    strEsp8266_Fram_Record .InfBit .FramFinishFlag = 1;
		
		ucCh = USART_ReceiveData( USART3 );                                                              //由软件序列清除中断标志位(先读USART_SR,然后读USART_DR)
	
		ucTcpClosedFlag = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "CLOSED\r\n" ) ? 1 : 0;                   //获取连接状态
		
  }	

}

void ESP8266_ExitUnvarnishSend ( void )
{
	delay_ms ( 1000 );
	
	macESP8266_Usart ( "+++" );
	
	delay_ms ( 500 ); 
	
}
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;
	
}

void ESP8266_CheckRecvDataTest(void)
{
  uint8_t ucStatus;
  uint16_t i;
  
  /* 如果接收到了串口调试助手的数据 */
  if(strUSART_Fram_Record.InfBit.FramFinishFlag == 1)
  {
    for(i = 0;i < strUSART_Fram_Record.InfBit.FramLength; i++)
    {
       USART_SendData( USART3 ,strUSART_Fram_Record.Data_RX_BUF[i]); //转发给ESP82636
       while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET){}      //等待发送完成
    }
    strUSART_Fram_Record .InfBit .FramLength = 0;                                //接收数据长度置零
    strUSART_Fram_Record .InfBit .FramFinishFlag = 0;                            //接收标志置零

  }
  /* 如果接收到了ESP8266的数据 */
  if(strEsp8266_Fram_Record.InfBit.FramFinishFlag)
  {                                                      
    for(i = 0;i < strEsp8266_Fram_Record .InfBit .FramLength; i++)               
    {
       USART_SendData( USART1 ,strEsp8266_Fram_Record .Data_RX_BUF[i]);    //转发给ESP8266
       while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET){}
    }
     strEsp8266_Fram_Record .InfBit .FramLength = 0;                             //接收数据长度置零
     strEsp8266_Fram_Record.InfBit.FramFinishFlag = 0;                           //接收标志置零

  }
  
  if ( ucTcpClosedFlag )                                             //检测是否失去连接
  {
    ESP8266_ExitUnvarnishSend ();                                    //退出透传模式
    
    do ucStatus = ESP8266_Get_LinkStatus ();                         //获取连接状态
    while ( ! ucStatus );
    
    if ( ucStatus == 4 )                                             //确认失去连接后重连
    {
      printf ( "\r\n正在重连热点和服务器 ......\r\n" );
      
      while ( !ESP8266_SET_HotPort() );
			//0--TCP
      
      while ( !	ESP8266_Set_CIPSTART(5) );
      
      printf ( "\r\n重连热点和服务器成功\r\n" );

    }
    
    while ( ! ESP8266_Send_Data () );		
    
  }
}

对应的.h文件:

#ifndef _ESP_DATA_H_
#define _ESP_DATA_H_
#include "stm32f10x.h"
#include <stdio.h>
#include <stdbool.h>
#pragma anon_unions

#define     macESP8266_Usart( fmt, ... )           USART_printf ( USART3, fmt, ##__VA_ARGS__ )

#define     macPC_Usart( fmt, ... )                printf ( fmt, ##__VA_ARGS__ )
#define RX_BUF_MAX_LEN     1024                                     //最大接收缓存字节数
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;

extern struct STRUCT_USARTx_Fram strUSART_Fram_Record;
void USART_printf ( USART_TypeDef * USARTx, char * Data, ... );
bool ESP8266_Cmd ( char * cmd, char * reply1, char * reply2, u32 waittime );
void ESP8266_CheckRecvDataTest(void);

#endif

3. 监听的服务器程序server.py:(可以运行在pc端监听单片机wifi模块发来的数据)

import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 监听所有可用接口,云服务器需用 0.0.0.0
server_socket.bind(('0.0.0.0', 8000))  
server_socket.listen(5)

print('服务器已启动,等待客户端连接...')

while True:
    client_socket, client_address = server_socket.accept()
    print(f'客户端 {client_address} 已连接')
    
    while True:
        data = client_socket.recv(1024)
        if not data:
            break
        print(f'收到数据: {data.decode("utf-8")}')
        client_socket.send(f"服务器已收到: {data.decode('utf-8')}".encode('utf-8'))

    client_socket.close()
    print(f'客户端 {client_address} 已断开')

        云服务器上运行:python3 server.py 

4. main.c:

#include "stm32f10x.h"
#include "esp8266.h"
#include "delay.h"

int main(void)
{
    // 1. 系统时钟配置(如果使用CubeMX生成则自动完成)
    SystemInit();
    
    // 2. 初始化延时函数(需要实现delay.c/h)
    delay_init();
    
    // 3. 配置USART1(用于调试信息输出到PC)
    // 假设USART1已经在其他地方初始化,波特率115200
    // 如果没有,需要添加USART1_Init(115200)之类的函数调用
    
    // 4. 配置USART3(用于与ESP8266通信)
    usart3_Init(115200);
    
    // 5. 配置ESP8266的控制引脚(EN和RST)
    ESP8266_IO_Config();
    
    // 6. 启动ESP8266并完成联网配置
    printf("\r\n==== ESP8266联网测试 ====\r\n");
    ESP8266_NET_Config();
    
    // 7. 主循环:持续检查并转发数据
    while(1)
    {
        // 检查并处理ESP8266与PC之间的数据转发
        ESP8266_CheckRecvDataTest();
        
        // 可以添加其他业务逻辑(如读取传感器数据等)
        
        // 适当延时,避免CPU占用过高
        delay_ms(10);
    }
}

5.步骤与现象:

1. 串口助手观察初始化过程

打开串口助手(波特率 115200),复位 STM32 后,应看到以下输出:

 
==== ESP8266联网测试 ====
配置ESP8266联网流程
AT测试.....
AT测试次数 0......
AT测试启动成功 0......
正在配置ESP8266模式
正在配置WIFI热点信息
正在配置单链接
正在配置服务器端信息
进入透传模式
进入透传模式成功
开始传输数据
2. 云服务器日志验证连接

Python 服务器应显示类似日志:

 
服务器已启动,等待客户端连接...
客户端 ('你的ESP8266 IP', 随机端口) 已连接
3. 数据透传测试
  • PC→云服务器
    在串口助手发送任意消息(如 Hello, server!),云服务器日志会显示:

    收到数据: Hello, server!
    
  • 云服务器→PC
    服务器会自动回复消息,串口助手会显示:

    服务器已收到: Hello, server!
    
4. 断开重连测试

手动停止云服务器上的 Python 程序,模拟断开连接。ESP8266 会自动检测到连接丢失,并在串口显示:

正在重连热点和服务器 ......

重新启动云服务器上的 Python 程序,ESP8266 会自动重连,串口显示:

重连热点和服务器成功

https://github.com/0voice  

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐