# 撰寫 Arduino 的 ESP8266 WiFi 函式
為了確定是否跟 MODE 為 1 或 3 有關, 今天又在快完成的 WiFi 函數的基礎上再進行測試. 結果 : 與工作模式無關, 只要是多重連線, TCP 連線就會失敗. 測試程式如下 :
#include <SoftwareSerial.h>
SoftwareSerial sSerial(10,11); //(RX,TX) 與 ESP8266 介接的軟體串列埠
String ssid="EDIMAX-tony"; //無線基地台識別
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("Set Mode=1 : " + set_mode(1));
Serial.println("Mode : " + get_mode());
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("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";}
}
其輸出如下 :
*** SoftSerial connection to ESP8266 ***
Firmware version : 0018000902
Set Mode=1 : OK
Mode : 1
Mux : 0
Set Mux=0 : OK
Mux : 0
Get AP : "H30-L02-webbot"
Get IP : 192.168.43.151
Connect Google : OK (成功)
Send GET : OK
Connect Thingspeak : OK (成功)
Send GET : OK
可見在 mode=1 (station), mux=0 (single) 時, TCP 連線可正常建立. 接下來測試 mode=1 (station), mux=1 (multiple) 情況, 下面只列測試程式, 函式不再列出 :
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("Set Mode=1 : " + set_mode(1)); //Station mode
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("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"));
}
其輸出為 :
*** SoftSerial connection to ESP8266 ***
Firmware version : 0018000902
Set Mode=1 : OK
Mode : 1
Mux : 0
Set Mux=1 : OK
Mux : 1
Get AP : "H30-L02-webbot"
Get IP : 192.168.43.151
Connect Google : NG (失敗)
Send GET : NG
Connect Thingspeak : NG (失敗)
Send GET : NG
可見只要一改到多重連線, TCP 連線就無法順利建立了. 接下來要測試是否 mode 會影響 TCP 連線, 程式如下 :
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("Set Mode=3 : " + set_mode(3)); //Station+AP mode
Serial.println("Mode : " + get_mode());
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("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"));
}
其輸出如下 :
*** SoftSerial connection to ESP8266 ***
Firmware version : 0018000902
Set Mode=3 : OK
Mode : 3
Mux : 0
Set Mux=0 : OK
Mux : 0
Get AP : "H30-L02-webbot"
Get IP : 192.168.4.1
Connect Google : OK (成功)
Send GET : OK
Connect Thingspeak : OK (成功)
Send GET : OK
可見在模式 3, 單一連線情況下, TCP 連線沒問題. 若改為多重連線呢? 程式如下 :
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("Set Mode=3 : " + set_mode(3)); //Station+AP mode
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("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"));
}
輸出如下 :
*** SoftSerial connection to ESP8266 ***
Firmware version : 0018000902
Set Mode=3 : OK
Mode : 3
Mux : 0
Set Mux=1 : OK
Mux : 1
Get AP : "H30-L02-webbot"
Get IP : 192.168.4.1
Connect Google : NG (失敗)
Send GET : NG
Connect Thingspeak : NG (失敗)
Send GET : NG
由上面測試可知,0.9.2.2 版韌體在多重連線下, TCP 連線無法建立, 與模式是 Station 或 Sattion + AP 無關. Why? 難道是與韌體版本有關嗎? 下次有空再來測試看看 0.9.5 版.
2015-11-09 補充 :
原因找到了, 今天在測試 WeeESP8266 函式庫時發現, 原來是在多重連線模式下,必須指定代表連線之通道編號 (0~4) 才行. 參考 :
# ITEAD WeeESP8266 函式庫測試
因此我加寫了 start_tcp() 與 send_data() 這兩個函式的多型, 即多一個通道 id 參數來處理 :
#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("Set Mode=3 : " + set_mode(3)); //Station+AP mode
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("Get AP : " + get_ap());
Serial.println("Get IP : " + get_ip());
Serial.println("Connect Google : " + start_tcp(0,"www.google.com",80));
Serial.println("Send GET : " + send_data(0,"GET /"));
Serial.println("Connect Thingspeak : " + start_tcp(0,"184.106.153.149",80));
Serial.println("Send GET : " + send_data(0,"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 start_tcp(byte id, String address, byte port) {
sSerial.println("AT+CIPSTART=" + String(id) + ",\"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 send_data(byte id,String s) {
String s1=s + "\r\n"; //務必加上跳行
sSerial.println("AT+CIPSEND=" + String(id) + "," + 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";}
}
這裡因通道 id 為 byte 類型, 因此務必用 String() 函數將其字串化後再串接, 其輸出如下 :
*** SoftSerial connection to ESP8266 ***
Firmware version : 0018000902
Set Mode=3 : OK
Mode : 3
Mux : 1
Set Mux=1 : OK
Mux : 1
Get AP : "H30-L02-webbot"
Get IP : 192.168.4.1
Connect Google : OK
Send GET : OK
Connect Thingspeak : OK
Send GET : OK
這個問題終於解決了.
沒有留言:
張貼留言