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

文章目录

  • 需求
  • 一、WiFi模块概要
  • 二、配置流程
    • 1.配置通信串口,引脚和中断
    • 2.AT指令
    • 3.发送逻辑编写
  • 三、需求实现代码
  • 总结


需求

完成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,USART3RCC_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);//PE6GPIO_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停止位,波特率115200USART_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~15NVIC_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){//设置为STAreturn 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,USART3RCC_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);//PE6GPIO_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停止位,波特率115200USART_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~15NVIC_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){//设置为STAreturn 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.在主函数中调用并按照需求进行实现。

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

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

相关文章

【LLM第8篇】Delta Tuning

如何对large-scale PLM进行调整呢&#xff1f; 一个有效的方式是delta tuning&#xff1b;只更新PLM中的一小部分参数&#xff0c;其它参数不动。 把解决任务的能力具象化成delta object这样的参数&#xff0c;只需要几十兆参数存储。 过去模型参数是随机的&#xff0c;现在预…

【MySQL】逻辑架构与存储引擎

一、逻辑架构 1、MySQL逻辑架构 我们可以根据上图来对sql的执行过程进行分析 第一步&#xff1a;客户端与服务器建立一个连接&#xff0c;从连接池中分配一个线程处理SQL语句第二步&#xff1a;SQL接口接受SQL指令第三步&#xff1a;如果是5.7版本&#xff0c;就会先去缓存中…

Python字符串处理常用的30种操作

我们平时编写代码时&#xff0c;经常需要对字符串进行处理&#xff0c;本文详细介绍Python处理字符串常用的30种操作&#xff0c;并给出了对应的代码。 分割 使用split()方法将字符串按照指定的分隔符进行分割。 s "Hello,World" result s.split(","…

国产AI芯片被撕下遮羞布,宁买阉割八成性能的NVIDIA,也不买国产

曾经有传言指有国产AI芯片大受欢迎&#xff0c;还卖出了100万片&#xff0c;不过半年多时间过去&#xff0c;海外分析机构指出国内的互联网企业纷纷抢购NVIDIA阉割八成性能的H20&#xff0c;至于国产AI芯片则不获欢迎。 导致如此结果&#xff0c;在于NVIDIA拥有许多独特的优势&…

论文略读: LLaMA Pro: Progressive LLaMA with Block Expansion

ACL 2024 人类通常在不损害旧技能的情况下获得新技能 然而&#xff0c;对于大型语言模型&#xff08;LLMs&#xff09;&#xff0c;例如从LLaMA到CodeLLaMA&#xff0c;情况正好相反。深度学习笔记&#xff1a;灾难性遗忘-CSDN博客——>论文提出了一种用于LLMs的新的预训练…

Nettyの源码分析

本篇为Netty系列的最后一篇&#xff0c;按照惯例会简单介绍一些Netty相关核心源码。 1、Netty启动源码分析 代码就使用最初的Netty服务器案例&#xff0c;在bind这一行打上断点&#xff0c;观察启动的全过程&#xff1a; 由于某些方法的调用链过深&#xff0c;节约篇幅&#xf…

昇思MindSpore学习笔记4-03生成式--Diffusion扩散模型

摘要&#xff1a; 记录昇思MindSpore AI框架使用DDPM模型给图像数据正向逐步添加噪声&#xff0c;反向逐步去除噪声的工作原理和实际使用方法、步骤。 一、概念 1. 扩散模型Diffusion Models DDPM(denoising diffusion probabilistic model) &#xff08;无&#xff09;条件…

【嵌入式DIY实例-ESP8266篇】-LCD ST7735显示BMP280传感器数据

LCD ST7735显示BMP280传感器数据 文章目录 LCD ST7735显示BMP280传感器数据1、硬件准备与接线2、代码实现本文介绍如何将 ESP8266 NodeMCU 板 (ESP-12E) 与 Bosch Sensortec 的 BMP280 气压和温度传感器连接。 NodeMCU 微控制器 (ESP8266EX) 从 BMP280 传感器读取温度和压力值,…

普通Java工程如何在代码中引用docker-compose.yml中的environment值

文章目录 一、概述二、常规做法1. 数据库配置分离2. 代码引用配置3. 编写启动类4. 支持打包成可执行包5. 支持可执行包打包成docker镜像6. docker运行 三、存在问题分析四、改进措施1. 包含environment 变量的编排文件2. 修改读取配置文件方式3. 为什么可以这样做 五、运行效果…

python库(6):Pygments库

1 Pygments介绍 在软件开发和文档编写中&#xff0c;代码的可读性是至关重要的一环。无论是在博客文章、技术文档还是教程中&#xff0c;通过代码高亮可以使程序代码更加清晰和易于理解。而在Python世界中&#xff0c;Pygments库就是这样一个强大的工具&#xff0c;它能够将各…

ValueError: Expected EmbeddingFunction.__call__ to have the following signature

题意&#xff1a; 使用 langchain 时&#xff0c;特别是在定义或调用嵌入函数&#xff08;Embedding Function&#xff09;时&#xff0c;签名&#xff08;函数的参数列表和返回类型&#xff09;不符合预期 问题背景&#xff1a; When I try to pass a Chroma Client to Lang…

搭建论坛和mysql数据库安装和php安装

目录 概念 步骤 安装mysql8.0.30 安装php 安装Discuz 概念 搭建论坛的架构&#xff1a; lnmpDISCUZ l 表示linux操作系统 n 表示nginx前端页面的web服务 m 表示 mysql 数据库 用来保存用户和密码以及论坛的相关内容 p 表示php 动态请求转发的中间件 步骤 &#xff…

【C++深度探索】:继承(定义赋值兼容转换作用域派生类的默认成员函数)

✨ 愿随夫子天坛上&#xff0c;闲与仙人扫落花 &#x1f30f; &#x1f4c3;个人主页&#xff1a;island1314 &#x1f525;个人专栏&#xff1a;C学习 &#x1f680; 欢迎关注&#xff1a;&#x1f44d;点赞…

CVE-2024-0603 漏洞复现

CVE-2024-0603 源码&#xff1a;https://gitee.com/dazensun/zhicms 开题&#xff1a; CVE-2024-0603描述&#xff1a;ZhiCms up to 4.0版本的文件app/plug/controller/giftcontroller.php中存在一处未知漏洞。攻击者可以通过篡改参数mylike触发反序列化&#xff0c;从而远程…

python脚本“文档”撰写——“诱骗”ai撰写“火火的动态”python“自动”脚本文档

“火火的动态”python“自动”脚本文档&#xff0c;又从ai学习搭子那儿“套”来&#xff0c;可谓良心质量&#x1f44d;&#x1f44d;。 (笔记模板由python脚本于2024年07月07日 15:15:33创建&#xff0c;本篇笔记适合喜欢钻研python和页面源码的coder翻阅) 【学习的细节是欢悦…

【学习笔记】程序设计竞赛

程序设计竞赛 文章目录 程序设计竞赛0x00 基本操作指南0x01 算法分析0x02 STL和基本数据结构栈队列集合map 0x03 排序插入排序归并排序&#xff08;Merge Sort)快速排序 0x04 搜索技术BFSDFS回溯与剪枝 深度迭代ID A*A star双向广搜 0x05 递推方程0x06 高级数据结构并查集二叉树…

Hi6602 恒压恒流SSR电源方案

Hi6602是一款针对离线式反激电源设计的高性能PWM控制器。Hi6602内集成有通用的原边恒流控制技术&#xff0c;可支持断续模式和连续模式工作&#xff0c;适用于恒流输出的隔离型电源应用中。Hi6602内部具有高精度65kHz开关频率振荡器&#xff0c;且带有抖频功能可优化EMI性能。H…

17.优化算法之解决拓扑排序4

0.基础 1.课程表1 207. 课程表 - 力扣&#xff08;LeetCode&#xff09; class Solution {public boolean canFinish(int n, int[][] p) {// 1. 准备⼯作int[] in new int[n]; // 统计每⼀个顶点的⼊度Map<Integer, List<Integer>> edges new HashMap<>…

第六十周:文献精读

目录 摘要 Abstract 文献阅读&#xff1a;可解释多水平时间序列预测的时间融合Transformer 一、多水平预测&#xff08;Multi-horizon forecasting&#xff09; 二、过去相关研究 三、现存问题 四、提出方法 五、模型架构 1、门控残差网络(GRN) 2、变量选择网络 3、…

android中activity与fragment之间的各种跳转

我们以音乐播放、视频播放、用户注册与登录为例【Musicfragment&#xff08;音乐列表页&#xff09;、Videofragment&#xff08;视频列表页&#xff09;、MusicAvtivity&#xff08;音乐详情页&#xff09;、VideoFragment&#xff08;视频详情页&#xff09;、LoginActivity&…