好了, 言歸正傳, 昨晚翻閱 "Arduino Cookbook 錦囊妙計" 第 15 章乙太網路和網路連結 15.7 節 "處理傳進來的網路需求", 書中範例是用 Wiznet 乙太網路擴充板讓 Arduino 連上區網, 並將乙太網板設定為網頁伺服器, 由 Arduino 當 HTTP 協定處理器, 負責回應前端的網頁要求. 我是打算將乙太網改成 ESP8266 ESP01 板來進行同樣的實驗, 使用我自行焊接的 Nano+ESP8266 IOT 模組, 參考 :
# 製作 Arduino Nano + ESP8266 物聯網模組 (四) : 完結篇
本實驗的目的, 是要讓使用者以瀏覽器連線 Arduino 的網頁伺服器, 透過不同的網址來設定 Arduino 個針腳的值, 亦即, 可透過網路遠端控制 Arduino 的輸出入. 其網址格式為 :
http://192.168.2.104/?pinD2=1 (將 Arduino D2 針腳設為 HIGH 輸出)
http://192.168.2.104/?pinA5=1023 (將 Arduino A5 針腳設為 1023 輸出)
對 Arduino Nano 而言, 其可程式化輸出入腳如下 :
- 數位腳位 :
D0~D13 共 14 個, 其中 D0 (Rx) 與 D1 (Tx) 與 USB 共接; D3, D5,D6,D9~D11 六隻腳具有 PWM 類比模擬功能. - 類比腳位 :
A0~A6 共 7 個, 具有 A/D 轉換功能, 作為輸入時可將外部 0~5V 類比輸入轉為 0~1023 的數值; 反之作為輸出時可將 0~1023 的數值轉成 0~5V 的電壓輸出.
# Arduino Nano規格簡介
本實驗就是要透過網頁來遠端控制 Arduino 的 IO 腳的輸出. 下面程式的寫法參考了我為 IOT 模組所寫的 Wifi 設定程式碼, 參考 :
# 以 Arduino+ESP8266 物聯網模組重作 DHT11 溫溼度實驗
完整程式如下 :
測試 1 :
#include <SoftwareSerial.h>
#define DEBUG true
SoftwareSerial esp8266(7,8); //(RX,TX)
String ssid="H30-L02-webbot";
String pwd="1234567890";
void setup() {
Serial.begin(9600);
esp8266.begin(9600);
sendData("AT+RST\r\n",2000,DEBUG); // reset ESP8266
sendData("AT+CWMODE=1\r\n",1000,DEBUG); //configure as station
sendData("AT+CIPMUX=1\r\n",1000,DEBUG); //enable multiple connections
sendData("AT+CIPSERVER=1,80\r\n",2000,DEBUG); //turn on server 80 port
while (!connectWifi(ssid, pwd)) {
Serial.println("Connecting WiFi ... failed");
delay(2000);
}
sendData("AT+GMR\r\n",1000,DEBUG);
delay(3000); //wait for wifi connection to get local ip
sendData("AT+CIFSR\r\n",1000,DEBUG); //get ip address
}
void loop() {
if (esp8266.available()) { // check if esp8266 is sending message
int digitalRequests=0;
int analogRequests=0;
if (esp8266.find("+IPD,")) { //get client request
delay(1000); //waiting for response: ?pinD2=1 or ?pinA4=1023
int connectionId=esp8266.read()-48; //turn ASCII to number
if (esp8266.find("GET /?pin")) { //retrieve page name (router)
char type=(char)esp8266.read(); //read char after ?pin
int pin=esp8266.parseInt(); //get first int number from serial
int val=esp8266.parseInt(); //get first int number from serial
if (type=='D') {
Serial.print("Digital pin ");
pinMode(pin, OUTPUT); //set pin as ouput
digitalWrite(pin, val);
digitalRequests++;
}
else if (type=='A') {
Serial.print("Analog pin ");
analogWrite(pin, val);
analogRequests++;
}
else {
Serial.println("Unexpected type:" + type);
}
Serial.print(pin);
Serial.print("=");
Serial.println(val);
String webpage="<html>";
webpage += (String)digitalRequests + " digital pin(s) written<br>";
webpage += (String)analogRequests + " analog pin(s) written<br><br>";
for (byte i=0; i<6; i++) {
webpage += "A" + (String)i + "=" + (String)analogRead(i) + "<br>";
}
webpage += "</html>";
String cipSend="AT+CIPSEND=";
cipSend += connectionId;
cipSend += ",";
cipSend += webpage.length();
cipSend += "\r\n";
sendData(cipSend,1000,DEBUG);
sendData(webpage,2000,DEBUG);
sendData("AT+CIPCLOSE=" + (String)connectionId + "\r\n",3000,DEBUG);
}
}
}
}
boolean connectWifi(String ssid, String pwd) {
String res=sendData("AT+CWJAP=\"" + ssid + "\",\"" + pwd + "\"\r\n",8000,DEBUG);
res.replace("\r\n",""); //remove all line terminator
if (res.indexOf("OK") != -1) {return true;}
else {return false;}
}
String sendData(String command, const int timeout, boolean debug) {
String res="";
esp8266.print(command);
long int time=millis();
while ((time + timeout) > millis()) {
while(esp8266.available()) {res.concat((char)esp8266.read());}
}
if (debug) {Serial.print(res);}
return res;
}
此程式編譯後記憶體占用情形如下 :
草稿碼使用了 10,602 bytes (34%) 的程式存儲空間。最大值為 30,720 bytes。
全域變數使用了 645 bytes (31%) 的動態記憶體,剩餘 1,403 bytes 供局部變數。最大值為 2,048 bytes 。
在此程式的 setup() 函數中, 我先將 ESP8266 設定為 mode 1 (station), 並且啟動可多重連線之網頁伺服器, 然後呼叫 connectWifi 連線無線基地台, ESP8266 將從 AP 取得一個區網 IP, 此 IP 即為網頁伺服器之連線網址. 接著程式就進入 loop() 函數等待用戶端連線.
在 loop() 函數中, 呼叫序列埠的 available() 函數可偵測 Arduino 的軟體序列埠緩衝器是否有資料從 ESP8266 送過來, 有的話就在緩衝器中尋找 "+IPD," 字串, 此乃客戶端正在連線的標記, 其格式例如 :
+IPD,0,298:GET /?pinD2=1 HTTP/1.1
在 "+IPD," 後面的數字即客戶端的連線通道 ID, 因為 ESP8266 的多重連線僅有 0~4 這五個 ID, 因此只要用 read() 讀取即可 (一個字元), 從序列埠讀到的其實是 ASCII 編碼的字元, 是個整數, 因此必須減掉 48 才是 0~9 的數字, 因為 0~9 的數字在 ASCII 編碼中為 48~57.
讀取通道 ID 後緩衝區就剩下 ",298:GET /?pin......" 了, 因為 read() 函數在讀取緩衝區時, 會將該字元從緩衝區刪除. 接下來我們直接呼叫序列埠的 find() 函數在緩衝區中尋找 "GET /?pin" 字串, 與 read() 一樣, 找到後此函數會將包含 "GET /?pin" 在內的之前字元串都從緩衝區內刪除, 因此緩衝區這時只剩下例如 "D2=1" 或 "A3=1023" 的字元串了. 這時再呼叫序列埠的 read() 便能擷取出是數位腳位 'D' 還是類比腳位 'A' 了. 這樣緩衝區就剩下 "2=1" 或 "3=1023" 了, 最後, 利用序列埠的 parseInt() 函數便能依序取得 pin 腳編號以及其值 val 了, 此函數會跳過所有非數字字元, 傳回第一個找到的數字 (整數)就停止, 因此它找到 "=" 時便停止, 傳回 pin 編號, 再呼叫 parseInt() 則跳過 "=" 傳會 val 值.
參考 :
# https://www.arduino.cc/en/Serial/Read
# https://www.arduino.cc/en/Serial/Find
# https://www.arduino.cc/en/Reference/ParseInt
擷取出客戶端要求網址中的 type, pin 與 value 後, 便可用 digitalWrite() 或 analogWrite() 去控制 Arduino 的輸出了, 然後向客戶端輸出網頁, 顯示有幾個腳位被變更, 以及類比輸入所量測到數值. 注意, 串接輸出網頁內容字串時若使用 += 的話, 若一次串接一個非字串型態的 int, char 等類別時會自動轉型, 不須強制轉型; 若用 + 串接的話則必須用 (String) 強制轉型, 否則編譯失敗.
將程式上傳後, 從序列埠監控視窗可看到 ESP8266 伺服器已經啟動, 而且從所連線的無線基地台 DHCP 獲得一個 IP : 192.168.43.111, 等待用戶端連線進來 :
AT+RST
OK
bB�鑭b禔S��#� B�侒��餾�
[System Ready, Vendor:www.ai-thinker.com]
AT+CWMODE=1
no change
AT+CIPMUX=1
OK
AT+CIPSERVER=1,80
OK
AT+CWJAP="H30-L02-webbot","1234567890"
OK
AT+GMR
0018000902
OK
AT+CIFSR
192.168.2.114
OK
我使用筆電連線 ESP8266 網頁伺服器 IP=192.168.2.114 可獲得伺服器回應之網頁 :
Analog pin 2=1023
HTTP/1.1
Host: 192.168.2.114
ConnectiAT+CIPSEND=2,132
> <html>0 digital pin(s) written<br>1 analog pin(s) written<br><b
SEND OK
AT+CIPCLOSE=2
+IPD,1,348:GET /favicon.ico HTTP/1.1
Host: 192.168.2.114
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36
Accept: */*
Referer: http://192.168.43.111/?pinA2=1023
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-TW,zh;q=0.8,en-US;q=0.6,en;q=0.4
OK
OK
不過這實驗也可以用 WeeESP8266 函式庫來做, 對於網址路徑就可以單純用字串來處理, 而不是像上面範例那樣直接處理序列埠送收. 事實上我起先是採用此函式庫來做書上的實驗的. 但因為有點不順利, 還是乖乖地去直接處理序列埠送收, 就是上面測試 1 的程式. 關於 WeeESP8266 函式庫用法, 參考 :
# ITEAD WeeESP8266 函式庫測試
# ITEAD WeeESP8266 函式庫測試 (二) : 網頁伺服器
# 使用 WeeESP8266 函式庫重作 NTP 對時實驗
# 使用 ITEAD WeeESP8266 函式庫改寫物聯網模組 wifi 設定程式
# 深入淺出 Wifi 晶片 ESP8266 with Arduino
完整程式如下 :
測試 2 :
#include <SoftwareSerial.h>
#include "ESP8266.h"
SoftwareSerial esp8266(7,8); //(D7:RX, D8:TX)
ESP8266 wifi(esp8266); //create wifi object
String ssid="EDIMAX-tony";
String pwd="1234567890";
void setup() {
Serial.begin(9600);
wifi.restart(); //reset ESP8266
Serial.print(F("Firmware version ... "));
Serial.println(wifi.getVersion()); //
boolean ok=true; //default result ok
ok &= wifi.setOprToStation(); //set esp8266 : mode 1
ok &= wifi.enableMUX(); //enable multi-connection
ok &= wifi.startTCPServer(80); //enable sep8266 web server
if (ok) {Serial.println(F("Enable web server ... OK"));}
while (!wifi.joinAP(ssid, pwd)) {
Serial.println("Connecting WiFi ... failed");
delay(2000);
}
delay(3000); //wait for wifi connection to get local ip
Serial.print(F("IP ... "));
Serial.println(wifi.getLocalIP()); //show local ip
}
void loop() {
uint8_t buffer[128]={0}; //init receiving buffer to store esp response
uint8_t mux_id; //TCP connection id (0~4)
uint32_t len=wifi.recv(&mux_id, buffer, sizeof(buffer), 2000); //get response
if (len > 0) { //data received, fetch requested path from HTTP
String path=""; //init path
int digitalRequests=0; //digital request counts
int analogRequests=0; //analog request counts
for (uint32_t i=0; i<len; i++) { //concat path string
if (!path.endsWith(" HTTP/")) {path.concat((char)buffer[i]);}
else {break;}
}
path=path.substring(path.indexOf("/") + 1, path.indexOf(" HTTP/"));
Serial.println(path); //eg: ?pinD2=1 or ?pinA4=1023
char type=path.charAt(4);
int pin=path.substring(5, path.indexOf("=")).toInt();
int val=path.substring(path.indexOf("=") + 1).toInt();
if (type=='D') {
Serial.print("Digital pin ");
pinMode(pin, OUTPUT);
digitalWrite(pin, val);
digitalRequests++;
}
else if (type=='A') {
Serial.print("Analog pin ");
analogWrite(pin, val);
analogRequests++;
}
else {
Serial.print("Unexpected type:");
Serial.println(type);
}
Serial.print(pin);
Serial.print("=");
Serial.println(val);
String webpage="<html>" + (String)digitalRequests + " digital pin(s) written<br>" +
(String)analogRequests + " analog pin(s) written<br><br>";
for (byte i=0; i<6; i++) {
webpage += "A" + (String)i + "=" + (String)analogRead(i) + "<br>";
}
webpage += "</html>";
wifi.send(mux_id, (const uint8_t*)webpage.c_str(), webpage.length());
wifi.releaseTCP(mux_id);
}
}
使用 WeeESP8266 函式庫需先建立一個名為 ESP8266 物件, 並傳入與 ESP8266 通訊的序列埠物件, 這裡是使用 D7 與 D8 作為 Rx 與 Dx 的軟體序列埠. 同樣在 setup() 函數中呼叫 SetOprToStation() 以設定 ESP8266 工作在 mode 1, 並呼叫 enableMUX() 與 startTCPServer() 啟動多重連線之網頁伺服器, 然後呼叫 joinAP() 連上無線基地台.
進入 loop() 後就開始偵測 ESP8266 是否有收到送客戶端的連線要求. 使用 WeeESP8266 送收資料須準備一個 uint_8 型態的緩衝器 buffer 與連線通道紀錄器 mux_id 當參數, 傳入 recv() 接收函數中, 它會將回應字元放入緩衝器內, 將連線通道紀錄在 mux_id 中, 並傳回緩衝器收到的資料長度 len. 當 len 不為 0 表示有收到客戶端要求, 這時可用一個迴圈去讀取緩衝區, 直到 "HTTP/" 為止, 放入路徑字串變數 path 中, 其內容例如 :
+IPD,1,248:GET /?pinD2=1 HTTP/
這樣便可以利用 Arduino 的字串函數來擷取要設定的腳位與值. 關於字串處理請參考 :
# Arduino 基本語法筆記
透過下列指令即可取出介於第一個斜線與空白之間的 URL 資訊 :
path=path.substring(path.indexOf("/") + 1, path.indexOf(" HTTP/"));
這樣 path 就得到 ?pinD2=1 或 ?pinA3=1023 的字串了. 利用 char() 可得到數位腳 (D) 或類比腳 (A), 而透過 substring() 與 indexOf() 就可以抓出腳位編號 pin 與其設定值 val. 注意, 因為擷取出來的 pin 與 val 是數字字串, 因此必須用 toInt() 轉成整數, 以便傳入 digitalWrite() 與 analogWrite() 之中.
編譯後記憶體占用情形如下 :
草稿碼使用了 14,726 bytes (47%) 的程式存儲空間。最大值為 30,720 bytes。
全域變數使用了 853 bytes (41%) 的動態記憶體,剩餘 1,195 bytes 供局部變數。最大值為 2,048 bytes 。
程式上傳後以手機連線同一無線基地台, 輸入 ESP8266 伺服器網址, 這次改為設定數位腳位 D2, 得到預期結果 :
序列埠監控視窗擷取訊息如下 :
Firmware version ... 0018000902
Enable web server ... OK
Firmware version ... 0018000902
IP ... 192.168.2.114
?pinD2=0
Digital pin 2=0
favicon.ico
Unexpected type:c
0=0
比較上面兩個測試, 當然測試 1 直接處理序列埠較低階麻煩, 但好處是省記憶體, 而且比較能理解底層運作的細節; 測試 2 使用函式庫, 字串處理較簡單, 程式看來解結易懂, 但較吃記憶體. 不管哪種做法, 都還是要在瀏覽器上輸入網址來操控, 還是麻煩. 雖然已有 App 介面可以讓遠端控制 Arduino 的輸出更容易, 但書上這個實驗能讓我們更熟悉序列埠與字串的操作.
2016-07-30 補充 :
今天早上重新檢視程式碼時覺得為啥要設 digitalRequests 與 analogRequests 這兩個變數呢? 不是一次設定一個腳位嗎? 仔細看作者在 15.7 節末尾的說明才發現, 原來書中的範例程式可以一次設定好幾個腳位, 每一組參數都用 & 連起來即可, 例如 :
192.168.2.114/?pinD2=1&pinA2=1023
上面兩個測試程式只能一次處理一個參數而已. 所以我將其修改為可一次設定多個參數的程式如下 :
測試 3 :
#include <SoftwareSerial.h>
#define DEBUG true
SoftwareSerial esp8266(7,8); //(RX,TX)
String ssid="EDIMAX-tony";
String pwd="1234567890";
void setup() {
Serial.begin(9600);
esp8266.begin(9600);
sendData("AT+RST\r\n",2000,DEBUG); // reset ESP8266
sendData("AT+CWMODE=1\r\n",1000,DEBUG); //configure as station
sendData("AT+CIPMUX=1\r\n",1000,DEBUG); //enable multiple connections
sendData("AT+CIPSERVER=1,80\r\n",2000,DEBUG); //turn on server 80 port
while (!connectWifi(ssid, pwd)) {
Serial.println("Connecting WiFi ... failed");
delay(2000);
}
sendData("AT+GMR\r\n",1000,DEBUG);
delay(3000); //wait for wifi connection to get local ip
sendData("AT+CIFSR\r\n",1000,DEBUG); //get ip address
}
void loop() {
if (esp8266.available()) { // check if esp8266 is sending message
int digitalRequests=0;
int analogRequests=0;
if (esp8266.find("+IPD,")) {
delay(1000); //waiting for response: ?pinD2=1&pinA2=1023
int connectionId=esp8266.read()-48; //turn ASCII to number
if (esp8266.find("GET /")) { //retrieve page name (router)
while (esp8266.findUntil("pin", "\r\n")) {
char type=(char)esp8266.read();
int pin=esp8266.parseInt();
int val=esp8266.parseInt();
if (type=='D') {
Serial.print("Digital pin ");
pinMode(pin, OUTPUT);
digitalWrite(pin, val);
digitalRequests++;
}
else if (type=='A') {
Serial.print("Analog pin ");
analogWrite(pin, val);
analogRequests++;
}
else {
Serial.println("Unexpected type:" + type);
}
Serial.print(pin);
Serial.print("=");
Serial.println(val);
}
String webpage="<html>";
webpage += (String)digitalRequests + " digital pin(s) written<br>";
webpage += (String)analogRequests + " analog pin(s) written<br><br>";
for (byte i=0; i<6; i++) {
webpage += "A" + (String)i + "=" + (String)analogRead(i) + "<br>";
}
webpage += "</html>";
String cipSend="AT+CIPSEND=";
cipSend += connectionId;
cipSend += ",";
cipSend += webpage.length();
cipSend += "\r\n";
sendData(cipSend,1000,DEBUG);
sendData(webpage,2000,DEBUG);
sendData("AT+CIPCLOSE=" + (String)connectionId + "\r\n",3000,DEBUG);
}
}
}
}
boolean connectWifi(String ssid, String pwd) {
String res=sendData("AT+CWJAP=\"" + ssid + "\",\"" + pwd + "\"\r\n",8000,DEBUG);
res.replace("\r\n",""); //remove all line terminator
if (res.indexOf("OK") != -1) {return true;}
else {return false;}
}
String sendData(String command, const int timeout, boolean debug) {
String res="";
esp8266.print(command);
long int time=millis();
while ((time + timeout) > millis()) {
while(esp8266.available()) {res.concat((char)esp8266.read());}
}
if (debug) {Serial.print(res);}
return res;
}
主要的改變是加入一個 while 迴圈用序列埠的 findUntil() 不斷去找 "pin". 編譯後記憶體耗用 :
草稿碼使用了 10,856 bytes (35%) 的程式存儲空間。最大值為 30,720 bytes。
全域變數使用了 645 bytes (31%) 的動態記憶體,剩餘 1,403 bytes 供局部變數。最大值為 2,048 bytes 。
瀏覽器連線結果正確 :
而使用 WeeESP8266 函式庫測試 2 則被改成下列測試 4 :
測試 4 :
#include <SoftwareSerial.h>
#include "ESP8266.h"
SoftwareSerial esp8266(7,8); //(D7:RX, D8:TX)
ESP8266 wifi(esp8266); //create wifi object
String ssid="EDIMAX-tony";
String pwd="1234567890";
void setup() {
Serial.begin(9600);
wifi.restart(); //reset ESP8266
Serial.print(F("Firmware version ... "));
Serial.println(wifi.getVersion()); //
boolean ok=true; //default result ok
ok &= wifi.setOprToStation(); //set esp8266 : mode 1
ok &= wifi.enableMUX(); //enable multi-connection
ok &= wifi.startTCPServer(80); //enable sep8266 web server
if (ok) {Serial.println(F("Enable web server ... OK"));}
while (!wifi.joinAP(ssid, pwd)) {
Serial.println("Connecting WiFi ... failed");
delay(2000);
}
delay(3000); //wait for wifi connection to get local ip
Serial.print(F("IP ... "));
Serial.println(wifi.getLocalIP()); //show local ip
}
void loop() {
uint8_t buffer[128]={0}; //init receiving buffer to store esp response
uint8_t mux_id; //TCP connection id (0~4)
uint32_t len=wifi.recv(&mux_id, buffer, sizeof(buffer), 2000); //get response
if (len > 0) { //data received, fetch requested path from HTTP
String path=""; //init path
int digitalRequests=0; //digital request counts
int analogRequests=0; //analog request counts
for (uint32_t i=0; i<len; i++) { //concat path string
if (!path.endsWith(" HTTP/")) {path.concat((char)buffer[i]);}
else {break;}
} //path : "+IPD,1,248:GET /?pinD2=1&pinA4=1023 HTTP/"
path=path.substring(path.indexOf("?") + 1, path.indexOf(" HTTP/"));
Serial.println(path); //eg : pinD2=1 or pinD2=1&pinA4=1023
while (path.indexOf("pin") != -1) { //parsing not finished
char type=path.charAt(3);
int pin=path.substring(4, path.indexOf("=")).toInt();
int val=path.substring(path.indexOf("=") + 1).toInt();
if (type=='D') {
Serial.print("Digital pin ");
pinMode(pin, OUTPUT);
digitalWrite(pin, val);
digitalRequests++;
}
else if (type=='A') {
Serial.print("Analog pin ");
analogWrite(pin, val);
analogRequests++;
}
else {
Serial.print("Unexpected type:");
Serial.println(type);
}
Serial.print(pin);
Serial.print("=");
Serial.println(val);
if (path.indexOf("&") != -1) { //multiple parameters
path=path.substring(path.indexOf("&") + 1); //remove parameter
}
else {path="";} //terminate loop
}
String webpage="<html>" + (String)digitalRequests + " digital pin(s) written<br>" +
(String)analogRequests + " analog pin(s) written<br><br>";
for (byte i=0; i<6; i++) {
webpage += "A" + (String)i + "=" + (String)analogRead(i) + "<br>";
}
webpage += "</html>";
wifi.send(mux_id, (const uint8_t*)webpage.c_str(), webpage.length());
wifi.releaseTCP(mux_id);
}
}
主要的變更也是多加了一個 while 迴圈來偵測是否還有 "pin" 字眼存在, 最重要的是迴圈末尾要自 path 字串中移除目前所處理的參數, 若已無 & 字元表示已處理完全部參數, 要把 path 設為空字串來終止迴圈. 編譯後記憶體耗用如下 :
草稿碼使用了 14,950 bytes (48%) 的程式存儲空間。最大值為 30,720 bytes。
全域變數使用了 861 bytes (42%) 的動態記憶體,剩餘 1,187 bytes 供局部變數。最大值為 2,048 bytes 。
以手機瀏覽器連線 192.168.2.114/?pinD2=1&pinD3=0&pinA2=1023 結果如下 :
可見迴圈會累計有幾個腳位被設定輸出值了.
序列埠監控視窗訊息如下 :
Firmware version ... 0018000902
Enable web server ... OK
IP ... 192.168.2.114
pinD2=1&pinD3=0&pinA2=1023
Digital pin 2=1
Digital pin 3=0
Analog pin 2=1023
GET /favicon.ico
請問能改成AP server來控制arduino嗎?
回覆刪除可以喔, 參考 :
回覆刪除http://yhhuang1966.blogspot.tw/2015/11/esp8266-at.html
http://yhhuang1966.blogspot.tw/2016/06/allaboutee-esp8266_2.html
作者已經移除這則留言。
回覆刪除您好:
回覆刪除請問手機控制輸入輸出需要與ESP8266連同一個網路嗎?
還是可以在不同地區使用不同網路去遠端控制?
謝謝。
遠端的話可以利用物聯網網站或 Blynk 喔! 參考 :
回覆刪除http://yhhuang1966.blogspot.com/2016/08/blynk.html
hi 您好:
回覆刪除想請問我用您的範例三可以成功用電腦瀏覽器讀取arduino數值,
但為何用手機瀏覽器讀取都無法讀到數值,手機瀏覽器會一直秀連線逾時,
但序列峊視窗卻有connectid出現呢?
感謝
此實驗為 Arduino 透過 ESP8288 連接家中無線基地台, 獲得基地台配發如 192.168.2.114 網址, ESP8266 又開啟 AP 模式作為伺服器, 因此手機應該先連線無線基地台再用瀏覽器瀏覽 ESP8288 網址.
回覆刪除