STM32封装ESP8266一键配置函数:实现AP模式和STA模式切换、服务器与客户端创建

207 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第13天,点击查看活动详情

ESP8266是一款串口WIFI模组,内置了完善的网络协议栈,并且有完善的AT指令集,单片机可以通过串口控制ESP8266完成网络编程,在物联网领域使用非常多。有了这款WIFI,这也降低了的物联网、嵌入式工程师的网络编程难度。这篇文章就详细介绍ESP8266的使用方法,介绍AP模式、STA模式的配置方法,完成TCP服务器、TCP客户端的创建。

一、硬件环境介绍

1. ESP8266 : 采用安信可的模组,型号是ESP12F

img

2. STM32 : 采用STM32F103C8T6

3. 编程软件 : 采用Keil5

ESP8266编程调试过程中用到的相关软件下载地址:

img

img

img

img

二、ESP8266通信的调试与运行效果

下面几张图是将ESP8266配置成AP+TCP服务器模式,电脑连接ESP8266的热点之后,实现数据通信。通信的效果是,在电脑点击物联网控制系统软件,实现控制开发板上的LED灯和蜂鸣器,开发板上将检测的光敏数据、温度数据、RC522刷卡数据传输到电脑的软件上进行显示。----局域网通信

img

img

img

三、硬件接线与代码技术部分介绍

硬件连接: 下面会贴出核心代码,在当前开发板上,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");  //查看状态信息
         }
    }
 }

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); 
         }
    }
 }