STM32第十六课:WiFi模块的配置及应用


需求

完成WiFi模块的配置,使其最终能和服务器相互发送消息。
在这里插入图片描述
在这里插入图片描述


一、WiFi模块概要

本次使用的WiFi模块为ESP-12F模块(安信可)
驱动芯片为ESP8266(乐鑫)。
ESP8266的使用:
1.作为mcu开发,再次搭建一下它的环境,开发周期较长。
2.利用官方固件使用AT指令(AT+**)开发。
在这里插入图片描述
芯片引脚:
在这里插入图片描述
通信接口:
在这里插入图片描述

二、配置流程

1.配置通信串口,引脚和中断

配置串口3(本次使用的WiFi模块串口接的是串口3)
默认配置: 波特率115200  8位数据位 0位校验位 1位停止位

配置PB10(TX) PB11(RX)
TX:复用推挽 RX:浮空输入

配置PE6(ESP模块的使能引脚)
高电平使能

void Esp8266_Config()
{
	  //开时钟:GPIOB,USART3
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
	  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
	
	    //配置对应的IO口 PB10(tx):复用推挽 PB11(RX):浮空输入
	    GPIO_InitTypeDef GPIO_InitStruct = {0};
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOB,&GPIO_InitStruct);
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;
		GPIO_Init(GPIOB,&GPIO_InitStruct);
		//PE6
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
	    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOE,&GPIO_InitStruct);
		
		
	    //配置串口3  8数据位,0校验位,1停止位,波特率115200
		USART_InitTypeDef USART_InitStruct = {0};//可以通过结构体类型跳转
		USART_InitStruct.USART_BaudRate = 115200;//波特率
		USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件控制流不开
		USART_InitStruct.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;//打开发送和接收
		USART_InitStruct.USART_Parity = USART_Parity_No;
		USART_InitStruct.USART_StopBits = USART_StopBits_1;
		USART_InitStruct.USART_WordLength = USART_WordLength_8b;
		USART_Init(USART3,&USART_InitStruct);
		USART_Cmd(USART3,ENABLE);
        //配置串口3的中断
		USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);//USART1->CR1 |= 0x1<<5;//使能串口1的接收非空中断
		NVIC_SetPriority(USART3_IRQn,7);//设置优先级0~15
		NVIC_EnableIRQ(USART3_IRQn);//使能中断通道
		GPIO_SetBits(GPIOE,GPIO_Pin_6);
	    Delay_nms(500);
}

最后加的延时是为了保证所有配置都配置完。

2.AT指令

在配置中断的发送和接收前,我们要了解一下AT指令。
  AT 命令(AT Commands)最早是由发明拨号调制解调器(MODEM)的贺氏公司(Hayes)为了控制 MODEM 而发明的控制协议。后来随着网络带宽的升级,速度很低的拨号 MODEM 基本退出一般使用市场,但是 AT 命令保留下来。
  在嵌入式开发中,经常是使用AT命令去控制各种通讯模块,比如ESP8266 WIFI模块、4G模块、GPRS模块等等。一般就是主芯片通过硬件接口(比如串口、SPI)发送AT命令给通讯模块,模块接收到数据之后回应响应的数据。
AT指令的分类:
在这里插入图片描述
要注意:基本所有AT指令,结尾必须换行(\r\n)
ESP12F模块的工作模式:STA(连接热点) AP(释放热点) STA+AP
STA模式:模组作为节点去连接热点,然后就可连接某个服务器。
AP模式:模组作为热点,释放网络,可以在模组上创建服务器,其他设备连接他。
该模块的指令:
AT :测试固件的
AT+RST :重启ESP8266
ATE0 :关闭回显
ATE1 :打开回显
AT+CWMODE_DEF(_DEF有些固件支持,有些不支持)=x
x=1为设置工作模式 STA模式(可以连接其他设备热点),2为AP模式,3为组合模式。
AT+CWJAP_DEF=“WIFI名”,“WIFI密码” 连接WIFI。
AT+CWSAP :配置 ESP8266 SoftAP 参数(配置释放的热点) 。
AT+CIPAP :设置 ESP8266 SoftAP 的 IP 地址。
多连接情况下 (AT+CIPMUX=1),才能开启 TCP 服务器。
AT+CIPSERVER :建⽴ TCP 服务器
AT+CIPSTART=“TCP”,“IP”,端口号 以TCP的形式连接服务器
AT+CIPMODE=1 : 开启透传 (向wifi发送的所有消息(除+++外)都认为不是指令)
AT+CIPSEND : 启动发送功能
+++ 没有回车 : 退出透传
AT+CIPCLOSE : 退出服务器连接

连接服务器需要那些步骤:
1.连接网络
2.设置位连接热点模式:STA
3.连接热点:名字和密码
4.连接服务器 ip 和 端口
5.收发数据
AT是AT指令还是收发的数据
透传模式(透明传输,所有消息都认为是普通收发的消息)

3.发送逻辑编写

给串口发送命令,可以理解为发送字符串。
为了实现发送字符串,我们先写一个能发送单字节的函数

void Usart3Senddata(uint8_t data)
{
	//等待发送完成
	while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==0);
	//如果上次发送完成,就发送
	USART_SendData(USART3,data);
}

由于字符串的末尾为"\0",我们结合单字节发送函数就能实现字符串的发送。

void U3_SendStr(uint8_t * data)
{
	while(*data!='\0')
	{
		Usart3Senddata(*data);
		data++;
	}
}

一个一个字符发送,发送一个data+1,遇到反斜杠0结束。
为了能够将发送的命令保存起来。
我们先定义一个结构体方便后续操作。

typedef struct{
	uint8_t recvbuf[1024];
	uint16_t recvcnt;//保存命令的条数,起到计数作用,防溢出。
}WIFIDATA;

在这里插入图片描述
此时我们写一个WiFi发送命令的函数 Wifi_Send_Cmd(char * cmd,char * recv,uint32_t timeout)
参数:命令,期待返回值,超时时间
之所以设置超时时间,是因为这些指令的执行都需要时间,反应较慢。

uint8_t Wifi_Send_Cmd(char * cmd,char * recv,uint32_t timeout)
{
	uint32_t timecnt=0;
	memset(&wifidata,0,sizeof(wifidata));//先清空
	U3_SendStr((uint8_t *)cmd);//发送命令
	while(strstr((char *)wifidata.recvbuf,recv)==NULL)
	{
	timecnt++;
	Delay_nms(1);
		if(timecnt>=timeout){
		printf("发送超时失败%s",cmd);
		return 1;
	 }
	}
	printf(" 发送成功 ");
	return 0;
}

其中strstr函数为查询目标字符串种是否有所需字符串,若有则返回所需字符串的地址,没有则返回0。
strstr(目标字符串,所需字符串)

然后就是写IP链接函数了

uint8_t Wifi_ConnectIP(void)
{
	if(Wifi_Send_Cmd("AT\r\n","OK",1000) != 0){//测试
		return 1;
	}
	if(Wifi_Send_Cmd("AT+CWMODE=1\r\n","OK",2000) != 0){//设置为STA
		return 1;
	}
	if(Wifi_Send_Cmd("AT+CWJAP=\"LEGION-5169\",\"88888888\"\r\n","OK",10000)!= 0){//连接热点
		return 1;
	}
	if(Wifi_Send_Cmd("AT+CIPSTART=\"TCP\",\"36.137.226.30\",37233\r\n","OK",10000)!= 0){//连接服务器
		return 1;
	}
	if(Wifi_Send_Cmd("AT+CIPMODE=1\r\n","OK",1000)!= 0){//开启透传
		return 1;
	}
	if(Wifi_Send_Cmd("AT+CIPSEND\r\n","OK",1000)!= 0){//启动发送功能
		return 1;
	}
	return 0;	
}

要注意:"需要反斜杠转义

最后编写串口3和串口1的中断函数:

void USART3_IRQHandler(void)
{
	
	uint8_t data=0;
	if((USART3->SR&0x1<<5)!=0)
	{//执行该中断函数的原因有很多,所以判断一下是不是接收导致的
		data = USART_ReceiveData(USART3);//读操作,同时也是清空中断标志位
		wifidata.recvbuf[wifidata.recvcnt] = data;
		wifidata.recvcnt++;
		wifidata.recvcnt%=1024;
		USART_SendData(USART1, data); 
	}
}
void USART1_IRQHandler(void)
{
	uint8_t data=0;
	if((USART1->SR&0x1<<5)!=0)
	{//执行该中断函数的原因有很多,所以判断一下是不是接收导致的
		//接收数据
		data = USART_ReceiveData(USART1);//读操作,同时也是清空中断标志位
     	USART3->DR = data;//发送数据
		//USART_SendData(USART5, data); 
	}
}

逻辑如下:
串口3先读接收到的数据,然后将数据保存到结构体中,结构体中的计数器++并对1024取余防止溢出,最后将数据发送给串口1。
串口1先读接收到的数据,后将数据发送给串口3。

三、需求实现代码

main.c

#include "stm32f10x.h"
#include "usart.h"
#include "stdio.h"
#include "delay.h"
#include "string.h"
#include "wifi.h"
uint8_t Send_wifidata[102];

int main()
{
	NVIC_SetPriorityGrouping(5);//两位抢占两位次级
    Usart1_Config(); 
	SysTick_Config(72000);
	Esp8266_Config();
    strcpy((char*)Send_wifidata, "hello world");
	Wifi_ConnectIP();
    U3_SendStr(Send_wifidata);
    while(1)
    {	
    }
		return 0;
}

WiFi.c

#include "wifi.h"

WIFIDATA wifidata={0};

//配置串口3  8数据位,0校验位,1停止位,波特率115200
//PB10(TX) PB11(RX)
void Esp8266_Config()
{
	 //开时钟:GPIOB,USART3
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
	  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
	
	  //配置对应的IO口 PB10(tx):复用推挽 PB11(RX):浮空输入
	  GPIO_InitTypeDef GPIO_InitStruct = {0};
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOB,&GPIO_InitStruct);
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;
		GPIO_Init(GPIOB,&GPIO_InitStruct);
		//PE6
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
	    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOE,&GPIO_InitStruct);
		
		
	  //配置串口3  8数据位,0校验位,1停止位,波特率115200
		USART_InitTypeDef USART_InitStruct = {0};//可以通过结构体类型跳转
		USART_InitStruct.USART_BaudRate = 115200;//波特率
		USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件控制流不开
		USART_InitStruct.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;//打开发送和接收
		USART_InitStruct.USART_Parity = USART_Parity_No;
		USART_InitStruct.USART_StopBits = USART_StopBits_1;
		USART_InitStruct.USART_WordLength = USART_WordLength_8b;
		USART_Init(USART3,&USART_InitStruct);
		USART_Cmd(USART3,ENABLE);
    //配置串口3的中断
		USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);//USART1->CR1 |= 0x1<<5;//使能串口1的接收非空中断
		NVIC_SetPriority(USART3_IRQn,7);//设置优先级0~15
		NVIC_EnableIRQ(USART3_IRQn);//使能中断通道
		GPIO_SetBits(GPIOE,GPIO_Pin_6);
	    Delay_nms(500);
}

void USART3_IRQHandler(void)
{
	
	uint8_t data=0;
	if((USART3->SR&0x1<<5)!=0)
	{//执行该中断函数的原因有很多,所以判断一下是不是接收导致的
		data = USART_ReceiveData(USART3);//读操作,同时也是清空中断标志位
		wifidata.recvbuf[wifidata.recvcnt] = data;
		wifidata.recvcnt++;
		wifidata.recvcnt%=1024;
		USART_SendData(USART1, data); 
	}
}

//串口5发送单字节函数
void Usart3Senddata(uint8_t data)
{
	//等待发送完成
	while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==0);
	//如果上次发送完成,就发送
	USART_SendData(USART3,data);
}

//串口5发送数组函数
void U3_Sendarr(uint8_t * data,uint32_t len)
{
	uint32_t i=0;
	for(i=0;i<len;i++){
		Usart3Senddata(*data);
		data++;
	}
}

void U3_SendStr(uint8_t * data)
{	
	while(*data!='\0')
	{
		Usart3Senddata(*data);
		data++;
	}
}

uint8_t Wifi_Send_Cmd(char * cmd,char * recv,uint32_t timeout)
{
	uint32_t timecnt=0;
	memset(&wifidata,0,sizeof(wifidata));
	U3_SendStr((uint8_t *)cmd);
	while(strstr((char *)wifidata.recvbuf,recv)==NULL){
	timecnt++;
	Delay_nms(1);
		if(timecnt>=timeout){
		printf("发送超时失败%s",cmd);
		return 1;
	 }
	}
	printf(" 发送成功 ");
	return 0;
}

uint8_t Wifi_ConnectIP(void)
{
	if(Wifi_Send_Cmd("AT\r\n","OK",1000) != 0){//测试
		return 1;
	}
	if(Wifi_Send_Cmd("AT+CWMODE=1\r\n","OK",2000) != 0){//设置为STA
		return 1;
	}
	if(Wifi_Send_Cmd("AT+CWJAP=\"LEGION-5169\",\"88888888\"\r\n","OK",10000)!= 0){//连接热点
		return 1;
	}
	if(Wifi_Send_Cmd("AT+CIPSTART=\"TCP\",\"36.137.226.30\",37233\r\n","OK",10000)!= 0){//连接服务器
		return 1;
	}
	if(Wifi_Send_Cmd("AT+CIPMODE=1\r\n","OK",1000)!= 0){//开启透传
		return 1;
	}
	if(Wifi_Send_Cmd("AT+CIPSEND\r\n","OK",1000)!= 0){//启动发送功能
		return 1;
	}
	return 0;	
}

wifi.h

#ifndef _WIFI_H_
#define _WIFI_H_
#include "stm32f10x.h"
#include "delay.h"
#include "stdio.h"
#include "string.h"
typedef struct{
	uint8_t recvbuf[1024];
	uint16_t recvcnt;
}WIFIDATA;

void Esp8266_Config();
void U3_SendStr(uint8_t * data);
uint8_t Wifi_Send_Cmd(char * cmd,char * recv,uint32_t timeout);
uint8_t Wifi_ConnectIP(void);
void U3_SendStr(uint8_t * data);
#endif
		

总结

1.先看原理图,配串口,引脚和中断。
2.根据发送逻辑进行中断函数的编写。
3.在主函数中调用并按照需求进行实现。

  • 45
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32WiFi模块可以作为客户端与热点进行通信。 首先,客户端模式是模块的一种工作模式,用于连接到已存在的无线热点。在这种模式下,STM32WiFi模块可以扫描周围的无线网络,找到目标热点,并与其建立连接。通过连接到热点,该模块就可以通过Wi-Fi进行数据传输,实现与热点之间的通信。 在与热点建立连接之后,STM32WiFi模块可以作为TCP/IP协议栈的一部分,实现与远程服务器的通信。通过该模块,可以使用HTTP、FTP等协议与云平台或服务器进行数据交互,从而实现对互联网资源的访问。 此外,STM32WiFi模块还支持其他的通信协议,如MQTT协议。MQTT是一种轻量级的消息传输协议,适用于物联网设备间的通信。利用STM32WiFi模块,可以将设备作为MQTT客户端,连接到MQTT代理服务器,实现设备之间的实时通信和数据交换。 综上所述,STM32WiFi模块客户端与热点可以通过无线网络实现数据的双向传输。通过连接到热点,模块可以与互联网以及其他设备进行通信,实现各种物联网或智能设备应用。 ### 回答2: STM32 WiFi模块可以作为客户端连接到热点。首先,我们需要配置WiFi模块的参数,包括热点的名称(SSID)和密码。然后,通过设置模块的工作模式为客户端模式,并启动WiFi连接。 在连接过程中,WiFi模块会扫描附近的热点,并与指定的热点进行认证和连接。认证过程中,WiFi模块会向热点发送认证请求,包括安全证书(如果需要)和密码等信息。如果认证成功,WiFi模块将与热点建立TCP/IP连接。在连接建立后,WiFi模块可以通过TCP/IP协议与热点进行通信。 一旦与热点建立连接,WiFi模块可以通过发送和接收数据来与云服务器或其他设备进行通信。客户端可以向热点发送请求(如HTTP请求),并接收服务器的响应。这样,我们可以使用STM32 WiFi模块连接到热点,并通过互联网实现与其他设备的通信。 在实际应用中,我们可以利用这个功能实现许多有用的功能,比如远程控制、数据采集和监控等。通过与热点连接,STM32 WiFi模块可以作为智能家居、工业自动化和物联网等领域中的关键组件,提供更多的应用和便利。 总之,STM32 WiFi模块可以作为客户端连接到热点,通过TCP/IP协议与其他设备进行通信,为各种应用提供了更大的灵活性和便捷性。 ### 回答3: STM32WiFi模块是一种能够与无线网络进行通信的模块,可以充当客户端连接到热点。热点是无线局域网中提供无线网络连接的设备,如路由器、无线接入点等。 要实现STM32WiFi模块与热点的连接,首先需要配置模块的网络参数。使用相关的库函数,我们可以设置模块的连接方式(如STA模式),并输入热点的SSID(网络名称)和密码等参数。 当STM32WiFi模块与热点建立连接后,它会通过WiFi协议与热点进行通信。模块可以发送数据给热点或从热点接收数据。这样,模块就能够与热点所在的局域网中的其他设备进行交互。 对于STM32WiFi模块来说,作为客户端连接热点后,它可以像一台电脑或手机一样访问互联网。通过网络协议(如TCP/IP),模块可以与服务器进行通信,发送HTTP请求、接收响应等。这使得我们可以通过STM32WiFi模块实现物联网应用、远程控制等功能。 总之,STM32WiFi模块可以实现成为热点的客户端连接,通过无线网络与其他设备进行通信。这为我们的物联网项目提供了便利,使得我们能够实现更多的智能化、远程控制等功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值