当前位置:网站首页>STM32封装ESP8266一键配置函数:实现实现AP模式和STA模式切换、服务器与客户端创建
STM32封装ESP8266一键配置函数:实现实现AP模式和STA模式切换、服务器与客户端创建
2022-07-06 22:23:00 【华为云】
一、硬件环境介绍
1. ESP8266 : 采用安信可的模组,型号是ESP12F
2. STM32 : 采用STM32F103C8T6
3. 编程软件 : 采用Keil5
ESP8266编程调试过程中用到的相关软件下载地址:
二、ESP8266通信的调试与运行效果
下面几张图是将ESP8266配置成AP+TCP服务器模式,电脑连接ESP8266的热点之后,实现数据通信。通信的效果是,在电脑点击物联网控制系统软件,实现控制开发板上的LED灯和蜂鸣器,开发板上将检测的光敏数据、温度数据、RC522刷卡数据传输到电脑的软件上进行显示。----局域网通信
三、硬件接线与代码技术部分介绍
硬件连接: 下面会贴出核心代码,在当前开发板上,ESP8266接在STM32F103C8T6的串口3上。
代码分为以下几个部分:
(1) STM32程序里的串口接收采用定时器+接收中断的形式接收数据,使用这种方式可以接收不定长度数据,方便接下来与ESP8266进行通信。
(2). ESP8266驱动代码:代码实现了STA+TCP客户端的一键配置函数,AP+TCP服务器的一键配置函数,要配置ESP8266只需要调用对应的函数传入参数即可。
四、核心代码部分
4.1 ESP8266.c代码
#include "esp8266.h"u8 ESP8266_IP_ADDR[16]; //255.255.255.255u8 ESP8266_MAC_ADDR[18]; //硬件地址/*函数功能: ESP8266命令发送函数函数返回值:0表示成功 1表示失败*/u8 ESP8266_SendCmd(char *cmd){ u8 i,j; for(i=0;i<10;i++) //检测的次数--发送指令的次数 { USARTx_StringSend(USART3,cmd); for(j=0;j<100;j++) //等待的时间 { delay_ms(50); if(USART3_RX_FLAG) { USART3_RX_BUFFER[USART3_RX_CNT]='\0'; USART3_RX_FLAG=0; USART3_RX_CNT=0; if(strstr((char*)USART3_RX_BUFFER,"OK")) { return 0; } } } } return 1;}/*函数功能: ESP8266硬件初始化检测函数函数返回值:0表示成功 1表示失败*/u8 ESP8266_Init(void){ //退出透传模式 USARTx_StringSend(USART3,"+++"); delay_ms(50); return ESP8266_SendCmd("AT\r\n");}/*函数功能: 一键配置WIFI为AP+TCP服务器模式函数参数:char *ssid 创建的热点名称char *pass 创建的热点密码 (最少8位)u16 port 创建的服务器端口号函数返回值: 0表示成功 其他值表示对应错误值*/u8 ESP8266_AP_TCP_Server_Mode(char *ssid,char *pass,u16 port){ char *p; u8 i; char ESP8266_SendCMD[100]; //组合发送过程中的命令 /*1. 测试硬件*/ if(ESP8266_SendCmd("AT\r\n"))return 1; /*2. 关闭回显*/ if(ESP8266_SendCmd("ATE0\r\n"))return 2; /*3. 设置WIFI模式*/ if(ESP8266_SendCmd("AT+CWMODE=2\r\n"))return 3; /*4. 复位*/ ESP8266_SendCmd("AT+RST\r\n"); delay_ms(1000); delay_ms(1000); delay_ms(1000); /*5. 关闭回显*/ if(ESP8266_SendCmd("ATE0\r\n"))return 5; /*6. 设置WIFI的AP模式参数*/ sprintf(ESP8266_SendCMD,"AT+CWSAP=\"%s\",\"%s\",1,4\r\n",ssid,pass); if(ESP8266_SendCmd(ESP8266_SendCMD))return 6; /*7. 开启多连接*/ if(ESP8266_SendCmd("AT+CIPMUX=1\r\n"))return 7; /*8. 设置服务器端口号*/ sprintf(ESP8266_SendCMD,"AT+CIPSERVER=1,%d\r\n",port); if(ESP8266_SendCmd(ESP8266_SendCMD))return 8; /*9. 查询本地IP地址*/ if(ESP8266_SendCmd("AT+CIFSR\r\n"))return 9; //提取IP地址 p=strstr((char*)USART3_RX_BUFFER,"APIP"); if(p) { p+=6; for(i=0;*p!='"';i++) { ESP8266_IP_ADDR[i]=*p++; } ESP8266_IP_ADDR[i]='\0'; } //提取MAC地址 p=strstr((char*)USART3_RX_BUFFER,"APMAC"); if(p) { p+=7; for(i=0;*p!='"';i++) { ESP8266_MAC_ADDR[i]=*p++; } ESP8266_MAC_ADDR[i]='\0'; } //打印总体信息 USART1_Printf("当前WIFI模式:AP+TCP服务器\n"); USART1_Printf("当前WIFI热点名称:%s\n",ssid); USART1_Printf("当前WIFI热点密码:%s\n",pass); USART1_Printf("当前TCP服务器端口号:%d\n",port); USART1_Printf("当前TCP服务器IP地址:%s\n",ESP8266_IP_ADDR); USART1_Printf("当前TCP服务器MAC地址:%s\n",ESP8266_MAC_ADDR); return 0;}/*函数功能: TCP服务器模式下的发送函数发送指令: */u8 ESP8266_ServerSendData(u8 id,u8 *data,u16 len){ u8 i,j,n; char ESP8266_SendCMD[100]; //组合发送过程中的命令 for(i=0;i<10;i++) { sprintf(ESP8266_SendCMD,"AT+CIPSEND=%d,%d\r\n",id,len); USARTx_StringSend(USART3,ESP8266_SendCMD); for(j=0;j<10;j++) { delay_ms(50); if(USART3_RX_FLAG) { USART3_RX_BUFFER[USART3_RX_CNT]='\0'; USART3_RX_FLAG=0; USART3_RX_CNT=0; if(strstr((char*)USART3_RX_BUFFER,">")) { //继续发送数据 USARTx_DataSend(USART3,data,len); //等待数据发送成功 for(n=0;n<200;n++) { delay_ms(50); if(USART3_RX_FLAG) { USART3_RX_BUFFER[USART3_RX_CNT]='\0'; USART3_RX_FLAG=0; USART3_RX_CNT=0; if(strstr((char*)USART3_RX_BUFFER,"SEND OK")) { return 0; } } } } } } } return 1;}/*函数功能: 配置WIFI为STA模式+TCP客户端模式函数参数:char *ssid 创建的热点名称char *pass 创建的热点密码 (最少8位)char *p 将要连接的服务器IP地址u16 port 将要连接的服务器端口号u8 flag 1表示开启透传模式 0表示关闭透传模式函数返回值:0表示成功 其他值表示对应的错误*/u8 ESP8266_STA_TCP_Client_Mode(char *ssid,char *pass,char *ip,u16 port,u8 flag){ char ESP8266_SendCMD[100]; //组合发送过程中的命令 //退出透传模式 //USARTx_StringSend(USART3,"+++"); //delay_ms(50); /*1. 测试硬件*/ if(ESP8266_SendCmd("AT\r\n"))return 1; /*2. 关闭回显*/ if(ESP8266_SendCmd("ATE0\r\n"))return 2; /*3. 设置WIFI模式*/ if(ESP8266_SendCmd("AT+CWMODE=1\r\n"))return 3; /*4. 复位*/ ESP8266_SendCmd("AT+RST\r\n"); delay_ms(1000); delay_ms(1000); delay_ms(1000); /*5. 关闭回显*/ if(ESP8266_SendCmd("ATE0\r\n"))return 5; /*6. 配置将要连接的WIFI热点信息*/ sprintf(ESP8266_SendCMD,"AT+CWJAP=\"%s\",\"%s\"\r\n",ssid,pass); if(ESP8266_SendCmd(ESP8266_SendCMD))return 6; /*7. 设置单连接*/ if(ESP8266_SendCmd("AT+CIPMUX=0\r\n"))return 7; /*8. 配置要连接的TCP服务器信息*/ sprintf(ESP8266_SendCMD,"AT+CIPSTART=\"TCP\",\"%s\",%d\r\n",ip,port); if(ESP8266_SendCmd(ESP8266_SendCMD))return 8; /*9. 开启透传模式*/ if(flag) { if(ESP8266_SendCmd("AT+CIPMODE=1\r\n"))return 9; //开启 if(ESP8266_SendCmd("AT+CIPSEND\r\n"))return 10; //开始透传 if(!(strstr((char*)USART3_RX_BUFFER,">"))) { return 11; } //如果想要退出发送: "+++" } //打印总体信息 USART1_Printf("当前WIFI模式:STA+TCP客户端\n"); USART1_Printf("当前连接的WIFI热点名称:%s\n",ssid); USART1_Printf("当前连接的WIFI热点密码:%s\n",pass); USART1_Printf("当前连接的TCP服务器端口号:%d\n",port); USART1_Printf("当前连接的TCP服务器IP地址:%s\n",ip); return 0;}/*函数功能: TCP客户端模式下的发送函数发送指令: */u8 ESP8266_ClientSendData(u8 *data,u16 len){ u8 i,j,n; char ESP8266_SendCMD[100]; //组合发送过程中的命令 for(i=0;i<10;i++) { sprintf(ESP8266_SendCMD,"AT+CIPSEND=%d\r\n",len); USARTx_StringSend(USART3,ESP8266_SendCMD); for(j=0;j<10;j++) { delay_ms(50); if(USART3_RX_FLAG) { USART3_RX_BUFFER[USART3_RX_CNT]='\0'; USART3_RX_FLAG=0; USART3_RX_CNT=0; if(strstr((char*)USART3_RX_BUFFER,">")) { //继续发送数据 USARTx_DataSend(USART3,data,len); //等待数据发送成功 for(n=0;n<200;n++) { delay_ms(50); if(USART3_RX_FLAG) { USART3_RX_BUFFER[USART3_RX_CNT]='\0'; USART3_RX_FLAG=0; USART3_RX_CNT=0; if(strstr((char*)USART3_RX_BUFFER,"SEND OK")) { return 0; } } } } } } } return 1;}
4.2 ESP8266.h
#ifndef _ESP8266_H#define _ESP8266_H#include "stm32f10x.h"#include "usart.h"#include "delay.h"//函数声明u8 ESP8266_Init(void);u8 ESP8266_SendCmd(char *cmd);u8 ESP8266_AP_TCP_Server_Mode(char *ssid,char *pass,u16 port);u8 ESP8266_ServerSendData(u8 id,u8 *data,u16 len);u8 ESP8266_STA_TCP_Client_Mode(char *ssid,char *pass,char *ip,u16 port,u8 flag);u8 ESP8266_ClientSendData(u8 *data,u16 len);#endif
4.3 串口部分代码
/*函数功能: 串口1的初始化硬件连接: PA9(TX) 和 PA10(RX)*/void USART1_Init(u32 baud){ /*1. 开时钟*/ RCC->APB2ENR|=1<<14; //USART1时钟 RCC->APB2ENR|=1<<2; //PA RCC->APB2RSTR|=1<<14; //开启复位时钟 RCC->APB2RSTR&=~(1<<14);//停止复位 /*2. 配置GPIO口的模式*/ GPIOA->CRH&=0xFFFFF00F; GPIOA->CRH|=0x000008B0; /*3. 配置波特率*/ USART1->BRR=72000000/baud; /*4. 配置核心寄存器*/ USART1->CR1|=1<<5; //开启接收中断 STM32_SetPriority(USART1_IRQn,1,1); //设置中断优先级 USART1->CR1|=1<<2; //开启接收 USART1->CR1|=1<<3; //开启发送 USART1->CR1|=1<<13;//开启串口功能}/*函数功能: 串口3的初始化硬件连接: PB10(TX) 和 PB11(RX)*/void USART3_Init(u32 baud){ /*1. 开时钟*/ RCC->APB1ENR|=1<<18; //USART3时钟 RCC->APB2ENR|=1<<3; //PB RCC->APB1RSTR|=1<<18; //开启复位时钟 RCC->APB1RSTR&=~(1<<18);//停止复位 /*2. 配置GPIO口的模式*/ GPIOB->CRH&=0xFFFF00FF; GPIOB->CRH|=0x00008B00; /*3. 配置波特率*/ USART3->BRR=36000000/baud; /*4. 配置核心寄存器*/ USART3->CR1|=1<<5; //开启接收中断 STM32_SetPriority(USART3_IRQn,1,1); //设置中断优先级 USART3->CR1|=1<<2; //开启接收 USART3->CR1|=1<<3; //开启发送 USART3->CR1|=1<<13;//开启串口功能}u8 USART3_RX_BUFFER[USART3_RX_LENGTH]; //保存接收数据的缓冲区u32 USART3_RX_CNT=0; //当前接收到的数据长度u8 USART3_RX_FLAG=0; //1表示数据接收完毕 0表示没有接收完毕//串口3的中断服务函数void USART3_IRQHandler(void){ u8 data; //接收中断 if(USART3->SR&1<<5) { TIM3->CNT=0; //清除计数器 TIM3->CR1|=1<<0; //开启定时器3 data=USART3->DR; //读取串口数据 // if(USART3_RX_FLAG==0) //判断上一次的数据是否已经处理完毕 { //判断是否可以继续接收 if(USART3_RX_CNT<USART3_RX_LENGTH) { USART3_RX_BUFFER[USART3_RX_CNT++]=data; } else //不能接收,超出存储范围,强制表示接收完毕 { USART3_RX_FLAG=1; } } }}/*函数功能: 字符串发送*/void USARTx_StringSend(USART_TypeDef *USARTx,char *str){ while(*str!='\0') { USARTx->DR=*str++; while(!(USARTx->SR&1<<7)){} }}/*函数功能: 数据发送*/void USARTx_DataSend(USART_TypeDef *USARTx,u8 *data,u32 len){ u32 i; for(i=0;i<len;i++) { USARTx->DR=*data++; while(!(USARTx->SR&1<<7)){} }}/*函数功能: 格式化打印函数*/char USART1_PRINTF_BUFF[1024];void USART1_Printf(char *fmt,...){ va_list ap; /*1. 初始化形参列表*/ va_start(ap,fmt); /*2. 提取可变形参数据*/ vsprintf(USART1_PRINTF_BUFF,fmt,ap); /*3. 结束,释放空间*/ va_end(ap); /*4. 输出数据到串口1*/ USARTx_StringSend(USART1,USART1_PRINTF_BUFF); //USART1_Printf("%d%s",123,454656); //int data=va_arg(ap,int);}
4.4 定时器部分代码
/*函数功能: 配置定时器3函数参数: psc 预分频器 arr重装载值*/void TIMER3_Init(u16 psc,u16 arr){ /*1. 开时钟*/ RCC->APB1ENR|=1<<1; //开启定时器3的时钟 RCC->APB1RSTR|=1<<1;//开启定时器3复位时钟 RCC->APB1RSTR&=~(1<<1);//关闭定时器3复位时钟 /*2. 配置核心寄存器*/ TIM3->PSC=psc-1; TIM3->ARR=arr; TIM3->DIER|=1<<0; //开启更新中断 STM32_SetPriority(TIM3_IRQn,1,1); //设置中断优先级 // TIM3->CR1|=1<<0; //开启定时器3}/*函数功能: 定时器3中断服务函数*/void TIM3_IRQHandler(void){ if(TIM3->SR&1<<0) { TIM3->SR&=~(1<<0); USART3_RX_FLAG=1; //表示接收完毕 TIM3->CR1&=~(1<<0); //关闭定时器3 }}
4.5 主函数调用部分(STA+TCP客户端)示例
int main(){ u8 key,cnt=0; LED_Init(); BEEP_Init(); KEY_Init(); USART1_Init(115200); USART3_Init(115200);//串口-WIFI TIMER3_Init(72,20000); //超时时间20ms USART1_Printf("正在初始化WIFI请稍等.\n"); if(ESP8266_Init()) { USART1_Printf("ESP8266硬件检测错误.\n"); } else { USART1_Printf("WIFI:%d\n",ESP8266_STA_TCP_Client_Mode("ChinaNet-wbyw","12345678","192.168.101.6",8088,1)); } while(1) { if(USART3_RX_FLAG) { USART3_RX_BUFFER[USART3_RX_CNT]='\0'; USART1_Printf("%s",USART3_RX_BUFFER); USART3_RX_CNT=0; USART3_RX_FLAG=0; } key=KEY_Scan(0); if(key==2) { USARTx_StringSend(USART3,"AT+GMR\r\n"); //查看版本信息 } else if(key==3) { USARTx_StringSend(USART3,"12345ABCD"); } else if(key==4) //退出透传模式 { USARTx_StringSend(USART3,"+++"); } else if(key==5) //发送AT { USARTx_StringSend(USART3,"AT+CIPSTATUS\r\n"); //查看状态信息 } }}
4.6 主函数调用部分(AP+TCP服务器)示例
int main(){ u8 key; LED_Init(); BEEP_Init(); KEY_Init(); USART1_Init(115200); USART3_Init(115200);//串口-WIFI TIMER3_Init(72,20000); //超时时间20ms USART1_Printf("正在初始化WIFI请稍等.\n"); //初始化WIFI硬件 if(ESP8266_Init())USART1_Printf("WIFI硬件错误.\n"); else { //配置WIFI的模式 USART1_Printf("WIFI配置状态:%d\n",ESP8266_AP_TCP_Server_Mode("esp8266_666","12345678",8088)); } while(1) { if(USART3_RX_FLAG) { USART3_RX_BUFFER[USART3_RX_CNT]='\0'; USART1_Printf("%s",USART3_RX_BUFFER); USART3_RX_CNT=0; USART3_RX_FLAG=0; } key=KEY_Scan(0); if(key==2) { ESP8266_ServerSendData(0,(u8*)"1234567890",10); } else if(key==3) { ESP8266_ServerSendData(0,(u8*)"abcd",4); } }}
边栏推荐
- 【736. Lisp 语法解析】
- 九章云极DataCanvas公司获评36氪「最受投资人关注的硬核科技企业」
- Implementation of JSTL custom function library
- What work items do programmers hate most in their daily work?
- Detect when a tab bar item is pressed
- JS input and output
- A row of code r shows the table of Cox regression model
- How does vscade use the built-in browser?
- ACL2022 | 分解的元学习小样本命名实体识别
- Vscode 如何使用内置浏览器?
猜你喜欢
DFS and BFS concepts and practices +acwing 842 arranged numbers (DFS) +acwing 844 Maze walking (BFS)
mpf2_ Linear programming_ CAPM_ sharpe_ Arbitrage Pricin_ Inversion Gauss Jordan_ Statsmodel_ Pulp_ pLU_ Cholesky_ QR_ Jacobi
Flex layout and usage
mpf2_线性规划_CAPM_sharpe_Arbitrage Pricin_Inversion Gauss Jordan_Statsmodel_Pulp_pLU_Cholesky_QR_Jacobi
Intel and Xinbu technology jointly build a machine vision development kit to jointly promote the transformation of industrial intelligence
How to package the parsed Excel data into objects and write this object set into the database?
How does vscade use the built-in browser?
What about the collapse of win11 playing pubg? Solution to win11 Jedi survival crash
深耕开发者生态,加速AI产业创新发展 英特尔携众多合作伙伴共聚
深入解析Kubebuilder
随机推荐
Vscode 如何使用内置浏览器?
jvm是什么?jvm调优有哪些目的?
A detailed explanation of head pose estimation [collect good articles]
Network Security Learning - Information Collection
软件测试之网站测试如何进行?测试小攻略走起!
什么是Web3
GPT-3当一作自己研究自己,已投稿,在线蹲一个同行评议
AttributeError: module ‘torch._C‘ has no attribute ‘_cuda_setDevice‘
How does vscade use the built-in browser?
Flex layout and usage
广告归因:买量如何做价值衡量?
ACL2022 | 分解的元学习小样本命名实体识别
JS input and output
DFS和BFS概念及实践+acwing 842 排列数字(dfs) +acwing 844. 走迷宫(bfs)
Gavin teacher's perception of transformer live class - rasa project actual combat e-commerce retail customer service intelligent business dialogue robot microservice code analysis and dialogue experim
If you ask me about R code debugging, I will tell you head, STR, help
九章云极DataCanvas公司蝉联中国机器学习平台市场TOP 3
Can I specify a path in an attribute to map a property in my class to a child property in my JSON?
leetcode 53. Maximum Subarray 最大子数组和(中等)
Organize five stages of actual attack and defense drill