一、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 指令(串口发送)期望返回作用说明
1AT+CWMODE=1OK设为 STA 模式
2AT+RST重启日志 + ready + OK重启生效模式
3AT+CWJAP="MyWiFi","1234"WIFI CONNECTED
WIFI GOT IP
OK
连 Wi-Fi 成功
4AT+CIPMUX=0OK设为单连接模式
5AT+CIPSTART="TCP","192.168.1.100",8888CONNECT OK连 TCP 服务器成功
6AT+CIPMODE=1OK开透传模式
7AT+CIPSEND>进入透传,可直接发数据
8Hello 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",8000sprintf(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 );//使能ESP8266printf("配置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 ) );elsereturn ( ( 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]); //转发给ESP82636while(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]);    //转发给ESP8266while(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--TCPwhile ( !	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 socketserver_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:breakprint(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  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/89250.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/89250.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/89250.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端设计模式应用精析

引言 设计模式是前端工程化架构的基石&#xff0c;通过抽象核心场景解法提升代码复用性与系统可维护性。本文精析 7 个核心模式&#xff0c;结合原生 JavaScript 与框架实践&#xff0c;揭示模式在现代前端架构中的底层映射与应用。1. 观察者模式&#xff08;Observer&#xff…

【机器学习深度学习】Ollama vs vLLM vs LMDeploy:三大本地部署框架深度对比解析

目录 前言 一、为什么要本地部署大语言模型&#xff1f; 二、三大主流部署方案简介 三、核心对比维度详解 1️⃣ 易用性对比 2️⃣ 性能与并发能力 3️⃣ 模型支持与生态兼容性 4️⃣ 部署环境与平台支持 四、一览对比表 五、详细介绍与比较 ✅ 1. Ollama ✅ 2. vL…

AWS ML Specialist 考试备考指南

以下是针对AWS机器学习专家认证(AWS Certified Machine Learning - Specialty)的备考指南精简版,涵盖核心要点和高效备考策略: ‌一、考试核心要点‌ ‌四大核心领域‌: ‌数据准备(28%)‌:S3数据存储、Glue ETL、Feature Store、数据清洗与特征工程。 ‌模型开发(26%…

yolo8+ASR+NLP+TTS(视觉语音助手)

&#x1f9e9; 模块总览&#xff1a;步骤模块作用①麦克风录音&#xff08;VAD支持&#xff09;获取语音并判断是否有人说话②Whisper语音识别把语音内容识别为文字③DeepSeek 聊天接口发送用户提问并获取 AI 回复④edge-tts 朗读回答把 DeepSeek 回答读出来⑤整合成语音助手主…

Zabbix 分布式监控系统架构设计与优化

一、概念 1.核心概念 Zabbix是一个CS(服务端/客户端)架构的服务Zabbix-Agent获取数据-->发送给-->Zabbix-Server服务端--- >数据会被存放在数据库 <--- Zabbix Web 页面展示数据 2.部署流程 部署ngxphp环境并测试部署数据库 mariadb 10.5及以上 然后进行配置编…

QT——文件选择对话框 QFileDialog

QFileDialog概述QFileDialog是Qt框架中提供的文件对话框类&#xff0c;用于让用户选择文件或目录。它提供了标准的文件选择界面&#xff0c;支持文件打开、保存、多选等常见操作。基本使用方式QFileDialog提供了两种使用方式&#xff1a;静态方法&#xff1a;直接调用类方法快速…

Flask+LayUI开发手记(十一):选项集合的数据库扩展类

条目较少的选项集合&#xff0c;确实可以在程序中直接定义&#xff08;其实最合适的还是存储在一个分类别的数据库表里&#xff09;&#xff0c;但条目较多的选项集合&#xff0c;或者是复杂的树型结构选项集合&#xff0c;一般都是存储在数据库中的&#xff0c;这样维护起来比…

AI学习笔记三十二:YOLOv8-CPP-Inference测试(Linux版本)

若该文为原创文章&#xff0c;转载请注明原文出处。主要介绍如何在Linux系统上安装和部署基于YOLOv8的C推理项目一、服务器准备使用AutoDL平台租用服务器AutoDL有git加速&#xff0c;可以自行启用二、环境配件1、检查Opencv版本pkg-config --modversion opencv4如果版本为4.5&a…

113:路径总和 II

题目&#xff1a;给你二叉树的根节点 root 和一个整数目标和 targetSum &#xff0c;找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。叶子节点 是指没有子节点的节点。解答&#xff1a;用 go主要坑有两个&#xff0c;一个是二维结果切片传递用指针&#xff0c;一个…

Perl 数组

Perl 数组 在Perl编程语言中&#xff0c;数组是处理数据的一种强大工具。数组允许我们将多个值存储在单个变量中&#xff0c;从而简化了代码并提高了效率。本文将详细介绍Perl数组的创建、操作、遍历以及一些高级用法。 数组的创建 在Perl中&#xff0c;创建一个数组非常简单。…

优先队列的实现

目录 引言 堆的基本概念与特性 堆的插入与向上调整 堆的删除与向下调整 优先队列的设计思路 模板参数设计 比较器的作用 核心接口实现 push pop top 附录(完整代码) 引言 优先队列&#xff08;Priority Queue&#xff09;是一种特殊的队列数据结构&#xff0c;其中每…

现代CSS实战:用变量与嵌套重构可维护的前端样式

现代CSS实战&#xff1a;用变量与嵌套重构可维护的前端样式 引言 在传统CSS开发中&#xff0c;我们常常陷入「样式冗余」与「维护噩梦」的循环&#xff1a; 想调整主题色&#xff1f;得全局搜索所有 #3498db 手动替换&#xff0c;稍有不慎就漏改某个角落&#xff1b; 写嵌套…

DHTMLX Suite 9.2 重磅发布:支持历史记录、类Excel交互、剪贴板、拖放增强等多项升级

全球知名的 JavaScript UI 组件库 DHTMLX Suite 迎来 9.2 新版本&#xff01;此次更新虽为次版本号&#xff0c;却实质性提升了 Grid 网格组件的交互能力与用户体验&#xff0c;引入了包括历史记录管理、剪贴板操作、数据选择范围管理、Block 区块选择等多项高级模块&#xff0…

深入理解Java中的Map.Entry接口

文章目录深入理解Java中的Map.Entry接口1. 接口定义2. 核心方法解析2.1 基本方法2.2 Java 8新增的静态方法3. 基本使用示例3.1 遍历Map的条目3.2 修改Map中的值3.3 使用比较器排序4. Java 8/9增强特性4.1 与Stream API结合4.2 Java 9的equals和hashCode默认方法5. 实际应用场景…

AI培训学习2

不要打扰用户的习惯&#xff0c;比如APP右下角的我的&#xff0c;放到第一个就不合适 先抄再超 lifeTime value NPS: 评价 Product market 平衡 ARPU&#xff1a; LT活跃时长 游戏中好友的重要性 不花钱存活率很少 如何花钱&#xff0c;1分钱买东西 联影医疗 figma uizard…

npm 安装时候怎么指定某一个子包的版本 overrides

有时候用 npm install 安装的时候会报错&#xff0c;比如 express 包依赖 "escape-html": "^1.0.2" 版本的包&#xff0c;但是因为 escape-html" 升级到 1.0.3 版本了&#xff0c;但是这个版本有问题&#xff0c;导致express 下载不下来。怎么固定下载…

python学智能算法(十九)|SVM基础概念-超平面

引言 前序学习进程中&#xff0c;对向量相关的基本知识进行了学习&#xff0c;链接为&#xff1a; 向量的值和方向 向量点积 在实际的支持向量机算法使用中&#xff0c;最核心的目标是找出可以实现分类的超平面&#xff0c;超平面就是分割的点、线或者面&#xff0c;不要在这个…

python 基于 httpx 的流式请求

文章目录1. 环境介绍2. 同步客户端2.1. 面向过程2.1.1. 流式输出2.1.2. 非流式输出2.2. 面向对象3. 异步客户端3.1. 面向过程3.2. 面向对象3.3. Attempted to call a sync iterator on an async stream.参考&#xff1a;https://www.jb51.net/article/262636.htm次要参考&#…

Python 数据建模与分析项目实战预备 Day 4 - EDA(探索性数据分析)与可视化

✅ 今日目标 使用 Pandas Matplotlib/Seaborn 对简历数据进行探索性分析分析不同字段与目标变量的相关性通过可视化呈现简历筛选的潜在规律&#x1f9fe; 一、建议分析内容 &#x1f539; 分类字段分析字段图表建议说明degree柱状图&#xff08;分组通过率&#xff09;分析学历…

力扣每日一题--2025.7.17

&#x1f4da; 力扣每日一题–2025.7.17 &#x1f4da; 3202. 找出有效子序列的最大长度 II&#xff08;中等&#xff09; 今天我们要解决的是力扣上的第 3202 题——找出有效子序列的最大长度 II。这道题是昨天 3201 题的扩展&#xff0c;需要我们处理更一般化的情况。 ⚠️…