2015年10月30日 星期五

撰寫 Arduino 的 ESP8266 WiFi 函式

ESP8266 的 AT 指令雖然簡單好用, 但若要在 Arduino 程式中發送與處理其回應訊息卻有點繁雜, 因此這兩天便思考如何將每一個 AT 指令寫成函式, 這樣主程式就只要呼叫函式即可, 會簡潔許多. 下面是此次實驗的紀錄, 當然也不是一次就 OK, 而是修修補補幾回才穩定下來.

因為手機以及鄉下與高雄的無線基地台之 SSID 與 PWD 都不同, 每次要用 ESP8266 連線不同的無線基地台做 Arduino 物聯網實驗時, 都必須先使用一條 USB-TTL 轉換線 (我用的是 PL2303HX) 連接 PC 與 ESP8266, 再用通訊程式如 Realterm 或 AccessPort 等連線 ESP8266 對其下達更改連線基地台之 AT 指令, 改好後又要拔掉 PL2303HX 再將 ESP8266 插回轉換板, 這樣杜邦線要拔來拔去實在很麻煩.

上回做 Arduino + ESP8266 連線 WiFi 實驗時, 意外地從 "阿喵就像家" 的簡報中發現 (page 83), 利用軟體序列埠函式庫就可以輕易地將 Arduino Nano 化身為 USB-TTL 轉換線, 可以直接用 Arduino IDE 對 ESP8266 下 AT 指令, 連 Realterm/AccessPort 等通訊程式都免了, 我覺得這方法蠻好用的, 我記錄在之前這篇 :

ESP8266 WiFi 模組與 Arduino 連線測試

下面的 WiFi 函式測試也是使用同樣的方法. 在過去的兩周, 我把 AMS1117V33/LD1117V33 與 1K+2K 電阻都焊在一塊洞洞板上面, 外加一個滑動開關來切換 CH_PD 之可控/不可控, 以及排針排母等元件製作了一個 ESP8266 轉接板, 大大降低了麵包板連線的麻煩, 只要四條線即可將 5V 運作的 Nano 與 3.3V 運作的 ESP8266 相連 , 如下圖所示 :



轉接板參考前篇 :

製作 ESP8266 轉接板

如果不想費工地去焊轉接板的話, 也可以照下面電路圖在麵包板上接線, 只需要 1K+2K 兩個元件而已 :


ESP8266 的 Vcc 取自 Nano 的 3.3v 輸出即可, 但如果發現 ESP8266 不穩定, 通常是電源不夠力, 這時就需要獨立的 3.3V 電源供應, 可用兩個 1.5V 乾電池串聯起來供電. 接好線後, 將下列程式上傳到 Arduino Nano 就可以利用序列埠監視視窗對 ESP01 模組下 AT 指令了, 參考 :

# ESP8266 WiFi 模組 AT command 測試

#include <SoftwareSerial.h>
SoftwareSerial sSerial(10,11); //(RX,TX)

void setup() {
  sSerial.begin(9600);  //軟體序列埠速率 (與硬體同步調整)
  Serial.begin(9600);    //硬體序列埠速率 (與軟體同步調整)
  Serial.println("SoftSerial to ESP8266 AT commands test ...");
  }

void loop() {
  if (sSerial.available()) {   //若軟體序列埠 Rx 收到資料 (來自 ESP8266)
    Serial.write(sSerial.read());  //讀取後寫入硬體序列埠 Tx (PC)
    }
  if (Serial.available()) {  //若硬體序列埠 Rx 收到資料 (來自 PC)
    sSerial.write(Serial.read());  //讀取後寫入軟體序列埠 Tx (ESP8266)
    }
  }

送電後打開序列埠監視視窗, 若出現 "SoftSerial to ESP8266 AT commands test ...", 表示這顆 ESP8266 之 Baud rate 是設定在 9600, 如果出現怪碼或無反應, 那麼 Baud rate 就不對, 可以嘗試將程式中的 9600 都改為 115200 上傳試試看. 我之前跟露天賣家買的一批 20 顆 ESP01 模組 AT 版本為 0.9.5, 預設速率就是 115200 bps, 所以一開始用 9600 連線都出現怪碼, 改成 115200 後即可正常顯示. 連線成功後下指令更改 Baud rate :

AT+UART=9600,8,1,0,0

然後關掉序列埠監視視窗後重開, 更改右下角之 Baud rate 為 9600 即可. 注意, 這個 AT+UART 指令在 0.9.5 版可用, 但在 0.9.2 不行. 韌體版本 0.9.2 的 AT 指令測試參考 :

ESP8266 WiFi 模組 AT command 測試

以下是我針對最穩定的 0.9.2 版韌體, 在上面 SoftwareSerial 函式庫支援下所撰寫的 WiFi 函式, 基本上就是把 AT 指令的操作細節包裝起來而已.

首先是定義一個讀取 ESP8266 回應字元的函式 get_ESP8266_response(), 它會將 ESP8266 傳回給軟體串列埠 RX 的回應字元以字串的 concat() 函式串接成回應字串, 去除頭尾的空白字元 (例如跳行與空格) 後傳回, 這樣我們便能從傳回的回應字串中搜尋關鍵字, 判斷 AT 指令是否執行成功, 或者擷取回應資訊, 例如 IP 等等 :

String get_ESP8266_response() {  //取得 ESP8266 的回應字串
  String str="";  //儲存接收到的回應字串
  char c;  //儲存接收到的回應字元
  while (sSerial.available()) {  //若軟體序列埠接收緩衝器還有資料
    c=sSerial.read();  //必須放入宣告為 char 之變數 (才會轉成字元)
    str.concat(c);  //串接回應字元
    delay(10);  //務必要延遲, 否則太快
    }
  str.trim();  //去除頭尾空白字元
  return str;
  }

注意這裡必須把讀取的字元先放在宣告為 char 的變數中再用 concat 串接, 不可直接丟給 concat, 例如 concat(sSerial.read()), 這樣它會以字元的整數值來串接, 而不是字元. 其次是迴圈裡最後要用 delay() 來延遲一下讀取速度, 否則會太快而讀不到任何東西.

為甚麼要把回應字元抄個副本來處理, 不直接用序列埠的 find() 去搜尋關鍵字呢? 主要的原因是 find() 函式會把接收緩衝區裡讀過的字元讀取過的字元都移除, 導致整個接收緩衝區的完整性被第一次的 find() 函式破壞, 如果需要對回應進行兩次搜尋, 那麼第二次的 find() 可能永遠也不會找到關鍵字, 即使那個關鍵字確實存在, 因為它可能已經被第一次的 find() 抹除了. 參考 :

Does Serial.find Clears Buffer If It Can't Find Anything

在這篇疑難的解答中有提到 "Serial.find() reads Serial buffer and removes every single byte from it", 亦即 find() 每讀取一個字元, 就會將其自接收緩衝區刪除. 但是在官網關於 Serial.find() 的說明卻沒有特別提到這一點, 參考 :

https://www.arduino.cc/en/Serial/Find

其實這主要在 AT+CWMODE 指令會有此問題, 其他 AT 指令大概無此問題. 若工作模式有變, 例如從 1 變 3, 它會回應 OK; 但若不變, 例如原先是 1, 又下 AT+CHMODE=1, 則會回應 "no change". 從下面以 AT 指令操作的回應訊息即可了解 :

AT+CWMODE?

+CWMODE:1     (目前為模式 1=Station)

OK
AT+CWMODE=3    (改為模式 3=AP+Station)


OK      (模式有改變回應 OK)
AT+CWMODE=3     (改為模式 3=AP+Station)

no change    (模式沒變回應 no change)

因此這兩種回應都是表示指令有正常執行, 因此必須做 sSerial.find("OK") || sSerial.find("no change") 的判斷, 但由於 find() 執行後會把緩衝區刪掉, 因此第二個 find() 永遠不會 true. 例如下面這個範例程式  :

#include <SoftwareSerial.h>
SoftwareSerial sSerial(10,11); //(RX,TX) 與 ESP8266 介接的軟體串列埠

void setup() {
  sSerial.begin(9600);  //設定軟體序列埠速率 (to ESP8266)
  Serial.begin(9600);  //設定軟體序列埠速率 (to PC)
  Serial.print("Set working mode as station ... ");
  sSerial.println("AT+CWMODE=1");  //設定為 Station 模式
  delay(1000);
  if (sSerial.find("OK") || sSerial.find("no change")) {
    Serial.println("OK");
    }
  else {
    Serial.println("No response");
    }
  }

void loop() {
  if (sSerial.available()) {   //若軟體序列埠 Rx 收到資料 (來自 ESP8266)
    Serial.write(sSerial.read());  //讀取後寫入硬體序列埠 Tx (PC)
    }
  if (Serial.available()) {  //若硬體序列埠 Rx 收到資料 (來自 PC)
    sSerial.write(Serial.read());  //讀取後寫入軟體序列埠 Tx (ESP8266)
    }
  }

在執行前先用手動方式用 AT+CWMODE=3 設定為模式 3, 然後再按兩次 Arduino 的 reset 鍵重新執行, 其回應結果為 :

AT+CWMODE=3


OK
Set working mode as station ... OK  (第一次, mode 3 改成 mode 1, 回應 OK)

Set working mode as station ... No response  (第二次, mode 1 改成 mode 1, 回應 No response)

其實往後再按 Reset 重新執行都是 No response, 因為  sSerial.find("OK") 執行完後, 接收緩衝區內已空無一物, 所以 sSerial.find("no change") 當然找不到 no change 啦. 如果使用上面這個 get_ESP8266_response() 函式先讀取接收緩衝區, 將其拷貝到字串變數中就可以避免此問題, 如下列範例所示 :

#include <SoftwareSerial.h>
SoftwareSerial sSerial(10,11); //(RX,TX) 與 ESP8266 介接的軟體串列埠

void setup() {
  sSerial.begin(9600);  //設定軟體序列埠速率 (to ESP8266)
  Serial.begin(9600);  //設定軟體序列埠速率 (to PC)
  Serial.print("Set working mode as station ... ");
  sSerial.println("AT+CWMODE=1");  //設定為 Station 模式
  delay(1000);
  String str=get_ESP8266_response();  //取得 ESP8266 回應字串
  if (str.indexOf("OK") != -1 || str.indexOf("no change") != -1) {
    Serial.println("OK");
    }
  else {Serial.println("No response");}
  }

void loop() {
  if (sSerial.available()) {   //若軟體序列埠 Rx 收到資料 (來自 ESP8266)
    Serial.write(sSerial.read());  //讀取後寫入硬體序列埠 Tx (PC)
    }
  if (Serial.available()) {  //若硬體序列埠 Rx 收到資料 (來自 PC)
    sSerial.write(Serial.read());  //讀取後寫入軟體序列埠 Tx (ESP8266)
    }
  }

  String get_ESP8266_response() {  //取得 ESP8266 的回應字串
  String str="";  //儲存接收到的回應字串
  char c;  //儲存接收到的回應字元
  while (sSerial.available()) {  //若軟體序列埠接收緩衝器還有資料
    c=sSerial.read();  //必須放入宣告為 char 之變數 (才會轉成字元)
    str.concat(c);  //串接回應字元
    delay(10);  //務必要延遲, 否則太快
    }
  str.trim();  //去除頭尾空白字元
  return str;
  }

其回應如下 :

AT+CWMODE?   (手動查詢工作模式)

+CWMODE:1   (目前工作模式為 1)

OK
AT+CWMODE=3   (手動改為工作模式 3)


OK   (按 Reset)
Set working mode as station ... OK   (按 Reset)
Set working mode as station ... OK   (按 Reset)
Set working mode as station ... OK   (按 Reset)
Set working mode as station ... OK   (按 Reset)

可見不管是 ESP8266 第一次回應的 "OK" 或之後的 "no change", Arduino 都會輸出 OK 表示 ESP8266 回應正常, 如此 find() 的問題便解決了.

接下來就可以為 ESP8266 的每一個 AT 指令撰寫函式, 以後直接呼叫即可, 不用再處理繁雜的序列埠讀寫了. 下面是我針對 0.9.2 版 AT 指令韌體所撰寫的 AT WiFi 函式, 以及相關的測試程式, 主要是用在把 ESP8266 當 Station 用的情況, 沒有包含 Station + AP 以及當 Server 時的函式 (以後用到再說) :

#include <SoftwareSerial.h>
SoftwareSerial sSerial(10,11); //(RX,TX) 與 ESP8266 介接的軟體串列埠
String ssid="H30-L02-webbot";  //無線基地台識別
String pwd="blablabla";  //無線基地台密碼

void setup() {
  sSerial.begin(9600);  //設定軟體序列埠速率 (to ESP8266)
  Serial.begin(9600);  //設定軟體序列埠速率 (to PC)
  Serial.println("*** SoftSerial connection to ESP8266 ***");
  Serial.println("Firmware version : " + get_version());
  Serial.println("Baud rate : " + get_baud());
  Serial.println("Get IP : " + get_ip());
  Serial.println("Mode : " + get_mode());
  Serial.println("Set Mode=3 : " + set_mode(3));  
  Serial.println("Mode : " + get_mode());
  Serial.println("Set Mode=1 : " + set_mode(1));  
  Serial.println("Mode : " + get_mode());
  Serial.println("Mux : " + get_mux());
  Serial.println("Set Mux=1 : " + set_mux(1));
  Serial.println("Mux : " + get_mux());
  Serial.println("Set Mux=0 : " + set_mux(0));
  Serial.println("Mux : " + get_mux());  
  Serial.println("Get AP : " + get_ap());      
  Serial.println("Quit AP : " + quit_ap());  
  Serial.println("Get AP : " + get_ap());
  Serial.println("Get IP : " + get_ip());    
  Serial.println("Joint AP : " + joint_ap(ssid, pwd));
  Serial.println("Get AP : " + get_ap());
  Serial.println("Get IP : " + get_ip());
  Serial.println("Connect Google : " + start_tcp("www.google.com",80));
  Serial.println("Send GET : " + send_data("GET /"));
  Serial.println("Connect Thingspeak : " + start_tcp("184.106.153.149",80));
  Serial.println("Send GET : " + send_data("GET /update?api_key=NO5N8C7T2KINFCQE&field1=28.00&field2=82.40&field3=81.00"));        
  }

void loop() {
  if (sSerial.available()) {  //若軟體串列埠 RX 有收到來自 ESP8266 的回應字元
    Serial.write(sSerial.read());  //在串列埠監控視窗顯示 ESP8266 的回應字元
    }
  if (Serial.available()) {  //若串列埠 RX 有收到來自 PC 的 AT 指令字元 (USB TX)
    sSerial.write(Serial.read());  //將 PC 的傳來的字元傳給 ESP8266
    }
  }

String get_ESP8266_response() {  //取得 ESP8266 的回應字串
  String str="";  //儲存接收到的回應字串
  char c;  //儲存接收到的回應字元
  while (sSerial.available()) {  //若軟體序列埠接收緩衝器還有資料
    c=sSerial.read();  //必須放入宣告為 char 之變數 (才會轉成字元)
    str.concat(c);  //串接回應字元
    delay(10);  //務必要延遲, 否則太快
    }
  str.trim();  //去除頭尾空白字元
  return str;
  }

String get_version() {
  sSerial.println("AT+GMR");  //取得韌體版本
  sSerial.flush();  //等待序列埠傳送完畢
  delay(1000);
  String str=get_ESP8266_response();  //取得 ESP8266 回應字串
  if (str.indexOf("OK") == -1) {return "NG";}
  else {return str.substring(0,str.indexOf("\r\n"));}
  }

String get_baud() {
  sSerial.println("AT+CIOBAUD?");  //取得傳送速率
  sSerial.flush();  //等待序列埠傳送完畢
  delay(1000);
  String str=get_ESP8266_response();  //取得 ESP8266 回應字串
  if (str.indexOf("OK") == -1) {return "NG";}
  else {return str.substring(str.indexOf(":")+1,str.indexOf("\r\n"));}
  }

String get_ip() {
  sSerial.println("AT+CIFSR");  //取得 ESP8266 IP
  sSerial.flush();  //等待序列埠傳送完畢
  delay(1000);
  String str=get_ESP8266_response();  //取得 ESP8266 回應字串
  if (str.indexOf("OK") == -1) {return "NG";}
  else {return str.substring(0,str.indexOf("\r\n"));}
  }

String get_mode() {
  sSerial.println("AT+CWMODE?");  //取得工作模式
  sSerial.flush();  //等待序列埠傳送完畢
  delay(1000);
  String str=get_ESP8266_response();  //取得 ESP8266 回應字串
  if (str.indexOf("OK") != -1) {
    return str.substring(str.indexOf(":")+1,str.indexOf("\r\n"));
    }
  else {return "NG";}
  }

String set_mode(byte mode) {
  sSerial.println("AT+CWMODE=" + String(mode));  //設定工作模式
  sSerial.flush();  //等待序列埠傳送完畢
  delay(1000);
  String str=get_ESP8266_response();  //取得 ESP8266 回應字串
  if (str.indexOf("OK") != -1 || str.indexOf("no change") != -1) {return "OK";}
  else {return "NG";}
  }

String get_mux() {
  sSerial.println("AT+CIPMUX?");  //取得連線模式
  sSerial.flush();  //等待序列埠傳送完畢
  delay(1000);
  String str=get_ESP8266_response();  //取得 ESP8266 回應字串
  if (str.indexOf("OK") != -1) {
    return str.substring(str.indexOf(":")+1,str.indexOf("\r\n"));
    }
  else {return "NG";}
  }

String set_mux(byte mux) {  //0=single, 1=multiple
  sSerial.println("AT+CIPMUX=" + String(mux));  //設定連線模式
  sSerial.flush();  //等待序列埠傳送完畢
  delay(1000);
  String str=get_ESP8266_response();  //取得 ESP8266 回應字串
  if (str.indexOf("OK") != -1) {return "OK";}
  else {return "NG";}
  }

String get_ap() {
  sSerial.println("AT+CWJAP?");  //取得連線之AP
  sSerial.flush();  //等待序列埠傳送完畢
  delay(1000);
  String str=get_ESP8266_response();  //取得 ESP8266 回應字串
  if (str.indexOf("OK") != -1) {
    return str.substring(str.indexOf(":")+1,str.indexOf("\r\n"));
    }
  else {return "NG";}
  }

String joint_ap(String ssid, String pwd) {
  sSerial.println("AT+CWJAP=\"" + ssid + "\",\"" + pwd + "\"");  //連線
  sSerial.flush();  //等待序列埠傳送完畢
  delay(7000);
  String str=get_ESP8266_response();  //取得 ESP8266 回應字串
  if (str.indexOf("OK") != -1) {return "OK";}
  else {return "NG";}
  }

String quit_ap() {
  sSerial.println("AT+CWQAP");  //離線
  sSerial.flush();  //等待序列埠傳送完畢
  delay(1000);
  String str=get_ESP8266_response();  //取得 ESP8266 回應字串
  if (str.indexOf("OK") != -1) {return "OK";}
  else {return "NG";}
  }

String start_tcp(String address, byte port) {
  sSerial.println("AT+CIPSTART=\"TCP\",\"" + address + "\"," + String(port));
  sSerial.flush();  //等待序列埠傳送完畢
  delay(1000);
  String str=get_ESP8266_response();  //取得 ESP8266 回應字串
  if (str.indexOf("Linked") != -1) {return "OK";}
  else {return "NG";}
  }

String send_data(String s) {
  String s1=s + "\r\n";  //務必加上跳行
  sSerial.println("AT+CIPSEND=" + String(s1.length()));
  sSerial.flush();  //等待序列埠傳送完畢
  delay(1000);
  String str=get_ESP8266_response();  //取得 ESP8266 回應字串
  if (str.indexOf(">") != -1) {  //收到 > 開始傳送資料
    sSerial.println(s1); //傳送資料
    sSerial.flush();  //等待序列埠傳送完畢
    delay(7000);  
    str=get_ESP8266_response();  //取得 ESP8266 回應字串
    if (str.indexOf("+IPD") != -1) {return "OK";}  //傳送成功會自動拆線
    else {  //傳送不成功須自行拆線
      close_ip();  //關閉 IP 連線
      return "NG";
      }  
    }
  else {  //傳送不成功須自行拆線
    close_ip();  //關閉 IP 連線
    return "NG";
    }
  }

String close_ip() {
  sSerial.println("AT+CIPCLOSE");  //關閉 IP 連線
  sSerial.flush();  //等待序列埠傳送完畢
  delay(1000);
  String str=get_ESP8266_response();  //取得 ESP8266 回應字串
  if (str.indexOf("OK") != -1) {return "OK";}
  else {return "NG";}
  }

上面的函式中, 處理上比較特殊的是 set_mode(), start_tcp(), 以及 send_data() 這三個函式, set_mode() 已如上述, 有兩種成功的回應要處理; start_tcp() 是在剖析回應時尋找 "Linked" 這個關鍵字來判斷連線是否有建立; 而 send_data() 則有兩階段剖析, 第一階段是搜尋是否出現 > 符號以便傳送資料, 第二階段是搜尋是否有 +IPD 回應字串, 有的話才是傳送成功. 大部分的操作成功回應 "OK", 失敗回應 "NG"; 有些擷取資訊的例如, get_version(), get_baud() 等則是成功時傳回從回應訊息中過濾取得之資訊.

其次, 在 set_mode(), set_mux() 等函式中, 傳入參數為數值 (byte), 要組成 AT 指令字串時必須先用 String() 將其轉成字串才能串接, 否則會是空白. 另外, 在這個範例中的最後面, 我測試了 TCP 連線函式 start_tcp() 與 send_data(), 分別與 Google 首頁與物聯網伺服器 Thingspeak 建立 TCP 連線, 然後用 HTTP 的 GET 方法向伺服器提出 Request, 從回應可知均能得到正常回應, 檢查 Thingspeak 的 public 網頁, 確實有寫入資料庫. 關於利用 TCP 連線傳送資料, 參考 :

# ESP8266 WiFi 模組與 Arduino 連線測試
# 用 ESP8266 的 TCP/IP 連線抓取網頁

另外, 在上面的函式中, 向 ESP8266 傳送 AT 指令後, 都呼叫了序列埠物件的 flush() 函式, 功能是讓執行程序停住, 直到傳送緩衝區將 AT 指令全部傳送完畢再繼續往下執行, 參考 :

# https://www.arduino.cc/en/Serial/Flush

在下面這篇文章裡有特別提到 flush() 函數功能在 Arduino IDE 1.0 後的改變 :

When do you use the Arduino’s Serial.flush()? 

"The key to that statement is “outgoing”.  Serial.flush() doesn’t clear the “incoming” buffer, like many people think.  It pauses your program until the transmit buffer is finished."

這個函數名稱 flush() 容易讓人誤解為清掉接收緩衝區, 這在 Arduino IDE 1.0 以前確實是如此, 但現在不同了. 想要清空接收緩衝區的話, 必須呼叫 read() 函數一個一個字元去讀取, 每讀取一個字元, 接收緩衝區就會清掉一個字元, 這可以用 while 迴圈來完成 :

while (sSerial.available()) {sSerial.read();} //清空接收緩衝器

最後列出上面測試程式的回應並註解如下 :

*** SoftSerial connection to ESP8266 ***
Firmware version : 0018000902
Baud rate : 9600
Get IP : 192.168.43.151
Mode : 1   (目前為模式 1)
Set Mode=3 : OK  (改為模式 3)
Mode : 3   (目前為模式 3)
Set Mode=1 : OK  (改回模式 1)
Mode : 1   (目前為模式 1)
Mux : 0      (目前為單一連線)
Set Mux=1 : OK    (改為多重連線)
Mux : 1     (目前為多重連線)
Set Mux=0 : OK    (改回單一連線)
Mux : 0     (目前為單一連線)
Get AP : "H30-L02-webbot"    (顯示目前連線之 AP)
Quit AP : OK   (離線)
Get AP : NG    (目前沒有與 AP 連線)
Get IP : 0.0.0.0    (離線時預設 IP 為 0.0.0.0)
Joint AP : OK  (連線指定之 AP)
Get AP : "H30-L02-webbot"   (顯示目前連線 AP 之 SSID)
Get IP : 192.168.43.151   (顯示 ESP8266 取得之 IP)
Connect Google : OK   (連線 Google 首頁成功)
Send GET : OK   (向 Google 首頁傳送 GET 要求成功)
Connect Thingspeak : OK    (連線 Thingspeak 成功)
Send GET : OK   (向 Thingspeak 傳送 GET 要求成功)

可見所有函式均能正常運作. 這次測試時發現, 不知道為何, TCP 連線在 AT+CIPMUX=1 (多重連線) 下無法完成連線, 但只要改回單一連線即可.

其他參考 :

ESP8266 Wifi Temperature Logger

Serial Input Basics
Functions - return array or multiple variables?
Convert serial.read() into a useable string using Arduino?
How to convert int to string on Arduino?

2015-10-31 補充 :

今天在網路上找到跟我上面寫的 WiFi 函數類似的函式庫, 看起來更完整, 是專家寫的吧! 不過它主要是支援 UNO 與 MEGA, 而我寫的是針對 Nano/Pro mini, 參考 :

ITEADLIB_Arduino_WeeESP8266

有時間再仔細看看人家是怎麼寫的, 偷學幾招!

2015-11-01 補充 :

下面這篇的 waitForResponse() 寫法也有參考價值 :

# Using an ESP8266 as a time source (Part 1)


7 則留言 :

Unknown 提到...

您好
我目前嘗試使用esp8266+hm-10做接收beacon資訊的功能
不過目前遇到透過SoftwareSerial接收回來的值會不完整
請問一下這邊該如何解決?

小狐狸事務所 提到...

Sorry, 我還沒玩過藍芽, 但軟體序列埠資料不全問題可能跟緩衝器大小有關, 您可參考下面這篇調整緩衝器大小的方法試試看 :

http://yhhuang1966.blogspot.tw/2016/06/arduino-esp8266-ntp_12.html

Unknown 提到...

您好
感謝您得回覆
我後來有解決問題了
我是使用esp8266開發
後來是直接在宣告時加入buffer size的參數

Unknown 提到...

您好,我試著用您的最後一個程式讓arduino自己傳送指令到esp8266,但回應的結果如下:
*** SoftSerial connection to ESP8266 ***
Firmware version : AT+GMR

Baud rate :
+CIOBAUD:
Get IP : AT+CIFSR

Mode :
+CWMODE:
Set Mode=3 : OK
Mode :
+CWMODE:
Set Mode=1 : OK
Mode :
+CWMODE:
Mux :
+CIPMUX:
Set Mux=1 : OK
Mux :
+CIPMUX:
Set Mux=0 : OK
Mux :
+CIPMUX:
Get AP :
+CWJAP:
Quit AP : OK
Get AP : NG
Get IP : AT+CIFSR

Joint AP : OK
Get AP :
+CWJAP:
Get IP : AT+CIFSR

Connect Google : OK
Send GET : OK
Connect Thingspeak : OK
Send GET : NG
只有回應ok的程式可運作,但回傳不了如ip之類的資訊,請問問題出在哪?

小狐狸事務所 提到...

應該是韌體版本不同的關係, 我燒錄的是較舊但蠻穩定的 0018000902 (0.9.2) 版本, 請參考下列這篇燒錄看看 :

http://yhhuang1966.blogspot.tw/2015/08/esp8266.html

匿名 提到...

狐狸大大您好:
我們無法在ESP8266模式三的時候上傳資料到資料庫(改成模式三是看您的"AllAboutEE的ESP8266 伺服器測試 (一)"這篇文章),但是在模式一的時候可以。
然後
想請問您
1.這段程式碼跟改模式有相關嗎~?
boolean connectWiFi()
{
debug.println("AT+CWMODE=1");
Wifi_connect();
}

2.我們應該怎麼確定ESP8266是在甚麼模式~

3.我們把ESP8266改成模式三之後沒有跑出station的IP,請問是為甚麼~?

謝謝您撥空回答!!!!!!!!!!!!!!

小狐狸事務所 提到...


您好 :
1. AT+CWMODE=1 是設定為模式 1 (sta), 關閉內建伺服器, 只做 station 用
2. 下 AT 指令 AT+CWMODE? 即可得知目前模式
3. 模式 3 會有兩個 IP, 一是內建伺服器的 192.168.4.1 (固定), 二是從 DHCP 獲得的 station IP. 若沒有顯示 station IP, 表示 ESP8266 並沒有與 WIFI 基地台連線, 要檢查 SSID 與 PWD 是否正確.

如果不會用到內建伺服器, 其實只要打開模式 1 就好.