Arduino網路遠端遙控家電開關(二)

本文旨在補充《超圖解Arduino互動設計入門》第十六章「網路家電控制」單元,增加另一個網頁控制範例,以及說明使用指標(pointer)設定多重字串陣列的語法。

本文將把《Arduino網路遠端遙控家電開關(一)》製作的HTML頁面,放到Arduino控制板上執行。首先把網頁裡面,不會變動的HTML碼和CSS樣式,存入Arduino的程式記憶體(相關說明請參閱16-4頁):

底下是Webduino程式庫所需,處理預設命令(亦即:顯示首頁)的程式碼(相關說明請參閱16-4頁):

實際負責顯示網頁內容的程式碼,寫在名叫showPage()的自訂函數中,它接收一個WebServer類型的參數,透過這個參數,程式將能把網頁輸出給用戶端。

定義控制腳位編號及名稱

程式一開始,定義3個常數,儲存Arduino的控制輸出腳位,以及控制腳位的名字(如:”檯燈”和“熔岩燈”),好讓程式能產生動態頁面。

建立動態Arduino頁面

與控制腳位相關的3個常數定義如下:

Arduino官方的Ethernet以太網路控制板,當中的數位腳位編號4,保留給SD記憶卡的晶片選擇線使用,請不要挪做他用。

數位10~13腳是SPI介面的預設腳位,用於控制以太網路晶片,也請不要使用。

建立多重字串陣列指標

我們需要先定義好每個控制腳位的名稱,才能讓後續的迴圈程式取用。如5-15頁提到的,Arduino程式(C語言)採用陣列來存放字串,那麼,要儲存一組字串,就需要用到二維陣列了。

假設要在str陣列中儲存“str 1”, “str 2”和“str 3”這三個字串,底下兩種寫法都行:

儲存多重字串的二維陣列程式

假如每一組字串的長度不固定,元素的長度必須要確保能存入最長的字串,例如,以下的字串陣列中,“Android”佔7 個字元,因此元素的長度至少必須是8。

儲存多重字串的二維陣列程式

但是,那些用不滿8個字元空間的短字串(如:“iOS”),剩餘的空間就浪費掉了。

比較好的寫法是採用指標,如書本8-41頁提到,我們可以用指標變數來存取陣列元素。底下的敘述建立了一個包含3個指標元素的陣列,分別參照到3個字元陣列:

透過指標陣列存取多個字串

用指標記錄多個字串,就不會有空間被浪費掉。

因此,本程式透過一個名叫swNames的指標陣列,儲存6個控制腳位名稱。

動態顯示控制腳位狀態的網頁

讀取控制腳位值,並以HTML網頁形式輸出給用戶端的自訂函數,showPage()的程式原始碼如下,其中的for迴圈,將讀取6個控制腳位狀態,進而動態組成清單項目(<li>標籤)和超連結(<a>標籤)元素。

如果讀取到的數位腳是高電位,就在網頁上顯示ON;若是低電位,則顯示OFF:

動態顯示控制腳位狀態的自訂函數

接收並處理開關的查詢字串值

本單元的範例網頁裡的每個開關選項,都是超連結。每個選項連結都連到Arduino的自訂命令“sw”,並且附帶傳送id參數。例如,第一個選項的連結是“sw?id=0”,也就是以GET方式,傳送id為0的參數給sw頁面(請參閱16-31頁的「接收並處理透過GET方法傳送的查詢字串」單元):

處理查詢字串的流程

本程式的setup()函數,指定將sw頁面的請求,交給自訂函數getCmd處理:

自訂函數getCmd()的程式原始碼如下,因為預期的參數(亦即,id)和數值(0~5),都沒有超過兩個字,因此,筆者將接收URL參數的陣列長度設定成3(含字串結尾的Null字元)。

處理sw自訂命令的函數

下載Arduino網路遠端家電控制的原始碼

按此連結可下載本單元的Arduino原始碼。

Arduino官方的以太網路擴充板(Arduino Ethernet Shield),大約消耗180mA電流(W5100晶片本身約消耗150mA);Arduino UNO Rev 3控制板本身約消耗50mA電流(參閱《認識與實驗Arduino的睡眠模式》這篇貼文),兩者合計約230mA。

測試時如果發生不穩定的狀況,例如,顯示的網頁不完整,或者無法如預期般接收參數控制的情況,請將Arduino控制板接上外接電源再測試,不要接電腦的USB電源供電。

延伸閱讀

160 thoughts on “Arduino網路遠端遙控家電開關(二)

  1. 我目前有個小問題
    買的RFID為SPI介面
    SPI使用網路上的副程式
    我很好奇SPI中的MIMO是傳什麼資料出去
    給我的電子標籤,使電子標籤能夠回傳資料到MOMI

    還有所謂的SPI介面,MIMO式都發送固定的資料嗎??
    所以只要把鮑率改成一樣就行了嗎
    還有鮑率是只SCK的部分嗎??

    1. 你指的MIMO和MOMI應該是MISO和MOSI,它們都是序列訊號傳輸線(請參閱8-11頁說明),傳送的資料格式要看周邊設備而定,如8-20頁程式透過SPI介面,向MAX7219分別傳遞暫存器位址和資料,如果換成其他類型的IC,資料內容就不同了,詳細要查IC的規格書。

      如8-44頁提到的,MAX7219的頻率上限是10MHz,只要時脈速率在這個範圍內,傳遞資料都沒問題。其他類型的IC需要查閱規格書。

      thanks,
      jeffrey

  2. 老師你好:
    請教書本上:10-1 電路
    5V —>經過電組 330 歐母,經過可變電組10K歐母,接到 LED 陽極
    如無 330歐母,限流電組,當可變電組10K歐母,調到 0歐母時,會有大電流產生
    那這樣5V與接地會短路,你指的大電流是這個意思?
    那麼 LED 也會燒毀?

    1. hi jxchen:

      抱歉,剛剛發現10-2頁的可變電阻電路有誤,正確如下:

      用可變電阻調整LED亮度的電路

      實際的接線圖大致像這樣:

      可變電阻調整LED亮度的電路接法

      其實直接把LED接上Arduino的5V,並不會燒毀,但是我不知道這樣可以維持多久。為了避免折損LED的壽命,請加上限流電阻。

      thanks,
      jeffrey

  3. 請問作者大大:
    上面的實體圖,是怎麼畫出來的,是有專用的軟體嗎?或是您自己畫的
    因為現在學生真的要用這種圖,他們才看得懂,願意學,所以想請教作者是否有專用軟體以拉元件的方式來畫這種3D的立體圖,就我所知的只有FRITIZING有2D的元件符號,123D也是2D的元件符號,還沒看過3D實體的軟體,謝謝回復

    1. tanj老師:

      這些插圖是我用Flash軟體,搭配滑鼠畫出來的,並沒有使用現成的圖庫。

      thanks,
      jeffrey

  4. 請問老師

    我看這個程式碼是使用迴圈的方式,偵測腳位是否為高電位,或是低電位。
    原本的章節裡,可以delay(1000) 的方式來讓開關只開啟一秒鐘,
    簡單說就是做成只接觸一下

    因為我是要控制鐵捲門的,傳統上鐵捲門都是壓一下就有反應,不需要一直壓者。

    迴圈程式應該怎麼改寫好? 先謝謝老師囉!

    1. hi bullets:

      可能因為減速齒輪比、門窗高度不同、機械老化…等因素,我們無法得知鐵捲門的精確捲動時間,所以不應該依據時間來決定要啟動多久。

      鐵捲門通常都是採用類似下圖的結構,透過極限開關來判斷是否捲到底或者捲到頂:

      鐵捲門與極限開關

      當捲門往下移動時,程式要判斷是否碰觸到sw1開關;若往上捲,則判斷是否碰到sw0。

      thanks,
      jeffrey

  5. 老師,我了解你畫圖的意思

    但是我目前遇上的問題是…..
    我是把鐵捲門的 上、暫停、下 三個按鈕 (有通電)
    我把這三個迴路裝進四路繼電器中,由Arduino UNO 去控制繼電器開關

    我透過下列程式
    digitalwrite(UP,High)
    delay(1000)
    digitalwrite(UP,Down)
    這樣,就可以模擬出手指頭去觸碰開關按鈕,達成電路的接通

    依照老師的意思是希望我去接極限開關,但是這要爬很高去尋找馬達裡的極限開關,其實不好找
    所以我才使用牆壁上的按鈕開關,搭配繼電器控制

    這篇教學的網頁控制,是比書上的漂亮多了
    但是程式碼控制,是利用迴圈,尋找 i 的變化,來達到要嘛是ON , 要嘛是OFF

    好像沒有辦法,讓原本是OFF 的按鈕,按下ON 後的一秒鐘,在自動轉回OFF 啊!
    雖然稍微看得懂老師的程式碼,但是我自己卻不知怎麼改。

    只好再次請教老師了….

    1. showPage函數裡的迴圈只是讀取腳位的狀態,負責控制開關的是getCmd函數。因此,修改開關程式碼要從getCmd函數下手。

      這是修改後的程式碼,將在按下任何開關後,自動在一秒鐘內關閉它。

      另外,原始碼的HTML敘述的檔頭區,增加了每1秒更新(重新整理)並重新導向到首頁的敘述:

      <meta http-equiv=’refresh’ content=’1;url=192.168.1.25′>

      請將其中的IP位址改成你的IP位址。程式碼我沒有實機驗證過,應該可行。

      thanks,
      jeffrey

  6. 老師您好,

    我測試過您的程式碼,原則上是可以使用….. (一秒鐘控制,沒有問題)
    但是,
    這段程式碼確有問題,我試跑後發現他會接在網址後面,並不會回到首頁
    也就是說 http://192.168.1.25/192.168.1.25

    請問老師這應該怎麼修正才好?

    1. 請將重新導向的敘述改成:

      <meta http-equiv=’refresh’ content=’1′>

      再測試看看,下載檔案已經更新。

      thanks,
      jeffrey

  7. 老師,我上傳修正後的程式碼….
    結果變成,1秒後自動refresh,偏偏又是1秒中斷
    這樣例如我切第一個按鈕後,結果繼電器就變成每1秒切斷一次,又重整,再切斷
    陷入無限循環的窘境

    我去查過老師的程式碼,html的自動導向程式碼的確是那樣寫的,
    但是我搞不清楚這是為什麼,難道是函數不支援這樣寫嗎?

    1. hi bullets:

      會造成無限循環的原因是瀏覽器不停地重新整理,並傳送id=xxx的訊息,所以只要不帶URL參數地將瀏覽器導回首頁即可,請把meta敘述改成:

      <meta http-equiv=’refresh’ content=’1;url=http://192.168.1.25′>

      不過這種方式的缺點就是整個頁面會不停地更新,比較好的解決方式是透過JavaScript的XMLHttpRequest物件,或者jQuery的ajax方法,發起一個非同步的伺服端資料請求,這樣只需要更新部分頁面區域,不過這部份的背景概念已超出書本內容。

      但是它們背後的基本概念是一樣的:Web伺服器無法主動傳遞資料給用戶端,因此前端必須主動反覆連線到伺服器端,才能獲得最新的資料。

      此例更新畫面的目的,是要讓網頁上的控制按鈕能反映出被控制端的狀態(ON或OFF)。

      如果不需要反映控制端的ON, OFF狀態(一般的控制器都是如此),就不需要加上meta敘述了。

      另一個可以考慮的方向是,也許你可以建立一個類似定時器的「時間」值設定欄位,讓用戶輸入時間值來決定控制端的執行時間,按下按鈕之後,就交給Arduino執行,這樣也就不太需要持續更新頁面了。

      thanks,
      jeffrey

    1. hi luck:

      Ethernet Shield R3版,只是為了和Uno R3板相容,在板子上增加幾個接點,除此之外,硬體和程式庫和舊版都一樣。

      thanks,
      jeffrey

  8. 因為他宣告函數有小變動,想測試一個簡單的Web server,都連不到,老師寫的編譯不能成功(有些定義函數不同有改)

    1. Arduino程式的作用是指揮Arduino控制板本體上的微控制器,無論我們替Arduino加上那一種介面或擴展卡,都不會影響程式編譯過程。

      若出現編譯錯誤,那是程式本身或者程式庫有問題。

      Arduin控制板與擴展卡

      如果把Arduino的乙太擴展卡當成巴士,Arduino控制板就相當於司機;我們的程式是告訴司機如何開車,不是直接操縱車子。請問你的Arduino軟體是1.0.5版嗎?

      thanks,
      jeffrey

    1. 你用Arduino內建的範例,例如:檔案→範例→Ethernet→WebServer,編譯看看。

      如果出現錯誤訊息,請把訊息內容張貼出來,謝謝!

      thanks,
      jeffrey

  9. http://i.imgur.com/tPKvWm4.jpg
    左邊是老師做的教學原始碼,會編譯錯誤(不太懂怎改,可能有宣告有點問題)
    右邊是arduino提供的範例,是可以用

    我有一台無線AP,網路插WAN_Port,桌電插port1,arduino插port3,有開NAT功能跟DHCP伺服器指派IP
    桌電的DHCP指派的IP是192.168.2.101,順推arduino就是192.168.2.102
    在Web Server範例裡面要改DHCP給的IP → IPAddress ip(192.168.2.102);
    可以連,顯示的出網頁,但只能用在內網,要連到同的AP的網域IP才能顯是網頁(桌電跟UNO都是由DHCP指派的IP才連的到)
    如果從外面的網路像手機3G(外網)要連近arduino這個Web Server,是連不到的
    有辦法使用外網去連到arduino這個Web Server(對外可被連線的IP),小弟有疑惑的地方

    謝謝老師很有耐心指導

    1. 從編譯的錯誤訊息可以看出,Arduino找不到指定的程式庫。請將Webduino和Streaming程式庫放入libraries資料夾,再重新啟動Arduino工具程式,即可順利編譯。

      至於從外部連網到家裡的網路設備,你需要開啟路由器上的虛擬伺服器或DMZ,並且用ISP分配給你的IP位址連接。不同廠牌的路由器設定都太一樣,請搜尋相關關鍵字。

      thanks,
      jeffrey

    2. 用 arduino 1.0.6 無法complier 成功

      請問能否提供這兩個 .h file?
      “WebServer.h”
      “Streaming.h”

      謝謝

  10. 老師,請問byte mac[] = {
    0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

    是不是MAC=DE:AD:BE:EF:FE:ED
    這是自定義MAC碼??一定要這樣嗎??如果自行另外定義一組mac碼可行嗎?

    另外為什麼再無線ap裡面看不到Arduino Web Server他的名稱跟MAC號碼
    指能看的到電腦的名稱,電腦的MAC
    但是我設定虛擬伺服器,輸入DHCP指派的IP,他名稱顯示OFFLINE(應該是離線),卻可以使用(有測試實驗)

    目前有初步的小成功,對外網要定義gateway跟subnet

  11. 老師您好,我最近在做Arduino WIFI相關的專題
    但是我卡在WIFI設定好之後電腦可以連 但是不知道該從何下手
    我的WIFI是要做成client端去連PC server
    然後透過程式或虛擬網頁去連到APPserver
    我應該在arduino裡面加甚麼
    或是在server端加甚麼程式碼去抓取arduino wifi傳送的資料?

    還有我想問,如果做成client端是否要一個AP?
    那AP裡面有哪些必要的設定?

    1. hi harry:

      Arduino官網的WiFi程式庫頁面,有詳細列舉WiFi的詳細指令,並附帶範例程式碼,像WiFiWebClient(無線Web用戶端)範例。

      你可以把Arduino + WiFi看待成一般的瀏覽器,它讀取的資料就是Web伺服器提供的內容,沒有什麼特別的設定。

      我並沒有購買WiFi擴充介面,因為從DIY的角度來看,這個介面卡的價格可以購買兩、三個TP-LINK TL-WR703N無線路由器;而此無線路由器具備嵌入式Linux系統,與Arduino相連,發揮的空間比單純WiFi擴充卡大得多(呃…慚愧的是,它到現在還靜靜躺在我的抽屜裡…)

      thanks,
      jeffrey

  12. 老師您好:
    您說的WiFiWebClient(無線Web用戶端)範例我有試過
    但是他好像要一個AP,而AP的設定就直接預設值就可以了嗎?

    另外我是使用WiFi擴充版 KSB004這個
    裡面的手冊和範例也用過了
    但是現在想要實作從Arduino中跑數值,透過WiFi讓它顯示在電腦上
    不知道要如何使用…所以想問問老師
    是要利用電腦跑程式碼讓他去抓嗎還是?

    1. hi harry:

      使用WiFi無線網路,當然要有無線基地台,不然怎麼連網?無線基地台並不需要為Arduino做特別的設定。

      根據Arduino WiFi擴充板的官方說明頁,連接硬體的注意事項:

      1. 數位7, 10~13腳,是WiFi擴充板與Arduino的通訊腳,請不要使用這些腳位。
      2. 數位4腳,是WiFi板子上的SD記憶卡模組的晶片選擇(SS)腳位。

      就像用電腦和手機連接WiFi網路之前,需要先搜尋並指定要連接的WiFi基地台一樣,Arduino程式也需要指定連接的WiFi基地台(透過SSID識別名稱),並且視情況設定密碼和IP位址。

      底下的程式用於搜尋WiFi網路,並且在「序列埠監控視窗」顯示:

      1. WiFI擴充板的MAC位址
      2. 搜尋到的WiFi網路名稱(SSID)、訊號強度(Signal,dBm值)以及加密方式(Encryption)。

      底下的程式,可讓Arduino連上名叫”yourNetwork”的未加密(不需要輸入密碼)WiFi網路:

      底下的是連接到採用WPA/WPA2加密的WiFi網路範例程式:

      更多範例,請參閱官方網站的WiFi程式庫指令說明

      thanks,
      jeffrey

  13. 老師您好
    我測試出來結果我的MAC位置都是0
    這代表這塊WIFI版有問題嗎?
    還是我沒有設定呢?
    我也有將他RESET過了也還是顯示0:0:0:0:0

    1. 我的Serial顯示這些

      Initializing Wifi…
      MAC: 0:0:0:0:0:0
      Scanning available networks…
      ** Scan Networks **
      number of available networks:0

      我有開著AP但也是搜尋不到
      用家裡的數據機的WIFI也不能…

    2. 官方的WiFi擴充板有下列四個燈號:

      L9(黃):連接到數位9腳
      LINK(綠):亮燈代表已連上網路
      ERROR(紅):亮燈代表通訊錯誤
      DATA(藍):在傳送與接收資料時會閃爍

      不過,如果連板子的MAC位址都讀不到,WiFi擴充板可能有問題…

      thanks,
      jeffrey

    3. 老師您好
      那這樣這塊板子就不能用了嗎?
      有甚麼方法解決嗎?

      另外既然他沒辦法顯示MAC Address
      那為什麼他能夠用內建的程式碼…
      我有用它內建程式碼變成AP
      然後電腦和手機能夠連上
      但就是沒辦法搜尋到附近AP…
      所以一直沒辦法使用範例程式碼來測試

    4. 這樣的話,擴充卡的硬體本身沒有故障,應該能透過更新韌體解決。官網Upgrading the WiFi shield firmware這篇貼文有詳細的說明(需要透過Flip軟體更新HDG104和AT32UC3兩個韌體)。

      很抱歉,我沒有這張擴充卡,無法示範詳細的步驟。

      thanks,
      jeffrey

  14. 老師您好:
    我想在你的程式再結合藍芽控制
    但結合後某些腳位不能控制
    能幫我看看是什麼問題嗎
    謝謝

    char val1;
    int relay1=8;
    int relay2=7;
    int relay3=6;
    int relay4=5;
    int relay5=3;

    void setup()
    {
    Serial.begin(9600); // 設定Serial 傳輸速度

    pinMode(relay1,OUTPUT);
    pinMode(relay2,OUTPUT);
    pinMode(relay3,OUTPUT);
    pinMode(relay4,OUTPUT);
    pinMode(relay5,OUTPUT);

    }
    void loop()
    {
    val1=Serial.read();
    switch(val1)
    {
    //////////////////////////////////////////////////////////////////////////////////
    case ‘q’ :
    digitalWrite(relay1,HIGH); //
    break;
    case ‘a’ :
    digitalWrite(relay1,LOW); //
    break;
    //////////////////////////////////////////////////////////////////////////////////
    case ‘w’ :
    digitalWrite(relay2,HIGH); // 
    break;
    case ‘s’ :
    digitalWrite(relay2,LOW); // 
    break;
    //////////////////////////////////////////////////////////////////////////////////
    case ‘e’ :
    digitalWrite(relay3,HIGH); //  
    break;
    case ‘d’ :
    digitalWrite(relay3,LOW); //    
    break;
    /////////////////////////////////////////////////////////////////////////////////
    case ‘r’ :
    digitalWrite(relay4,HIGH); //   
    break;
    case ‘f’ :
    digitalWrite(relay4,LOW); //  
    break;
    /////////////////////////////////////////////////////////////////////////////////
    case ‘t’ :
    digitalWrite(relay4,HIGH); //   
    break;
    case ‘g’ :
    digitalWrite(relay4,LOW); //  
    break;
    /////////////////////////////////////////////////////////////////////////////////

    }

    }

    1. hi leo:

      檢查序列埠是否有新的資料傳入,請使用Serial.available()方法(請參閱5-21頁說明),程式碼改成:

      thanks,
      jeffrey

  15. 您好 想請問
    如果想用Ardunio利用WIFI取得上網後,
    再結合RFID模組,將偵測到的卡號傳到網頁該怎麼做呢?

    1. hi tang:

      妳的問題範圍太大,應該要分成:

      1. 先搞懂網路概念
      2. 使用HTML製作出你需要的網頁
      3. 實驗把你的HTML置入Arduino的Web伺服器程式
      4. 實驗將RFID數值存入陣列,並顯示在Arduino的「序列埠監控視窗」。
      5. 把上面兩個程式結合在一起。

      以上的內容,書本都有提到。

      have fun!
      jeffrey

  16. 老師您好:

    依本單元的程式,想再增加書本中16_1_3監控遠端的溫濕度值,請老師指點 , 感謝您.

    1. hi ming:

      DIY-16-1的程式碼就是把溫濕度值顯示在網頁上,因此,你只要按照該程式輸出網頁的敘述寫法,應用在本文的頁面即可。

      thanks,
      jeffrey

  17. 老師您好:

    1. 我在P(htmlHead)中 , 有加入這一行”” , 但溫度無法自動更新 .
    2. 程式碼不知要如何傳給老師指導.
    謝謝!

    1. 咦?請問你加入的refresh(重新整理頁面)敘述是類似這樣嗎?

      have fun!
      jeffrey

  18. 老師你好,我想請教一下,關於我想使用手機上網連線是ARDUINO
    我在程式中的IP改成我宿舍分配給我的IP
    static byte mac[] = { 0xF0, 0x7B, 0xCB, 0x4B, 0x7C, 0x9F };
    IPAddress ip(192, 168, 1, 178);
    IPAddress subnet(255, 255, 255, 0);
    IPAddress gateway(192, 168, 1, 1);

    但手機測試後無法連線
    是因為宿舍的網路關係還是我需要實體IP還是我需要在程式裡更改什麼設定呢
    麻煩老師了

    1. hi 默默:

      請先用宿舍中,相同網域(區域)的電腦連結看看。如果你的手機是用3G/4G上網,那肯定連不上宿舍的Arduino,因為學校分配給你的是區域網路IP。

      thanks,
      jeffrey

  19. 老師您好
    我想用網路控制舵機轉動
    ON是將舵機轉到90度
    OFF是將舵機轉到10度
    請問我程式應該如何修改呢

    1. 伺服馬達的控制程式挺簡單的,請先參考動手做11-1單元的「自製機械手臂」程式原始碼,自己改寫看看。

      thanks,
      jeffrey

  20. 再次請敎老師:

    查了半天有關arduCam 如:OV2640攝影機的使用,
    觀念上始終無法將arduino和arduCam在軟硬體上成功的串接起來
    不知老師是否有 arduino 連結 ArduCAM 的線路圖及程式碼的文章,
    可讓我解惑..

    謝謝

  21. 老師您好:

    請教老師
    如果有8個輸出腳2,3,4 5, 6, 7, 8, 9
    將使用2 3 4輸出腳,當按下按鈕啟動,已跑馬燈的形式隨機亮燈,在按一下停止,這應該要如何做呢?

    如果運用這篇的Code 應該要如何改成隨機亮燈呢?

    1. hi ted:

      根據你的程式需求,我大概會這樣寫:

      建立一個陣列,儲存LED燈腳位。
      依據腳位數量,隨機產生一個值。
      把隨機值當作陣列的索引,點亮該陣列元素存放的LED腳位。
      產生隨機值,如果隨機值和之前的相同,就再產生一個隨機值,直到不同為止。
      熄滅目前的LED。

      請拿出筆、紙,把自己的想法整理一遍。這些基本指令書本裡面都有談到。

      thanks,
      jeffrey

  22. 感謝老師的回覆

    我是有用random這指令,到老師這個Code來做測試,當按下按鈕確實會動作,不過網頁OFF按鈕沒切換到ON按鈕,程式也成無限迴圈的狀態,網頁就當了,有沒有辦法讓他等待我再按一次按鈕停止動作呢?

    1. 你的意思是,當Arduino隨機閃燈時,網頁也「同步」顯示LED狀態嗎?因為上文的程式會在Arduino每次改變狀態時,就更新網頁給前端,考量到Arduino的效能和網路所造成的延遲,你可能需要重新思考一下解決方案。

      如果閃爍的頻率不高,或許用AJAX網頁可以辦到;也就是當LED燈狀態改變,Arduino可以向網頁發出一段JSON資料,例如:{“on”:2}代表目前點亮的是第2腳,網頁的JavaScript解析之後,再更新網頁畫面。

      另外兩個可行的「非同步」方式:
      1. 隨機ON, OFF動畫交給JavaScript處理,等到用戶在手機按下某按鈕,再送出訊號交給Arduino點亮。
      2. 隨機點亮Arduino的LED燈,網頁上呈現「處理中」之類的訊息,等用戶按下按鈕,Arduino傳回點亮的LED更新畫面。

      have fun!
      jeffrey

    1. 你修改的程式會讓網頁「當掉」,應該是處理頁面內容的函式,例如getCmd(),當中的迴圈沒有終止。

      defaultCmd()和getCmd()函式用於處理「網頁」相關內容;若要讓Arduino反覆執行一段程式碼(如:閃爍LED),請將它放在loop()函式。

      例如,你可以先宣告一個全域變數,儲存LED的狀態:

      接著在getCmd()或者你設定的函式中,接收HTML表單值,並藉此設定LED的狀態:

      建立一個讓LED閃爍的自訂函式:

      在loop()函式中呼叫閃爍LED的函式:

      大致上就是這樣,建議你先從閃爍單一LED開始實驗,再改成多個LED的版本。

      thanks,
      jeffrey

  23. Dear Jeffrey
    謝謝您這麼快速的回應
    再請問您一個問題

    網路上看到一種說法︰
    為了怕電壓過大,
    所以可以在繼電器裝上保險絲。

    請問您是否知道這部份應當如何實作?
    謝謝!

    1. 保險絲通常是保護電路不受過大的電流破壞,如果有疑慮,你應該挑選耐電流大一點的繼電器,而不是加裝保險絲。或者,你可以將繼電器焊接在具備「過電流保護」的延長插座,這樣最簡單,

      thanks,
      jeffrey

  24. 感謝^_^~老師的解惑 測試了一段時間,終於有看到效果了

    不過還有問題要請教老師,我是使用2~9的輸出,設計6個按鈕,而前三個輸出(2~4)為一個按鈕來控制隨機變燈,其他輸出各自對應1個按鈕,遇到問題就是當我按下隨機變燈時,按鈕確實有動作,可是接著我按其他按鈕的時候,它直接關掉我”隨機變燈”按鈕的動作
    ><"~Oh My God!

    而且"隨機變燈"按鈕換會有延遲(思考中…),還有老師之前提到的產生隨機值,如果隨機值和之前的相同,就再產生一個隨機值,直到不同為止。

    我有想過這個問題,不過不知道該如何寫,有嘗試用randomSeed看不出效果…

    以下測試是修改老師的Code 麻煩老幫我檢查看看…
    https://mega.co.nz/#!CQgkyZTS!12hQCaWRHfjA_Q6bZQ_M6daPQ85p-8QhohmriIecH-k

    1. 檢查數值是否重複的方法,最簡單就是用一個迴圈,比較目前的值和之前的值,如果一樣,就再產生一個,直到不同為止。因為電腦的執行速度很快,用戶不會察覺這一點延遲。

      thanks,
      jeffrey

  25. 謝謝老師這麼快速的回應^_^

    不過我這問題是不知要如何解決,我設了6個按鈕,第1個按鈕控制2~4的輸出來做隨機變燈的功能,按下第1個按鈕時,功能有在動作,當按其它5個按鈕時,本身對應按鈕的功能有動作,不過卻把第1個按鈕的功能給關掉了….不知到程式哪邊干擾到了><"

    以下是測試的Code 麻煩老師幫我看一下 謝謝
    https://mega.co.nz/#!CQgkyZTS!12hQCaWRHfjA_Q6bZQ_M6daPQ85p-8QhohmriIecH-k

  26. 老師你好 之前提到的問題已處理好了…

    不過我剩下最後一個問題是,我設6個按鈕中的第1個按鈕為(隨機

    亮燈)的功能,當按下按鈕功能雖有正常運作,不過按鈕上的OFF文字

    不會切換為ON文字,點即確實有開跟關的功能,其他5個按鈕都正

    常運作….這發生了甚麼事(卻只有第1個按鈕有問題><")

    能麻煩老師幫我看下這Code 哪邊寫錯嗎?
    https://mega.co.nz/#!6dIxRAAb!YhSCFFdh7SRdVaw8MUd5kV-fBVTtwBan55GarFuWdlY

  27. 老師你好~之前提到到問題 都處理好了 ^^”

    這邊還有個問題是,當我按下第1個按鈕讓2~4輸出為隨機亮燈,其餘5個按鈕單純的切換開關,可是第1個按鈕卻無法切換Button上的文字OFF 變 ON,功能還是有動作,而其他5個按鈕都可正常切換,真不知道哪邊寫錯了而干擾到第1個按鈕嗎?

    想請老師幫我看看哪邊寫錯了…
    https://mega.co.nz/#!6dIxRAAb!YhSCFFdh7SRdVaw8MUd5kV-fBVTtwBan55GarFuWdlY

    1. 因為showPage()函式依據腳位的狀態顯示ON, OFF,你可以改寫其中的判斷條件 digitalRead(swPins[i]) == 1 敘述,改用一個陣列暫存ON, OFF狀態值,不要直接讀取數位腳的狀態,或者額外加入切換顯示第一個按鈕的程式碼。

      have fun!
      jeffrey

  28. 老師你好
    我想說在接完整個電路之前
    先測試是否能夠開關燈
    所以我把pin腳位改到13去控制板上的電燈
    是可以開燈
    但都是按一下 閃一下 而且網頁上一直都是顯示off
    想問老師要怎麼修正 因為我不太懂用web控制的方法嗚嗚 ˊˋ

    1. hi kevin:

      乙太網路卡採用SPI介面與Arduino相連(請參閱15-24頁),所以第13腳不能挪作他用。

      thanks,
      jeffrey

  29. 對耶對耶
    謝謝老師的迅速回覆太感動了嗚嗚嗚
    居然忘記這麼重要的東西還在那蝦改哈哈 = =

  30. 老師你好

    我想請問網路家電控制這個單元,如何用時間來控制,就是可以自行設定時間(10分鐘、1小時…等),他會自動開跟關,這要如何處理呢?

    1. hi ted:

      需要長時間計時的場合,建議搭配採用I2C介面的DS1307即時鐘IC,市面上很容易買到這種模組。搭配RTClib程式庫,可輕鬆設置定時觸發的時間。以RTClib提供的DS1307範例程式為例:

      // 取得現在的時間
      DateTime now = rtc.now();
      // 未來一小時的時間
      // 註:60分 x 60秒 = 3600秒
      DateTime future (now.unixtime() + 3600);

      在你的loop()函式中,不停地讀取目前的時間,再和預設的「未來」時間相減,即可判斷是否已到預設的時間,例如:

      // 取得現在的時間
      DateTime now = rtc.now();
      :
      if (future – now.unixtime() <= 0) {
      // 時間到…執行開關動作
      // 重新設定future時間
      future (now.unixtime() + 3600);
      }

      另外,你也可以參考並改寫datecalc(日期計算)的範例程式。

      thanks,
      jeffrey

  31. 感謝老師這麼快的回覆

    所以說要做到設定時間的功能,就需要用到DS1307即時鐘IC囉!

    他最多可控制多少個開關的時間呢? 例如:開關A設5分鐘開,開關B設10分鐘開,會衝突道嗎?

    而我要如何從網頁傳送信號到Arduino板上,他才知道我所設定的時間。

    我來研究看看….

    1. DS1307晶片的作用是提供微處理器一個穩定的時間資料,「定時」功能是靠自訂的程式完成,跟DS1307晶片無關。所以,如果你設定了5個「定時」時段,那就寫5個判斷條件…至於從網頁傳出資料,用POST或GET方法都行。

      thanks,
      jeffrey

  32. 老師你好

    請問那使用millis()可以做到「定時」功能嗎?
    老師書上是寫,當按下按鈕跟放開的時間相減,就知道按了多少時間,那當我按下按鈕儲存他的現在時間,再和預設的「未來」設定的時間相減要如何做呢?

    下面程式當時間大於10秒就會亮,不過這時millis()遠遠大於10秒,例如要做到按下10秒後亮,再按一次10秒後關….

    void Timer()
    {
    if(LED_State)
    {
    time = millis();

    if(time >10*1000)
    {

    digitalWrite(2, HIGH);
    }
    }
    }

    1. 可以用millis()計算經過時間,但是,其實Arduino已經有多個計時器相關程式庫可用,像SimpleTimer,它已經幫我們把millis()包裝成簡易使用的計時程式。

      請在此SimpleTimer的GitHub頁面下載程式庫,底下是取自arduino.cc上的範例程式碼:

      其中,setInterval()會不停地執行指定的函式,setTimeout()則會在時間到時,執行一次指定的函式,你可以利用它來撰寫定時執行的程式。

      thanks,
      jeffrey

  33. 謝謝老師得回覆

    那使用SimpleTimer的話,要如何讓他當按下按鈕就開始計時,例如10秒後亮燈,在按一次按鈕10秒後熄燈呢?

    而下面是用老師書上13-39範例來修改
    https://mega.co.nz/#!PYREGJQB!wJU6zq7NJKoKYvx8l8rVr6nfjmH7g_aDN6-_c_Ft5gc

    當我按下按鈕(網頁顯示SET)開始計時10秒後,輸出PIN2 LED有亮,當我在按一次,以樣開始計時10秒後LED就暗。

    我現在遇到的問題是,當開始計時途中,再按下按鈕如何將計時功能關掉呢?

    還有就是按下按鈕時,網頁顯示按鈕是紅色,如果當計時結束或中斷如何讓他變回綠色呢?應該說要如何讓他知道計時結束或中斷…

    1. 使用SimpleTimer程式庫,只要告訴它「幾微秒之後」要觸發哪個函式即可。以底下的程式碼為例,在序列埠監控視窗輸入’1’,即可打開LED,過了10秒之後,LED就熄滅:

      這開關的邏輯蠻單純的,其餘部份就麻煩你動腦筋了。

      thanks,
      jeffrey

  34. 老師你好

    有個問題就是,如何像設定鬧鐘的方式,譬如說按下開關要鬧鐘12:00響,在時間還沒到的期間,就把它關掉,當然12:00不會響了。

    開始計時的時間內如何讓他停止計時(暫停),時間到了也不會有動作…Orz

    1. 搭配ds1307即時鐘模組就沒有這個問題了,它就像使用電池運作的時鐘一樣,即使電器產品因為停電而無法運作,時鐘仍舊繼續轉動。模組使用的水銀(鋰)電池,足夠它運作好幾年。

  35. 謝謝老師的回覆

    不好意思再次倒擾…

    其實我想的功能不是要,當電器產品因為停電而無法運作,時鐘仍舊繼續轉動 ><"。

    是當在已設定好的時間內,按下啟動才開始計時,而在計時的這段期間臨時或突然不想要計時,因該如何中斷計時器,就像給計時器一個開關一樣。

    最近試了好久還是想不出如何控制….

  36. 老師你好~~~
    我想詢問一下
    我們是用cc3000wifi模組+三軸+arduino uno 板來做專題
    在cc3000 wifi 模組上架設一個網站來接收三軸的值
    然後利用手機的APP去抓取網站上的值並判讀他的資料
    我們是利用網路上提供的範例程式來修改
    目前我們已可以連線
    但在連線的部分
    發現如果cc3000連手機分享出來的行動網路
    要從別人手機裡看到網頁
    別人的手機也必須連上同一個行動網路然後輸入他產生出來的ip才有辦法看到網頁裡的東西
    那我們應該要怎麼樣修改或是怎麼做,任何人只要在有網路的情況下在瀏覽器上打ip就可以看到網頁呢~~

    1. hi kirby:

      你要設定讓cc3000 wifi模組連接到無線網路基地台;一般的基地台都具備虛擬伺服器(virtual server)或者虛擬非軍事區(DMZ)的功能,讓你指定將某個IP的裝置(如:cc3000 wifi模組)公開到網際網路上。

      詳細的設定方式請參閱說明書或洽詢廠商。

      thanks,
      jeffrey

    1. hi ted:

      SimpleTimer程式庫本身就有提供暫停計時的功能,函式名稱叫toggle()。

      底下的程式使用setInterval()每秒執行一次repeatMe()。在序列埠監控視窗輸入’1’即可啟動計時器,輸入’2’可暫停或重新啟動計時器:

      thanks,
      jeffrey

  37. 謝謝老了回覆 研究了之後現在知道如何使用了 謝謝

    老師寫的Code 是可以寫是讓秒數在 Serial Monitor顯示,我有嘗試顯示在網頁上,不過他都只會顯示一開始的秒數出值,如果按刷新網頁是可以看見秒數有在變化,不過這樣按刷新又會再觸發計時的功能

  38. 老師你好

    如果我要讓顯示秒數在網頁上呈現應該要如何做,雖然有顯示出開始的出值,不過要一直按重新仔入才看到數字的變化,不過這樣也導致相同的功能也一直的重複觸發,這應該要往哪邊做修改呢?

    1. 在網頁前端執行計時功能,需要透過JavaScript語言執行,網路上有很多相關的例子,市面上也有不少JavaScript書籍,再麻煩自行參考。

      thanks,
      jeffrey

  39. 老師你好:

    我有看書上的 家電控制範例,裡面有用POST來傳遞使用者輸入的”你好”。

    我有一些問題想請教老師:
    1. 怎麼讓網頁(webduino) 開啟一個.txt檔,讓裡面的文字可以透過網頁來傳遞?
    2. 在網頁上要怎麼加上 copy、paste 的功能? webduino有支援嗎?
    3. 可以讓輸入網頁的資料分批送過來嗎? 網頁可以自己做字元辨識,並轉成數值,送給Arduino嗎?

    1. hi brian:

      畢竟Arduino UNO只是個8位元控制器,效能有限,當作網路控制器的終端沒問題,例如,接收命令控制電器的開關,或者傳回感測器的數據。

      但是你的需求比較像是架設一般功能的網站(非控制器或感測器節點),像剪貼或字元辨識功能,那是透過瀏覽器端執行的JavaScript程式完成,跟後端(如:Arduino或其他網站伺服器程式)沒有直接的關聯性。

      thanks,
      jeffrey

  40. 老師您好!
    我使用您的程式碼後
    出現
    diy16_6.ino:7:23: fatal error: WebServer.h: No such file or directory
    compilation terminated.
    編譯時發生錯誤
    不知道是甚麼情況呢?
    新手上路><

  41. 老師您好:
    我使用你動手做的第16個單元,所提供的範例去測試,程式裡
    我有修改的部分如下(我用1024個數字字元去測試):

    1.
    char name[16], value[10001];
    while (server.readPOSTparam(name, 16, value, 10001))
    我發現,每次只要宣告為如此,瀏覽器就跳不到SW網頁,它
    會一直等在form。

    2.
    char name[16], value[1025];
    while (server.readPOSTparam(name, 16, value, 1025))
    網頁有正常秀出1024個字

    3.
    char name[16], value[10001];
    while (server.readPOSTparam(name, 16, value, 1025))
    瀏覽器就跳不到SW網頁,它在form網頁等待。

    4.
    char name[16], value[501];
    while (server.readPOSTparam(name, 16, value, 10001)){ 網頁秀出2048個字,有效的(跟pattern一樣的約600個)

    從以上的結果來看,還是看不出來,問題到底卡在哪裡?
    第4個情況更怪?
    老師,我想要達成透過網頁送給arduino,10000個字元,並正確
    秀在網頁上的目標,請老師指引,謝謝。

    1. 因為ATmega328P處理器的SRAM(主記憶體)只有2KB。你的需求,在個人電腦或Raspberry Pi之類的Linux微控制器,執行PHP, Node.js等的後端程式,很容易完成。

      如同我之前的回應,Arduino適合當作網路控制器或感測器節點,若需要大量的資訊處理機能,請選用其他控制器。

      thanks,
      jeffrey

  42. 謝謝老師的回覆,我目前還是想選用Arduino 板。

    我手上的控制器是 Arduino Mega 2560,SRAM有8K。
    我也試著將 value[10001],存入程式記憶體了,可是還是不行。

    請問老師,到底是卡在哪裡呢? 是 Arduino記憶體不夠,還是網頁function等的問題? 請老師指引,謝謝。

  43. 老師你好
    我想判斷輸出腳的電位
    再用XBEE來傳字元訊號
    這是我寫的
    val=digitalRead(3);
    switch(val)
    {
    case (HIGH):
    Serial.print(‘A’);
    delay(5000);
    break;
    case (LOW):
    Serial.print(‘B’);
    delay(5000);
    break;
    }
    可是XBEE會瘋狂一直傳字元 我只能藉由delay來減緩的一直傳送字元的速度
    有沒有辦法把它改成傳送一次就好 直到的電位改變 在傳送一次呢?

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *