2015年4月13日 星期一

【技術教學】打造Wifi遙控車(之一):使用 ESP8266進行 Wifi無線通訊

大家好,我是克里斯。我最近一年迷上了 Arduino (暱稱「阿堆諾」),於是開始進行了一些阿堆諾的學習/實驗專案。現在我打算要來試著做一台 Wifi遙控車。也就是說,這台遙控車會自行連接到 Wifi,而我只要也用手機連到同一個 Wifi就可以遙控它!

為了讓阿堆諾擁有連接無線網路跟手機通訊的能力,它會需要 ESP8266這塊Wifi電路板的協助。這一篇技術文章的主角就是 ESP8266,我會在後面說明它的使用方式,以及我花了兩天才好不容易馴服它的艱辛歷程(快被藏在細節裡的魔鬼們搞死了)。至於遙控車,就得再等一段時間才會完成啦~敬請期待。

※遙控車已經完成囉!請見:〈【作品】Wifi 遙控車!〉

ESP8266簡介

好了,這就是我們的主角:ESP8266
我是可愛的 ESP8266

這塊電路板因為體積小、價格低(可在露天或淘寶買到,約一兩百塊),而成為了 Maker們製作 Wifi相關專案時,相當適合的選擇。還有Maker為它做了一部介紹短片

它不但可以連線到無線網路,也可以自己成為AP(無線網路基地台)。他支援 TCP和UDP連線,可在無線區域網路中扮演伺服器(Server)等候連入,或扮演客戶端(Client)去與Server連線。

看來 ESP8266體積雖小卻功能強大。只是要馴服它可不是一件簡單的事情,因為有非常多的細節,是很多教學文章,或說明裡面根本沒提到的。克里斯也是撞牆+鬼打牆 N次,爬了很多中文+英文文章,才終於搞懂其中的"眉角",成功馴服它的。我也趁著個機會把這些重點寫下來(前面會加上「●」符號),免得以後忘記,又跑去撞一樣的牆。

其實這整個馴服過成,不過就是以下三個步驟:
  1. 讓 ESP8266跟電腦連接。
  2. 幫 ESP8266更新韌體。
  3. 透過指令(AT Command)去操作 ESP8266。
等我們把這三個步驟都完成,熟悉並駕馭了 ESP8266後,我們就不需要再用電腦去連接 ESP8266,而可以改用 Arduino去連接,並對 ESP8266發送指令了。

這三個步驟看起來簡單,其實非常麻煩......(你看文章的捲軸那麼小就知道了)
以下我將一一說明。

(一)讓 ESP8266跟電腦連接。

首先,我們要讓 ESP8266與電腦連接。可是,從圖片中我們可以看到,它有八支腳,而這八隻腳顯然跟 USB孔長得一點都不一樣。這到底是要怎麼接?

原來,ESP8266使用的通訊方式,是一種叫做序列(Serial)通訊的方式。這種通訊方式和一般的USB通訊方式是不同的。因此若要讓 ESP8266跟電腦通訊,我們就需要一個「USB轉 Serial」的轉換器,這種轉換器另有「USB轉 TTL」和「USB轉 UART」等不同的名稱(參考自這篇文章),但基本上是相同的東西,用這些名稱去搜尋就能購買到。

因此,接下來要登場的腳色,就是我所使用的一款「USB轉 Serial」轉換器──CP2102。(這些傢伙都是數字名,害我常常搞混或忘記......)
這是CP2102的長相:
「USB轉 Serial」轉換器 CP2102

終於看到熟悉的 USB接頭了,CP2102的另外一端有六隻腳,包括:3v3、TXD、RXD、GND和5V。其中有幾隻就是要用來跟 ESP8266連接的,大部分的轉換器的接腳都大同小異,因此不一定要用這一個型號的轉換器。

看完了CP2102的接腳後,我們也要來看一下 ESP8266的接腳又有哪些。

下面就是ESP8266的接腳說明圖:
接腳說明
我們可以看到,左邊的8個點,就是它的八隻接腳,旁邊的八串英文字,就是這八支接腳的代號名稱。

圖中的GND代表 Ground,即電源負極接腳。VCC則代表電源正極接腳。ESP8266需要 3.3V (可接受範圍1.7~3.6V)的電源輸入,若使用 5V電源會把它燒毀

要特別注意的是,ESP8266的電流消耗可達200~300mA,電源必須能提供足夠的電流,以確保它正常運作(參考自這篇文章,注意該文章的線路圖部分有誤)。

然而,大部分的「USB轉 TTL」轉換器,例如CP2102,雖然有提供3.3V的電源輸出,但是卻無法提供足夠的電流。因此我們需要使用其他的裝置做為電源。例如電源供應器或Arduino。

圖中的UTXD 和 URXD,是主要用來與電腦連接通訊的兩個接腳,TX表示它是用來發送訊號,RX則表示它是用來接收訊號。

關於其它的詳細技術規格,可以參考這個網頁

配線

現在我們要來為 ESP8266接線了。首先要接的就是電源。我們使用 Arduino做為電源。接法如下:
  1. 【Arduino】3.3V →【ESP8266】VCC
  2. 【Arduino】3.3V →【ESP8266】CH_PD
  3. 【Arduino】GND →【ESP8266】GND
  4. 【Arduino】GND →【CP2102】GND   
第4條很多教學沒有提到,但很重要。我之前沒有接,結果發現會導致 ESP8266無法運作。

●也有些教學說要把 3.3V也接到 ESP8266的 GPIO0、GPIO2和 RST,結果我卻發現那會導致ESP8266一直丟垃圾訊息給電腦。所以就像這一篇教學中的做法一樣,那幾條是不應該接的。
●另外要注意的是,Arduino的電流供應其實還是不夠大。雖然這對 ESP8266在一般運作時的影響不大。但要更新韌體的時候,就必須要改用電源供應器來供電了!

接著,我們要將訊號線與 CP2102連接, 接法如下:
  1. 【CP2102】TXD→【ESP8266】URXD
  2. 【CP2102】RXD→【ESP8266】UTXD
TX是發送端,所以要接到 RX接收端。

與電腦通訊

線都接好之後,我們就可以把 CP2102插到電腦的 USB孔了。要讓電腦透過 CP2102與 ESP8266通訊之前,我們還必須先安裝 CP2102(或你的其他轉換器)的驅動程式,CP2102的驅動程式可以在這裡下載(點選「工具」分頁)。

驅動程式安裝好之後,就可以在「裝置管理員」中看到它了:


從這裡我們也看出它的序列埠代號是 COM5。這個代號我們稍後會用到。

接著我們就要使用序列埠通訊軟體來和 ESP8266通訊了。在網路上可以找到很多種不同的序列埠通訊軟體。例如 putty、Realterm和 sscom32等(請自行搜尋下載)。

這裡我使用 Realterm做為示範。


一開始,我們先切換到 Port分頁。先設定 Baud (鮑率,Baud Rate) 和 Port。

Baud Rate是訊息發送/接收的速度,訊息的發送者和接收者的 Baud Rate設定必須相同才能順利通訊。

●要特別注意的是,你所買到的 ESP8266中所安裝的韌體是哪一個版本的。對於較舊的版本,他們的 Baud Rate一般是設置為 115200 或 57600,只有最新版(通常需要手動更新)的韌體(版本0018000902)的預設 Baud Rate才會是9600。所以,我們就必須拿這幾個數值去嘗試,看看能否與 ESP8266通訊。

至於 Port就是我們剛剛看到的「COM5」(你代號可能跟我的不同),所以就選 5。

●Stop Bits預設是「1Bit」,一般可以不必調。但如果你在發送命令的過程中,命令常常會有幾個字變成亂碼而導致失敗的話,可以切換為「2Bits」試試看。至少我調整後就不再發生這樣的問題。

接下來,我們就要來試著輸入命令,與 ESP8266通訊了。我們需要切換到 Send頁面去:


在這個頁面中,我們有兩排文字輸入框,兩個都可以用來發送命令訊息。發送時只要按下「Send ASCII」按鈕即可。

要跟 ESP8266通訊,我們需要使用一種叫做 AT Command的命令。完整的命令集可以參考這個PDF檔案(備用載點)。各種命令的使用說明範例也可以參考這篇:〈操控 ESP8266 無線模組 - 經由 AP、STA 和 AP+STA 三種模式,學習 ESP8266 AT 指令〉

現在,我們可以試著輸入「AT」測試命令並送出,如果得到「OK」的回應,那就表是成功跟 ESP8266通訊了。我們也可以輸入「AT+GMR」命令來取得目前的韌體版本號碼。

●如果試了很久,都只有「AT」命令成功,其他命令卻一直無法成功(出現 ERROR)的話,那很有可能是 Port打錯了。有可能你連接到的是電腦上的其他裝置(例如滑鼠),因為它們在收到「AT」命令時,也會回應「OK」。

●關於(上圖)最右邊的 EOL設定:如果是舊版的韌體似乎可以不用打勾就可以使用(不是很確定),但如果更新到最新的韌體後,必須要打勾才能成功發送訊息。EOL即 End of Line,也就是一行命令的結尾字元。如果打勾,就會在命令發送時自動在命令後面加上這些結尾字元。一般都使用LF(在程式碼中為 \n)作為 EOL,但更新韌體之後,ESP8266似乎就只接受CR+LF(即 \r\n)作為 EOL,因此才會把它們都打勾。


●如果覺得命令畫面的文字前面常常有「cr」或「lf」的小字感覺很煩的話,就到 Display分頁中,去把「Ascii」編碼改成「Ansi」(如上圖)。

確定可以跟它通訊之後,先別急著嘗試其他指令,等我們更新完韌體之後再繼續來玩也不遲。

(二)幫 ESP8266更新韌體

要更新韌體,是為了讓 Arduino可以跟 ESP8266通訊。因為,舊版的韌體  Baud Rate一般為 115200 或 57600,這樣的數值超過了 Arduino的 Baud Rate上限。理想上,我們希望把 Baud Rate降低到 9600(Arduino常用的 Baud Rate)。但因為舊版的韌體也不支援變更 Baud Rate的功能。所以,我們必須為它更新韌體。新版的韌體,不但支援這項功能,而且它的預設 Baud Rate正是 9600。

更新韌體時,ESP8266會消耗更大的電流,因此我們不能繼續用 Arduino作為電源,而必須把Arduino換成電源供應器,或其他可以提供更大電流的電源。除此之外,我們也必須稍微變更 ESP8266的配線,把 GPIO0連接到電源的 GND:
  1. 【電源供應器】GND →【ESP8266】GPIO0
重新配線的時候,建議把電源先關掉,等到配線完畢再把電源開啟。
把 GPIO0這樣接,會讓 ESP8266進入到「韌體更新」模式。在這個模式之下,是無法用輸入 AT Command(命令)的。韌體更新完之後記得把 GPIO0和 GND的連接拆掉,讓它恢復一般模式。

現在,我們需要去下載以下檔案來幫 ESP8266更新:
第一個檔案是韌體燒錄軟體,我們必須使用它來把第二個檔案(韌體檔案)燒錄進 ESP8266。這樣一來更新就完成了。


首先按「Bin」按鈕,去選擇我們所下載的第二個(v0.9.2.2 AT Firmware.bin)檔案。然後把 COM1改成 ESP8266所在的序列埠代號,例如我的就是跟前面一樣的「COM5」。最後按下Download按鈕,就會開始燒錄韌體到 ESP8266了。

●建議在執行第一個檔案時,以系統管理員身分執行。似乎這樣它才能正常運作。

●之前在更新韌體時,發現它常常寫入到一半,大概10~20%就會失敗。試了很多次都一樣,後來才發現原來是因為Arduino的電流不夠大,電流不足的問題。

(三)透過指令(AT Command)去操作 ESP8266

如我前面所述,當 ESP8266完成韌體更新之後,它的 Baud Rate就會自動變成 9600。因此接下來我們要重新與 ESP8266連接時,就需要使用 9600的 Baud Rate設定去與它連接。

我們一樣可以先使用 Realterm軟體,輸入「AT」與「AT+GMR」這兩個基本指令去測試它。
測試成功後,我們可以繼續用其他指令,來測試 ESP8266的核心網路功能。

以下會先把 ESP8266進行網路連線的流程和概念介紹一遍。實際的操作範例會放在最後面。

Wifi連線

首先,我們必須想辦法讓 ESP8266連進行 Wifi連線。

ESP8266的Wifi連線有三種模式:
  1. Station模式:扮演連線到現有Wifi的裝置。
  2. AP模式:扮演無線基地台,提供Wifi環境供連線。
  3. Station+AP混合模式:允許同時使用以上兩種模式的特有功能。
透過以下的指令,我們就可以設定或取得目前Wifi連線模式:
指令「AT+CWMODE」
「AT+CWMODE?」查詢當前模式
「AT+CWMODE=2」將模式設定為第2種(AP模式)。
我們最好先把 ESP8266設定到我們想要的模式,再使用其他的指令來連線。因為,有些指令只能在特定的模式中使用,使用指令時必須特別注意。

首先,我把模式設定成「1. Station模式」。讓 ESP8266去連接現有的 Wifi網路。那麼,我們要怎麼知道有哪些現有的網路可供連線呢?

這時我們就要使用以下指令:
指令「AT+CWLAP」
顯示可連線的Wifi網路清單。
知道有哪些網路之後,我們就可以選一個 Wifi網路來連線了。要進行連線必須使用以下指令:
指令「AT+CWJAP」
「AT+CWJAP=<SSID>,<Password>」連線到已存在的無線網路。
「AT+CWJAP?」查詢已連線到的無線網路。
<SSID>:無線網路的識別名稱(要加引號)。
<Password>:無線網路的密碼(要加引號)。
如果需要切斷 Wifi連線,我們可以也可使用這個指令:
指令「AT+CWQAP」
切斷已連線的無線網路。 

與目標裝置連線

雖然 ESP8266 已經連線到 Wifi,但是如果 ESP8266要跟同一個 Wifi中的其他裝置通訊,就必須要再跟該裝置建立 Socket連線。

ESP8266有兩種跟裝置建立 Socket連線的方式:
  1. 由 ESP8266扮演伺服器,等候其他裝置(客戶端)來與自己連接。
  2. 由其他裝置扮演伺服器,由 ESP8266(扮演客戶端)去主動連接該伺服器。
這兩種不同的方式,適合不同的情況,各有利弊。

一般來說,伺服器扮演的是類似店家的角色,必須經常保持待命,不可以隨便從Wifi中離線,否則客戶端就會找不到伺服器。所以我們必須評估連線的兩端,誰比較適合當伺服器或客戶端。或者連線的兩方都扮演客戶端,而讓第三方扮演伺服器,作為兩客戶端之間的橋梁,為他們轉送資訊。

當然,如果你只是要做個自己玩的玩具,想讓手機和遙控車一對一連線,那其實選哪個都可以,丟銅板隨便選一個就好。

要特別注意的是,如果要讓 ESP8266進入伺服器模式,必須先進行「多重連線」的設定。這個設定會影響 ESP8266是否能夠進行一對多的連線。而只有當「多重連線」被設定為開啟,ESP8266才能夠進入伺服器模式。
指令「AT+CIPMUX」
「AT+CIPMUX?」查詢目前的設定值
「AT+CIPMUX=1」允許一對多的多重連線。
「AT+CIPMUX=0」關閉多重連線,只能一對一連線。此時無法進入伺服器模式。
現在,我們可以來決定要讓 ESP8266扮演伺服器或客戶端了。

如果要讓 ESP8266扮演伺服器,等候客戶端的連線,我們需要使用以下指令:
指令「AT+CIPSERVER」
「AT+CIPSERVER= <mode>[,<port>]」開啟(或關閉)伺服器,等候客戶端透過指定的連接埠(Port)連線。
<mode>:0關閉伺服器,1開啟。
<port>:網路連接埠號碼。範圍從 0~65535皆可。連線到伺服器的裝置必須知道連接埠(Port)號碼才能進行連線。一般根據不同的用途,會有慣用的連接埠號碼,不過並沒有強制性。我們可以在49152到65535之間選一個號碼即可。
※注意:這裡的 Port和文章前半段所說的 Port是不同的東西。前面提到的 Port是「序列埠」(Serial Prot 或 COM Port),而此處的 Prot是「網路連接埠」(TCP/UDP Port)。

如果要讓 ESP8266扮演客戶端,對伺服器進行連線,我們需要使用以下指令:
指令「AT+CIPSTART」
「AT+CIPSTART=?」查詢目前已經建立的連線資訊。
「AT+CIPSTART =<type>,<addr>,<port>」建立連線,只適用於CIPMUX=0的情況。
「AT+CIPSTART=<id>,<type>,<addr>,<port>」建立連線,只適用於CIPMUX=1的情況。
<id>:範圍 0~4。推測最多可以連線到5台伺服器,這是用來代表此連線的代號。
<type>:連線類型,可為"TCP"或"UDP"(要加引號)。
<addr>:連線的 IP位址,如"192.168.43.31"(要加引號)。
<port>:伺服器接受連線的連接埠(Port)號碼(這個不用加引號)。
如果我們讓 ESP8266扮演伺服器,那麼我們必須知道 ESP8266的 IP位址,如此其他裝置才能根據這個 IP與 ESP8266連線。透過這個指令,我們就可以查詢到 ESP8266的 IP位址。
指令「AT+CIFSR」
顯示 ESP8266自己目前的 IP位址。
一旦連線建立之後,我們就可以透過以下指令傳送訊息:
指令「AT+CIPSEND」
「AT+CIPSEND=<length>」只適用於 CIPMUX=0 的情況。
「AT+CIPSEND=<id>,<length>」只適用於 CIPMUX=1 的情況。
<id>:在多重連線的情況下,需要輸入連線的代號,ESP8266才會知道要把訊息發送給哪一條連線。
<length>要發送的訊息長度。等到此指令發送出去之後,會出現「>」符號在螢幕,這時就可以輸入符合訊息長度的訊息。
最後如果要中斷連線,則可以使用以下指令:
指令「AT+CIPCLOSE」
「AT+CIPCLOSE=<id>」中斷指定的連線。適用於 CIPMUX=1 的情況
「AT+CIPCLOSE」中斷連線。適用於 CIPMUX=0 的情況
<id>:要中斷的連線代號。
※其他完整的指令,請參閱這個檔案(備用載點)。

 實際操作範例

以下我使用更新過韌體,Baud Rate為9600的 ESP8266進行操作。
首先我輸入「AT」和「AT+GMR」指令進行測試,並得到以下的結果:


接著,我想將 ESP8266連線到我的 Wifi「commandship」。

我先把的 Wifi連線模式設為 Station模式:
AT+CWMODE=1
由於我之前已經將它的模式設定為1了 (它在斷電重開後仍然會保留設定),因此得到的回應為「No Change」:

列出目前的Wifi清單:
AT+CWLAP
回應:

在這串裡面,我們看到共有四個Wifi被找到,而其中就有我要找的 Wifi:"commandship"。

現在,就要來與它連線了。
指令與回應:
AT+CWJAP="commandship","123456789"

OK
現在我們成功連線到 Wifi了。

接著,我要把「多重連線」打開,並讓 ESP8266進入伺服器模式,等候其他裝置與它連線:
AT+CIPMUX=1

OK                                                                            
AT+CIPSERVER=1,8087

OK
好了,現在 ESP8266已經進入伺服器模式了。接著我們還需要知道它的 IP,這樣別的裝置才能透過這個 IP與它連線通訊:
AT+CIFSR
192.168.43.45

OK 
接著我們需要準備另一個連到同一個 Wifi的裝置,去跟 ESP8266連線通訊。我決定使用我自己的筆記型電腦,讓它也連到 Wifi:"commandship"。這樣一來,我的筆電就可以與 ESP8266通訊了。

我自己寫了一個通訊程式「Connector-Test」。只要在筆電上使用這個程式,就能透過 Wifi連線到 扮演伺服器的 ESP8266了。這個程式可在此下載,且必須先安裝 Adobe Air才能使用。

開啟程式之後,可以選擇要扮演伺服器或客戶端。


因為 ESP8266扮演伺服器,所以筆電這端就需要扮演客戶端,才可以與它連線。


輸入剛剛 ESP8266告訴我們的 IP就可以連線了。本來應該也要輸入 Port才對,不過我的這個軟體預設就是使用 8087作為 Port,所以可以省略。這也是為什麼剛剛在設定 ESP8266時使用這個 Port號碼的原因。

一按下開始,就馬上看到好消息:


而 ESP8266這邊也同樣出現好消息「Link」,表示連上了:


所以接下來,它們就可以互相傳送訊息了。

在程式中輸入「hi」並按下 Enter後,訊息就傳到 ESP8266那裡了:
反過來,在 ESP8266中輸入指令:
AT+CIPSEND=0,5
> HELLO
busy s...

SEND OK
第一行命令的 0是連線的代號。第一個跟伺服器連線的裝置,連線代號就是0,第二個就是1,依此類推,也可以透過「AT+CIPSTATUS」指令去查詢共有幾個裝置連線到伺服器,以及這些連線的代號。第一行命令的5,是要傳送的訊息字元數,我們想傳送的"HELLO"訊息共5個字元。第一行命令發送出去後,出現「>」符號時,就可以輸入訊息"HELLO"了。

訊息送出之後,在程式那端就收到了:


現在我們終於大功告成,讓 ESP8266和筆電透過 Wifi通訊囉~~~~~~

※推薦參考文章:〈操控 ESP8266 無線模組 - 經由 AP、STA 和 AP+STA 三種模式,學習 ESP8266 AT 指令〉該文章作者使用了不同的軟體,並成功使用手機與 ESP8266的通訊。條條大路通羅馬,只要抓住基本的觀念,就可以用不同的方法和工具,達到同樣的目標。

下回預告

我們已經距離Wifi遙控車又近了一步。下一篇文章,是關於如何讓 Arduino透過 AT Command 操作 ESP8266,讓它跟 筆電(或手機)通訊。不過,要等我把實驗做出來再說囉~~

第二集請看這裡