STM32的WI-FI通讯(HAL库)

发布于:2025-07-26 ⋅ 阅读:(18) ⋅ 点赞:(0)

WI-FI的由来(了解即可,不必掌握):

”WI-FI“本质上是无线局域网的技术,而以太网针对的是有线局域网技术的搭建

WI-FI和WLAN(无线局域网)的区别:WLAN是统称包含WI-FI

WI-FI的发展和 IEEE 802.11标准:802都是争对局域网做的定义,具体实现又规划了子标准,例如802.3针对以太网的标准。

省略介绍第一代~第五代感兴趣的自己查找

第六代(目前应用最广的)以IEEE 802.11ax为准,世代名称为“Wi-Fi 6”,信道宽度20MHz、40MHz、80MHz、80+ 80MHz、160MHz,工作频段为2.4GHz和5GHz,最高8条空间流(一根天线表示一个数据收发的通道,8条就是8个通道并行传输),最大副载波调制1024-QAM,最高速率半双工9.6 Gbit/s。

IEEE 802.11:

WIFI可以看成是IEEE 802.11的一种具体实现

IEEE 802.11是IEEE 802标准委员会(IEEE 802 LAN/MAN Standards Committee)下属的无线局域网工作组,也指代由该组织制定的无线局域网标准

该协议一般与IEEE 802.2结合使用,设计目的是为了与以太网路无缝互通,经常用于承载IP流量。

IEEE 802.11标准定义一个媒体访问控制(MAC)和几个物理层(PHY)规范,为局域内的固定,便携式和可移动终端(STA)提供无线连接,标准还为监管机构提供了一种标准化方法,对局域网通信的一个或多个频带进行管理。

无线电波频段即基本原理:

无线信号到底怎么产生?LC振荡电路(最基础的),电磁振荡产生电磁波,电磁波的主要参数是频率,按频率划分:无线电,红外线,可见光(红橙黄绿蓝靛紫),紫外线,x射线,y射线 

我们研究范围无线电(300GHz一下的电波):低频段,高频段(射频传输:300M~300GHz)

频率和波长的关系:C=\lambdaf->CT=\lambda,所以路程就是波长,对于无线电波而言,由于C不变,频率越低波长就越大,能力就越小,所受周围环境影响大,但是可以做远距离传输。频率高,波长短,单个粒子携带能量强,但是穿墙能力弱。长波(波长在千米级别,一般都是沿着地表传输,也称地波),中波,短,超短波,微波(我们用到的手机移动蜂窝网络通信和WI-FI都是微波频段),中波,短波就从空中传播,能量足够可以打在空中的电离层,反射到更远的距离(天波),如果电磁波能量更强(超短波,微波),穿透空中的电离层到太空中,就没有办法借助电离层进行远距离传输了,但是可以跟卫星做通讯或者短距离高速率的传输,就叫做空间波

信号不稳定,频率低,那么可用频率就少,因为不同的信号以不同的频率进行传输,例如1kHzd 频段最多的频段的跳变也是几百Hz很容易收到外界环境的影响,如果是1GHz的频段跳变几百Hz就跟没有一样,那么所受周围环境的影响就小,可以变Hz范围就大,那么可传输的不同信号量就多。所以民用都是高频段(手机,WI-FI),低频段都是国家用在军事(海面作业,导航)等领域的 。

无线电波怎么进行信号传递的,信号如何基于电磁波进行传递?

LC振荡电路一般只在内部进行传输,为了将电磁波传出去就将电容的极板打开电磁场就可以发射出去了,然而电磁波功率不强,所以需要调整导线长度(发射天线)等于发射电磁波的波长时,能量就会很大,用天线发送,那么我们就用天线接收,感应接收到的电磁波频率和我们接收天线内部的固有频率一致时,那么接收的感应电流就会非常强烈,也就称为谐振,能量非常大,类似于共振。就像生活中的无线收音机,通过调台达到和广播节目一样的频率达到了谐振,就可以收到强烈的能量信息就能听到该台的内容了。所以不同台就会不同的频率,不能一样。C=\lambdaf,由于C=3*10^{8}m/s,我们人能够听到的声音频段:20~20000Hz,那么我们需要的天线至少也要15公里,这不现实,那我们怎么解决这个问题呢?

我们不直接发送低频电磁波,我们将其转换成高频电磁波,我们先定义一个高频的电磁波信号作为承载信号(也就是载波),将我们的低频信号加在这个承载信号中(这个过程叫调制),接收方就将接收信号分解成我们需要的低频信号(这个过程叫解调),那我们怎么叠加信号呢?手段1.频率不变,改变幅度,信号强就将载波幅度调大(这个叫调幅AM);手段2.常见手段:用频率变大表示数据比较大,频率变低表示数据较小(这叫调频FM),可是调频频率一直在变化,那我们收音调台又可以定死一个数值呢?注意,此处底层物理并非定死数据,而是表示可以就是在这个频率范围的跳变的电磁波信号

WI-FI的两个工作频段5G和2.4G的区别:本质就是工作频段的不同。理论上频率越高数据传输速率越高,这些工作频段都是国际组织规定的。信道频宽就是给工作频段再分出子集来给不同的进程用,避免信号干扰

2.4G的信道:这个划分规则看各国的规定吧

在标准协议里将2.4GHz频段划分出13个相互交叠的信道(我国标准),每个信道的频宽是20MHz(802.11g、802.11n每个信道占用20MHz,802.11b每个信道占用22MHz),每个信道都有自己的中心频率。手机信号走的是无线的蜂窝网络段,传统的信号段就是2点几G的信号段,不同的运营商(移动,联通)或者不同的号码段也会占用不同的频率段

这13个信道可以找出3个独立信道,即没有相互交叠的信道。独立信道由于没有频率的交叠区,相邻AP使用这3个独立信道不会彼此产生干扰。如下图中的1、6、11就是三个互不交叠的独立信道。

5G的信道:这个划分规则看各国的规定吧

移动通讯的5G(5generation第五代,兼容几百兆到几G大频率段和20几G的频率段都能使用)和我们这里定义的5G(指的是工作频段)不一样

标准协议将5GHz频段分为24个20MHz宽的信道,且每个信道都为独立信道。这为WLAN提供了丰富的信道资源,更多的独立信道也使得信道绑定更有价值。信道绑定是指将两个信道绑定成一个信道使用,能提供更大的带宽。如两个20MHz的独立信道绑定在一起可以获得40MHz的吞吐量,这好比将两条道路合并成一条使用,自然就提高了道路的通过能力。

下图中,黑色的半圆表示独立信道,红色的半圆表示标准协议推荐的信道绑定。

AP:(Access Point)无线接入点,我们的设备可以通过其接入无线网络中,AP的网线就1根网线连到交换机或者路由器那,然后自己将电平信号转化为无线电波广播出去,我们的设备通过扫描无线电波上网。如果是一个纯粹的无线电波的话就是这样设计的,但是现在我们都是用的无线路由器,就是路由器带上AP功能,将网络上的电平信号转化为无线电波广播出去。所有连接AP的设备都称为无线客户端,就是STA(Station),SSID就是无线网络名字,不一定唯一,如果设置到相同的SSID如何区分,底层是用BSSID(AP的MAC地址,就是唯一的,所有的网络设备的MAC地址都是全球唯一的,出厂即给出)区分的,ESSID就是扩展服务集标签,我们给多个无线路由器起个共同的名字,就类似于连锁商店,BSSID就是地图地址,SSID就是店面,ESSID就是品牌的公司名字

STM32扩展WI-FI模块进行无线通讯:乐鑫的ESP32-C3

ESP32-C3模块介绍:国际+国内应用广泛

搭载 RISC-V 32位单核处理器(精简指令集架构,国产很多都是基于此开发的),支持2.4 GHz Wi-FiBluetooth 5(LE),为物联网产品提供行业领先的射频性能、完善的安全机制和丰富的内存资源。ESP32-C3对Wi-Fi和Bluetooth 5(LE)的双重支持降低了设备配网难度,适用于广泛的物联网应用场景。

(1)高性能处理器

ESP32-C3 搭载 RISC-V 32位单核处理器,时钟频率高达160 MHz。

(2)丰富的内存资源

内置 400KB SRAM 和 384KB ROM,支持 SOC (片上系统,一个芯片就能完成很多核心功能,但是我们还是以STM32作为主控设备给它发指令控制WI-FI或蓝牙)模式开发,为程序运行和数据存储提供了充足的空间,能够满足不同应用场景下的需求

(3)多种外设接口

具有22个可编程 GPIO管脚、内置 400 KB SRAM,支持通过 SPI、Dual SPI、Quad SPI 和 QPI 接口外接多个 flash,满足各类物联网产品功能需求

(4)成熟的软件支持

ESP32-C3 沿用乐鑫成熟的物联网开发框架 ESP-IDF(类似于32开发的hal)。ESP32-C3 也支持在从机模式下工作,可通过 ESP-AT 和 ESP-Hosted SDK 为外部主机 MCU 提供 Wi-Fi 与 Bluetooth LE 连接功能,这样我们就可以把它当作无线网卡

STM32和ESP32-C3的身份:

SP32-C3本身就可以作为一个单片机使用,但是我们这里只是把ESP32-C3作为一个Wi-Fi/蓝牙模块使用。

STM32与ESP32-C3使用串口进行通讯。STM32可以给ESP32-C3发送命令,这种命令叫ESP-AT指令。

ESP-AT是什么?

ESP-AT 是乐鑫开发的可直接用于量产的物联网应用固件,本质上就是烧写在flash里的代码,只要我们主控芯片给它发相应的指令就能控制它辅助主控芯片加入无线网络、连接云平台、实现数据通信以及远程控制等(ESP-AT 是基于 ESP-IDF 实现的软件工程。它使 ESP32-C3 模组作为从机,MCU 作为主机。MCU 发送 AT 命令给 ESP32-C3 模组,控制 ESP32-C3 模组执行不同的操作,并接收 ESP32-C3 模组返回的 AT 响应。)就类似于我们调用HAL库代码,就能控制MCU外设那样,会看和用它给的用户指南就行

ESP-AT 提供了大量功能不同的 AT 命令,如 Wi-Fi 命令、TCP/IP 命令、Bluetooth LE 命令、Bluetooth 命令、MQTT 命令、HTTP 命令、Ethernet 命令等。

AT 命令以 “AT” 开始,代表 Attention,每条命令后都要加上回车换行就是C语言里的\r\n。输入的每条命令都会返回 OK 或 ERROR 的响应,表示当前命令的最终执行结果,就算是查询内部参数也都是先返回数据再给个响应。

注意,所有 AT 命令均为串行执行,每次只能执行一条命令。因此,在使用 AT 命令时,应等待上一条命令执行完毕后,再发送下一条命令。如果上一条命令未执行完毕,又发送了新的命令,则会返回 busy p...表示正忙呢

默认配置下,MCU 通过 UART 连接至 ESP32-C3 模组、发送 AT 命令以及接收 AT 响应。但是,用户也可以根据实际使用情况修改程序,使用其他的通信接口,例如 SDIO。

同样,用户也可以基于 ESP-AT 工程,自行开发更多的 AT 命令,以实现更多的功能。

硬件连接,读者板子没有内嵌ESP32-C3 ,就自己用杜邦线给它连起来:

固件烧录:

固件烧录工具下载:工具 | 乐鑫科技

固件下载:发布的固件 - ESP32-C3 - — ESP-AT 用户指南 latest 文档

下载官方推荐的版本

按照官方指示给下载了并烧录了,我这里不多赘述

WIFI案例1:测试AT指令(去官网下载ESP32的用户指南)

任务:测试AT指令是否能够正常控制ESP32的wifi,比如重启、读取设备信息等。

测试重启模块:进入正常运行模式就行,固件烧录我们先前已经完成了

esp.h

#ifndef __ESP32_H
#define __ESP32_H

#include "usart.h"
#include "string.h"
#include "stdio.h"

void ESP32_Init(void);
void ESP32_Send_CMD(uint8_t *cmd, uint16_t cmdLength);
void ESP32_ReadResponse(uint8_t responeBuff[], uint16_t size);
#endif

esp.c

#include "esp32.h"
uint8_t rBuff[1000] = {0};
/**
 * @description: 初始化ESP32
 */
void ESP32_Init(void)
{
    /* 1. 初始化串口2(通过串口2与ESP32进行通讯) */
    MX_USART2_UART_Init();

    /* 2. 重启 ESP32 */
    uint8_t *atCmd = "AT+RST=0\r\n";
    ESP32_Send_CMD(atCmd, strlen((char *)atCmd));
    HAL_Delay(3000);
}

/**
 * @description: 发送AT指令
 * @param {uint8_t} *cmd 要发送的AT指令(指令必须以 \r\n结束)
 * @param {uint16_t} cmdLength 指令长度
 */
void ESP32_Send_CMD(uint8_t *cmd, uint16_t cmdLength)
{
    HAL_UART_Transmit(&huart2, cmd, cmdLength, 1000);
    do
    {
        ESP32_ReadResponse(rBuff, 1000);
        printf("%s", rBuff);
    }while(strstr((char *)rBuff, "OK") == NULL); // 一直等到读到OK
    printf("\r\n=====================\r\n");
}

/**
 * @description: 发送AT指令后,用来接收响应
 *          要考虑到接收的响应为非定长数据。
 *
 * @param {uint8_t} responeBuff[] 存储接收的的响应的缓冲区。
 * @param {unin16_t} Size 缓冲区的长度
 */

void ESP32_ReadResponse(uint8_t responeBuff[], uint16_t size)
{
    /* 清空缓冲区 */
    memset(responeBuff, 0, size);
    uint16_t rxLen = 0;
    HAL_UARTEx_ReceiveToIdle(&huart2, responeBuff, size, &rxLen, 10000);
}

WiFi案例2:TCP通讯

重启ESP32和测试AT指令完成后,搭建TCP才能进行Socket通讯

1.确定ESP32的工作模式

1.1基站模式(STA模式):作为设备连接WI-FI网络

1.2.AP模式:作为WI-FI的发起方,给其他设备连接热点

1.3AP-STA共存模式:ESP32连了WI-FI后,自己有网了就给其他设备开热点 

2. 争对不同的工作模式做相应的处理

2.1ESP32设置为STA模式,则要(连接AP)连接WI-FI,连接上后ESP32的IP是自动分配的(现在我们用的设备都是自动分配IP的,目的给分配到和WI-FI同一局域网)

2.1.1查询ESP32分到的IP地址(因为是自动分配的查一下比较好)


static void WIFI_STA_Mode(void)
{
    //设置工作模式为STA
    printf("设置为STA模式...\n");
    uint8_t *cmd="AT+CWMODE=1\r\n";
    ESP32_SendCmd(cmd,strlen((char *)cmd));

    //连接到指定的AP
    printf("连接AP...\n");
    cmd="AT+CWJAP=\"haohaoyun\",\"13066201933\"\r\n";
    ESP32_SendCmd(cmd,strlen((char *)cmd));
    //查看本机IP
    printf("本机IP地址为:\n");
     cmd="AT+CIPSTA?\r\n";
    ESP32_SendCmd(cmd,strlen((char *)cmd));


    
}

2.2如果设置的AP模式,设置广播出自己的WI-FI信号让别的设备连接,ESP32就能主动工作了,但是你也可以给它设置WI-FI参数,你不给它设置, 你就查一下它默认参数是什么,然后用设备填它默认密码连接它WI-FI,

2.2.1查询谁连了ESP32

static void WIFI_AP_MODE(void)
{
    //设置工作模式为STA
    printf("设置为AP模式...\n");
    uint8_t *cmd="AT+CWMODE=2\r\n";
    ESP32_SendCmd(cmd,strlen((char *)cmd));

    //主动设置自己AP的广播参数,信道号:国内是0~13我们随便给就行
    printf("设置AP:\n");
    cmd = "AT+CWSAP=\"haoyunlai\",\"13066201933\",5,3\r\n";
    //cmd = "AT+CWSAP=\"haoyunlai\",\"13066201933\",0,3\r\n";奇怪通道0既然设置不成功!!!
    ESP32_SendCmd(cmd,strlen((char *)cmd));
    //查看本机IP
    printf("本机IP地址为:");
    cmd="AT+CIPAP=\"192.168.31.2\"\r\n";//连接了WIFI才ping到
    ESP32_SendCmd(cmd,strlen((char *)cmd));

}

3.设置好ESP32的底层后,就来设置传输层的TCP/IP,得给设备间的传输建个协议

3.1根据不同的工作模式做TCP配置,我们核心是想让ESP32发出WI-FI来,所以就将ESP32设置成AT模式的角度写的TCP代码

3.1.1如果ESP32是STA模式:要连哪个WI-FI得说清楚,我们设置的多连接

 

3.1.2如果的AT模式,我们提供WI-FI服务,所以就要主动创建TCP连接,把信号发给别人

 3.1.3开启多连接模式

3.2针对不同工作模式配TCP后,就要给TCP设置以什么方式传输 ,我们这里选的透传模式

3.3 你光搭建好TCP连接后,还得对收发数据做处理,所以要设置消息详情,我们将这里设置成1,你可能疑惑前面在设置AT模式的时候有查询连接了咱们WI-FI的Station的IP和端口号信息的功能,为什么在这里处理,不在设置AT模式的时候处理呢?注意

CWLIF:属于Wi-Fi连接管理部分,负责查询网络连接状态和客户端信息(获取当前Wi-Fi网络中已连接的Station(客户端)的IP地址和MAC地址列表)
CIPDINFO:属于TCP/IP数据传输部分,负责配置数据传输时的消息详情(配置是否在+IPD消息中包含对端IP和端口号等详细信息)


// 启动TCP服务器
void WIFI_TCP_ServerStart(void)
{

    //1.设置使能多连接
    printf("设置使能多连接:");
    uint8_t *cmd="AT+CIPMUX=1\r\n";//必须要有的参数必须写出
    ESP32_SendCmd(cmd,strlen((char *)cmd));

    //2.TCP打开服务器
    printf("开启TCP服务器:");
    cmd="AT+CIPSERVER=1,8080\r\n";//必须要有的参数必须写出
    ESP32_SendCmd(cmd,strlen((char *)cmd));


    //3.设置IPD数据格式,显示详情:AT消息,希望包含的信息最多,接收模式为主动模式,就不用发命令接收了(默认)

    //*4.显示对端IP和端口号信息
    printf("设置IPD数据格式:");
    cmd="AT+CIPDINFO=1\r\n";
    
    ESP32_SendCmd(cmd,strlen((char *)cmd));
}

3.4设置数据发送和接收

我们只想要+IPD后面的数据内容

主动发送“+++”就能退出数据模式

// 发送数据(包含连接ID)
void WIFI_TCP_SendData(uint8_t id, uint8_t *data ,uint16_t len)
{
    
    // //1.设置使能单连接
    // printf("设置使能单连接:");
     uint8_t cmd[50]={0};
    // ESP32_SendCmd(cmd,strlen((char *)cmd));

    //2.设置发送数据的连接ID和数据长度,进入数据模式
    printf("给对方发送数据:");
    sprintf((char *)cmd,"AT+CIPSEND=%d,%d\r\n",id,len);
    ESP32_SendCmd(cmd,strlen((char *)cmd));

    //3.通过串口发送数据(类似透传模式)
    HAL_UART_Transmit(&huart2,data,len,1000);

}
uint8_t tempBuff[1024];
uint16_t tempLen;
//读取缓冲区中的数据(包含连接ID和对端的IP以及端口号)
void WIFI_TCP_ReadData(uint8_t rxBuff[],uint16_t *rxlen,uint8_t *id,uint8_t *ip,uint16_t *port)
{
    //1.接收数据

    /*用临时缓冲区接收数据,临时变量也要占用栈空间,
    所以不能随便定义大小,我们芯片的栈空间最大就是1024,
    而且后面不能再定义其他的局部变量了*/
    /*虽然返回接收数据的长度没有用但是由于该函数需要,所以就给它定义一个变量*/
    HAL_UARTEx_ReceiveToIdle(&huart2,tempBuff,1024,&tempLen,1000);

    //2.解析数据
    if (strstr((char *)tempBuff,"+IPD")!=NULL)
    {
/*%*[\r\n]
作用:跳过所有连续的 \r 或 \n 字符(直到遇到非换行符)。
注意:%*[...] 中的 * 表示丢弃匹配内容,[\r\n] 是字符集,匹配 \r 或 \n。

IPD,
匹配字面量字符串 "IPD,",表示数据包的标识头。

%hhu
解析为 uint8_t 类型(无符号 8 位整数),对应变量 id。

%hu(第一个)
解析为 unsigned short 类型(16 位无符号整数),对应变量 rxlen(数据长度)。

\"%39[^\"]\"
解析双引号内的字符串,%39[^\"] 表示最多读取 39 个非 " 字符(防止缓冲区溢出)。
注意:需确保 ip 缓冲区大小 ≥ 40(例如 char ip[40])。

%hu(第二个)
解析为 unsigned short 类型,对应变量 port(端口号)。
*/
        sscanf((char *)tempBuff, "%*[\r\n]+IPD,%hhu,%hu,\"%[^\"]\",%hu",
             id, rxlen, ip, port);
        
        //利用sscanf和正则表达式提取所有的信息,前面可能会有\r\n,%是一个占位符,%*是要跳过
        char * pData = strstr((char *)tempBuff, ":") + 1;
        memcpy(rxBuff, pData, *rxlen);
    }  
        
    }
    



WI-FI.h


#ifndef __WIFI_H
#define __WIFI_H

#include "esp32.h"
//定义枚举类型,STA,AP
typedef enum
{
    STA=1,
    AP=2
}WIFI_MODE;
// 传入WIFI工作模式
void WIFI_Init(WIFI_MODE mode);

// 启动TCP服务器
void WIFI_TCP_ServerStart(void);
// 发送数据(包含连接ID)
void WIFI_TCP_SendData(uint8_t id, uint8_t *data ,uint16_t len);

//读取缓冲区中的数据(包含连接ID和对端的IP以及端口号)
void WIFI_TCP_ReadData(uint8_t rxBuff[],uint16_t *rxlen,uint8_t *id,uint8_t *ip,uint16_t *port);

#endif

WIFI.c

#include "wifi.h"
//定义内部函数设置工作模式及IP
static void WIFI_STA_Mode(void);
static void WIFI_AP_MODE(void);

// 传入WIFI工作模式
void WIFI_Init(WIFI_MODE mode)
{
    //1.初始化ESP32
ESP32_Init();
    //2.根据传入的参数,设置工作模式及IP
    if(mode==STA)
    {
        WIFI_STA_Mode();
    }
    else if(mode==AP)
    {
        WIFI_AP_MODE();
    }
    printf("WIFI finishing init");
}

static void WIFI_STA_Mode(void)
{
    //设置工作模式为STA
    printf("设置为STA模式...\n");
    uint8_t *cmd="AT+CWMODE=1\r\n";
    ESP32_SendCmd(cmd,strlen((char *)cmd));

    //连接到指定的AP
    printf("连接AP...\n");
    cmd="AT+CWJAP=\"haohaoyun\",\"13066201933\"\r\n";
    ESP32_SendCmd(cmd,strlen((char *)cmd));
    //查看本机IP
    printf("本机IP地址为:\n");
     cmd="AT+CIPSTA?\r\n";
    ESP32_SendCmd(cmd,strlen((char *)cmd));


    
}
static void WIFI_AP_MODE(void)
{
    //设置工作模式为STA
    printf("设置为AP模式...\n");
    uint8_t *cmd="AT+CWMODE=2\r\n";
    ESP32_SendCmd(cmd,strlen((char *)cmd));

    //主动设置自己AP的广播参数,信道号:国内是0~13我们随便给就行
    printf("设置AP:\n");
    cmd = "AT+CWSAP=\"haoyunlai\",\"13066201933\",5,3\r\n";
    //cmd = "AT+CWSAP=\"haoyunlai\",\"13066201933\",0,3\r\n";奇怪通道0既然设置不成功!!!
    ESP32_SendCmd(cmd,strlen((char *)cmd));
    //查看本机IP
    printf("本机IP地址为:");
    cmd="AT+CIPAP=\"192.168.31.2\"\r\n";//连接了WIFI才ping到
    ESP32_SendCmd(cmd,strlen((char *)cmd));

}

// 启动TCP服务器
void WIFI_TCP_ServerStart(void)
{

    //1.设置使能多连接
    printf("设置使能多连接:");
    uint8_t *cmd="AT+CIPMUX=1\r\n";//必须要有的参数必须写出
    ESP32_SendCmd(cmd,strlen((char *)cmd));

    //2.TCP打开服务器
    printf("开启TCP服务器:");
    cmd="AT+CIPSERVER=1,8080\r\n";//必须要有的参数必须写出
    ESP32_SendCmd(cmd,strlen((char *)cmd));


    //3.设置IPD数据格式,显示详情:AT消息,希望包含的信息最多,接收模式为主动模式,就不用发命令接收了(默认)

    //*4.显示对端IP和端口号信息
    printf("设置IPD数据格式:");
    cmd="AT+CIPDINFO=1\r\n";
    
    ESP32_SendCmd(cmd,strlen((char *)cmd));
}

// 发送数据(包含连接ID)
void WIFI_TCP_SendData(uint8_t id, uint8_t *data ,uint16_t len)
{
    
    // //1.设置使能单连接
    // printf("设置使能单连接:");
     uint8_t cmd[50]={0};
    // ESP32_SendCmd(cmd,strlen((char *)cmd));

    //2.设置发送数据的连接ID和数据长度,进入数据模式
    printf("给对方发送数据:");
    sprintf((char *)cmd,"AT+CIPSEND=%d,%d\r\n",id,len);
    ESP32_SendCmd(cmd,strlen((char *)cmd));

    //3.通过串口发送数据(类似透传模式)
    HAL_UART_Transmit(&huart2,data,len,1000);

}
uint8_t tempBuff[1024];
uint16_t tempLen;
//读取缓冲区中的数据(包含连接ID和对端的IP以及端口号)
void WIFI_TCP_ReadData(uint8_t rxBuff[],uint16_t *rxlen,uint8_t *id,uint8_t *ip,uint16_t *port)
{
    //1.接收数据

    /*用临时缓冲区接收数据,临时变量压要占用栈空间,
    所以不能随便定义大小,我们芯片的栈空间最大就是1024,
    而且后面不能再定义其他的局部变量了*/
    /*虽然返回接收数据的长度没有用但是由于该函数需要,所以就给它定义一个变量*/
    HAL_UARTEx_ReceiveToIdle(&huart2,tempBuff,1024,&tempLen,1000);

    //2.解析数据
    if (strstr((char *)tempBuff,"+IPD")!=NULL)
    {
        sscanf((char *)tempBuff, "%*[\r\n]+IPD,%hhu,%hu,\"%[^\"]\",%hu",
             id, rxlen, ip, port);
        
        //利用sscanf和正则表达式提取所有的信息,前面可能会有\r\n,%是一个占位符,%*是要跳过
        char * pData = strstr((char *)tempBuff, ":") + 1;
        memcpy(rxBuff, pData, *rxlen);
    }  
        
    }
    



 main.c

// 全局变量,接收数据缓冲区、长度、连接id、对端IP和端口号
uint8_t rxBuff[1024];
uint16_t rxLen;
uint8_t id;
uint8_t ip[16];
uint16_t port;


int main(void)
{

 
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  // MX_USART2_UART_Init();

  // 1. WiFi初始化
  WIFI_Init(AP);

  // 2. 启动TCP服务器
  WIFI_TCP_ServerStart();

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    // 3. 从串口读取
    WIFI_TCP_ReadData(rxBuff, &rxLen, &id, ip, &port);

    // 4. 如果接收到数据,就原样发回去
    if (rxLen > 0)
    {
      printf("接收到数据!连接ID = %d, 对端IP:端口号 = %s:%d, 数据长度 = %d, 内容 = %.*s\n",
        id, ip, port, rxLen, rxLen, rxBuff);

      WIFI_TCP_SendData(id, rxBuff, rxLen);

      // 将长度清0
      rxLen = 0;
    }
    
    /* USER CODE END WHILE */

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

测试:电脑要先连ESP32发出的WI-FI,然后才能用串口进行测试


网站公告

今日签到

点亮在社区的每一天
去签到