外设驱动库开发笔记27:ESP8266无线通讯驱动
我們的物聯(lián)網(wǎng)產(chǎn)品所使用的平臺(tái)都支持無(wú)線通訊,而且無(wú)線通訊本身更的成本較低,受到大家的歡迎。在本篇文章中,我們將詳細(xì)討論并實(shí)現(xiàn)ESP8266無(wú)線通訊模塊的驅(qū)動(dòng)。
1、功能概述
ESP8266是由樂(lè)鑫公司出品的一款物聯(lián)網(wǎng)芯片,因?yàn)閮r(jià)格較低,性能穩(wěn)定等收到很大關(guān)注。
該芯片可工作于三種WIFI模式下,分別是:station模式,AP模式以及混合模式,通過(guò)AT指令進(jìn)行控制,顯影的指令格式為:AT+CWMODE=<mode>。mode的取值決定設(shè)定的模式:
當(dāng)mode為1時(shí),ESP8266工作于station 模式:ESP8266 模塊通過(guò)路由器連接互聯(lián)網(wǎng),手機(jī)或電腦通過(guò)互聯(lián)網(wǎng)實(shí)現(xiàn)對(duì)設(shè)備的遠(yuǎn)程控制。
當(dāng)mode為2時(shí),ESP8266工作于softAP 模式:ESP8266 模塊作為熱點(diǎn),手機(jī)或電腦直接與模塊連接,實(shí)現(xiàn)局域網(wǎng)無(wú)線控制。
當(dāng)mode為3時(shí),ESP8266工作于softAP + station 模式:兩種模式的共存模式,即可以通過(guò)互聯(lián)網(wǎng)控制可實(shí)現(xiàn)無(wú)縫切換,方便操作。
ESP8266擁有2種傳輸模式,即正常模式和透?jìng)髂J?。而傳輸模式的配置也是采?/span>AT指令,具體格式為:AT+CIPMODE=<mode>。其中mode 取值0時(shí),為普通傳輸模式;而mode 取值1時(shí),為透?jìng)髂J?#xff0c;僅支持TCP單連接和 UDP固定通信對(duì)端的情況。在正常模式下,每次發(fā)送數(shù)據(jù)前都必須先發(fā)送指令AT+CIPSEND=<param>。而在透?jìng)髂J较?#xff0c;我們就不需要在每次發(fā)送數(shù)據(jù)前都發(fā)送指令AT+CIPSEND=<param>了,只需要發(fā)送一次AT+CIPSEND,之后發(fā)送的所有內(nèi)容全部當(dāng)成是數(shù)據(jù)了。但這又存在一個(gè)問(wèn)題,我們想要發(fā)送命令該如何呢?那么就需要發(fā)送數(shù)據(jù)"+++"來(lái)退出透?jìng)髂J健?/span>
ESP8266有幾種不同的使用方式,最為常見(jiàn)的就是使用AT指令進(jìn)行操作。ESP8266的AT指令分為基礎(chǔ)AT指令、WiFi功能AT指令和TCP/IP相關(guān)AT指令3個(gè)方面。這些指令從使用功能上講可分為4類:
按照相應(yīng)的格式發(fā)送不同的AT指令就可以實(shí)現(xiàn)ESP8266的數(shù)據(jù)通訊了。
2、驅(qū)動(dòng)設(shè)計(jì)與實(shí)現(xiàn)
ESP8266無(wú)線通訊模塊是常用的通訊模塊,我們已經(jīng)描述了其功能及通訊方式,接下來(lái)我們將設(shè)計(jì)并實(shí)現(xiàn)其驅(qū)動(dòng)程序。
2.1、對(duì)象定義
在使用一個(gè)對(duì)象之前我們需要獲得一個(gè)對(duì)象。同樣的我們想要ESP8266無(wú)線通訊模塊就需要先定義ESP8266無(wú)線通訊模塊的對(duì)象。
2.1.1、對(duì)象的抽象
我們要得到ESP8266無(wú)線通訊模塊對(duì)象,需要先分析其基本特性。一般來(lái)說(shuō),一個(gè)對(duì)象至少包含兩方面的特性:屬性與操作。接下來(lái)我們就來(lái)從這兩個(gè)方面思考一下ESP8266無(wú)線通訊模塊的對(duì)象。
先來(lái)考慮屬性,作為屬性肯定是用于標(biāo)識(shí)或記錄對(duì)象特征的東西。我們來(lái)考慮ESP8266無(wú)線通訊模塊對(duì)象屬性。我們考慮到ESP8266的WIFI模式以及數(shù)據(jù)傳輸模式?jīng)Q定了其工作方式,在使用過(guò)程中有時(shí)我們也需要了解這兩個(gè)模式的配置是什么,所以我們將其作為對(duì)象的屬性已記錄這兩個(gè)模式配置。我們每一個(gè)ESP8266對(duì)象都需要接收數(shù)據(jù),所以要有一個(gè)接受緩存區(qū),我們定義了一個(gè)結(jié)構(gòu)體變量來(lái)作為對(duì)象接收緩沖區(qū)。
接著我們還需要考慮ESP8266無(wú)線通訊模塊對(duì)象的操作問(wèn)題。我們想要使用ESP8266對(duì)象實(shí)現(xiàn)我們的功能,就需要發(fā)送命令或數(shù)據(jù)以及接收數(shù)據(jù)。串口接收數(shù)據(jù)我們一般使用中斷方式,所以定義了緩沖區(qū),不再需要特定的操作。串口發(fā)送消息需要實(shí)現(xiàn),但這依賴于具體的硬件平臺(tái),所以我們將其作為對(duì)象的操作。此外,我們使用串口通訊時(shí),需要控制時(shí)序就離不開(kāi)延時(shí)函數(shù),而延時(shí)操作一般都依賴于具體的軟硬件平臺(tái),所以我們將延時(shí)函數(shù)作為對(duì)象的一個(gè)操作。
根據(jù)上述我們對(duì)ESP8266無(wú)線通訊模塊的分析,我們可以定義ESP8266無(wú)線通訊模塊的對(duì)象類型如下:
/*定義ESP8266對(duì)象*/ typedef struct Esp8266Object {Esp8266CWModeType cwMode;???? //WIFI模式Esp8266CIPModeType cipMode;?? //傳輸模式,正常或透?jìng)鱯truct EspRxBuffer{uint8_t queue[Esp8266RxBufferLength];?? //數(shù)據(jù)存儲(chǔ)隊(duì)列uint8_t lengthRecieving;?????????????? //正在接收的數(shù)據(jù)長(zhǎng)度uint8_t lengthRecieved;??????????????? //已經(jīng)接收的數(shù)據(jù)長(zhǎng)度}rxBuffer;void (*SendData)(uint8_t *sData,uint16_t sSize);//數(shù)據(jù)發(fā)送函數(shù)指針void (*Delayms)(volatile uint32_t nTime);???? //延時(shí)操作指針 }Esp8266ObjectObject;2.1.2、對(duì)象初始化
我們知道,一個(gè)對(duì)象僅作聲明是不能使用的,我們需要先對(duì)其進(jìn)行初始化,所以這里我們來(lái)考慮ESP8266無(wú)線通訊模塊對(duì)象的初始化函數(shù)。一般來(lái)說(shuō),初始化函數(shù)需要處理幾個(gè)方面的問(wèn)題。一是檢查輸入?yún)?shù)是否合理;二是為對(duì)象的屬性賦初值;三是對(duì)對(duì)象作必要的初始化配置。據(jù)此我們?cè)O(shè)計(jì)ESP8266無(wú)線通訊模塊對(duì)象的初始化函數(shù)如下:
/*ESP8266對(duì)象初始化*/ void Esp8266Initialization(Esp8266ObjectObject *esp,??? //ESP8266對(duì)象Esp8266CWModeType cwMode,??? //WIFI模式Esp8266CIPModeType cipMode,? //傳輸模式,正常或透?jìng)鱟har *wifiName,????????????? //WIFI名稱char *wifiPassword,????????? //WIFI密碼ESP8266SendDataType send,??? //發(fā)送函數(shù)指針ESP8266DelaymsType delayms?? //毫秒延時(shí)函數(shù)) {char cwjap[50];char cwsap[50];if((esp==NULL)||(send==NULL)||(delayms==NULL)){return;}esp->SendData=send;esp->Delayms=delayms;esp->cwMode=cwMode;esp->cipMode=cipMode;esp->rxBuffer.lengthRecieved=0;ClearReciveBuffer(esp);//設(shè)置工作模式 1:station模式?? 2:AP模式? 3:兼容 AP+station模式if(Esp8266SendCommmand(esp,cwModeCmd[esp->cwMode],"OK",50)==Esp8266_TxFial){return;}//讓W(xué)ifi模塊重啟的命令if(Esp8266SendCommmand(esp,"AT+RST","OK",20)==Esp8266_TxFial){return;}esp->Delayms(3000);???????? //延時(shí)3S等待重啟成功if(esp->cwMode==Esp8266_StationMode){sprintf(cwjap,"AT+CWJAP_CUR=\"%s\",\"%s\"\r\n",wifiName,wifiPassword);//讓模塊連接上自己的路由if(Esp8266SendCommmand(esp,cwjap,"OK",600)==Esp8266_TxFial){return;}if(esp->cipMode==Esp8266_TransMode){if(Esp8266EnterTrans(esp)==Esp8266_TxFial){return;}}else{//=0:單路連接模式???? =1:多路連接模式if(Esp8266SendCommmand(esp,"AT+CIPMUX=0\r\n","OK",20)==Esp8266_TxFial){return;}}}else if(esp->cwMode==Esp8266_SoftAPMode){sprintf(cwsap,"AT+CWSAP_CUR=\"%s\",\"%s\"\r\n",wifiName,wifiPassword);//設(shè)置模塊的WIFI名和密碼if(Esp8266SendCommmand(esp,cwsap,"OK",600)==Esp8266_TxFial){return;}}else if(esp->cwMode==Esp8266_MixedMode){//尚未使用,有待添加} }2.2、對(duì)象操作
我們已經(jīng)完成了ESP8266無(wú)線通訊模塊對(duì)象類型的定義和對(duì)象初始化函數(shù)的設(shè)計(jì)。但我們的主要目標(biāo)是獲取對(duì)象的信息,接下來(lái)我們還要實(shí)現(xiàn)面向ESP8266無(wú)線通訊模塊的各類操作。
對(duì)于ESP8266來(lái)說(shuō),發(fā)送命令主要是AT命令,這是與發(fā)送數(shù)據(jù)完全不同的操作,所以我們?cè)O(shè)計(jì)了一個(gè)專用于命令發(fā)送的操作函數(shù)。
/*ESP8266發(fā)送命令*/ static Esp8266TxStatusType Esp8266SendCommmand(Esp8266ObjectObject *esp,char *cmd,char *ack,uint16_t timeOut) {esp->SendData((unsigned char *)cmd, strlen((const char *)cmd));?????? //寫(xiě)命令到網(wǎng)絡(luò)設(shè)備if(ack&&timeOut){while(timeOut--)????? //等待超時(shí){if(ChecRecieveFinished(esp) == Esp8266_RxFinish)??? //如果數(shù)據(jù)接收完成{if(strstr((const char *)esp->rxBuffer.queue,ack) != NULL)?????? //如果檢索到關(guān)鍵詞{ClearReciveBuffer(esp);return Esp8266_RxSucceed;}}esp->Delayms(10);}}return Esp8266_TxFial; }而ESP8266在發(fā)送數(shù)據(jù)時(shí),因發(fā)送模式的不同會(huì)有一定區(qū)別。在透?jìng)髂J较轮恍枰l(fā)送數(shù)據(jù)就好了。而在普通模式下,需要先發(fā)送AT命令再發(fā)送發(fā)送數(shù)據(jù)。所以我們可設(shè)計(jì)數(shù)據(jù)發(fā)送函數(shù)如下:
/*ESP8266發(fā)送數(shù)據(jù)*/ void Esp8266SendData(Esp8266ObjectObject *esp,uint8_t *sData,uint16_t sSize) {if(esp->cipMode==Esp8266_TransMode){esp->SendData(sData,sSize);}else{char cmd[32];esp->Delayms(50);ClearReciveBuffer(esp);sprintf(cmd,"AT+CIPSEND=%d\r\n",sSize);if(Esp8266SendCommmand(esp,cmd, ">", 1)==Esp8266_RxSucceed)???? //收到‘>’時(shí)可以發(fā)送數(shù)據(jù){esp->SendData(sData,sSize);}} }3、驅(qū)動(dòng)的使用
我們已經(jīng)設(shè)計(jì)并實(shí)現(xiàn)了ESP8266無(wú)線通訊模塊的驅(qū)動(dòng)程序。接下來(lái)我們將設(shè)計(jì)一個(gè)簡(jiǎn)單的應(yīng)用以驗(yàn)證驅(qū)動(dòng)的設(shè)計(jì)是否符合要求。
3.1、聲明并初始化對(duì)象
使用基于對(duì)象的操作我們需要先得到這個(gè)對(duì)象,所以我們先要使用前面定義的ESP8266無(wú)線通訊模塊對(duì)象類型聲明一個(gè)ESP8266無(wú)線通訊模塊對(duì)象變量,具體操作格式如下:
Esp8266ObjectObject esp;
聲明了這個(gè)對(duì)象變量并不能立即使用,我們還需要使用驅(qū)動(dòng)中定義的初始化函數(shù)對(duì)這個(gè)變量進(jìn)行初始化。這個(gè)初始化函數(shù)所需要的輸入?yún)?shù)如下:
?????? Esp8266ObjectObject *esp,??? //ESP8266對(duì)象
Esp8266CWModeType cwMode,??? //WIFI模式
Esp8266CIPModeType cipMode,? //傳輸模式,正?;蛲?jìng)?/span>
char *wifiName,????????????? //WIFI名稱
char *wifiPassword,????????? //WIFI密碼
ESP8266SendDataType send,??? //發(fā)送函數(shù)指針
ESP8266DelaymsType delayms?? //毫秒延時(shí)函數(shù)
對(duì)于這些參數(shù),對(duì)象變量我們已經(jīng)定義了。而WIFI模式與傳輸模式均為枚舉,根據(jù)實(shí)際情況選擇就好了。同樣WIFI名稱和WIFI密碼更具實(shí)際使用情況輸入,注意時(shí)字符串就可以了。最主要的是我們需要定義幾個(gè)函數(shù),并將函數(shù)指針作為參數(shù)。這幾個(gè)函數(shù)的類型如下:
/*定義ESP8266數(shù)據(jù)發(fā)送指針類型*/ typedef void (*ESP8266SendDataType)(uint8_t *sData,uint16_t sSize);/*延時(shí)操作指針*/ typedef void (*ESP8266DelaymsType)(volatile uint32_t nTime);???對(duì)于這幾個(gè)函數(shù)我們根據(jù)樣式定義就可以了,具體的操作可能與使用的硬件平臺(tái)有關(guān)系。實(shí)際上我們主要需要關(guān)注的是串口發(fā)送函數(shù)。具體函數(shù)定義如下:
/*串口數(shù)據(jù)發(fā)送*/ static void SendDataForEsp8266(uint8_t *txData,uint16_t length) {HAL_UART_Transmit(&esp8266huart,txData,length,1000); }對(duì)于延時(shí)函數(shù)我們可以采用各種方法實(shí)現(xiàn)。我們采用的STM32平臺(tái)和HAL庫(kù)則可以直接使用HAL_Delay()函數(shù)。于是我們可以調(diào)用初始化函數(shù)如下:
/*ESP8266對(duì)象初始化*/Esp8266Initialization(&esp,?????????????????? //ESP8266對(duì)象Esp8266_StationMode,??? //WIFI模式Esp8266_TransMode,????? //傳輸模式,正常或透?jìng)鱳ifiName,?????????????? //WIFI名稱wifiPassword,?????????? //WIFI密碼SendDataForEsp8266,???? //發(fā)送函數(shù)指針HAL_Delay?????????????? //毫秒延時(shí)函數(shù));3.2、基于對(duì)象進(jìn)行操作
我們定義了對(duì)象變量并使用初始化函數(shù)給其作了初始化。接著我們就來(lái)考慮操作這一對(duì)象獲取我們想要的數(shù)據(jù)。我們?cè)隍?qū)動(dòng)中已經(jīng)將獲取數(shù)據(jù)并轉(zhuǎn)換為轉(zhuǎn)換值的比例值,接下來(lái)我們使用這一驅(qū)動(dòng)開(kāi)發(fā)我們的應(yīng)用實(shí)例。
/*ESP8266數(shù)據(jù)通訊*/ void Esp8266DataCommunication(void) {uint8_t sData[16]={0x10,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F};Esp8266SendData(&esp,sData,16); }4、應(yīng)用總結(jié)
在這一篇中我們?cè)O(shè)計(jì)并實(shí)現(xiàn)了ESP8266無(wú)線模塊的驅(qū)動(dòng),并基于次驅(qū)動(dòng)程序設(shè)計(jì)了一個(gè)簡(jiǎn)單的驗(yàn)證應(yīng)用。測(cè)試結(jié)果是符合我們的預(yù)期的,說(shuō)明我們?cè)O(shè)計(jì)的驅(qū)動(dòng)沒(méi)有問(wèn)題。
?????? 在使用驅(qū)動(dòng)程序時(shí)需要注意,這一驅(qū)動(dòng)只是實(shí)現(xiàn)了ESP8266的基本功能,所以要想實(shí)現(xiàn)更復(fù)雜的功能是可以在驅(qū)動(dòng)基礎(chǔ)上擴(kuò)展的。后續(xù)我們也會(huì)根據(jù)使用的需要進(jìn)一步擴(kuò)充驅(qū)動(dòng)。當(dāng)然這個(gè)驅(qū)動(dòng)是基于AT指令來(lái)實(shí)現(xiàn)操作的,擴(kuò)充這個(gè)驅(qū)動(dòng)程序的功能也需要使用AT指令來(lái)實(shí)現(xiàn)。
?????? 本驅(qū)動(dòng)程序在設(shè)計(jì)時(shí),考慮使用串口中斷來(lái)接收數(shù)據(jù),所以我們?yōu)閷?duì)象設(shè)計(jì)了一個(gè)接收數(shù)據(jù)緩存結(jié)構(gòu)。在設(shè)計(jì)應(yīng)用時(shí)需在串口中斷服務(wù)函數(shù)中向緩存種添加數(shù)據(jù)。
歡迎關(guān)注:
?
總結(jié)
以上是生活随笔為你收集整理的外设驱动库开发笔记27:ESP8266无线通讯驱动的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
 
                            
                        - 上一篇: mac php errorlog,Mac
- 下一篇: 文件系统应用笔记之一:FatFS在STM
