前言
提示:這里可以添加本文要記錄的大概內(nèi)容:之前在忙著,現(xiàn)在繼續(xù)補(bǔ)充完整,然后這次的ESP-01S的典型應(yīng)用圖是沒有連接RST引腳的,但是我的項(xiàng)目是用到了RST引腳的,所以需要使用跳線連接一下RST引腳。
本項(xiàng)目需要基礎(chǔ)的stm32單片機(jī)知識(shí),這里我推薦
鏈接:https://www.bilibili.com/video/BV1th411z7sn?p=1&vd_source=e9ab6ae9ee7c74bb73c9334f2da0a743
如果不想看那么多,看到4-2 OLED顯示屏就差不多。我使用的是他的OLED基本例程。
提示:以下是本篇文章正文內(nèi)容,下面案例可供參考
一、ESP8266-01S模塊
ESP-01S 是由安信可科技開發(fā)的 Wi-Fi 模塊,該模塊核心處理器 ESP8266 在較小尺寸封裝中集成了業(yè)界領(lǐng)先的 Tensilica L106 超低功耗 32 位微型 MCU,帶有 16 位精簡(jiǎn)模式,主頻支持 80 MHz 和 160 MHz,支持 RTOS,集成 Wi-Fi MAC/ BB/RF/PA/LNA。
ESP-01S Wi-Fi 模塊支持標(biāo)準(zhǔn)的 IEEE802.11 b/g/n 協(xié)議,完整的 TCP/IP 協(xié)議棧。用戶可以使用該模塊為現(xiàn)有的設(shè)備添加聯(lián)網(wǎng)功能,也可以構(gòu)建獨(dú)立的網(wǎng)絡(luò)控制器。
ESP8266 擁有完整的且自成體系的 Wi-Fi 網(wǎng)絡(luò)功能,既能夠獨(dú)立應(yīng)用,也可以作為從機(jī)搭載于其他主機(jī) MCU 運(yùn)行。
這里我截一些規(guī)格書和說明書上面一些圖給大家參考一下。可以去這個(gè)網(wǎng)址找規(guī)格書和說明書:https://docs.ai-thinker.com/esp8266/docs
我們可以看到ESP8266-01S模塊是支持UART通信的,通信的波特率默認(rèn)為115200bps。一般來說,EN和RST引腳需要外接一個(gè)上拉電阻,但是看原理圖我們可以發(fā)現(xiàn),ESP-01S內(nèi)部已經(jīng)上拉這兩個(gè)引腳了,不需要我們操心,所以我們按照下面的電路圖將ESP-01S連接到STM32上即可。但是我的代碼中還使用了RST引腳作為復(fù)位引腳,所以還需要連接RST引腳到STM32上。
RST引腳因?yàn)樯侠娮璧淖饔媚J(rèn)高電平,低電平有效,所以我們想要復(fù)位一次的話,只需要使用STM32拉低RST引腳,再將它拉高回到默認(rèn)高電平狀態(tài)。
還有使用說明書上有個(gè)注意事項(xiàng),不清楚這是為什么。但是我測(cè)試的時(shí)候發(fā)現(xiàn)如果接到ESP-01S的3.3V和GND不穩(wěn)定會(huì)出現(xiàn)無法通信的情況,并且ESP-01S會(huì)發(fā)熱變得燙手,所以測(cè)試的過程請(qǐng)隨時(shí)注意ESP-01S的狀態(tài)避免發(fā)生意外,注意、注意、注意(一般是剛上電的時(shí)候)。解決辦法是可以將3.3V和GND重新連接,直到可以通信?;蛘呦朕k法找個(gè)穩(wěn)定的3.3V和GND
二、ESP8266-01S模塊使用方法
1.AT指令
ESP8266 系列模組出廠時(shí)已默認(rèn)內(nèi)置 AT 固件,且默認(rèn)波特率為 115200。我們只需要將ESP8266-01S模塊通過UART連接到STM32上,然后使用STM32發(fā)送AT指令的方式將可以控制ESP8266-01S模塊執(zhí)行各種功能。
我這里就只介紹我用到的AT指令,其他的你們可以去網(wǎng)上找,也可以去看說明書。網(wǎng)址:https://www.cnblogs.com/milton/p/14718010.html
還有AT指令需要加回車符和換行符"\r\n".
- AT :測(cè)試AT開發(fā)模式啟動(dòng)
- AT+CWMODE=1 :設(shè)置WIFI應(yīng)用模式,1–Station模式,2–AP模式,3–AP兼Station模式。 AP指ESP8266 作為接入點(diǎn),station指ESP8266 作為客戶端
- AT+CWJAP=“WIFI名字”,“WIFI密碼” :設(shè)置 ESP8266 Station 需連接的 AP。
- AT+CIPSTART=“TCP”,“59.82.34.102”,80 :ESP8266 設(shè)備作為 TCP client 連接到服務(wù)器,這里高德地圖的遠(yuǎn)端 IP 地址為59.82.34.102,遠(yuǎn)端端口號(hào)為 80。
- AT+CIPMODE=1 :設(shè)置透?jìng)髂J剑纯梢砸恢卑l(fā)送。透?jìng)髂J絺鬏敃r(shí),如果連接斷開,ESP8266 會(huì)不停嘗試重連,此時(shí)單獨(dú)輸? +++【不用加回車換行符】 退出透?jìng)?,則停?重連;普通傳輸模式則不會(huì)重連,提示連接斷開。)(一般來說普通傳輸模式交換一次數(shù)據(jù)后就會(huì)斷開TCP連接,如果想要繼續(xù)通信需要重新進(jìn)行TCP連接,所以為了方便一直獲取天氣和時(shí)間信息,這里選擇透?jìng)髂J剑?/li>
- AT+CIPSEND : ESP8266 設(shè)備向服務(wù)器發(fā)送數(shù)據(jù),在透?jìng)髂J綍r(shí),進(jìn)?透?jìng)髂J桨l(fā)送數(shù)據(jù),每包最大 2048 字節(jié),或者每包數(shù)據(jù)以 20 ms 間隔區(qū)分。(進(jìn)入發(fā)送數(shù)據(jù)模式后,AT指令無效,如需退出發(fā)送數(shù)據(jù)模式,發(fā)送 +++【不用加回車換行符】,然后就可以使用AT指令)。
2.代碼分析
首先是串口外設(shè)初始化函數(shù)和串口發(fā)送功能函數(shù),這里使用重定義print函數(shù)的方法實(shí)現(xiàn)串口print函數(shù)打印,但是實(shí)際測(cè)試過程發(fā)現(xiàn)UsartPrintf()發(fā)送大量數(shù)據(jù)時(shí),會(huì)出現(xiàn)數(shù)據(jù)丟失的情況,(應(yīng)該是因?yàn)閁sartPrintfBuf[296]設(shè)置的數(shù)組長度不夠,如果想要發(fā)送大量數(shù)據(jù)可以試著修改一下這個(gè)數(shù)組長度),所以發(fā)送大量字符串?dāng)?shù)據(jù)時(shí)可以使用Usart_SendString()函數(shù)。然后本項(xiàng)目使用串口1進(jìn)行調(diào)試,所以需要對(duì)串口1進(jìn)行初始化,但是串口1并不進(jìn)行接收數(shù)據(jù)操作,所以可以注釋掉串口1的接收中斷使能和接收中斷函數(shù),效果不會(huì)改變。項(xiàng)目使用串口2和ESP-01S連接通信,使用串口2發(fā)送AT指令和接收ESP-01S返回的數(shù)據(jù),為了方便這里將串口2的接收中斷函數(shù)放到ESP-01S操作文件中。
/*
************************************************************
* 函數(shù)名稱: UsartPrintf
*
* 函數(shù)功能: 格式化打印
*
* 入口參數(shù): USARTx:串口組
* fmt:不定長參
*
* 返回參數(shù): 無
*
* 說明:
************************************************************
*/
void UsartPrintf(USART_TypeDef *USARTx, char *fmt,...)
{
unsigned char UsartPrintfBuf[296]; /*接收輸入變量數(shù)組,如果數(shù)組不夠大,可以修改一下*/
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);
}
}
/*
************************************************************
* 函數(shù)名稱: Usart_SendString
*
* 函數(shù)功能: 串口數(shù)據(jù)發(fā)送
*
* 入口參數(shù): USARTx:串口組
* str:要發(fā)送的數(shù)據(jù)
* len:數(shù)據(jù)長度
*
* 返回參數(shù): 無
*
* 說明:
************************************************************
*/
void Usart_SendString(USART_TypeDef *USARTx, unsigned char *str, unsigned short len)
{
unsigned short count = 0;
for(; count < len; count++)
{
USART_SendData(USARTx, *str++); //發(fā)送數(shù)據(jù)
while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET); //等待發(fā)送完成
}
}
還有介紹一下USART_FLAG_TXE標(biāo)志位,USART_FLAG_TXE是數(shù)據(jù)寄存器空標(biāo)志位。串口發(fā)送數(shù)據(jù)的方式是數(shù)據(jù)先從MCU內(nèi)部的CPU到數(shù)據(jù)寄存器,再到移位寄存器,然后由移位寄存器發(fā)送到TX線上。而使用USART_SendData()函數(shù)就是將數(shù)據(jù)從CPU轉(zhuǎn)移到數(shù)據(jù)寄存器,這個(gè)過程是非常迅速的,而數(shù)據(jù)從數(shù)據(jù)寄存器到移位寄存器的過程相對(duì)比較緩慢,因?yàn)橐莆患拇嫫饕晃晃坏匕l(fā)送數(shù)據(jù),而數(shù)據(jù)寄存器需要等移位寄存器變空才能發(fā)送數(shù)據(jù)到移位寄存器,所以為了避免數(shù)據(jù)從CPU轉(zhuǎn)移到數(shù)據(jù)寄存器的過程太快而導(dǎo)致數(shù)據(jù)覆蓋產(chǎn)生數(shù)據(jù)丟失的問題,需要設(shè)置一個(gè)while循環(huán)等USART_FLAG_TXE變?yōu)?,即數(shù)據(jù)寄存器變空。
經(jīng)過這個(gè)項(xiàng)目,我對(duì)于串口中斷有不一樣的理解。我一開始以為串口接收到一幀數(shù)據(jù)(指多bit數(shù)據(jù))會(huì)一直處于接收中斷函數(shù)中,不會(huì)中途跳回主函數(shù)中。但經(jīng)過測(cè)試,事實(shí)上,串口接收到一幀數(shù)據(jù)時(shí)當(dāng)然會(huì)先進(jìn)入中斷函數(shù)接收1bit數(shù)據(jù),然而就算后面還有幾bit數(shù)據(jù)沒接收完,它還是會(huì)跳回主函數(shù)執(zhí)行一小段時(shí)間,然后再回到中斷函數(shù)接收下一bit數(shù)據(jù),循環(huán)這個(gè)過程,直到接收完成。
所以如果接收不定長數(shù)據(jù)并且沒有特定結(jié)束符,我們無法在主函數(shù)中直接判斷什么時(shí)候接收完成。但是有位大佬使用了一個(gè)嘆為觀止的方法實(shí)現(xiàn)了判斷接收不定長數(shù)據(jù)的完成。就是程序中的ESP8266_WaitRecive()函數(shù),調(diào)用函數(shù)時(shí)會(huì)比較上一次接收到的數(shù)據(jù)量和這一次接收到的數(shù)據(jù)量進(jìn)行比較。如果不相同,證明程序進(jìn)入了接收中斷函數(shù)使得接收到的數(shù)據(jù)量發(fā)生了變化,然后將發(fā)生變化后的數(shù)據(jù)量賦值給上一次接收到的數(shù)據(jù)量。如果相同,證明程序沒有再進(jìn)入中斷函數(shù),即已經(jīng)接收完成。我們只需要循環(huán)調(diào)用這個(gè)函數(shù)即可判斷這一幀數(shù)據(jù)是否接收完成。
#define REV_OK 0 //接收完成標(biāo)志
#define REV_WAIT 1 //接收未完成標(biāo)志
unsigned short esp8266_cnt = 0, esp8266_cntPre = 0; /*esp8266_cnt為當(dāng)前接收到的數(shù)據(jù)數(shù)量,esp8266_cntPre為上一次接收到的數(shù)據(jù)數(shù)量*/
//==========================================================
// 函數(shù)名稱: ESP8266_WaitRecive
//
// 函數(shù)功能: 判斷是否接收完成
//
// 入口參數(shù): 無
//
// 返回參數(shù): REV_OK-接收完成 REV_WAIT-接收超時(shí)未完成
//
// 說明: 循環(huán)調(diào)用檢測(cè)是否接收完成
//==========================================================
_Bool ESP8266_WaitRecive(void)
{
if(esp8266_cnt == 0) //如果接收計(jì)數(shù)為0 則說明沒有處于接收數(shù)據(jù)中,所以直接跳出,結(jié)束函數(shù)
return REV_WAIT;
if(esp8266_cnt == esp8266_cntPre) //如果上一次的值和這次相同,則說明接收完畢
{
// esp8266_cnt = 0; //清0接收計(jì)數(shù),注釋掉是為了接收幾幀數(shù)據(jù)
return REV_OK; //返回接收完成標(biāo)志
}
esp8266_cntPre = esp8266_cnt; //置為相同
return REV_WAIT; //返回接收未完成標(biāo)志
}
ESP8266_SendCmd()函數(shù)就使用到了上面提到的判斷一幀數(shù)據(jù)的方法。這個(gè)函數(shù)是用來發(fā)送AT指令給ESP8266的,并且通過串口1返回ESP8266的響應(yīng)數(shù)據(jù),通過這個(gè)數(shù)據(jù)即可判斷和調(diào)試ESP8266是否正確執(zhí)行指令。
串口1的返回如下:
ESP8266的實(shí)際返回如下:
其實(shí)ESP8266實(shí)際返回的數(shù)據(jù)中有幾個(gè)數(shù)據(jù)返回是幾幀數(shù)據(jù)返回的,如圖中的
[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完成后返回的幾幀數(shù)據(jù),而ESP8266_SendCmd()函數(shù)里面通過ESP8266_WaitRecive()判斷一幀數(shù)據(jù)接收完后,繼續(xù)通過判斷響應(yīng)數(shù)據(jù)中的"OK"判斷響應(yīng)數(shù)據(jù)包是否接收完,即接收幾幀的數(shù)據(jù)包,就可以將響應(yīng)數(shù)據(jù)包接收完整,然后通過串口1打印出來。
//==========================================================
// 函數(shù)名稱: ESP8266_SendCmd
//
// 函數(shù)功能: 發(fā)送命令
//
// 入口參數(shù): cmd:命令
// res:需要檢查的返回指令
//
// 返回參數(shù): 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幀數(shù)據(jù)
{
if(strstr((const char *)esp8266_buf, res) != NULL) //如果檢索到關(guān)鍵詞
{
UsartPrintf(USART_DEBUG, "%s", esp8266_buf); //通過調(diào)試串口將接收到的返回指令顯示出來以便判斷
ESP8266_Clear(); //清空緩存
return 0; //數(shù)據(jù)包接收完成跳出循環(huán)
}
}
Delay_ms(10); //通過延時(shí)循環(huán)等待數(shù)據(jù)包接收完成
}
return 1;
}
3.完整代碼
usart.h
#ifndef _USART_H_
#define _USART_H_
#include "stm32f10x.h"
#define USART_DEBUG USART1 //調(diào)試打印所使用的串口組
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
//硬件驅(qū)動(dòng)
#include "usart.h"
#include "delay.h"
//C庫
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
/*
************************************************************
* 函數(shù)名稱: Usart1_Init
*
* 函數(shù)功能: 串口1初始化
*
* 入口參數(shù): baud:設(shè)定的波特率
*
* 返回參數(shù): 無
*
* 說明: 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; //接收和發(fā)送
usartInitStruct.USART_Parity = USART_Parity_No; //無校驗(yàn)
usartInitStruct.USART_StopBits = USART_StopBits_1; //1位停止位
usartInitStruct.USART_WordLength = USART_WordLength_8b; //8位數(shù)據(jù)位
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);
}
/*
************************************************************
* 函數(shù)名稱: Usart2_Init
*
* 函數(shù)功能: 串口2初始化
*
* 入口參數(shù): baud:設(shè)定的波特率
*
* 返回參數(shù): 無
*
* 說明: 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; //接收和發(fā)送
usartInitStruct.USART_Parity = USART_Parity_No; //無校驗(yàn)
usartInitStruct.USART_StopBits = USART_StopBits_1; //1位停止位
usartInitStruct.USART_WordLength = USART_WordLength_8b; //8位數(shù)據(jù)位
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);
}
/*
************************************************************
* 函數(shù)名稱: Usart_SendString
*
* 函數(shù)功能: 串口數(shù)據(jù)發(fā)送
*
* 入口參數(shù): USARTx:串口組
* str:要發(fā)送的數(shù)據(jù)
* len:數(shù)據(jù)長度
*
* 返回參數(shù): 無
*
* 說明:
************************************************************
*/
void Usart_SendString(USART_TypeDef *USARTx, unsigned char *str, unsigned short len)
{
unsigned short count = 0;
for(; count < len; count++)
{
USART_SendData(USARTx, *str++); //發(fā)送數(shù)據(jù)
while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET); //等待發(fā)送完成
}
}
/*
************************************************************
* 函數(shù)名稱: UsartPrintf
*
* 函數(shù)功能: 格式化打印
*
* 入口參數(shù): USARTx:串口組
* fmt:不定長參
*
* 返回參數(shù): 無
*
* 說明:
************************************************************
*/
void UsartPrintf(USART_TypeDef *USARTx, char *fmt,...)
{
unsigned char UsartPrintfBuf[296]; /*接收輸入變量數(shù)組,如果數(shù)組不夠大,可以修改一下*/
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);
}
}
///*
//************************************************************
//* 函數(shù)名稱: USART1_IRQHandler
//*
//* 函數(shù)功能: 串口1收發(fā)中斷
//*
//* 入口參數(shù): 無
//*
//* 返回參數(shù): 無
//*
//* 說明:
//************************************************************
//*/
//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 //接收完成標(biāo)志
#define REV_WAIT 1 //接收未完成標(biāo)志
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文章來源:http://www.zghlxwxcb.cn/news/detail-780578.html
//單片機(jī)頭文件
#include "stm32f10x.h"
//網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)
#include "esp8266.h"
//硬件驅(qū)動(dòng)
#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的返回?cái)?shù)據(jù)數(shù)組*/
unsigned short esp8266_cnt = 0, esp8266_cntPre = 0; /*esp8266_cnt為當(dāng)前接收到的數(shù)據(jù)數(shù)量,esp8266_cntPre為上一次接收到的數(shù)據(jù)數(shù)量*/
//unsigned char send_data[]="GET\r\n";
//==========================================================
// 函數(shù)名稱: ESP8266_Clear
//
// 函數(shù)功能: 清空緩存
//
// 入口參數(shù): 無
//
// 返回參數(shù): 無
//
// 說明:
//==========================================================
void ESP8266_Clear(void)
{
memset(esp8266_buf, 0, sizeof(esp8266_buf));
esp8266_cnt = 0;
}
//==========================================================
// 函數(shù)名稱: ESP8266_WaitRecive
//
// 函數(shù)功能: 判斷是否接收完成
//
// 入口參數(shù): 無
//
// 返回參數(shù): REV_OK-接收完成 REV_WAIT-接收超時(shí)未完成
//
// 說明: 循環(huán)調(diào)用檢測(cè)是否接收完成
//==========================================================
_Bool ESP8266_WaitRecive(void)
{
if(esp8266_cnt == 0) //如果接收計(jì)數(shù)為0 則說明沒有處于接收數(shù)據(jù)中,所以直接跳出,結(jié)束函數(shù)
return REV_WAIT;
if(esp8266_cnt == esp8266_cntPre) //如果上一次的值和這次相同,則說明接收完畢
{
// esp8266_cnt = 0; //清0接收計(jì)數(shù),注釋掉是為了接收幾幀數(shù)據(jù)
return REV_OK; //返回接收完成標(biāo)志
}
esp8266_cntPre = esp8266_cnt; //置為相同
return REV_WAIT; //返回接收未完成標(biāo)志
}
//==========================================================
// 函數(shù)名稱: ESP8266_SendCmd
//
// 函數(shù)功能: 發(fā)送命令
//
// 入口參數(shù): cmd:命令
// res:需要檢查的返回指令
//
// 返回參數(shù): 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) //如果收到數(shù)據(jù)
{
if(strstr((const char *)esp8266_buf, res) != NULL) //如果檢索到關(guān)鍵詞
{
UsartPrintf(USART_DEBUG, "%s", esp8266_buf); //通過調(diào)試串口將接收到的返回指令顯示出來以便判斷
ESP8266_Clear(); //清空緩存
return 0;
}
}
Delay_ms(10);
}
return 1;
}
//==========================================================
// 函數(shù)名稱: ESP8266_SendData
//
// 函數(shù)功能: 發(fā)送數(shù)據(jù)
//
// 入口參數(shù): data:數(shù)據(jù)
// len:長度
//
// 返回參數(shù): 無
//
// 說明:
//==========================================================
void ESP8266_SendData(unsigned char *data, unsigned short len)
{
char cmdBuf[32];
ESP8266_Clear(); //清空接收緩存
sprintf(cmdBuf, "AT+CIPSEND=%d\r\n", len); //發(fā)送命令
if(!ESP8266_SendCmd(cmdBuf, ">")) //收到‘>’時(shí)可以發(fā)送數(shù)據(jù)
{
UsartPrintf(USART_DEBUG, "you are real");
Usart_SendString(USART2, data, len); //發(fā)送設(shè)備連接請(qǐng)求數(shù)據(jù)
}
}
//==========================================================
// 函數(shù)名稱: ESP8266_GetIPD
//
// 函數(shù)功能: 獲取平臺(tái)返回的數(shù)據(jù)
//
// 入口參數(shù): 等待的時(shí)間(乘以10ms)
//
// 返回參數(shù): 平臺(tái)返回的原始數(shù)據(jù)
//
// 說明: 不同網(wǎng)絡(luò)設(shè)備返回的格式不同,需要去調(diào)試
// 如ESP8266的返回格式為 "+IPD,x:yyy" x代表數(shù)據(jù)長度,yyy是數(shù)據(jù)內(nèi)容
//==========================================================
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頭的延遲,還是需要等待一會(huì),但不會(huì)超過設(shè)定的時(shí)間
{
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); //延時(shí)等待
} while(timeOut--);
return NULL; //超時(shí)還未找到,返回空指針
}
//==========================================================
// 函數(shù)名稱: ESP8266_Init
//
// 函數(shù)功能: 初始化ESP8266
//
// 入口參數(shù): 無
//
// 返回參數(shù): 無
//
// 說明:
//==========================================================
void ESP8266_Init(void)
{
GPIO_InitTypeDef GPIO_Initure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
//ESP8266復(fù)位引腳
GPIO_Initure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_Initure.GPIO_Pin = GPIO_Pin_14; //GPIOC14-復(fù)位
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回到默認(rèn)狀態(tài)
Delay_ms(500);
ESP8266_Clear(); //清空上一次的接收緩存
Delay_ms(500);
UsartPrintf(USART_DEBUG, "0. AT\r\n");
ESP8266_SendCmd(" AT\r\n", "OK"); //測(cè)試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"); //設(shè)置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"); //連接到服務(wù)器
Delay_ms(500);
UsartPrintf(USART_DEBUG, "4. AT+CIPMODE=1\r\n");
ESP8266_SendCmd("AT+CIPMODE=1\r\n", "OK"); //設(shè)置透?jìng)髂J?/span>
Delay_ms(500);
UsartPrintf(USART_DEBUG, "5. AT+CIPSEND\r\n");
ESP8266_SendCmd("AT+CIPSEND\r\n", ">"); //開啟數(shù)據(jù)傳輸模式
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");
// }
}
//==========================================================
// 函數(shù)名稱: USART2_IRQHandler
// 函數(shù)功能: 串口2收發(fā)中斷
// 入口參數(shù): 無
// 返回參數(shù): 無
// 說明:
//==========================================================
void USART2_IRQHandler(void)
{
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //串口2接收中斷
{
if(esp8266_cnt >= sizeof(esp8266_buf)) esp8266_cnt = 0; //防止串口被刷爆,如果接收超過了接收數(shù)組的容量,從第一位開始覆蓋接收數(shù)組
esp8266_buf[esp8266_cnt++] = USART_ReceiveData(USART2); //將接收到的數(shù)據(jù)放到接收數(shù)組里
USART_ClearFlag(USART2, USART_FLAG_RXNE); //清除中斷標(biāo)志位
}
}
總結(jié)
這次介紹了一下ESP8266的使用方法和注意事項(xiàng),還有我對(duì)串口中斷的了解。因?yàn)樘L了,所以獲取和處理天氣、時(shí)間信息就放在下一文章中。文章來源地址http://www.zghlxwxcb.cn/news/detail-780578.html
到了這里,關(guān)于從零開始制作一個(gè)基于STM32和ESP8266-01S的智能時(shí)鐘(3)ESP8266-01S模塊(上)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!