2019年上半年,爲了準備一個機器人比賽,就去研究了一下ESP8266 WIFI模塊。模塊自己已經被封裝得很好了,但是在搭載到單片機上出現了不少問題,藉此機會總結一下:單片機配置流程和中間可能遇到的一些坑。html
作什麼:單片機 控制 ESP8266。node
怎麼作:a.STM32核心板提供ESP8266所須要的硬件環境; b.程序中寫好特定格式的命令,經過串口發送給ESP8266。web
技術路線:windows
我用的是下面這塊裸板,爲的是能直接焊在板子上,節省空間。服務器
根據模塊提供的手冊,對引腳進行配置,通常來講咱們使用運行模式。app
模式 | CH_PD(EN) | RST | GPIO15 | GPIO0 | GPIO2 | TXD0 |
---|---|---|---|---|---|---|
運行模式 | 高 | 高 | 低 | 高 | 高 | 高 |
下載模式 | 高 | 高 | 低 | 低 | 高 | 高 |
對應的電路設計能夠參考下面這張圖less
注意:ide
1.模塊最終能有效運行的關鍵因素就是上圖中的引腳是否電平配置到位,若是模塊接入電路,通 svg
電時,模塊上面自帶的藍色LED小燈沒有閃爍一下,那就說明模塊硬件環境沒有配置好(或者學習
模塊燒燬)。建議挨個檢查引腳的電壓,可能遇到的狀況有a.電壓不足b.徹底沒有電壓c.過
壓。那麼你就要根據電路圖,原理圖找找是否存在斷路,分壓和短路等狀況了。
2.個人是裸板,個人是裸板,沒有VCC,GND,RX,TX等六個引腳直接引出。像下面這樣:
圖中的裸板已經搭載在一個配套電路上了,實現了我上面說的電路設計,拿來通上電直接用,對
剛接觸的人來講特別友好,不過我是爲了集成化,節約空間,就直接拿裸板焊本身板子上,因此
須要本身配置引腳(特別坑,當初也是直接VCC,GND直接懟,結果沒卵用),因此你買的什麼
模塊,就看店家提供的資料,別人的不必定適合本身。
3.模塊GND要和STM32的GND相連。
先利用電腦經過串口發送信息給 ESP8266模塊,熟悉一下流程。
選擇正確的 COM 號(WIFI與你電腦相連的串口),而後設置波特率爲 115200,勾選發送新行 (必選!即自動添加回車換行功能)而後發送 AT指令 到 ESP8266模塊。
而後理清楚一下服務器(主機)和客戶端(從機)分別須要執行什麼AT指令。
服務器(主機) | AT指令 | 客戶端(從機) | AT指令 |
---|---|---|---|
檢測模塊是否在線 | AT | 檢測模塊是否在線 | AT |
修改服務器WIFI名和密碼 | AT+CWSAP="ALIENTEK","15902020353",11,3 | 設置 WIFI 模式1 | AT+CWMODE=1 |
設置 WIFI 模式2 | AT+CWMODE=2 | 重啓生效 | AT+RST |
重啓生效 | AT+RST | 鏈接服務器的WIFI | AT+CWJAP="ALIENTEK","15902020353" |
創建服務器指令 | AT+CIPSERVER=1,8089 | 鏈接服務器 | AT+CIPSTART="TCP","你的服務器 IP 地址",8089 |
獲取服務器IP地址 | AT+CIFSR | 開啓透傳模式 | AT+CIPMODE=1 |
開始透傳 | AT+CIPSEND |
說明:
a. 我修改服務器WIFI名爲ALIENTEK,密碼15902020353,修改完後復位,能夠在電腦上找到這個WIFI名,
這也是後面客戶端要鏈接服務器時所用到的帳號密碼。
b. WIFI模式分爲3種:1爲station(客戶端);2爲access point(服務器);3爲1和2的兼容模式
c. 若是想要一個服務器與多個客戶端通訊,能夠在服務器復位後插入AT+CIPMUX=1(啓動多鏈接)便可。那
問題來了,服務器怎麼知道本身要通訊的客戶端是誰呢?能夠這樣,先讓客戶端鏈接上服務器WIFI,對客
戶端使用AT+CIPSTATUS,就會返回當前模塊的攔截狀態和鏈接參數 STATUS: +CIPSTATUS:,,<remote_ip>,, <local_port>, 。id就是咱們要的值,而後AT+CIPSND =0,5就能夠針對0號客戶端發送5個字節的數據了。
d. 結束透傳的話須要發送"+++"(該指令必須在開啓透傳模式下使用 )
關於AT指令的使用細則網上已經有不少資料,我再也不贅述,能夠參考這篇文章 兩個ESP8266一個做爲服務器一個做爲客戶端實現互相通信
多操做兩遍,摸清楚流程,在電腦上能實現二者互相通訊後,接下來就是在單片機上寫好程序了。在單片機上寫好上面AT指令,經過串口發送給ESP8266模塊。上面我說到硬件最大的問題就是電壓有沒有給到位,而代碼中最關鍵的問題有兩個,一是格式,二是速度。
軟件我是這樣寫的:
/*************************************************
服務器邏輯代碼
*************************************************/
void atk_8266_server(void)
{
atk_8266_send_cmd("AT","OK",20); //檢查WIFI模塊是否在線
atk_8266_send_cmd("AT+CWMODE=2","OK",20); //1.Station模式2.Ap模式3.兼容1.2兩個模式
atk_8266_send_cmd("AT+RST","OK",200); //重啓復位,模式生效
atk_8266_send_cmd("AT+CIPMUX=1","OK",20); //啓動多鏈接指令
atk_8266_send_cmd("AT+CIPSERVER=1,8089","OK",20);//創建服務器server指令
USART2_RX_STA=0;
while(1) //等待倒計時
{
delay_ms(100);
if(USART2_RX_STA&0X8000) //接收到期待的應答結果
{
if(atk_8266_check_cmd("start"))//服務器接收數據"start"
{
actions();
break;
}
USART2_RX_STA=0;
}
}
}
/*************************************************
向ESP8266發送命令
cmd:發送的命令字符串
ack:期待的應答結果,若是爲空,則表示不須要等待應答
waittime:等待時間(單位:10ms)
返回值:0,發送成功(獲得了期待的應答結果)
1,發送失敗
*************************************************/
u8 atk_8266_send_cmd(u8 *cmd,u8 *ack,u16 waittime)
{
u8 res=0;
USART2_RX_STA=0;
USART2_printf("%s\r\n",cmd);//發送命令
//delay_ms(100);
//USART2_printf("%s\r\n",cmd);若是碰到長指令發送無效,能夠嘗試發送兩遍,親測有效!!!
if(ack&&waittime) //須要等待應答
{
while(--waittime) //等待倒計時
{
delay_ms(10);
if(USART2_RX_STA&0X8000)//接收到期待的應答結果
{
if(atk_8266_check_cmd(ack))
{
//printf("ack:%s\r\n",(u8*)ack);
break; //獲得有效數據
}
USART2_RX_STA=0;
}
}
if(waittime==0)res=1;
}
return res;
}
/*************************************************
ESP8266發送命令後,檢測接收到的應答
str:期待的應答結果
返回值:0,沒有獲得期待的應答結果
其餘,期待應答結果的位置(str的位置)
*************************************************/
u8* atk_8266_check_cmd(u8 *str)
{
char *strx=0;
if(USART2_RX_STA&0X8000)//接收到一次數據了
{
USART2_RX_BUF[USART2_RX_STA&0X7FFF]=0;//添加結束符
strx=strstr((const char*)USART2_RX_BUF,(const char*)str);
}
return (u8*)strx;
}
/*************************************************
ESP8266退出透傳模式
返回值:0,退出成功;
1,退出失敗
*************************************************/
u8 atk_8266_quit_trans(void)
{
while((USART2->SR&0X40)==0);//等待發送空
USART2->DR='+';
delay_ms(15);//大於串口組幀時間(10ms)
while((USART2->SR&0X40)==0);//等待發送空
USART2->DR='+';
delay_ms(15);//大於串口組幀時間(10ms)
while((USART2->SR&0X40)==0);//等待發送空
USART2->DR='+';
delay_ms(500);//等待500ms
return atk_8266_send_cmd("AT","OK",20);//退出透傳判斷.
}
xxxxxxxxxx
/*************************************************
客戶端代碼
*************************************************/
void atk_8266_test(void)
{
atk_8266_send_cmd("AT+CWMODE=1","OK",20);//1.Station模式 2.Ap模式 3.兼容1.2兩個模式
atk_8266_send_cmd("AT+RST","OK",200); //重啓復位
atk_8266_send_cmd("AT+CWJAP=\"ALIENTEK\",\"15902020353\"","OK",2000); //鏈接WIFI
atk_8266_send_cmd("AT+CIPSTART=\"TCP\",\"192.168.4.1\",8089","OK",1000);//鏈接服務器
atk_8266_send_cmd("AT+CIPSEND=5","OK",20);//發送5個字節數據
atk_8266_send_cmd("start","OK",100); //發送"start"
}
注意:
a.格式問題基本如上,上面的AT指令能夠經過串口發送,ESP8266也能識別。
b.速度問題,我必須強調一下,單片機發送命令的速度是很是快的,遠快於8266模塊接收到指令並返回給單片機
這個過程。有可能一連串指令中有一個反應慢了點(客戶端WIFI鏈接服務器WIFI時耗用的時間在1秒到10秒不
等),單片機就可能會略過這個指令,致使WIFI鏈接不上。但對於單片機來講,你又沒法直接看到究竟是哪一個指
令失效,個人作法比較笨,有兩個思路:一是在程序中每一個指令若執行成功就會有返回值,並經過串口打印在電
腦上;二是將單片機控制的ESP8266和電腦串口控制的ESP8266進行通訊,這樣你能確保電腦控制的必定不會出
錯,同時鏈接時產生的一些信息會打印在串口助手窗口上,有利於排查錯誤。總之,每一個指令的等待時間不一
樣,須要本身不斷調整。
c.若是單獨發一條格式正確的長指令(好比修改WIFI名指令),也可能會出現沒有接收成功的問題。有一個不清楚
問題在哪的辦法:延時一兩百毫秒,再發送一遍。(慚愧,沒搞清楚爲何這樣弄一下就會有用,若是有知道的
大佬麻煩在評論區指出。)
終於理解嵌入式爲何坑了,配個WIFI花了大半時間在硬件上,板子設計缺陷,焊接錯誤,8266電路配置不到位,整得我死去活來的,說多了都是自閉。最終仍是對硬件,串口有了更好的掌握。可能先買模塊組裝比較好,或者有人帶帶上手比較快,否則太折磨人了。
沒有在電腦上經過串口控制ESP8266模塊的經驗,會對在單片機上配置帶來沒有可參照標準現象,8266實際反應速度等 相對精準的參考依據,就像在黑暗中只能用手摸着路回家了,其難度可想而知。因此仍是要借用別人成熟的項目經驗,本身模仿着來操做,會少踩不少坑,也會少作不少無用功。
買開發板搭配視頻學習>尋找本身感興趣且別人有教程的項目>積累足夠經驗開始本身開發。像我這個新手直接硬剛真的是遭罪啊。