Showing posts with label Arduino. Show all posts
Showing posts with label Arduino. Show all posts

Tuesday, June 2, 2015

[智能家居]用Arduino官方WiFi Shield的控制LED開關(使用Mac環境)

文章攢寫時間︰2015/06/02 14:03

一、前言

前一篇更新完WiFi Shield的韌體(firmware v1.1.0)後,
我們也因此進入一個天馬行空的世界。
能利用這塊板子做些什麼事呢?

嗯⋯就從微智能家居「控制LED的開關」開始吧~

二、文章開始

步驟1 準備需要的環境

這個專案需要使用到以下的玩具
  • 可連線上網的無線路由器AP
  • Arduino UNO
  • WiFi Shield
  • 330Ω電阻(橙橙棕) x1
  • LED燈泡 x1
  • 跳線 x2
麵包板示意圖
實際連接的樣子

步驟2 下載需要的函式庫Webduino

這個專案需要使用到支援WiFi Shield的Webduino函式庫,
我有針對Webduino Library稍做修改以支援WiFi Shield。

請至GitHub下載並放在
你的Arduino目錄\libraries底下



不熟悉Git的人,
可以到此下載zip壓縮包

步驟3 複製程式碼並引用需要的函式庫


開啟一個全新的Arduino專案,
將下方程式碼全數貼上。
char ssid[] = "換成你的WiFi無線網路名稱";
char pass[] = "換成你的WiFi無線網路密碼";

int status = WL_IDLE_STATUS;
WebServer webserver("", 80);

P(homePage) =
  "<!doctype html>"
  "<html>Arduino微網站</title>"
  "</head><body>"
  "這是微網站首頁。"
  "</body></html>";

P(lightPage) =
  "<!doctype html>"
  "<html>Arduino微網站</title>"
  "</head><body>"
  "這是燈泡控制專頁。"
  "</body></html>";

P(Get_head) = "<h1>收到了GET</h1>";
P(Post_head) = "<h1>收到了POST</h1>";
P(Unknown_head) = "<h1>UNKNOWN request</h1>";

const byte LED_PIN = 9;//LED燈泡插在PIN腳9

/**預設的指令是印岀homePage的文案*/
void defaultCmd(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
{
  server.httpSuccess();
  Serial.println("httpSuccess");
  if (type != WebServer::HEAD)
  {
    server.printP(homePage);
  }
}

/**當收到燈泡控制的指令時*/
void lightCmd(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
{
  server.httpSuccess();
  Serial.println("httpSuccess");
  if (type != WebServer::HEAD)
  {
    //檢查是傳來的是GET或是POST
    switch (type)
    {
      case WebServer::GET:
        server.printP(Get_head);
        server.println(" ");
        break;
      case WebServer::POST:
        server.printP(Post_head);
        server.println(" ");
        parsePost(server);
        break;
      default:
        server.printP(Unknown_head);
    }
    server.printP(lightPage);
  }
}

/**解析傳來的POST指令*/
void parsePost(WebServer &server) {
  Serial.println("parsePost");

  char key[16];
  char value[16];
  while (server.readPOSTparam(key, 16, value, 16)) {

    //比對字元使用的是strcmp,當回傳值為0時代表字元符合
    if (strcmp(key, "light") == 0) { 
      server.print("燈光已經");
      if (strcmp(value, "on") == 0) {
        digitalWrite(LED_PIN, HIGH);
        server.print("打開。");
      } else {
        digitalWrite(LED_PIN, LOW);
        server.print("關閉。");
      }
    }
  }
}

void setup() {
  pinMode(LED_PIN, OUTPUT);//初始化LED燈
  
  Serial.begin(9600);//初始化序列埠至9600

  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }

  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 5 seconds for connection:
    delay(5000);
  }

  // 設定當外部連線連入Arduino時,相對應的處理函式
  webserver.setDefaultCommand(&defaultCmd);   // 處理「首頁」的請求
  webserver.addCommand("light.html", &lightCmd);  // 處理「燈泡控制頁」的請求
  webserver.begin();

  // you're connected now, so print out the status:
  printWifiStatus();
}

void loop() {
  webserver.processConnection();
}

/**印岀連線的WiFi狀態*/
void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

步驟4 引用函式庫

這個專案需要用到WiFi、SPI和上面所述的Webduino共三個函式庫,
請在Arduino IDE工具列中使用[草稿碼]→[include Library]來引用。

※剛才下載到libraries目錄底下的Webduino岀現在Contributed libraries裡了(見下圖)

步驟5 編譯並啟動

引用完所需要的函式庫以後,
就可以驗證並上傳程式至Arduino UNO裡了。
啟動序列埠監控視窗(Shift + Command + M),
等待連線的ip位址陸出。

步驟6 使用CocoaRestClient對WiFi Shield發岀POST連線

因為範例裡是使用POST的方式去發岀key為light和value為on/off的參數去控制LED燈,
推薦使用CocoaRestClient這套軟體去發岀POST請求。


接著就可以等著看結果囉!


三、注意事項
Arduino官方有提到WiFi Shield的以下數位PIN腳已被使用,
串接LED燈時請不要再使用這些腳位了。

數位PIN腳4 被用來當作SD卡的Slave Select(控制訊號)了。
數位PIN腳7 被用來當作WiFi Shield和Arduino之間的握手協定(handshake)了。
數位PIN腳10 被用來當作WiFi的Slave Select(控制訊號)了。
數位PIN腳11, 12, 13被用來當作Arduino溝通的序列埠了。

所以我們只能用數位PIN腳 3, 5, 6, 8, 9來控制LED燈。

四、結論

我們透過HTTP的POST方式將參數丟給Arduino WiFi Shield,
當然我們也就可以用GET來丟參數。
但因為Webduino這套第3方函式庫對於POST有較佳的程式支援,
理所當然就使用POST來傳輸以控制LED燈的開關嚕!

在成功使用WiFi控制LED燈後,
接下來聰明的你還想玩些什麼呢?(笑)

相關連結

1. Arduino官方網站
2. 更新WiFi Shield firmware

Friday, May 29, 2015

更新Arduino官方WiFi Shield的firmware(使用Mac環境)

文章攢寫時間︰2015/05/29 15:13
文章更新時間︰2015/05/31 18:04
文章更新次數︰2

一、前言

花了3千塊買了一塊官方的WiFi Shield板子,
原以為好日子就此開始,
疏不知用板子對外發岀request時,
居然一直回應我connected failed.

查了一下才知道因為原廠的firmware過舊(v.1.0.0),
解決辦法有︰
1.不更新韌體,繼續研用舊版v1.0.0搭配Arduino IDE 1.0.2對外連線(請參考Ken Yang部落格)
2.更新WiFi Shield的韌體讓最新版Arduino IDE 1.6.4能順利對外連線

查看韌體版本可透過以下語法
Serial.begin(9600);
Serial.println(WiFi.firmwareVersion());
記得include SPI.h 和 WiFi.h 兩個類別!

這裡我就來實作更新韌體的部份!

二、文章開始
依照官方的教學的說明,
在更新韌體進板子前,
務必將WiFi Shield從Arduino板子上拔除

步驟1 安裝MacPorts

MacPorts 是一個用於編譯、安裝與管理 Mac OS X 中各類開放原始碼軟體的工具,
其由開放原始碼社群負責主導與開發,
透過這個工具可以簡化安裝軟體的編譯工作,
並且可以自動處理套件相依性問題,
概念上很類似 Linux 的 apt 與 yum,
只要下達一些簡單的指令就可以輕鬆安裝各種軟體。
(以上解釋來至CTW論壇)

MacPorts官網依照你的Mac OS版本下載相對應的安裝檔案。


步驟2 更新MacPorts至最新版

進入終端機裡,輸入以下指令
$sudo port selfupdate


步驟3 下載DFU Programmer

DFU(Device Firmware Update) Programmer這套軟體被Arduino專門用來更體韌體專用,
因此,
我們透過MacPorts將DFU Programmer軟體下載下來。
語法是
$sudo port install dfu-programmer

下載下來後,請確保是最新版本。
語法如下
$sudo port upgrade outdated

※請確認安裝完的DFU Programmer版本在v0.5.4(含)或之後。

步驟4 下載或在電腦中找岀最新的韌體檔

如果要下載最新版的WiFi軔體,可以到GitHub下載(wifishield整個目錄便是)。
或者,也會直接放在最新版的Arduino application裡。
1.使用Finder開啟應用程式資料夾
2.對Arduino.app點擊滑鼠右鍵選擇「顯示套件內容」

3.我的wifishield韌體資料夾路徑是在
/Applications/Arduino/Arduino164.app/Contents/Java/hardware/arduino/avr/firmwares/wifishield/

步驟5 執行腳本檔以利燒錄韌體至板子中

官方有替Linux或Mac版本的使用者寫一套自動化安裝流程,
語法的存放路徑在剛才目錄中的底下目錄scripts裡
分別可看到有2個檔案
ArduinoWifiShield_upgrade_mac.sh(Mac專用)

ArduinoWifiShield_upgrade.sh(Linux專用)

因為腳本檔是用DFU-Programmer寫起來的,
因此只要剛才DFU-Programmer在v0.5.4以後,
就可以開始接下來的步驟!

為了讓WiFi Shield進入programming mode,
需使用Jumper將J3連結點串聯起來。

將Jumper拔起來並完整的接上2根排針以進入Programming mode模式
將已拔除Arduino板的WiFi Shield插入電腦USB,另一端插在板子的Mini USB孔上。

接著在終端機裡執行剛才的腳本檔
我下的語法如下
$sudo sh /Applications/Arduino/Arduino164.app/Contents/Java/hardware/arduino/avr/firmwares/wifishield/scripts/ArduinoWifiShield_upgrade_mac.sh -a /Applications/Arduino/Arduino164.app/Contents/Java -f shield

順利的話,就能看到韌體更新成功視窗了。

最後記得將Jumper拔掉並按下板子上的RESET鍵,
整個韌體更新的動作就完成囉!

查看一下,
WiFi firmware的版本已更新至最新v1.1.0無誤。


使用client.connect(server, 80)對Google發岀一次頁面request,
也不會再遇到connect failed了!


三、其它
如果有使用Webduino Library
與Arduino IDE 1.6.4匹配的Webduino版本是1.7。

四、結論

更新完WiFi Shield firmware後,
接下來做些什麼呢?

嗯⋯跟我一起玩微智能家居吧!

相關連結

1. Ken Yang的部落格
2. Arduino官方
3. 國外一篇更新韌體的部落格教學