STM32外设系列—ESP8266(WIFI)

文章目录

  • 一、ESP8266简介
  • 二、固件库烧录
  • 三、常用AT指令
  • 四、访问API
    • 4.1 获取IP地址
    • 4.2 GET天气信息
    • 4.3 访问结果展示
  • 五、实战项目
    • 5.1 串口配置
    • 5.2 检测WIFI模块连接状态
    • 5.3 发送配置指令
    • 5.4 解析天气信息
  • 六、成果展示

一、ESP8266简介

ESP8266是嵌入式和物联网开发中常用的模块,它可以单独作为MCU使用,也可以作为一个简单的WIFI模块。ESP8266可以利用串口与单片机进行通讯。利用ESP8266可以访问一些API,获取天气信息或者完成网络授时,也可以连接云平台进行开发。

二、固件库烧录

有些新买来的ESP01-S并不能支持AT指令,需要我们手动烧录固件库。虽然烧录固件库有许多教程,但是博主烧录过两次,过程都不是特别顺利,这里专门整理一下烧录步骤,也方便后续使用。固件库和烧录软件可以联系卖家索要,这里就不再放链接了。

首先按照下表连接好引脚

引脚连接
3.3V3.3V
RST3.3V
EN3.3V
IO23.3V
GNDGND
IO0GND
TXDRXD
RXDTXD

打开烧写软件,选择ESP8266

ESP8266

按照下图配置

烧写固件配置图

选择串口,点击“START”,烧写完成后关闭即可。

烧写完成

此时,拔掉IO0的接地,重新上电。打开串口调试助手检查烧录情况。打开串口调试助手,发送“AT”,换行加回车,观察返回信息。如果返回“OK”,说明烧录成功。

烧录成功

三、常用AT指令

下面简单介绍一些WIFI模块常用的AT指令

  • AT\r\n
    检查ESP8266模块连接是否正常
  • AT+CWMODE=1\r\n
    配置模块为Sta模式
  • AT+CWJAP=“WIFI名称”,“WIFI密码”\r\n
    连接指定WIFI
  • AT+CIPMUX=0\r\n
    设置成单连接
  • AT+CIPMODE=1\r\n
    开启透传模式
  • AT+CIPSTART=“TCP”,“203.119.175.194”,80\r\n
    创建TCP连接
    如何获取IP地址,后面会有介绍
  • AT+CIPMODE=1\r\n
    进入透传模式
    进入到透传模式后AT指令就会失效,需要退出后才能生效
  • AT+CIPSEND\r\n
    准备向服务器发送请求,前面都成功的前提下发送完这个指令后会出现一个>,此时输入GET信息即可

四、访问API

下面以访问心知天气API为例,介绍一下利用WIFI模块访问API的流程。关于心知天气API的一些介绍,这里就不再赘述了。在开始下面的操作之前,需要先按照上面介绍的AT指令顺序,配置好WIFI模块。

4.1 获取IP地址

电脑win+R,输入ping api.seniverse.com,点击确定就可以获取到IP。

ping心知天气API的返回信息

其中“116.62.81.138”就是IP地址。

4.2 GET天气信息

按照第三小节常用AT指令的输入顺序,连接WIFI,建立TCP连接。最后获取天气信息。获取天气信息时,输入以下内容

GET https://api.seniverse.com/v3/weather/now.json?key=你的密钥&location=beijing&language=zh-Hans&unit=c

4.3 访问结果展示

利用USB转TTL连接WIFI模块,利用串口调试助手发送AT指令,完成对心知天气API的访问。结果如下

心知天气API返回信息

可以看到,虽然一些是乱码,但是能够接收到天气现象代码和温度。关于天气现象代码,心知天气的API文档里有介绍

天气现象代码

后面还有很多,这里就不再列举了,具体可以去看看文档。

五、实战项目

下面就以利用WIFI模块,搭配STM32,访问心知天气API来获取天气和温度为例,展示一下WIFI的程序设计,仅供参考。该项目有以下功能

  • 串口1与WIFI模块通信,能够检测WIFI连接是否正常
  • 利用WIFI模块访问心知天气API,利用串口2将获取到的天气和温度打印到电脑

5.1 串口配置

这里需要用到两个串口。关于串口通信的相关内容这里就不再赘述了,详细可见博主的STM32速成笔记专栏串口通信篇。串口初始化程序如下

/**==============================================================================*函数名称:uart_init*函数功能:初始化USART*输入参数:UARTx:串口几;bound:波特率*返回值:无*备  注:可以修改成输入初始化哪个USART*==============================================================================*/
void uart_init(UART_TypeDef UARTx,u32 bound)
{// 相关结构体定义GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;switch (UARTx){case 0:// 使能USART1,GPIOA时钟RCC_APB2PeriphClockCmd (RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);	// USART1_TX   GPIOA.9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;   // PA.9GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   // 复用推挽输出GPIO_Init(GPIOA, &GPIO_InitStructure);   // 初始化GPIOA.9// USART1_RX	  GPIOA.10初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;   // PA10GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   // 浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure);   // 初始化GPIOA.10  // Usart1 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;   // 抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;   // 子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   // IRQ通道使能NVIC_Init(&NVIC_InitStructure);   // 根据指定的参数初始化VIC寄存器// USART 初始化设置USART_InitStructure.USART_BaudRate = bound;   // 串口波特率USART_InitStructure.USART_WordLength = USART_WordLength_8b;   // 字长为8位数据格式USART_InitStructure.USART_StopBits = USART_StopBits_1;   // 一个停止位USART_InitStructure.USART_Parity = USART_Parity_No;   // 无奇偶校验位// 无硬件数据流控制USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;   // 收发模式USART_Init(USART1, &USART_InitStructure);   // 初始化串口1USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);   // 开启串口接收中断USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);   // 使能空闲中断USART_Cmd(USART1, ENABLE);   // 使能串口1break;case 1:// 使能USART2,GPIOA时钟RCC_APB1PeriphClockCmd (RCC_APB1Periph_USART2 | RCC_APB2Periph_GPIOA, ENABLE);	// USART2_TX   GPIOA.2GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;   // PA.2GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   // 复用推挽输出GPIO_Init(GPIOA, &GPIO_InitStructure);   // 初始化GPIOA.2// USART2_RX	  GPIOA.3初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;   // PA3GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   // 浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure);   // 初始化GPIOA.3 // Usart2 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;   // 抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;   // 子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   // IRQ通道使能NVIC_Init(&NVIC_InitStructure);   // 根据指定的参数初始化VIC寄存器// USART2 初始化设置USART_InitStructure.USART_BaudRate = bound;   // 串口波特率USART_InitStructure.USART_WordLength = USART_WordLength_8b;   // 字长为8位数据格式USART_InitStructure.USART_StopBits = USART_StopBits_1;   // 一个停止位USART_InitStructure.USART_Parity = USART_Parity_No;   // 无奇偶校验位// 无硬件数据流控制USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;   // 收发模式USART_Init(USART2, &USART_InitStructure);   // 初始化串口2USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);   // 开启串口接收中断USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);   // 使能空闲中断USART_Cmd(USART2, ENABLE);   // 使能串口2break;default:break;}
}

值得注意的是,串口2挂载在APB2上,开启串口2时钟时需要注意。博主最开始用错了开启时钟的函数,导致PA2引脚一直输出低电平。

printf用于串口1的输出,需要再定义一个串口发送函数

/**==============================================================================*函数名称:USART_Send*函数功能:串口发送函数*输入参数:str:要发送的数据的数组首地址;UARTx:串口几*返回值:无*备  注:调用前先将需要发送的内容利用sprintf()函数转换成字符串,再进行发送*==============================================================================*/
void USART_Send (UART_TypeDef UARTx,u8 *str)
{u8 index = 0;do{switch (UARTx){case 0:USART_SendData(USART1,str[index ++]);while (USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);break;case 1:USART_SendData(USART2,str[index ++]);while (USART_GetFlagStatus(USART2,USART_FLAG_TXE) == RESET);break;}}while(str[index] != 0);
}

5.2 检测WIFI模块连接状态

检测原理十分简单,只需要利用串口1给WIFI模块发送“AT\r\n”,检测是否接收到“OK”。如果接收到“OK”,说明连接正常。如果没有接收到“OK”,说明连接异常。利用串口2输出连接状态。串口1给WIFI模块发送“AT”程序如下

u8 gOkFlag = 0;   // 配置成功标志位/**==============================================================================*函数名称:Med_Esp8266_CheckLink*函数功能:检查ESP8266连接状态*输入参数:无*返回值:0:未连接;1:连接正常*备  注:一直发送AT,直到接收到OK*==============================================================================*/
u8 Med_Esp8266_CheckLink (void)
{while (!gOkFlag){// 发送AT,检查连接状态printf ("AT\r\n");delay_ms(100);return 0;}gOkFlag = 0;   // 清零配置成功变量return 1;
}

一直循环发送,直到检测到返回的内容中有“OK”。串口1的接收中断函数和解析函数如下

/**==============================================================================*函数名称:USART1_IRQHandler*函数功能:USART1中断服务函数*输入参数:无*返回值:无*备  注:无*==============================================================================*/
u32 gReceCount = 0;   // 接收计数变量
u32 gClearCount = 0;   // 清空接收数组计数变量
u8 gReceFifo[1500];   // 接收数组
u8 gReceEndFlag = 0;   // 接收完成标志位 void USART1_IRQHandler(void)  
{if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)   //接收到一个字节  {gReceFifo[gReceCount++] = USART_ReceiveData(USART1);}else if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)   //接收到一帧数据{USART1->SR;   // 先读SRUSART1->DR;   // 再读DRgReceEndFlag = 1;   // 接收完成标志置1 } 
}
/**==============================================================================*函数名称:Uart_Rece_Pares*函数功能:解析串口接收内容*输入参数:无*返回值:无*备  注:无*==============================================================================*/
extern u8 gOkFlag;   // 配置成功标志位void Uart_Rece_Pares(void)   // 串口接收内容解析函数
{u16 tempVar = 0;   // 临时循环变量if (gReceEndFlag  == 1)   // 如果接收完成{// 解析接收内容for (tempVar = 0;tempVar < gReceCount;tempVar ++){if (gReceFifo[tempVar] == 'O' && gReceFifo[tempVar + 1] == 'K'){gOkFlag = 1;   // 成功标志位置1break;}}// 清空接收数组for (gClearCount = 0;gClearCount < gReceCount;gClearCount ++){gReceFifo[gClearCount] = ' ';}gReceEndFlag = 0;   // 清除接收完成标志位gReceCount = 0;   // 清零接收计数变量}
}

上电后检查WIFI模块连接状态,串口2返回信息

	u32 checkCunt = 0;   // 检测连接状态计次变量Med_Mcu_Iint();   // 系统初始化// 检查ESP8266模块连接状态while (!Med_Esp8266_CheckLink()){checkCunt = checkCunt + 1;   // 检测计数变量加1// 检测接收内容Uart_Rece_Pares();// 未连接if (checkCunt > 1){sprintf((char*)gString,"ESP8266未连接!\r\n");USART_Send(UART2,gString);delay_ms(500);}}sprintf((char*)gString,"ESP8266已连接!\r\n");USART_Send(UART2,gString);

5.3 发送配置指令

这里给出一个发送配置指令的函数,串口1给WIFI模块发送指令,串口2观察发送是否成功。

/**==============================================================================*函数名称:Med_Esp8266_CheckLink*函数功能:检查ESP8266连接状态*输入参数:str:要发送的指令*返回值:无*备  注:调用前先将需要发送的内容利用sprintf()函数转换成字符串串口1发送指令,串口2返回信息*==============================================================================*/
u8 gSendCunt = 0;   // 记录发送次数void Med_Esp8266_SendCmd (u8 *str)
{u8 string[100];while (!gOkFlag){// 发送AT指令USART_Send(UART1,str);delay_ms(1000);gSendCunt = gSendCunt + 1;   // 发送次数加1// 检测接收内容Uart_Rece_Pares();if (gSendCunt > 10){sprintf((char*)string,"%s指令发送失败!\r\n",str);USART_Send(UART2,string);}}sprintf((char*)string,"%s指令发送成功!\r\n",str);USART_Send(UART2,string);gSendCunt = 0;   // 清零发送次数gOkFlag = 0;   // 清零配置成功变量
}

配置步骤如下

	// 配置模块为Sta模式sprintf((char*)gString,"AT+CWMODE=1\r\n");Med_Esp8266_SendCmd(gString);// 连接指定WIFIsprintf((char*)gString,"AT+CWJAP=\"ertu\",\"ertu201801101102\"\r\n");Med_Esp8266_SendCmd(gString);// 设置成单连接sprintf((char*)gString,"AT+CIPMUX=0\r\n");Med_Esp8266_SendCmd(gString);// 开启透传模式sprintf((char*)gString,"AT+CIPMODE=1\r\n");Med_Esp8266_SendCmd(gString);// 创建TCP连接sprintf((char*)gString,"AT+CIPSTART=\"TCP\",\"116.62.81.138\",80\r\n");Med_Esp8266_SendCmd(gString);// 进入透传模式sprintf((char*)gString,"AT+CIPMODE=1\r\n");Med_Esp8266_SendCmd(gString);// 准备向服务器发送请求sprintf((char*)gString,"AT+CIPSEND\r\n");Med_Esp8266_SendCmd(gString);

5.4 解析天气信息

接下来就是向服务器请求天气信息,然后解析。需要修改一下串口接收内容的解析函数,接收到“code”认为天气信息获取成功,解析并返回天气信息。

/**==============================================================================*函数名称:Uart_Rece_Pares*函数功能:解析串口接收内容*输入参数:无*返回值:无*备  注:无*==============================================================================*/
extern u8 gOkFlag;   // 配置成功标志位void Uart_Rece_Pares(void)   // 串口接收内容解析函数
{u16 tempVar = 0;   // 临时循环变量u8 string[100];   // 串口打印数组if (gReceEndFlag  == 1)   // 如果接收完成{// 解析接收内容for (tempVar = 0;tempVar < gReceCount;tempVar ++){if (gReceFifo[tempVar] == 'O' && gReceFifo[tempVar + 1] == 'K'){gOkFlag = 1;   // 成功标志位置1break;}// 接收到API返回结果// 针对心知天气APIif (gReceFifo[tempVar] == 'c' && gReceFifo[tempVar + 1] == 'o' && gReceFifo[tempVar + 2] == 'd'&& gReceFifo[tempVar + 3] == 'e'){sprintf((char*)string,"天气信息获取成功\r\n");USART_Send(UART2,string);// 提取天气信息sprintf((char*)string,"天气现象代码:%c   温度:%c%c℃\r\n",gReceFifo[tempVar + 7],gReceFifo[tempVar + 25],gReceFifo[tempVar + 26]);USART_Send(UART2,string);break;}}// 清空接收数组for (gClearCount = 0;gClearCount < gReceCount;gClearCount ++){gReceFifo[gClearCount] = ' ';}gReceEndFlag = 0;   // 清除接收完成标志位gReceCount = 0;   // 清零接收计数变量}
}

六、成果展示

成果展示

总结来看,博主对于ESP8266的指令发送函数比较满意,但是由于博主能力有限,这些仅供参考。

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

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

相关文章

【STM32智能车】寻迹模块

【STM32智能车】寻迹模块 寻迹模块 传感器原理接线说明 智能车寻迹是一种机器人控制技术&#xff0c;它通过使用传感器和程序算法&#xff0c;使汽车能够在行驶过程中识别出路径上的黑线&#xff0c;并沿着该线路行驶。 智能车寻迹常用于竞赛或教育用途&#xff0c;可以提高学生…

大模型浪潮下的平台、框架、AI编译器和芯片架构丨2023智源大会精彩回顾

导读 在大模型时代&#xff0c;应该如何组织AI系统使其能力与市场需求对齐&#xff0c;是底层的AI工程师需要不断思考和探讨的话题。围绕这一问题&#xff0c;在2023智源大会AI系统分论坛上&#xff0c;从事AI框架开发、芯片研发和AI编译器优化的专家汇聚在一起&#xff0c;共同…

Java编译器IDE-Java学习帮手(移动端)

应用商店搜索"java" 编码测试 import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List;public class SplitTime {private static List<Date> dateSplit(Date start…

Java开发框架:Spring介绍

Spring 概述特点Spring 程序遇到的问题与解决概述 Spring 是 Java EE 编程领域中的一个轻量级开源框架,由 Rod Johnson 在 2002 年最早提出并随后创建,目的是解决企业级编程开发中的复杂性,实现敏捷开发的应用型框架 。其中,轻量级表现在 Spring 是非侵入式的,即开发应用中…

Python安装完成后执行pip命令报错:‘pip‘ 不是内部或外部命令,也不是可运行的程序

解决办法&#xff1a; 已安装pip的情况下&#xff0c;把这个Scripts文件夹的目录添加到Path环境变量即可。   我的电脑 -> 右键 属性 -> 高级系统设置 -> 环境变量 -> path -> 编辑&#xff1a;加入Scripts文件夹的目录    确定即可

读发布!设计与部署稳定的分布式系统(第2版)笔记20_实例层之代码

1. 术语的定义 1.1. 服务 1.1.1. 指共同协作、以单元的形式对外提供功能的跨机器进程集合 1.1.2. 一个服务可以由多种可执行文件组成 1.1.3. 一个服务可能包含来自多个可执行文件的多个进程 1.1.4. 可能对外呈现单个IP地址&#xff0c;并在后台进行负载均衡 1.1.5. 可能有…

HOT47-从前序与中序遍历序列构造二叉树

leetcode原题链接&#xff1a;从前序与中序遍历序列构造二叉树 题目描述 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 示例 1: 输入: preorder …

获取java对象被更新的属性和值

业务场景 更新User信息后&#xff0c;需要收集哪些字段的哪些值被更新了。 思路 比较originUser和newUser&#xff0c;收集值不同的属性以及变化前后的值。 代码实现 public static Map<String, Map<String, Object>> getChange(Object originObject, Object ne…

YoloV5/YoloV7改进---注意力机制:SRM,卷积神经网络再校准模块,性能优于SE、GE

目录 1.SRM介绍 ​编辑 2.SRM引入到yolov5 2.1 加入common.py中&#xff1a; 2.2 加入yolo.py中&#xff1a; 2.3 yolov5s_SRM.yaml 2.4 yolov5s_SRM1.yaml 3.YOLOv5/YOLOv7魔术师专栏介绍 1.SRM介绍 论文&#xff1a;https://openaccess.thecvf.com/content…

人工智能学习07--pytorch22--目标检测:YOLO V3 SPP

视频链接&#xff1a; https://www.bilibili.com/video/BV1t54y1C7ra/?vd_sourceb425cf6a88c74ab02b3939ca66be1c0d yolov3 spp spp&#xff1a;空间金字塔池化 trick&#xff1a;实现的小技巧&#xff0c;方法。&#xff08; up&#xff1a;Bag of Freebies里有很多trick&…

多实例部署和Nginx+Tomcat负载均衡、动静分离

目录 一、Tomcat多实例部署 1.安装好 jdk 2.安装 tomcat 3.配置 tomcat环境变量 4.修改 tomcat2 中的 server.xml文件&#xff0c;要求各 tomcat 实例配置不能有重复的端口号 5.修改各 tomcat 实例中的 startup.sh 和 shutdown.sh 文件&#xff0c;添加 tomcat 环境变量 6.启…

4.44ue4:相机抖动

1.创建相机抖动类 右键内容面板&#xff0c;点击创建蓝图类&#xff0c;搜索shake&#xff08;camera shake&#xff09; 2.使用相机抖动&#xff1a; 节点&#xff1a;play world .. api解释&#xff1a; epicenter&#xff1a;震源 inner Radius&#xff1a;内圈范围&a…