基于STM32和ESP8266-01S的智能时钟制作教程(3):ESP8266-01S模块详解

文章目录

  • 前言
  • 一、ESP8266-01S模块
  • 二、ESP8266-01S模块使用方法
  • 1.AT指令
  • 2.代码分析
  • 3.完整代码
  • 总结

  • 前言

    提示:这里可以添加本文要记录的大概内容:之前在忙着,现在继续补充完整,然后这次的ESP-01S的典型应用图是没有连接RST引脚的,但是我的项目是用到了RST引脚的,所以需要使用跳线连接一下RST引脚。

    本项目需要基础的stm32单片机知识,这里我推荐
    链接:https://www.bilibili.com/video/BV1th411z7sn?p=1&vd_source=e9ab6ae9ee7c74bb73c9334f2da0a743
    如果不想看那么多,看到4-2 OLED显示屏就差不多。我使用的是他的OLED基本例程。


    提示:以下是本篇文章正文内容,下面案例可供参考

    一、ESP8266-01S模块

    ESP-01S 是由安信可科技开发的 Wi-Fi 模块,该模块核心处理器 ESP8266 在较小尺寸封装中集成了业界领先的 Tensilica L106 超低功耗 32 位微型 MCU,带有 16 位精简模式,主频支持 80 MHz 和 160 MHz,支持 RTOS,集成 Wi-Fi MAC/ BB/RF/PA/LNA。
    ESP-01S Wi-Fi 模块支持标准的 IEEE802.11 b/g/n 协议,完整的 TCP/IP 协议栈。用户可以使用该模块为现有的设备添加联网功能,也可以构建独立的网络控制器。
    ESP8266 拥有完整的且自成体系的 Wi-Fi 网络功能,既能够独立应用,也可以作为从机搭载于其他主机 MCU 运行。

    这里我截一些规格书和说明书上面一些图给大家参考一下。可以去这个网址找规格书和说明书:https://docs.ai-thinker.com/esp8266/docs

    实物图

    原理图

    我们可以看到ESP8266-01S模块是支持UART通信的,通信的波特率默认为115200bps。一般来说,EN和RST引脚需要外接一个上拉电阻,但是看原理图我们可以发现,ESP-01S内部已经上拉这两个引脚了,不需要我们操心,所以我们按照下面的电路图将ESP-01S连接到STM32上即可。但是我的代码中还使用了RST引脚作为复位引脚,所以还需要连接RST引脚到STM32上。
    RST引脚因为上拉电阻的作用默认高电平,低电平有效,所以我们想要复位一次的话,只需要使用STM32拉低RST引脚,再将它拉高回到默认高电平状态。

    还有使用说明书上有个注意事项,不清楚这是为什么。但是我测试的时候发现如果接到ESP-01S的3.3V和GND不稳定会出现无法通信的情况,并且ESP-01S会发热变得烫手,所以测试的过程请随时注意ESP-01S的状态避免发生意外,注意、注意、注意(一般是刚上电的时候)。解决办法是可以将3.3V和GND重新连接,直到可以通信。或者想办法找个稳定的3.3V和GND

    二、ESP8266-01S模块使用方法

    1.AT指令

    ESP8266 系列模组出厂时已默认内置 AT 固件,且默认波特率为 115200。我们只需要将ESP8266-01S模块通过UART连接到STM32上,然后使用STM32发送AT指令的方式将可以控制ESP8266-01S模块执行各种功能。

    我这里就只介绍我用到的AT指令,其他的你们可以去网上找,也可以去看说明书。网址:https://www.cnblogs.com/milton/p/14718010.html
    还有AT指令需要加回车符和换行符"\r\n".

    1. AT :测试AT开发模式启动
    2. AT+CWMODE=1 :设置WIFI应用模式,1–Station模式,2–AP模式,3–AP兼Station模式。 AP指ESP8266 作为接入点,station指ESP8266 作为客户端
    3. AT+CWJAP=“WIFI名字”,“WIFI密码” :设置 ESP8266 Station 需连接的 AP。
    4. AT+CIPSTART=“TCP”,“59.82.34.102”,80 :ESP8266 设备作为 TCP client 连接到服务器,这里高德地图的远端 IP 地址为59.82.34.102,远端端口号为 80。
    5. AT+CIPMODE=1 :设置透传模式(即可以一直发送。透传模式传输时,如果连接断开,ESP8266 会不停尝试重连,此时单独输⼊ +++【不用加回车换行符】 退出透传,则停⽌重连;普通传输模式则不会重连,提示连接断开。)(一般来说普通传输模式交换一次数据后就会断开TCP连接,如果想要继续通信需要重新进行TCP连接,所以为了方便一直获取天气和时间信息,这里选择透传模式)
    6. AT+CIPSEND : ESP8266 设备向服务器发送数据,在透传模式时,进⼊透传模式发送数据,每包最大 2048 字节,或者每包数据以 20 ms 间隔区分。(进入发送数据模式后,AT指令无效,如需退出发送数据模式,发送 +++【不用加回车换行符】,然后就可以使用AT指令)。

    2.代码分析

    首先是串口外设初始化函数和串口发送功能函数,这里使用重定义print函数的方法实现串口print函数打印,但是实际测试过程发现UsartPrintf()发送大量数据时,会出现数据丢失的情况,(应该是因为UsartPrintfBuf[296]设置的数组长度不够,如果想要发送大量数据可以试着修改一下这个数组长度),所以发送大量字符串数据时可以使用Usart_SendString()函数。然后本项目使用串口1进行调试,所以需要对串口1进行初始化,但是串口1并不进行接收数据操作,所以可以注释掉串口1的接收中断使能和接收中断函数,效果不会改变。项目使用串口2和ESP-01S连接通信,使用串口2发送AT指令和接收ESP-01S返回的数据,为了方便这里将串口2的接收中断函数放到ESP-01S操作文件中。

    /*
    ************************************************************
    *	函数名称:	UsartPrintf
    *
    *	函数功能:	格式化打印
    *
    *	入口参数:	USARTx:串口组
    *				fmt:不定长参
    *
    *	返回参数:	无
    *
    *	说明:		
    ************************************************************
    */
    void UsartPrintf(USART_TypeDef *USARTx, char *fmt,...)
    {
    
    	unsigned char UsartPrintfBuf[296];		/*接收输入变量数组,如果数组不够大,可以修改一下*/
    	va_list ap;
    	unsigned char *pStr = UsartPrintfBuf;
    	
    	va_start(ap, fmt);
    	vsnprintf((char *)UsartPrintfBuf, sizeof(UsartPrintfBuf), fmt, ap);							//格式化
    	va_end(ap);
    	
    	while(*pStr != 0)
    	{
    		USART_SendData(USARTx, *pStr++);
    		while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
    	}
    
    }
    
    /*
    ************************************************************
    *	函数名称:	Usart_SendString
    *
    *	函数功能:	串口数据发送
    *
    *	入口参数:	USARTx:串口组
    *				str:要发送的数据
    *				len:数据长度
    *
    *	返回参数:	无
    *
    *	说明:		
    ************************************************************
    */
    void Usart_SendString(USART_TypeDef *USARTx, unsigned char *str, unsigned short len)
    {
    
    	unsigned short count = 0;
    	
    	for(; count < len; count++)
    	{
    		USART_SendData(USARTx, *str++);									//发送数据
    		while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);		//等待发送完成
    	}
    
    }
    
    

    还有介绍一下USART_FLAG_TXE标志位,USART_FLAG_TXE是数据寄存器空标志位。串口发送数据的方式是数据先从MCU内部的CPU到数据寄存器,再到移位寄存器,然后由移位寄存器发送到TX线上。而使用USART_SendData()函数就是将数据从CPU转移到数据寄存器,这个过程是非常迅速的,而数据从数据寄存器到移位寄存器的过程相对比较缓慢,因为移位寄存器要一位位地发送数据,而数据寄存器需要等移位寄存器变空才能发送数据到移位寄存器,所以为了避免数据从CPU转移到数据寄存器的过程太快而导致数据覆盖产生数据丢失的问题,需要设置一个while循环等USART_FLAG_TXE变为1,即数据寄存器变空。

    经过这个项目,我对于串口中断有不一样的理解。我一开始以为串口接收到一帧数据(指多bit数据)会一直处于接收中断函数中,不会中途跳回主函数中。但经过测试,事实上,串口接收到一帧数据时当然会先进入中断函数接收1bit数据,然而就算后面还有几bit数据没接收完,它还是会跳回主函数执行一小段时间,然后再回到中断函数接收下一bit数据,循环这个过程,直到接收完成。

    所以如果接收不定长数据并且没有特定结束符,我们无法在主函数中直接判断什么时候接收完成。但是有位大佬使用了一个叹为观止的方法实现了判断接收不定长数据的完成。就是程序中的ESP8266_WaitRecive()函数,调用函数时会比较上一次接收到的数据量和这一次接收到的数据量进行比较。如果不相同,证明程序进入了接收中断函数使得接收到的数据量发生了变化,然后将发生变化后的数据量赋值给上一次接收到的数据量。如果相同,证明程序没有再进入中断函数,即已经接收完成。我们只需要循环调用这个函数即可判断这一帧数据是否接收完成。

    #define REV_OK		0	//接收完成标志
    #define REV_WAIT	1	//接收未完成标志
    
    unsigned short esp8266_cnt = 0, esp8266_cntPre = 0;		/*esp8266_cnt为当前接收到的数据数量,esp8266_cntPre为上一次接收到的数据数量*/
    
    //==========================================================
    //	函数名称:	ESP8266_WaitRecive
    //
    //	函数功能:	判断是否接收完成
    //
    //	入口参数:	无
    //
    //	返回参数:	REV_OK-接收完成		REV_WAIT-接收超时未完成
    //
    //	说明:		循环调用检测是否接收完成
    //==========================================================
    _Bool ESP8266_WaitRecive(void)
    {
    
    	if(esp8266_cnt == 0) 							//如果接收计数为0 则说明没有处于接收数据中,所以直接跳出,结束函数
    		return REV_WAIT;
    		
    	if(esp8266_cnt == esp8266_cntPre)				//如果上一次的值和这次相同,则说明接收完毕
    	{
    //		esp8266_cnt = 0;							//清0接收计数,注释掉是为了接收几帧数据
    		
    		return REV_OK;								//返回接收完成标志
    	}
    		
    	esp8266_cntPre = esp8266_cnt;					//置为相同
    	
    	return REV_WAIT;								//返回接收未完成标志
    
    }
    

    ESP8266_SendCmd()函数就使用到了上面提到的判断一帧数据的方法。这个函数是用来发送AT指令给ESP8266的,并且通过串口1返回ESP8266的响应数据,通过这个数据即可判断和调试ESP8266是否正确执行指令。

    串口1的返回如下:

    ESP8266的实际返回如下:

    其实ESP8266实际返回的数据中有几个数据返回是几帧数据返回的,如图中的

    [15:51:47.291]收←◆AT+CWJAP=“DSKrurudo”,“12359680” WIFI DISCONNECT

    [15:51:47.510]收←◆WIFI CONNECTED

    [15:51:48.525]收←◆WIFI GOT IP
    OK

    这是连接wifi完成后返回的几帧数据,而ESP8266_SendCmd()函数里面通过ESP8266_WaitRecive()判断一帧数据接收完后,继续通过判断响应数据中的"OK"判断响应数据包是否接收完,即接收几帧的数据包,就可以将响应数据包接收完整,然后通过串口1打印出来。

    //==========================================================
    //	函数名称:	ESP8266_SendCmd
    //
    //	函数功能:	发送命令
    //
    //	入口参数:	cmd:命令
    //				res:需要检查的返回指令
    //
    //	返回参数:	0-成功	1-失败
    //
    //	说明:		
    //==========================================================
    _Bool ESP8266_SendCmd(char *cmd, char *res)
    {
    	
    	unsigned char timeOut = 200;
    
    	Usart_SendString(USART2, (unsigned char *)cmd, strlen((const char *)cmd));
    	
    	while(timeOut--)
    	{
    		if(ESP8266_WaitRecive() == REV_OK)							//如果收到1帧数据
    		{
    			if(strstr((const char *)esp8266_buf, res) != NULL)		//如果检索到关键词
    			{
    				UsartPrintf(USART_DEBUG, "%s", esp8266_buf);		//通过调试串口将接收到的返回指令显示出来以便判断
    				ESP8266_Clear();									//清空缓存
    				
    				return 0;		//数据包接收完成跳出循环
    			}
    		}
    		Delay_ms(10);		//通过延时循环等待数据包接收完成
    	}
    	
    	return 1;
    }
    

    3.完整代码

    usart.h

    #ifndef _USART_H_
    #define _USART_H_
    
    
    #include "stm32f10x.h"
    
    
    #define USART_DEBUG		USART1		//调试打印所使用的串口组
    
    
    void Usart1_Init(unsigned int baud);
    
    void Usart2_Init(unsigned int baud);
    
    void Usart_SendString(USART_TypeDef *USARTx, unsigned char *str, unsigned short len);
    
    void UsartPrintf(USART_TypeDef *USARTx, char *fmt,...);
    
    #endif
    
    

    usart.c

    //硬件驱动
    #include "usart.h"
    #include "delay.h"
    
    //C库
    #include <stdarg.h>
    #include <string.h>
    #include <stdio.h>
    
    
    /*
    ************************************************************
    *	函数名称:	Usart1_Init
    *
    *	函数功能:	串口1初始化
    *
    *	入口参数:	baud:设定的波特率
    *
    *	返回参数:	无
    *
    *	说明:		TX-PA9		RX-PA10
    ************************************************************
    */
    void Usart1_Init(unsigned int baud)
    {
    
    	GPIO_InitTypeDef gpioInitStruct;
    	USART_InitTypeDef usartInitStruct;
    //	NVIC_InitTypeDef nvicInitStruct;
    	
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    	
    	//PA9	TXD
    	gpioInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    	gpioInitStruct.GPIO_Pin = GPIO_Pin_9;
    	gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &gpioInitStruct);
    	
    	//PA10	RXD
    	gpioInitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    	gpioInitStruct.GPIO_Pin = GPIO_Pin_10;
    	gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &gpioInitStruct);
    	
    	usartInitStruct.USART_BaudRate = baud;
    	usartInitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;		//无硬件流控
    	usartInitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;						//接收和发送
    	usartInitStruct.USART_Parity = USART_Parity_No;									//无校验
    	usartInitStruct.USART_StopBits = USART_StopBits_1;								//1位停止位
    	usartInitStruct.USART_WordLength = USART_WordLength_8b;							//8位数据位
    	USART_Init(USART1, &usartInitStruct);
    	
    	USART_Cmd(USART1, ENABLE);														//使能串口
    	
    //	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);									//使能接收中断
    //	
    //	nvicInitStruct.NVIC_IRQChannel = USART1_IRQn;
    //	nvicInitStruct.NVIC_IRQChannelCmd = ENABLE;
    //	nvicInitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    //	nvicInitStruct.NVIC_IRQChannelSubPriority = 2;
    //	NVIC_Init(&nvicInitStruct);
    
    }
    
    /*
    ************************************************************
    *	函数名称:	Usart2_Init
    *
    *	函数功能:	串口2初始化
    *
    *	入口参数:	baud:设定的波特率
    *
    *	返回参数:	无
    *
    *	说明:		TX-PA2		RX-PA3
    ************************************************************
    */
    void Usart2_Init(unsigned int baud)
    {
    
    	GPIO_InitTypeDef gpioInitStruct;
    	USART_InitTypeDef usartInitStruct;
    	NVIC_InitTypeDef nvicInitStruct;
    	
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    	
    	//PA2	TXD
    	gpioInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    	gpioInitStruct.GPIO_Pin = GPIO_Pin_2;
    	gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &gpioInitStruct);
    	
    	//PA3	RXD
    	gpioInitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    	gpioInitStruct.GPIO_Pin = GPIO_Pin_3;
    	gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &gpioInitStruct);
    	
    	usartInitStruct.USART_BaudRate = baud;
    	usartInitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;		//无硬件流控
    	usartInitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;						//接收和发送
    	usartInitStruct.USART_Parity = USART_Parity_No;									//无校验
    	usartInitStruct.USART_StopBits = USART_StopBits_1;								//1位停止位
    	usartInitStruct.USART_WordLength = USART_WordLength_8b;							//8位数据位
    	USART_Init(USART2, &usartInitStruct);
    	
    	USART_Cmd(USART2, ENABLE);														//使能串口
    	
    	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);									//使能接收中断
    	
    	nvicInitStruct.NVIC_IRQChannel = USART2_IRQn;
    	nvicInitStruct.NVIC_IRQChannelCmd = ENABLE;
    	nvicInitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    	nvicInitStruct.NVIC_IRQChannelSubPriority = 0;
    	NVIC_Init(&nvicInitStruct);
    
    }
    
    /*
    ************************************************************
    *	函数名称:	Usart_SendString
    *
    *	函数功能:	串口数据发送
    *
    *	入口参数:	USARTx:串口组
    *				str:要发送的数据
    *				len:数据长度
    *
    *	返回参数:	无
    *
    *	说明:		
    ************************************************************
    */
    void Usart_SendString(USART_TypeDef *USARTx, unsigned char *str, unsigned short len)
    {
    
    	unsigned short count = 0;
    	
    	for(; count < len; count++)
    	{
    		USART_SendData(USARTx, *str++);									//发送数据
    		while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);		//等待发送完成
    	}
    
    }
    
    /*
    ************************************************************
    *	函数名称:	UsartPrintf
    *
    *	函数功能:	格式化打印
    *
    *	入口参数:	USARTx:串口组
    *				fmt:不定长参
    *
    *	返回参数:	无
    *
    *	说明:		
    ************************************************************
    */
    void UsartPrintf(USART_TypeDef *USARTx, char *fmt,...)
    {
    
    	unsigned char UsartPrintfBuf[296];		/*接收输入变量数组,如果数组不够大,可以修改一下*/
    	va_list ap;
    	unsigned char *pStr = UsartPrintfBuf;
    	
    	va_start(ap, fmt);
    	vsnprintf((char *)UsartPrintfBuf, sizeof(UsartPrintfBuf), fmt, ap);							//格式化
    	va_end(ap);
    	
    	while(*pStr != 0)
    	{
    		USART_SendData(USARTx, *pStr++);
    		while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
    	}
    
    }
    
    ///*
    //************************************************************
    //*	函数名称:	USART1_IRQHandler
    //*
    //*	函数功能:	串口1收发中断
    //*
    //*	入口参数:	无
    //*
    //*	返回参数:	无
    //*
    //*	说明:		
    //************************************************************
    //*/
    //void USART1_IRQHandler(void)
    //{
    
    //	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
    //	{
    //		USART_ClearFlag(USART1, USART_FLAG_RXNE);
    //	}
    
    //}
    

    esp8266.h

    #ifndef _ESP8266_H_
    #define _ESP8266_H_
    
    
    
    
    
    #define REV_OK		0	//接收完成标志
    #define REV_WAIT	1	//接收未完成标志
    
    
    void ESP8266_Init(void);
    
    void ESP8266_Clear(void);
    
    void ESP8266_SendData(unsigned char *data, unsigned short len);
    
    unsigned char *ESP8266_GetIPD(unsigned short timeOut);
    _Bool ESP8266_SendCmd(char *cmd, char *res);
    _Bool ESP8266_WaitRecive(void);
    
    
    #endif
    
    

    esp8266.c

    //单片机头文件
    #include "stm32f10x.h"
    
    //网络设备驱动
    #include "esp8266.h"
    
    //硬件驱动
    #include "Delay.h"
    #include "usart.h"
    
    //C库
    #include <string.h>
    #include <stdio.h>
    
    
    
    #define ESP8266_WIFI_INFO		"AT+CWJAP=\"DSKrurudo\",\"12359680\"\r\n"			/*连接wifi的AT指令*/
    
    //#define ESP8266_ONENET_INFO		"AT+CIPSTART=\"TCP\",\"broker.emqx.io\",1883\r\n"
    
    #define ESP8266_TIANQI_INFO		"AT+CIPSTART=\"TCP\",\"59.82.34.102\",80\r\n"		/*连接高德地图TCP的AT指令*/
    
    unsigned char esp8266_buf[360];			/*接收ESP-01s的返回数据数组*/
    unsigned short esp8266_cnt = 0, esp8266_cntPre = 0;		/*esp8266_cnt为当前接收到的数据数量,esp8266_cntPre为上一次接收到的数据数量*/
    
    //unsigned char send_data[]="GET\r\n";
    
    //==========================================================
    //	函数名称:	ESP8266_Clear
    //
    //	函数功能:	清空缓存
    //
    //	入口参数:	无
    //
    //	返回参数:	无
    //
    //	说明:		
    //==========================================================
    void ESP8266_Clear(void)
    {
    
    	memset(esp8266_buf, 0, sizeof(esp8266_buf));
    	esp8266_cnt = 0;
    
    }
    
    //==========================================================
    //	函数名称:	ESP8266_WaitRecive
    //
    //	函数功能:	判断是否接收完成
    //
    //	入口参数:	无
    //
    //	返回参数:	REV_OK-接收完成		REV_WAIT-接收超时未完成
    //
    //	说明:		循环调用检测是否接收完成
    //==========================================================
    _Bool ESP8266_WaitRecive(void)
    {
    
    	if(esp8266_cnt == 0) 							//如果接收计数为0 则说明没有处于接收数据中,所以直接跳出,结束函数
    		return REV_WAIT;
    		
    	if(esp8266_cnt == esp8266_cntPre)				//如果上一次的值和这次相同,则说明接收完毕
    	{
    //		esp8266_cnt = 0;							//清0接收计数,注释掉是为了接收几帧数据
    		
    		return REV_OK;								//返回接收完成标志
    	}
    		
    	esp8266_cntPre = esp8266_cnt;					//置为相同
    	
    	return REV_WAIT;								//返回接收未完成标志
    
    }
    
    //==========================================================
    //	函数名称:	ESP8266_SendCmd
    //
    //	函数功能:	发送命令
    //
    //	入口参数:	cmd:命令
    //				res:需要检查的返回指令
    //
    //	返回参数:	0-成功	1-失败
    //
    //	说明:		
    //==========================================================
    _Bool ESP8266_SendCmd(char *cmd, char *res)
    {
    	
    	unsigned char timeOut = 200;
    
    	Usart_SendString(USART2, (unsigned char *)cmd, strlen((const char *)cmd));
    	
    	while(timeOut--)
    	{
    		
    		if(ESP8266_WaitRecive() == REV_OK)							//如果收到数据
    		{
    			if(strstr((const char *)esp8266_buf, res) != NULL)		//如果检索到关键词
    			{
    				UsartPrintf(USART_DEBUG, "%s", esp8266_buf);		//通过调试串口将接收到的返回指令显示出来以便判断
    				ESP8266_Clear();									//清空缓存
    				
    				return 0;
    			}
    			
    		}
    		
    		Delay_ms(10);
    		
    	}
    	
    	return 1;
    
    }
    
    //==========================================================
    //	函数名称:	ESP8266_SendData
    //
    //	函数功能:	发送数据
    //
    //	入口参数:	data:数据
    //				len:长度
    //
    //	返回参数:	无
    //
    //	说明:		
    //==========================================================
    void ESP8266_SendData(unsigned char *data, unsigned short len)
    {
    
    	char cmdBuf[32];
    	
    	ESP8266_Clear();								//清空接收缓存
    	sprintf(cmdBuf, "AT+CIPSEND=%d\r\n", len);		//发送命令
    	if(!ESP8266_SendCmd(cmdBuf, ">"))				//收到‘>’时可以发送数据
    	{
    		UsartPrintf(USART_DEBUG, "you are real");
    		Usart_SendString(USART2, data, len);		//发送设备连接请求数据
    	}
    
    }
    
    //==========================================================
    //	函数名称:	ESP8266_GetIPD
    //
    //	函数功能:	获取平台返回的数据
    //
    //	入口参数:	等待的时间(乘以10ms)
    //
    //	返回参数:	平台返回的原始数据
    //
    //	说明:		不同网络设备返回的格式不同,需要去调试
    //				如ESP8266的返回格式为	"+IPD,x:yyy"	x代表数据长度,yyy是数据内容
    //==========================================================
    unsigned char *ESP8266_GetIPD(unsigned short timeOut)
    {
    
    	char *ptrIPD = NULL;
    	
    	do
    	{
    		if(ESP8266_WaitRecive() == REV_OK)								//如果接收完成
    		{
    			ptrIPD = strstr((char *)esp8266_buf, "IPD,");				//搜索“IPD”头
    			if(ptrIPD == NULL)											//如果没找到,可能是IPD头的延迟,还是需要等待一会,但不会超过设定的时间
    			{
    				UsartPrintf(USART_DEBUG, "\"IPD\" not found\r\n");
    			}
    			else
    			{
    				ptrIPD = strchr(ptrIPD, ':');							//找到':'
    				if(ptrIPD != NULL)
    				{
    					ptrIPD++;
    					return (unsigned char *)(ptrIPD);
    				}
    				else
    					return NULL;
    				
    			}
    		}
    		
    		Delay_ms(5);													//延时等待
    	} while(timeOut--);
    	
    	return NULL;														//超时还未找到,返回空指针
    
    }
    
    //==========================================================
    //	函数名称:	ESP8266_Init
    //
    //	函数功能:	初始化ESP8266
    //
    //	入口参数:	无
    //
    //	返回参数:	无
    //
    //	说明:		
    //==========================================================
    void ESP8266_Init(void)
    {
    	
    	GPIO_InitTypeDef GPIO_Initure;
    	
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    
    	//ESP8266复位引脚
    	GPIO_Initure.GPIO_Mode = GPIO_Mode_Out_OD;
    	GPIO_Initure.GPIO_Pin = GPIO_Pin_14;					//GPIOC14-复位
    	GPIO_Initure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOC, &GPIO_Initure);
    	
    	GPIO_WriteBit(GPIOC, GPIO_Pin_14, Bit_RESET);		//拉低GPIOC14使能RST引脚
    	Delay_ms(500);
    	GPIO_WriteBit(GPIOC, GPIO_Pin_14, Bit_SET);			//拉高GPIOC14回到默认状态
    	Delay_ms(500);
    	
    	ESP8266_Clear();		//清空上一次的接收缓存
    	Delay_ms(500);
    	
    	UsartPrintf(USART_DEBUG, "0. AT\r\n");
    	ESP8266_SendCmd(" AT\r\n", "OK");		//测试AT
    	Delay_ms(500);
    	
    //	UsartPrintf(USART_DEBUG, "1. RST0\r\n");
    //	ESP8266_SendCmd("AT+RST\r\n", "OK");
    //	UsartPrintf(USART_DEBUG, "1. RST1\r\n");
    //		Delay_ms(500);
    //	ESP8266_SendCmd("AT+CIPCLOSE\r\n", "OK");
    //	UsartPrintf(USART_DEBUG, "1. RST2\r\n");
    //		Delay_ms(500);
    	
    	UsartPrintf(USART_DEBUG, "1. CWMODE\r\n");
    	ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK");		//设置ESP8266作为客户端
    	Delay_ms(500);
    	
    //	UsartPrintf(USART_DEBUG, "3. AT+CWDHCP\r\n");
    //	ESP8266_SendCmd("AT+CWDHCP=1,1\r\n", "OK");
    //		Delay_ms(500);
    //		Delay_ms(500);
    	
    	UsartPrintf(USART_DEBUG, "2. CWJAP\r\n");
    	ESP8266_SendCmd(ESP8266_WIFI_INFO, "OK");		//连接wifi
    	Delay_ms(500);
    	
    //	UsartPrintf(USART_DEBUG, "5. CIPSTART\r\n");
    //	while(ESP8266_SendCmd(ESP8266_ONENET_INFO, "CONNECT"))
    //		Delay_ms(500);
    	
    	UsartPrintf(USART_DEBUG, "3. CIPSTART\r\n");
    	ESP8266_SendCmd(ESP8266_TIANQI_INFO, "OK");		//连接到服务器
    	Delay_ms(500);
    	
    	UsartPrintf(USART_DEBUG, "4. AT+CIPMODE=1\r\n");
    	ESP8266_SendCmd("AT+CIPMODE=1\r\n", "OK");		//设置透传模式
    	Delay_ms(500);
    	
    	UsartPrintf(USART_DEBUG, "5. AT+CIPSEND\r\n");
    	ESP8266_SendCmd("AT+CIPSEND\r\n", ">");		//开启数据传输模式
    	Delay_ms(500);
    
    //	UsartPrintf(USART_DEBUG, "6.AT+CIPSEND=5\r\n");
    //	ESP8266_SendCmd("AT+CIPSEND=6\r\n", ">");
    //		Delay_ms(500);
    	
    //	UsartPrintf(USART_DEBUG, "8. GET\r\n");
    //	ESP8266_SendData(send_data, 6);
    
    	
    //	if(ESP8266_GetIPD(0) != NULL)
    //	{
    //		UsartPrintf(USART_DEBUG, "noNULL\r\n");
    //	}
    
    }
    
    //==========================================================
    //	函数名称:	USART2_IRQHandler
    
    //	函数功能:	串口2收发中断
    
    //	入口参数:	无
    
    //	返回参数:	无
    
    //	说明:		
    //==========================================================
    void USART2_IRQHandler(void)
    {
    
    	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //串口2接收中断
    	{
    		if(esp8266_cnt >= sizeof(esp8266_buf))	esp8266_cnt = 0; //防止串口被刷爆,如果接收超过了接收数组的容量,从第一位开始覆盖接收数组
    		esp8266_buf[esp8266_cnt++] = USART_ReceiveData(USART2);		//将接收到的数据放到接收数组里
    		USART_ClearFlag(USART2, USART_FLAG_RXNE);			//清除中断标志位
    	}
    
    }
    

    总结

    这次介绍了一下ESP8266的使用方法和注意事项,还有我对串口中断的了解。因为太长了,所以获取和处理天气、时间信息就放在下一文章中。

    物联沃分享整理
    物联沃-IOTWORD物联网 » 基于STM32和ESP8266-01S的智能时钟制作教程(3):ESP8266-01S模块详解

    发表评论