工程源码下载: https://download.csdn.net/download/xiaolong1126626497/15805037
1. ESP8266 :采用安信可的模组,型号是ESP12F
2. STM32 : 采用STM32F103C8T6
3. 编程软件 : 采用Keil5
ESP8266编程调试过程中用到的相关软件下载地址:
物联网网调试终端:https://download.csdn.net/download/xiaolong1126626497/12624530
TCP调试助手:https://download.csdn.net/download/xiaolong1126626497/12624461
串口调试助手:https://download.csdn.net/download/xiaolong1126626497/12624450
二、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.255 u8 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"); //查看状态信息 } } }