单片机(STM32-WIFI模块)

一、WIFI模块介绍

1. ESP12-F模组介绍

1.1 简介

ESP12-F模组(安信可(Ai-Thinker)ESP8266系列模组)是一款基于乐鑫(Espressif)公司ESP8266芯片的Wi-Fi无线通信模块,广泛应用于物联网(IoT)领域。它体积小巧,集成度高,内置Wi-Fi功能和32位处理器,支持802.11 b/g/n无线标准。ESP12-F模组内置4MB Flash存储,拥有丰富的GPIO(通用输入输出)、UART、SPI、I2C、PWM、ADC等接口,方便与各种传感器和外设连接。它既可以通过AT指令作为Wi-Fi串口透传模块使用,也可以烧录自定义固件(如NodeMCU、MicroPython或原生SDK)实现复杂的控制和联网功能。ESP12-F模组功耗低支持深度休眠,非常适合智能家居、远程控制、无线传感器、数据采集等应用场景。使用时需要注意其所有引脚电平为3.3V,不能直接接5V电源或信号,否则可能损坏芯片。

1.2 什么是固件?

ESP12-F模组本质就是集成好的一个小板子,固件就是代码存储的地方,这个模组能做那么多事,就是按照固件里的程序执行任务,是开发这个模组的人员提前烧录进去的。

1.3 安信可 ESP8266 系列模组

https://docs.ai-thinker.com/esp8266

2. 原理分析

2.1 原理图分析

三个开放引脚:

(1) GPIO0:控制WIFI模式,GPIO0为低电平是下载模式,高电平为运行模式

运行模式:此时串口为正常的通信功能

下载模式:此时串口为下载固件的功能

注意:一般买WiFi模块的时候,一定要了解是否已经下载固件到WIFI模块内,如果有一般都是没有问题可以直接使用的(功能没有问题)。

(2) 22号引脚 TXD为WIFI模组的串口发送引脚

可以切换我们的WiFi模组串口发送的消息是直接通过底板typec口和电脑通信还是发送给单片机串口通信

TXD(Transmit Data)是ESP-12F WiFi模组的串口发送端,用于将模块内部处理后的数据通过串口发送到外部设备。在实际应用中,TXD的信号可以通过底板的电路切换,选择发送到单片机的串口,实现与主控MCU的数据交互,也可以通过Type-C转USB串口发送到电脑,便于调试、监控或固件下载。这样设计的好处是,开发者可以根据需要灵活选择通信对象:在正常运行模式下,TXD用于与单片机进行数据通信,实现物联网数据上传、远程控制等功能;在调试或下载模式下,TXD则用于与电脑通信,输出调试信息或配合下载工具烧录固件。需要注意的是,TXD输出的电平为3.3V,外部设备应与之匹配,避免电平不兼容导致通信异常或损坏模块。通过合理切换TXD的连接对象,可以大大提升WiFi模组的开发效率和使用灵活性。

(3) 21号引脚 RXD为WIFI模组的串口接收引脚

RXD(Receive Data)是ESP-12F WiFi模组的串口接收端,用于接收外部设备(如单片机或电脑)通过串口发送过来的数据。在实际应用中,RXD可以通过底板的电路切换,实现与单片机串口或通过Type-C转USB串口与电脑通信。这样,WiFi模组既可以接收来自单片机的数据,实现本地控制和数据交互,也可以在调试或下载固件时接收来自电脑的指令和数据。需要注意的是,RXD引脚的电平为3.3V,不能直接接收5V电平信号,否则可能损坏模块。实际使用时,确保信号线连接正确,避免串口信号冲突,保证数据通信的可靠性和安全性。

总结:
  • GPIO0控制启动模式,低电平为下载模式,高电平为运行模式;
  • TXD(22脚)为串口发送,RXD(21脚)为串口接收;
  • 运行模式下串口用于数据通信,下载模式下串口用于固件烧录;
  • 原理图设计保证了模式切换和串口功能的灵活性与可靠性。
我们可以通过掰动三个开关调节WiFi功能,一定要注意选择的模式和对应的图一致。

2.2 WiFi模块通过串口通信的两种方式(硬件连线):

都是我从原理图中找出来相关元器件进行连接,这是一种很好的培养思维的方式,多去尝试一下。

(1) WiFi模块串口直接和电脑USB口相连

1. Wi-Fi无线模块(ESP-12F)部分

ESP-12F模块的TXD(发送)、RXD(接收)等引脚通过跳线和开关与外部电路相连。通过开关可以选择WiFi模块的串口信号是与单片机通信还是与电脑通信,实现模式切换。GPIO0等引脚用于控制模块的启动模式(运行/下载)。

2. 协议转换芯片(CH340E)部分

CH340E芯片用于将USB信号转换为串口信号,实现电脑与WiFi模块之间的串口通信。这样,WiFi模块既可以和单片机通信,也可以通过CH340E与电脑直接通信,便于调试和固件下载。

3. Type-C接口部分

Type-C接口(J4)用于与电脑进行物理连接,提供数据通信和电源。通过Type-C线缆,电脑可以直接与电路板上的CH340E芯片通信,进而与WiFi模块进行数据交互。

(2) WiFi模块串口和单片机串口相连

1. 单片机引脚区:单片机(如STM32)通过串口引脚(如PA9、PA10或PB10、PB11等)与核心板排针接口(J2)连接,信号经过排针扩展,便于模块化和后续维护。

2. 核心板排针接口(J2):核心板的排针接口将单片机的串口信号引出,通过排线与底板排针接口(J5)相连,实现信号的延伸和分配。

3. 底板排针接口(J5):底板排针接口接收来自核心板的信号,并将其分配到底板上的各个功能模块,包括Wi-Fi无线模块(ESP-12F)。

4. Wi-Fi无线模块(ESP-12F):ESP-12F的TXD(发送)和RXD(接收)引脚分别与底板排针的UART3_RX和UART3_TX相连,实现与单片机的串口通信。同时,ESP-12F的GPIO0引脚通过电阻和插针与外部电路连接,用于切换运行模式和下载模式。

5. USB转串口接口:底板上还设计了USB转串口电路,可以通过Type-C接口将Wi-Fi模块的串口信号与电脑连接,方便调试和固件下载。

6. 电源和地线:各模块的3.3V电源和GND地线均已连接,保证电路正常供电和信号参考一致。

3.ESP8266的AT指令

3.1 AT指令集,详细可见安信可官网

https://docs.espressif.com/projects/esp-at/zh_CN/latest/esp32/AT_Command_Set/index.html

3.2 基础指令集大全:

官网内详细指令集合,不是所有指令都可以使用,不同的WiFi模组可使用的不同。

3.3 ESP12-F模组连接网络流程:

准备工作:

按照上面把三个按键拨到TXD和RXD模式上,连接WiFi模组所在的板子的typeC口到电脑上,一根线就可以,因为我们目前还不需要进行烧录,先熟悉一下AT指令。

可以打开一个网络调试助手,设置好IP和端口号,设置为服务器server,准备后面连接发送数据

(1) 复位

AT+RST

这个指令就是复位指令,也可以通过按板子上的reset复位键进行复位,复位后会断开之前的连接,相当于重启。
有乱码是正常的。
(2) 设置WiFi模式
AT+CWMODE=
查询/设置 Wi-Fi 模式 (Station/SoftAP/Station+SoftAP)
  • 0: 无 Wi-Fi 模式,并且关闭 Wi-Fi RF
  • 1: Station 模式---------可以连接其他热点
  • 2: SoftAP 模式---------变身成为一个路由器,可以发射wifi信号成为一个热点
  • 3: SoftAP+Station------模式 混合模式

这里我们要联网,所以选择模式1,连接热点。

(3) 连接WiFi热点

AT+CWJAP="热点名字","热点密码"

为了保险起见,此处设置的热点明不要出现比较另类的字符,尽量为纯数字或者字母组合。
连接错误会回复的错误码:
回复错误码1:连接超时
回复错误码2:密码错误
回复错误码3:找不到该AP
回复错误码4:连接失败
这里我们用电脑开热点,因为大多数WiFi模组(比如我使用的ESP12-F模组)只兼容2.4GHz频段;而且ESP12-F模组是低功耗模组,而2.4G模组功耗更低,信号穿透能力更强,覆盖范围更广
,复杂环境下稳定性更高。
打开2.4G热点:
先编辑一下网络信息,名称和密码简单一些,再设置频段为2.4GHZ,最后打开热点。
发送指令:
(4) 连接服务器
AT+CIPSTART="TCP","服务器IP",服务器端口

此时需要打开一个同网络下的服务器,可以是虚拟机的用代码写的服务器或者在Windows上打开一个服务器模拟器

1. 网络架构理解

当你使用电脑开热点给WiFi模组提供网络时,你的电脑实际上扮演了路由器的角色:

  • 电脑 = 路由器(提供网络服务)
  • WiFi模组 = 客户端设备(连接到电脑热点)

2. IP地址的区分

错误的做法:查看电脑连接公共网络的IP地址

  • 使用 ipconfig 查看的是电脑连接外网的IP
  • 这个IP是电脑作为客户端获取的,不是路由器IP

正确的做法:查看电脑热点网络的IP地址

  • 需要在网络调试助手中查看热点网络的主机IP
  • 这个IP才是WiFi模组能够访问的地址

3. 网络层次:

公共网络 ←→ 电脑(路由器) ←→ WiFi模组
        外网IP             热点IP

推测出电脑作为热点主机的IP,并且使用该IP的作为服务器IP,然后打开服务器:
(5) 发送数据

AT+CIPSEND=5         //发送五个字节给服务器

这种方式只能实现单次固定长度数据的发送

输入后会出现箭头,表示等待串口向服务器发送五个字节的数据。

发送五个字节数据:

服务器成功接收到数据。

(6)总结

通信数据走向:

3.4 透传模式设置

之前的发送很别扭,每次都要提前发送指令告诉WiFi模块准备发送数据,还有长度限制,十分不友好,有什么办法解决吗?有的兄弟有的!

(1) 什么是透传模式

简介:

透传模式(Transparent Transmission)是一种数据传输方式,设备或系统在通信过程中不对数据内容进行解析或处理,仅作为通道将原始数据完整、无修改地传递给目标端。常见于串口通信、网络协议、物联网设备等场景。

也就是ESP8266作为一个搬运共,不去辨别串口发送过来的数据是什么,只是无脑的发送给服务器。

(2) 设置透传

1.设置透传模式:

AT+CIPMODE=1

2.使能透传发送:

AT+CIPSEND

连续发送数据:

想退出透传模式可以发送"+++",就会退出透传模式:

4. 使用单片机控制WiFi模块

4.1 思路梳理

  1. 核心设备

    • STM32 MCU:主控制器

    • ESP8266模块:通过 USART1 连接 STM32(自带固件程序)

    • PC串口调试助手:通过 UART5 连接 STM32(Type-C直连核心板)

  2. 关键开关设置

    • S2/S3:拨向 MCU方向(连接ESP8266与STM32)

    • S4:拨到 运行模式(使能ESP8266正常工作)

    • Type-C:插入核心板(供电+调试通信)

整体流程总结:

1. PC通过串口调试助手(UART5)发送指令给STM32。

2. STM32通过空闲中断接收完整指令,解析指令。

3. STM32通过USART1向ESP8266发送相应的AT指令或数据。

4. ESP8266执行操作(如连接服务器、发送数据等)。

5. ESP8266将服务器返回的数据通过USART1传给STM32。

6. STM32将结果通过UART5格式化输出到PC串口调试助手。

4.2  cubeMX 配置

4.3 代码编写

1. 向uart.c添加驱动函数

(1) 两个串口格式化输出函数:

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 */
void USART_printf(UART_HandleTypeDef * USARTx, char * Data, ... )
{const char *s;int d;   char buf[16];char singleBuff[1];va_list ap;va_start(ap, Data);while ( * Data != 0 )     // 判断数据是否到达结束符{                                         if ( * Data == 0x5c )  //'\'{                                     switch ( *++Data ){case 'r':                                     //回车符singleBuff[0] = 0x0d;    __HAL_UART_CLEAR_FLAG(USARTx, UART_CLEAR_TCF);						HAL_UART_Transmit(USARTx, (void*)singleBuff, 1, 1);//阻塞式发送数据Data ++;break;case 'n':                                     //换行符singleBuff[0] = 0x0a;    __HAL_UART_CLEAR_FLAG(USARTx, UART_CLEAR_TCF);/* Clear the TC flag in the ICR register */HAL_UART_Transmit(USARTx, (void*)singleBuff, 1, 1);//阻塞式发送数据Data ++;break;default:Data ++;break;}            }else if ( * Data == '%'){                                     switch ( *++Data ){               case 's':                                         //字符串s = va_arg(ap, const char *);for ( ; *s; s++) {singleBuff[0] = *s;    HAL_UART_Transmit(USARTx, (void*)singleBuff, 1, 1);//阻塞式发送数据while(__HAL_UART_GET_FLAG(USARTx, UART_FLAG_TXE) == RESET);}Data++;break;case 'd':           d = va_arg(ap, int);itoa(d, buf, 10);for (s = buf; *s; s++) {singleBuff[0] = *s;    HAL_UART_Transmit(USARTx, (void*)singleBuff, 1, 1);//阻塞式发送数据while(__HAL_UART_GET_FLAG(USARTx, UART_FLAG_TXE) == RESET);}Data++;break;default:Data++;break;}        }else{singleBuff[0] = *Data++;    __HAL_UART_CLEAR_FLAG(USARTx, UART_CLEAR_TCF);/* Clear the TC flag in the ICR register */HAL_UART_Transmit(USARTx, (void*)singleBuff, 1, 1);//阻塞式发送数据}		while (__HAL_UART_GET_FLAG(USARTx, UART_FLAG_TXE) == RESET);}
}
(2) 把上述驱动函数放在uart.c文件内,这样就可以使用这些函数:

(3) 把头文件加入uart.c文件中,因为上面两个函数用到这些库

#include <stdio.h>
#include <string.h>
#include <stdarg.h>

(4) 然后在uart.h文件中加上对两个函数的声明,保证导入.h文件主函数可以正常使用,后面的wifi驱动文件也会用到:

static char *itoa(int value, char *string, int radix );
void USART_printf(UART_HandleTypeDef * USARTx, char * Data, ... );

 2. 添加WiFi驱动文件

(1) 下面是ESP8266的WiFi驱动文件,导入项目后,就可以使用内置状态机函数实现单片机代替串口发送AT指令给WiFi模块,让WiFi模块进行联网和通信。
wifi.c:

#include "wifi.h"int connect_flag = 0; // 是否连接成功的标志
int tt_flag = 0;	  // 是否有网络发过来的透传数据标志char WIFI_Config0(int time) // 找到ready 返回 没有找到返回1
{memset(WiFi_RX_BUF, 0, 1024);WiFi_RxCounter = 0;while (time--){HAL_Delay(100);if (strstr((char *)WiFi_RX_BUF, "ready")){break;}// u1_USART ("WIFI_Config0:=%s",WiFi_RX_BUF);}if (time > 0)return 0;elsereturn 1;
}char WIFI_Config(int time, char *cmd, char *response) // 等待时间 发送内容 判断返回的内容
{memset(WiFi_RX_BUF, 0, 1024);WiFi_RxCounter = 0;ESP8266_USART("%s\r\n", cmd);while (time--){HAL_Delay(100);if (strstr((char *)WiFi_RX_BUF, response)){break;}// u1_USART("%d ", time);}if (time > 0)return 0;elsereturn 1;
}char WIFI_Router(int time) // 配置WIFI名和密码
{memset(WiFi_RX_BUF, 0, 1024);WiFi_RxCounter = 0;//	ESP8266_USART("AT+CIPMUX=0");//	HAL_Delay(100);ESP8266_USART("AT+CWJAP=\"%s\",\"%s\"\r\n", ID, PASSWORD);while (time--){HAL_Delay(1000);if (strstr((char *)WiFi_RX_BUF, "OK")){break;}u1_USART("连接路由倒计时: %d\r\n ", time);}if (time > 0)return 0;elsereturn 1;
}char WIFI_ConnectTCP(int time) // 配置TCP
{memset(WiFi_RX_BUF, 0, 1024);WiFi_RxCounter = 0;ESP8266_USART("AT+CIPSTART=\"TCP\",\"%s\",%d\r\n", ServerIP, ServerPort);while (time--){HAL_Delay(100);if (strstr((char *)WiFi_RX_BUF, "OK")){break;}u1_USART("正在建立TCP连接 :%d ", time);}if (time > 0)return 0;elsereturn 1;
}enum WIFI_STATE
{WIFI_READY = 0,WIFI_CONFIG1,WIFI_ROUTER,WIFI_CONFIG2,  //进入透传模式WIFI_CONNECT, //连接服务器WIFI_CONFIG3,WIFI_COMPLETE	//连接完成
};#define WAIT_TIME 1000void WIFI_Connect()//状态机
{int state = WIFI_READY;  //默认等待复位while (1){if(state == WIFI_COMPLETE){u1_USART("连接服务器完成并开启透传!\r\n");memset(WiFi_RX_BUF,0,1024);//WIFI_SendData("hello world");break;  //这里直接跳出while(1)循环即可}switch (state){case WIFI_READY://检测是否手动复位了/*0、按键复位*/u1_USART("0、准备按键复位!\r\n");if (WIFI_Config0(100))//判是否收到ready{u1_USART("按键复位失败!\r\n");HAL_Delay(WAIT_TIME);}else//成功了 找到了{u1_USART("按键复位成功!\r\n");state = WIFI_CONFIG1;}break;case WIFI_CONFIG1:/*1、配置WIFI模式*/u1_USART("1、准备配置WIFI模式!\r\n");if (WIFI_Config(50, "AT+CWMODE=1\r\n", "OK"))//发送命令 检测OK{u1_USART("配置WIFI模式失败!\r\n");HAL_Delay(WAIT_TIME);break;}else//成功u1_USART("配置WIFI模式成功!\r\n");u1_USART("\r\n");/*2、重启(命令方式)*/u1_USART("2、准备复位!\r\n");if (WIFI_Config(50, "AT+RST\r\n", "ready")){u1_USART("复位失败!\r\n");HAL_Delay(WAIT_TIME);break;}elseu1_USART("复位成功!\r\n");u1_USART("\r\n");/*3、取消自动连接*/u1_USART("3、准备取消自动连接\r\n");if (WIFI_Config(50, "AT+CWAUTOCONN=0\r\n", "OK"))//取消热点自动连接 检测OK{u1_USART("取消自动连接失败!\r\n");HAL_Delay(WAIT_TIME);break;}elseu1_USART("取消自动连接成功!\r\n");WiFi_RxCounter = 0;state = WIFI_ROUTER;break;case WIFI_ROUTER:/*4、连接路由器*/u1_USART("4、准备连接路由器\r\n");if (WIFI_Router(50))//连接热点并检测是否连接成功{u1_USART("连接路由器失败!\r\n");HAL_Delay(WAIT_TIME);}else{u1_USART("连接路由器成功!\r\n");state = WIFI_CONFIG2;}break;case WIFI_CONFIG2:/*5、配置单路连接模式*/u1_USART("5、准备配置单路连接模式!\r\n");if (WIFI_Config(50, "AT+CIPMUX=0\r\n", "OK"))//配置单路连接{u1_USART("配置单路连接模式失败!\r\n");HAL_Delay(WAIT_TIME);break;}else{u1_USART("配置单路连接模式成功!\r\n");}u1_USART("\r\n");/*6、开启透传模式*/u1_USART("6、准备开启透传模式\r\n");if (WIFI_Config(50, "AT+CIPMODE=1\r\n", "OK")){u1_USART("开启透传模式失败!\r\n");HAL_Delay(WAIT_TIME);break;}else{u1_USART("开启透传模式成功!\r\n");}state = WIFI_CONNECT;break;case WIFI_CONNECT:/*7、建立TCP连接*/u1_USART("7、准备建立TCP连接\r\n");if (WIFI_ConnectTCP(50))//连接TCP{u1_USART("建立TCP连接失败!\r\n");HAL_Delay(WAIT_TIME);}else{u1_USART("建立TCP连接成功!\r\n");state = WIFI_CONFIG3;}break;case WIFI_CONFIG3:/*8、进入透传模式*/u1_USART("8、准备进入透传模式\r\n");if (WIFI_Config(50, "AT+CIPSEND\r\n", "\r\nOK\r\n\r\n>")){u1_USART("进入透传模式失败!\r\n");HAL_Delay(WAIT_TIME);}else{u1_USART("进入透传模式成功!\r\n");state = WIFI_COMPLETE;connect_flag = 1;break;}default:break;}}
}//int WIFI_SendData(const char *data)
//{
//	ESP8266_USART("%s", data);
//	//u1_USART("数据发送完成\r\n");
//	return 0;
//	if (WIFI_Config(10, "AT+CIPSEND=5\r\n", ">"))
//	{
//		ESP8266_USART("%s", data);
//		u1_USART("数据发送完成\r\n");
//		return 0;
//	}
//	else
//	{
//		u1_USART("数据发送失败!\r\n");
//		return -1;
//	}
//}

wifi.h:

#ifndef _WIFI_H
#define _WIFI_H
#include <string.h>
#include "usart.h"
extern uint8_t USART5_RxBuff[1024];
extern volatile uint8_t USART5_RxCounter;
#define WiFi_RxCounter    USART5_RxCounter    
#define WiFi_RX_BUF       USART5_RxBuff 
#define ESP8266_USART(fmt, ...)  USART_printf(&huart5, fmt, ##__VA_ARGS__) 
#define u1_USART(fmt, ...)  USART_printf(&huart1, fmt, ##__VA_ARGS__) 
#define ID   "zkm"                      //网络名字       
#define PASSWORD   "12345611"           //网络密码#define ServerIP   "192.168.43.148"     //服务器IP地址       
#define ServerPort  4399                //服务器端口char WIFI_Config0(int time);
char WIFI_Config(int time,char*cmd,char*response);
char WIFI_Router(int time);
char WIFI_ConnectTCP(int time);
void WIFI_Connect(void);
void ESP8266_Clear(void);
#endif

添加外部文件的方式可以参考之前文章,在标题五下的8.2:单片机(STM32-IIC)-CSDN博客

3. 添加串口5空闲中断

       上述准备工作做完,我们已经有了WiFi模组的函数WIFI_Connect(),还有直接向串口五发送数据的函数USART_printf(UART_HandleTypeDef * USARTx, char * Data, ... ),WIFI_Connect()函数是依赖于串口接收中断函数,所以我们需要搭建串口五点空闲中断。(推荐自己先看看wifi文件)

       在我们之前使用AT指令的时候,发送给ESP8266一个数据,会回复相应的消息,WIFI_Connect()函数就是依靠这个逻辑。这个函数让单片机按顺序给ESP8266发送指令,只有接收到ESP8266的ready消息才会发送下一条指令,如果没有接收到ready消息或者接收到错误消息,会一直尝试连接,由此可见这个函数是阻塞进程的,所以我们要开启串口5的空闲接收中断,而且必须在调用WIFI_Connect()函数前开启一次中断接收,再在中断回调函数内开启中断接收,每接收到一次数据就开启下一次中断接收。

(1) 定义全局变量

uint8_t USART5_RxBuff[1024]={0};
volatile uint8_t USART5_RxCounter=0;

(2) 添加接受中断函数(不定长)和接收中断回调函数

细节可以看我的单片机(STM32-串口通信)_stm32串行同步通信-CSDN博客,最好是用不定长接收,因为接收长度是未知的,只要设定长度够大就能接收并触发中断。

中断函数:

 void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)

写回调: 

extern int connect_flag;
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{if(huart == &huart5){USART5_RxCounter=1;//此变量置1,则代表wifi发过来了数据HAL_UARTEx_ReceiveToIdle_IT(&huart5,USART5_RxBuff,1024);}
}
4. 尝试联网:
(1) 修改wifi.h中的信息

(2) 添加头文件

(3) 调用wifi连接函数
必须在调用WIFI_Connect()函数前开启一次中断接收,前面说了WIFI_Connect()函数是阻塞的,因为没开启接收中断函数,单片机一直接收不到任何消息,会卡在函数出不来就会一直复位失败。

5. 打开服务器,烧录后复位单片机

注意:

(1) 别忘了要更换USB口到单片机的核心板,让单片机和串口直接通信,ESP8266的模式(S3,S2)也需要切换,切换为MCU模式。

(2) 服务器和单片机连接的网络处于一个网络下,按照之前连接网络和配置网络虚拟机(服务器)的方式的方式。

(3) 串口助手显示单片机接收信息,网络虚拟机充当服务器发送数据到单片机,如下图:

点击复位后,串口会输出下面提示信息,如果成功就说明网络连接成功,如果卡在某一个位置就去处理响应的问题。 

6. 常见问题解决:

问题一:卡在0.复位,那就是单片机接受不到ESP8266发送的信息

(1) 查看s3,s2是否调节到mcu模式,

(2) 查看cubemx是否配置串口5的中断

(3) 再查看是否在调用wifi_connect函数前开启串口5的中断接收。

(4) 最后再检查配置流程是否和前面一致。

问题二:卡在4.连接路由器

(1) 先耐心等待几分钟,有时候连接时间比较长

(2) 查看网络是否可用,是否是2.4GHZ频段下

问题三:卡在准备6.建立TCP连接

查看服务器地址和端口号是否准确,是否按照前面配置方式确定服务器IP地址。

7. 和服务器通信

和服务器通信分两部分:接收和发送;

(1)、接收已经有了,就是串口5接收中断函数,只需要在中断内判断USART5_RxBuff[1024]字符串,执行操作就可以:

extern int connect_flag;
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{if(huart == &huart5){USART5_RxCounter=1;//此变量置1,则代表wifi发过来了数据if(connect_flag == 1){u1_USART("server:%s\n",USART5_RxBuff);if(strcmp(USART5_RxBuff,"FAN_ON") == 0)        //服务器发送FAN_ON打开风扇{HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,1);}if(strcmp(USART5_RxBuff,"FAN_OFF") == 0)        //关闭风扇{HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,0);}memset(USART5_RxBuff,0,1024);                    //清空字符数组}HAL_UARTEx_ReceiveToIdle_IT(&huart5,USART5_RxBuff,1024);}
}

(2)、发送就是uart.c函数内添加的驱动函数USART_printf函数,在wifi.c中宏定义改名为ESP8266_USART函数,导入头文件wifi.h后,两个函数都可以用,最好直接发送字符串,sprintf拼接字符串后发送。虽然可以“USART_printf("temp:%d",temp);”进行发送,但是对“USART_printf("temp:%f",temp);”就会发送错误字符串。

当可以通过串口调试助手控制单片机就大功告成。

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

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

相关文章

PyTorch 数据类型和使用

关于PyTorch的数据类型和使用的学习笔记 系统介绍了PyTorch的核心数据类型Tensor及其应用。Tensor作为多维矩阵数据容器&#xff0c;支持0-4维数据结构&#xff08;标量到批量图像&#xff09;&#xff0c;并提供了多种数值类型&#xff08;float32/int64等&#xff09;。通过…

[python刷题模板] LogTrick

[python刷题模板] LogTrick 一、 算法&数据结构1. 描述2. 复杂度分析3. 常见应用4. 常用优化二、 模板代码1. 特定或值的最短子数组2. 找特定值3. 找位置j的最后一次被谁更新4. 问某个或和的数量三、其他四、更多例题五、参考链接一、 算法&数据结构 1. 描述 LogTric…

Vim与VS Code

Vim is a clone, with additions, of Bill Joys vi text editor program for Unix. It was written by Bram Moolenaar based on source for a port of the Stevie editor to the Amiga and first released publicly in 1991.其实这个本身不是 IDE &#xff08;只有在加入和配置…

[2025CVPR-图象分类方向]CATANet:用于轻量级图像超分辨率的高效内容感知标记聚合

​1. 研究背景与动机​ ​问题​&#xff1a;Transformer在图像超分辨率&#xff08;SR&#xff09;中计算复杂度随空间分辨率呈二次增长&#xff0c;现有方法&#xff08;如局部窗口、轴向条纹&#xff09;因内容无关性无法有效捕获长距离依赖。​现有局限​&#xff1a; SPI…

课题学习笔记3——SBERT

1 引言在构建基于知识库的问答系统时&#xff0c;"语义匹配" 是核心难题 —— 如何让系统准确识别 "表述不同但含义相同" 的问题&#xff1f;比如用户问 "对亲人的期待是不是欲&#xff1f;"&#xff0c;系统能匹配到知识库中 "追名逐利是欲…

在Word和WPS文字中把全角数字全部改为半角

大部分情况下我们在Word或WPS文字中使用的数字或标点符号都是半角&#xff0c;但是有时不小心按错了快捷键或者点到了输入法的全角半角切换图标&#xff0c;就输入了全角符号和数字。不用担心&#xff0c;使用它们自带的全角、半角转换功能即可快速全部转换回来。一、为什么会输…

数据结构的基本知识

一、集合框架1、什么是集合框架Java集合框架(Java Collection Framework),又被称为容器(container),是定义在java.util包下的一组接口(interfaces)和其实现类(classes).主要表现为把多个元素(element)放在一个单元中,用于对这些元素进行快速、便捷的存储&#xff08;store&…

WebStack-Hugo | 一个静态响应式导航主题

WebStack-Hugo | 一个静态响应式导航主题 #10 shenweiyan announced in 1.3-折腾 WebStack-Hugo | 一个静态响应式导航主题#10 ​编辑shenweiyan on Oct 23, 2023 6 comments 7 replies Return to top shenweiyan on Oct 23, 2023 Maintainer Via&#xff1a;我给自己…

01 基于sklearn的机械学习-机械学习的分类、sklearn的安装、sklearn数据集、数据集的划分、特征工程中特征提取与无量纲化

文章目录机械学习机械学习分类1. 监督学习2. 半监督学习3. 无监督学习4. 强化学习机械学习的项目开发步骤scikit-learn1 scikit-learn安装2 sklearn数据集1. sklearn 玩具数据集鸢尾花数据集糖尿病数据集葡萄酒数据集2. sklearn现实世界数据集20 新闻组数据集3. 数据集的划分特…

携全双工语音通话大模型亮相WAIC,Soul重塑人机互动新范式

近日&#xff0c;WAIC 2025在上海隆重开幕。作为全球人工智能领域的顶级盛会&#xff0c;本届WAIC展览聚焦底层能力的演进与具体垂类场景的融合落地。坚持“模应一体”方向、立足“AI社交”的具体场景&#xff0c;Soul App此次携最新升级的自研端到端全双工语音通话大模型亮相&…

第2章 cmd命令基础:常用基础命令(1)

Hi~ 我是李小咖&#xff0c;主要从事网络安全技术开发和研究。 本文取自《李小咖网安技术库》&#xff0c;欢迎一起交流学习&#x1fae1;&#xff1a;https://imbyter.com 本节介绍的命令有目录操作&#xff08;cd&#xff09;、清屏操作&#xff08;cls&#xff09;、设置颜色…

Java 10 新特性解析

Java 10 新特性解析 文章目录Java 10 新特性解析1. 引言2. 本地变量类型推断&#xff08;JEP 286&#xff09;2.1. 概述2.2. 使用场景2.3. 限制2.4. 与之前版本的对比2.5. 风格指南2.6. 示例代码2.7. 优点与注意事项3. 应用程序类数据共享&#xff08;JEP 310&#xff09;3.1. …

【WRF工具】服务器中安装编译GrADS

目录 安装编译 GrADS 所需的依赖库 conda下载库包 安装编译 GrADS 编译前检查依赖可用性 安装编译 GrADS 参考 安装编译 GrADS 所需的依赖库 以统一方式在 $HOME/WRFDA_LIBS/grads_deps 下安装所有依赖: # 选择一个目录用于安装所有依赖库 export DIR=$HOME/WRFDA_LIBS库包1…

数据结构之队列(C语言)

1.队列的定义&#xff1a; 队列&#xff08;Queue&#xff09;是一种基础且重要的线性数据结构&#xff0c;遵循先进先出&#xff08;FIFO&#xff09;​​ 原则&#xff0c;即最早入队的元素最先出队&#xff0c;与栈不同的是出队列的顺序是固定的。队列具有以下特点&#xff…

C#开发基础之深入理解“集合遍历时不可修改”的异常背后的设计

前言 欢迎关注【dotnet研习社】&#xff0c;今天我们聊聊一个基础问题“集合已修改&#xff1a;可能无法执行枚举操作”背后的设计。 在日常 C# 开发中&#xff0c;我们常常会操作集合&#xff08;如 List<T>、Dictionary<K,V> 等&#xff09;。一个新手开发者极…

【工具】图床完全指南:从选择到搭建的全方位解决方案

前言 在数字化内容创作的时代&#xff0c;图片已经成为博客、文档、社交媒体等平台不可或缺的元素。然而&#xff0c;如何高效、稳定地存储和分发图片资源&#xff0c;一直是内容创作者面临的重要问题。图床&#xff08;Image Hosting&#xff09;作为专门的图片存储和分发服务…

深度学习篇---PaddleDetection模型选择

PaddleDetection 是百度飞桨推出的目标检测开发套件&#xff0c;提供了丰富的模型库和工具链&#xff0c;覆盖从轻量级移动端到高性能服务器的全场景需求。以下是核心模型分类、适用场景及大小选择建议&#xff08;通俗易懂版&#xff09;&#xff1a;一、主流模型分类及适用场…

cmseasy靶机密码爆破通关教程

靶场安装1.首先我们需要下载一个cms靶场CmsEasy_7.6.3.2_UTF-8_20200422,下载后解压在phpstudy_pro的网站根目录下。2.然后我们去访问一下安装好的网站&#xff0c;然后注册和链接数据库3.不知道自己数据库密码的可以去小皮面板里面查看4.安装好后就可以了来到后台就可以了。练…

【C语言】指针深度剖析(一)

文章目录一、内存和地址1.1 内存的基本概念1.2 编址的原理二、指针变量和地址2.1 取地址操作符&#xff08;&&#xff09;2.2 指针变量和解引用操作符&#xff08;*&#xff09;2.2.1 指针变量2.2.2 指针类型的解读2.2.3 解引用操作符2.3 指针变量的大小三、指针变量类型的…

半导体企业选用的跨网文件交换系统到底应该具备什么功能?

在半导体行业的数字化转型过程中&#xff0c;跨网文件交换已成为连接研发、生产、供应链的关键纽带。半导体企业的跨网文件交换不仅涉及设计图纸、工艺参数等核心知识产权&#xff0c;还需要满足跨国协同、合规审计等复杂需求。那么&#xff0c;一款适合半导体行业的跨网文件交…