STM32之WIFI通信(ESP8266 ESP

您所在的位置:网站首页 esp8266软件设计流程图 STM32之WIFI通信(ESP8266 ESP

STM32之WIFI通信(ESP8266 ESP

2024-07-11 03:49| 来源: 网络整理| 查看: 265

STM32之WIFI通信(ESP8266 ESP-01S) 前言

本文:使用的是 STM32F103C8T6 + ESP-01S模块 通过采用串口的通信方式 来实现 WIFI功能

ESP8266的介绍

ESP8266指的是乐鑫推出的ESP8266EX芯片,用ESP8266EX芯片和FLASH芯片等封装在PCB上、金属屏蔽罩下便得到ESP8266模块。

ESP8266EX 由乐鑫公司开发,提供了⼀套⾼度集成的 Wi-Fi SoC 解决⽅案,其低功耗、 紧凑设计和⾼稳定性可以满⾜⽤户的需求。

ESP8266EX 拥有完整的且⾃成体系的 Wi-Fi 网络功能,既能够独立应用,也可以作为从机 搭载于其他主机 MCU 运⾏。当 ESP8266EX 独⽴应⽤时,能够直接从外接 Flash 中启动。 内置的⾼速缓冲存储器有利于提⾼系统性能,并且优化存储系统。此外 ESP8266EX 只需通过 SPI/SDIO 接⼝或 I2C/UART ⼝即可作为 Wi-Fi 适配器,应⽤到基于任何微控制器的 设计中。 ESP8266EX 集成了天线开关、射频 balun、功耗放⼤器、低噪放⼤器、过滤器和电源管理 模块。这样紧凑的设计仅需极少的外部电路并且将 PCB 的尺⼨降到最⼩

ESP-01S的介绍

ESP-01S 是由安信可科技开发的Wi-Fi模块,该模块核心处理器 ESP8266 在较小尺寸封装中集成了业界领先的 Tensilica L106 超低功耗 32 位微型 MCU,带有 16 位精简模式,主频支持 80 MHz 和 160 MHz,支持 RTOS,集成 Wi-Fi MAC/ BB/RF/PA/LN

ESP-01S Wi-Fi 模块支持标准的 IEEE802.11 b/g/n 协议,完整的 TCP/IP 协议栈。用户可以使用该模块为现有的设备添加联网功能,也可以构建独立的网络控制器。

ESP-01S 脚序 名称 功能说明 1 GND 接地 2 IO2 GPIO2/UART1_TXD 3 IO0 GPIO0;下载模式:外部拉低;运行模式:悬空或者外部拉高 4 RXD UART0_RXD/GPIO3 5 TXD UART0_TXD/GPIO1 6 EN 芯片使能端,高电平有效 7 RST 复位 8 VCC 3.3V 供电(VDD);外部供电电源输出电流建议在500mA以上

官方说明: EN 脚和 RST 脚必须上拉到 VCC

通过我的实践经验:

遇到最头疼问题(当时),就是感觉模块时好时不好,偶然发现 拔掉重新插就好的现象,后来再到将 ESP-01S的VCC重新插拔就好了,知道了: 官方 推荐 3.3V 电压,峰值 500mA 以上电 说明我们的板子供电可能不足 所以建议使用外部电源 我们STM32单片机 和 ESP-01S模块通过串口通信时连接可以只用使用 VCC GND TXD RXD 这四个引脚 但是我自己感觉会有点问题的存在: 就是 在复位时 并不会 出现上电时候 那些乱码 ESP8266_Start 所以我想到了 是不是因为 我当时RST复位引脚 在测试时没有上拉到VCC也可以正常使用 那我板子复位了 但WIFI模块不复位 重新跑我的程序 我觉得也是可以的 但是呢 这时发现 EN 使能位 出现了问题 不插可以 插就出现问题 我加上EN使能位时,单片机重新复位程序时 容易卡死 而不使用EN使能位时 程序非常快的执行了一遍 但是不会出现上电时的那些乱码了 这个问题还需加深考虑 最终:我还是将 VCC GND TXD RXD EN RST 引脚,都接上了 并且 在STM32复位时 将 RST复位引脚/VCC引脚 插拔一下 会更好的 运行 感觉是硬件问题 因为我使用的是最小开发板+模块 STM32与ESP8266通信

好了 上面是关于 如何对ESP-01S的模块硬件上的连接 以及一些AT指令 那么我接下来讲一下如何使STM32和ESP-01S进行通信 最后WIFI连接到我们的电脑上

STM32_ESP_01S

在单片机内部

串口助手发送给USART1的数据 USART1通过USART2再传给 ESP8266 ESP8266发送给USART2的数据 USART2通过USART1再传给串口助手

可以看出以上就是我们STM32在串口助手和ESP01S之间的通信方式了,所以只要学会串口通信,在学习一下发送给ESP8266的指令就可以使用WIFI连接到我们的网路了,下面介绍一下 AT指令

AT指令

AT指令,其实就是一种通信协议,你可以理解为 串口是马路,而AT指令就是交通规则,只有正确的驾驶才可以通过,即我们通过串口向ESP8266发送数据帧 它会检测 你发送的是不是AT指令,从而做出相应的动作 指令集主要分为:基础 AT 指令、Wi-Fi 功能 AT 指令、TCP/IP 相关的 AT 指令

AT指令集非常多,我在这里只列举几个最常用的AT指令:

指令 含义 响应 AT 测试 AT 启动 OK AT+RST 重启模块 OK AT+CWMODE=1/2/3 设置 Wi-Fi 模式 (Station/SoftAP/Station+SoftAP) OK AT+CWJAP="SSID","PWD" 设置 ESP8266 Station 需连接的 AP -- 连接WIFI OK AT+CIPSTART="TCP","122.114.122.174",37590 建⽴ TCP 连接,UDP 传输或 SSL 连接 "安可信网址""端口号" OK AT+CIPMODE=1 设置传输模式(0:普通传输模式 ‣ 1:透传模式,仅⽀持 TCP 单连接和 UDP 固定通信对端的情况) 透传模式传输时,如果连接断开,ESP8266 会不停尝试重连,此时单独输⼊ +++ 退出透传,则停⽌重 连;普通传输模式则不会重连,提示连接断开。 OK AT+CIPSEND 发送数据 收到此命令后先换⾏返回 > ,注意:在不退出透传时AT指令将不起作用 > +++ 退出透传模式(不能加换行) OK AT+CIPCLOSE 关闭 TCP/UDP/SSL 传输 OK AT+CIPMUX=1 设置多连接 OK AT+CWSAP="ESP8266","1234567890",5,3 配置 ESP8266 SoftAP 参数 -- ESP8266为WIFI源 OK AT+CIPSERVER=1,5050 建立TCP服务器( 0:关闭服务器 ‣ 1:建⽴服务器),端口号 OK AT+CIFSR 查询本地 IP 地址 OK

AT指令的使用时,需要自动加上换行符号

想要练习AT指令 可以使用 安信可透传云 V1.0进行测试 使用多条发送的数据并不会打印到串口上,我们平常发送AT会有数据回显是因为厂商设置的我们也可以是使用ATE0指令来关闭回显

ESP8266_ANXINKE

STM32实战演习

通过以上学习,我们就可以与ESP8266进行通信 并连接自己的热点 注意:WIFI热点要开2.4GHZ的

本次实现连接淘宝API然后获取当前时间,获取时间的格式为 JSON数据 我们可以对JSON数据格式进行解析 然后把时间发送给RTC这样我们就可以永久保持这个时间了 对了当长时间不与TCP进行连接时服务器会主动断开与我们的连接

STM32_WIFIGetTime

USART1.h

#ifndef __USART_H__//如果没有定义了则参加以下编译 #define __USART_H__//一旦定义就有了定义 所以 其目的就是防止模块重复编译 #include "stm32f10x.h" #include "stdio.h" #include void Usart_Init(void); void Usart1_SendByte(uint8_t Byte); #endif //结束编译

USART1.c

#include "usart.h" uint8_t RxFlag; /* *PA9 -- TX *PA10 -- RX */ void Usart_Init(void) { //使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);//使能时钟A和USART1 //为初始化函数做准备 GPIO_InitTypeDef GPIO_InitStructure;//定义结构体 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//设置PA9引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP ;//设置输出模式为复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ;//设置输出速度为50MHZ //初始化函数PIN9↓ GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//设置PA10引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;//设置输出模式为上拉输入 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ;//设置输出速度为50MHZ //初始化函数PIN10↓ GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化 USART_InitTypeDef USART_InitStructure; //定义串口结构体 USART_InitStructure.USART_BaudRate = 115200; //波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//数字帧长度 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_Tx|USART_Mode_Rx; //模式为发送+接收 //初始化串口1 USART_Init(USART1, &USART_InitStructure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); NVIC_InitTypeDef NVIC_InitStructure; //定义结构体 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //根据上面的我们所选取的USART1 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//这里选择的是抢占 1 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //这里选择的是响应1 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能指定的中断通道 //初始化函数↓ NVIC_Init(&NVIC_InitStructure); //使能串口1 USART_Cmd(USART1, ENABLE); } /** * @brief 串口1发送字节 -- 发送的最基本的函数 -->其它发送函数都是基于它 * @param * @retval */ void Usart1_SendByte(uint8_t Byte) { USART_SendData(USART1,Byte); while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET ); } /** * @brief 串口中断函数 中断函数里面可以放你想要实现的功能函数 * @param * @retval */ void USART1_IRQHandler(void) { uint8_t data = 0; if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) { USART_ClearITPendingBit(USART1, USART_IT_RXNE); data = USART_ReceiveData(USART1);//获取串口助手发送给单片机的数据 USART_SendData(USART2,data);//通过串口2发送 --> ESP8266 } } /** * @brief 函数重定义--封装printf函数 * @param * @retval */ int fputc(int ch, FILE *f) { Usart1_SendByte(ch); return ch; }

ESP8266.h

#ifndef __ESP8266_H__//如果没有定义了则参加以下编译 #define __ESP8266_H__//一旦定义就有了定义 所以 其目的就是防止模块重复编译 #include "stm32f10x.h" #include "delay.h" #include "stdlib.h" #include "string.h" void ESP8266_Init(void); void Usart2_SendByte(uint8_t Byte); void Usart2_SendString(uint8_t *string); void Esp8266_SendString(uint8_t *string,uint16_t len);//串口2 发送字符串 uint8_t EspSendCmdAndCheckRecvData(uint8_t *cmd,uint8_t *Rcmd,uint16_t outtime); void WIFI_ConnectTaoBao(void); typedef struct{ uint8_t rxbuff[1024]; uint16_t rxcount; uint8_t rxover; uint8_t txbuff[1024]; uint16_t txcount; }WIFI; extern WIFI wifi; #endif //结束编译

ESP8266.c

#include "ESP8266.h" /** * @brief ESP8266初始化 PA2--TX PA3--RX PA5--ESP8266使能引脚 */ WIFI wifi = {0}; void ESP8266_Init(void) { //使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能时钟A RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//使能时钟USART2 //为初始化函数做准备 GPIO_InitTypeDef GPIO_InitStructure;//定义结构体 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;//设置PA2引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP ;//设置输出模式为复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ;//设置输出速度为50MHZ //初始化函数PIN2 GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//设置PA3引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;//设置输出模式为上拉输入 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ;//设置输出速度为50MHZ //初始化函数PIN3↓ GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//设置PA5引脚 -- //ESP8266使能引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;//设置输出模式为推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ;//设置输出速度为50MHZ //初始化函数PIN5↓ GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化 USART_InitTypeDef USART_InitStructure; //定义串口结构体 USART_InitStructure.USART_BaudRate = 115200; //波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//数字帧长度 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_Tx|USART_Mode_Rx; //模式为发送+接收 //初始化串口2 USART_Init(USART2, &USART_InitStructure); USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//使能接收中断 USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);//使能空闲中断 NVIC_InitTypeDef NVIC_InitStructure; //定义结构体 NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //根据上面的我们所选取的USART2 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//这里选择的是抢占 1 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //这里选择的是响应2 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能指定的中断通道 //初始化函数↓ NVIC_Init(&NVIC_InitStructure); //使能串口2 USART_Cmd(USART2, ENABLE); GPIO_SetBits(GPIOA,GPIO_Pin_5);//GPIOA 高电平有效 -- 使能ESP8266 Delay_ms(2000);//延时 等待WiFi模块稳定 } /** * @brief 串口2发送字节 -- 发送的最基本的函数 -->其它发送函数都是基于它 * @param * @retval */ void Usart2_SendByte(uint8_t Byte) { USART_SendData(USART2,Byte); while(USART_GetFlagStatus(USART2,USART_FLAG_TXE) == RESET ); } /** * @brief 串口中断函数 中断函数里面可以放你想要实现的功能函数 * @param * @retval */ void USART2_IRQHandler(void) { uint8_t data = 0; if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET) { USART_ClearITPendingBit(USART2, USART_IT_RXNE); data = USART_ReceiveData(USART2);//ESP8266 发送给 STM32的数据 wifi.rxbuff[wifi.rxcount++] = data;//将 ESP8266 发送给单片机的数据 转存到rxbuff里面 USART_SendData(USART1,data); //可通过 串口助手在电脑屏幕上 显示 } if(USART_GetITStatus(USART2, USART_IT_IDLE) == 1) //串口空闲中断 { data = USART2->SR; data = USART2->DR; wifi.rxover = 1; } } /** * @brief 发送字符串 * @param string 字符串 * @retval */ void Usart2_SendString(uint8_t *string) { for(uint8_t i = 0;string[i] != '\0';i++) { Usart2_SendByte(string[i]); } } /** * @brief 发送字符串 + 带长度 * @param * @retval */ void Esp8266_SendString(uint8_t *string,uint16_t len)//串口3 发送字符串 { for(uint16_t i=0;i 才会进入串口2中断服务 while(outtime) { if(wifi.rxover == 1) { if(strstr((char *)wifi.rxbuff,(char *)Rcmd) != NULL) { data = 1; break; } } outtime--; Delay_ms(1); } return data; } /** * @brief 连接淘宝API 获取当前时间 * @param * @retval */ void WIFI_ConnectTaoBao(void) { if(EspSendCmdAndCheckRecvData("AT\r\n","OK",1000) == 1) { if(EspSendCmdAndCheckRecvData("AT+CWMODE=1\r\n","OK",1000) == 1) { if(EspSendCmdAndCheckRecvData("AT+CWJAP=\"你的WIFI\",\"你的WIFI密码\"\r\n","OK",100000) == 1) { if(EspSendCmdAndCheckRecvData("AT+CIPSTART=\"TCP\",\"api.m.taobao.com\",80\r\n","OK",10000)==1) { EspSendCmdAndCheckRecvData("AT+CIPMODE=1\r\n","OK",1000);//开启透传 EspSendCmdAndCheckRecvData("AT+CIPSEND\r\n",">",1000);//发送数据 //清空回收的buff memset(wifi.rxbuff,0,1024); wifi.rxover = 0; wifi.rxcount = 0; Delay_ms(1000); Usart2_SendString("GET http://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp\r\n"); Delay_ms(1000); Usart2_SendString("+++");//退出透传模式 } } } } } /** * @brief 解析JSON数据 * @param * @retval */ void GetTime_RecvData(void) { char Val[20] = {0}; char tep[20] = {0}; uint8_t i = 0; uint32_t timeget = 0; // long long timeget = 0; time_t time = 0; if(wifi.rxover==1) { wifi.rxover = 0; if(wifi.rxcount>10)//判断是否是 下发指令的回传的指令 而不是上传时系统默认下发的 //防止有影响 { char *addr = strstr((char *)(wifi.rxbuff+6),"\"t\""); addr+=5; while(*(addr + i) != '"') { Val[i] = *( addr+i); i++; } printf("%s\r\n",Val); // sscanf(Val, "%lld", &timeget); // 存储类型为long long int // printf("%lld\r\n",timeget); for(i = 0;i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3