本文章教各位讀者如何用手機撰寫App Inventor的應用程式,並透過Wi-Fi 來控制LinkIt 7697開發板上所接的 RGB 三色LED燈。在此會把7697作為 web server,App Inventor則是透過 IP 搭配指定字元來與它互動。
| 作者/攝影 | 曾吉弘 |
| 時間 | 3小時 |
| 難度 | ★★★★☆ |
| 材料表 |
|
本文要介紹如何將LinkIt 7697 作為一個簡易的web server (修改自MTK原廠範例),可透過網頁與App Inventor 來控制它。CAVEDU 2017年已經執行了超過30場的 LinkIt 7697研習,請參考我們的教學投影片,也歡迎找我們去上課啦~
硬體組裝
請將LinkIt 7697與共陰RGB LED接上麵包板後,按照以下對應來接線:
| RGB LED | LinkIt 7697 |
| R | P11 (D11) |
| G | P9 |
| B | P7 (也是板載的USR LED) |
| GND | 任一GND即可 |
完成如下圖

App Inventor
請登入MIT App Inventor之後,建立一個新專案。或直接由App Inventor中文學習網匯入本專案原始檔,唯一要修改的地方就是LinkIt 7697於您所指定網路所取得的IP位址。
Designer
- 新增一個HorizontalArrangement,其中放入一個按鈕與Label,按鈕是用於設定IP,label則是用於顯示各種訊息。
- 新增一個Textbox,Text設為空,Hint則設為”check 7697 ip in serial monitor”,用於輸入7697的實際IP
- 新增一個TableArrangement,寬度設為Fill parent,高度為200像素。Row=2。Column=3。接著放入五個按鈕,寬度各為33%,高度則為100像素。這些分別用於讓RGB LED亮紅色(R)、綠色(G)、藍色(B)、白色(W)與熄滅。
- 新增一個
完成後如下圖:

STEP1 IP變數與設定IP按鈕
在此宣告一個變數,內容為”http://192.168.1.73”,這是LinkIt 7697於您所指定網路中所取得的IP。後續會把這個變數值用於Web元件的Url屬性。如果您只有一片LinkIt 7697或已經確定其IP的話,可以在此把它寫死不用修改。
不過為了方便起見,我們可以透過Textbox來設定新的IP,這在您現場有多片LinkIt 7697要控制時很方便。按下Button_setIP按鈕,會先檢查Textbox是為空,如果已輸入內容就將設定結果顯示於Label,否則將顯示錯誤訊息於Label。

STEP2 副程式用於設定URL與顯示訊息
在此宣告一個副程式來管理每次按下按鈕時所發送的字元與顯示訊息。請新增一個procedure,並點選藍色方塊來新增參數,點選副程式與參數名稱即可修改名稱。在此副程式名稱改為sendData,參數名稱為message / command。

在sendData副程式中,我們會把送進來的參數分別用於7697的網址(組合結果:http://192.168.1.73/R,不同字元對應不同動作)與要顯示的訊息。最後再呼叫Web.Get來呼叫LinkIt 7697所產生的網址即可。

STEP3 各顏色燈光按鈕
這樣做程式是否變的很清爽呢?每個按鈕的差別只在於參數不同而已,當然如果我們要發送/W出去的話,LinkIt 7697也要有對應的程式才行。簡列如下:
Button_R(紅燈):Red 與 /R
Button_G(綠燈):Green 與 /G
Button_B(藍燈):Blue 與 /B
Button_W(白燈):white 與 /R
Button_off(紅燈):Red 與 /o (小寫的o~)

LinkIt 7697Wifi範例:
本範例修改自LinkIt 7697的SimpleWebServerWifi範例(就是多加幾個字元而已),重點段落
1.連上指定網路
[pastacode lang=”markup” manual=”while%20(status%20!%3D%20WL_CONNECTED)%20%7B%0A%20%20%20%20Serial.print(%22Attempting%20to%20connect%20to%20Network%20named%3A%20%22)%3B%0A%20%20%20%20Serial.println(ssid)%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20print%20the%20network%20name%20(SSID)%3B%0A%0A%20%20%20%20%2F%2F%20Connect%20to%20WPA%2FWPA2%20network.%20Change%20this%20line%20if%20using%20open%20or%20WEP%20network%3A%0A%20%20%20%20status%20%3D%20WiFi.begin(ssid%2C%20pass)%3B%0A%20%20%7D%0A%20%20server.begin()%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20start%20the%20web%20server%20on%20port%2080%0A%20%20printWifiStatus()%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20you’re%20connected%20now%2C%20so%20print%20out%20the%20status%0A” message=”” highlight=”” provider=”manual”/]2.於7697簡易網頁中網頁顯示訊息,您可在7697所產生的網頁上編寫簡易的html。在此使用超連結可以直接點選。當然目標是透過App Inventor來發送囉。
[pastacode lang=”markup” manual=”client.print(%22Click%20%3Ca%20href%3D%5C%22%2FR%5C%22%3Ehere%3C%2Fa%3E%20to%20light%20red%3Cbr%3E%22)%3B%0Aclient.print(%22Click%20%3Ca%20href%3D%5C%22%2FG%5C%22%3Ehere%3C%2Fa%3E%20to%20light%20green%3Cbr%3E%22)%3B%0Aclient.print(%22Click%20%3Ca%20href%3D%5C%22%2FB%5C%22%3Ehere%3C%2Fa%3E%20to%20light%20blue%3Cbr%3E%22)%3B%0Aclient.print(%22Click%20%3Ca%20href%3D%5C%22%2FW%5C%22%3Ehere%3C%2Fa%3E%20to%20light%20white%3Cbr%3E%22)%3B%0Aclient.print(%22Click%20%3Ca%20href%3D%5C%22%2Fo%5C%22%3Ehere%3C%2Fa%3E%20to%20light%20off%3Cbr%3E%22)%3B%0A” message=”” highlight=”” provider=”manual”/]3.檢查網址並呼叫自定義函式來控制LED。如果我們檢查到某次client request(手機或透過網頁點選)的結尾等於我們所指定的字元,就呼叫led()函式,並透過參數來決定哪一個顏色亮起。1,0,0就是紅色,0,0,1是藍色等。
在此我們並沒有調整每一種顏色的亮度,所以只有亮暗兩種狀態,您可以思考一下如何透過這樣的架構把參數送進來給analogWrite()函式來調整RGB LED的亮度,例如(128, 130, 255),這樣顏色的變化會更繽紛喔!
[pastacode lang=”markup” manual=”%2F%2F%20Check%20client%20request%0A%20%20%20%20%20%20%20%20if%20(currentLine.startsWith(%22GET%20%2FR%22))%20%7B%20%20%2F%2F%20GET%20%2FR%20to%20light%20red%0A%20%20%20%20%20%20%20%20%20%20led(1%2C0%2C0)%3B%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%7D%0A%2F%2F%E5%85%B6%E9%A4%98%E7%9C%81%E7%95%A5%0A%0Avoid%20led(int%20R%2C%20int%20G%2C%20int%20B)%20%7B%0A%20%20digitalWrite(11%2C%20R)%3B%0A%20%20digitalWrite(9%2C%20G)%3B%0A%20%20digitalWrite(7%2C%20B)%3B%0A%7D%0A” message=”” highlight=”” provider=”manual”/]操作
請先確認7697端程式已經執行,並開啟Serial Monitor來看7697的IP為何。將App Inventor中的ip變數值改好之後執行(由於本範例並非使用藍牙,所以模擬器也可執行)。

確認好IP之後,先開啟瀏覽器,您所使用的裝置需與7697位於同一個網段之下才行喔,如以下的192.168.1.73。

開啟app吧,設定IP成功畫面如下圖左,點選各個按鈕可以看到畫面右上角的label會顯示對應的訊息,您的RGB LED順利亮起來了嗎?


Simple:13
[pastacode lang=”markup” manual=”%2F*%0A%20%20WiFi%207697%20LED%20control%0A%20%20If%20the%20IP%20address%20of%20your%20shield%20is%20yourAddress%3A%0A%20%20http%3A%2F%2FyourAddress%2FR%20to%20light%20red%0A%20%20http%3A%2F%2FyourAddress%2FG%20to%20light%20green%0A%20%20http%3A%2F%2FyourAddress%2FB%20to%20light%20blue%0A%20%20http%3A%2F%2FyourAddress%2FW%20to%20light%20white%0A%20%20http%3A%2F%2FyourAddress%2Fo%20to%20turn%20off%20LED%0A%0A%20%20Circuit%3A%0A%20%20%20%20LinkIt%207697%20HDK%0A%20%20%20%20RGB%20LED%20(common%20cathode)%20%0A%20%20%20%20R%20-%20LinkIt%20D11%0A%20%20%20%20G%20-%20LinkIt%20D9%0A%20%20%20%20B%20-%20LinkIt%20D7%0A%0A%20%20created%2025%20Nov%202012%0A%20%20by%20Tom%20Igoe%0A%20%20modified%203%20Nov%202017%0A%20%20by%20CAVEDU%0A*%2F%0A%23include%20%3CLWiFi.h%3E%0A%0Achar%20ssid%5B%5D%20%3D%20%22ssid%22%3B%20%20%20%20%20%20%2F%2F%20%20your%20network%20SSID%20(name)%0Achar%20pass%5B%5D%20%3D%20%22pass%22%3B%20%20%20%2F%2F%20your%20network%20password%0Aint%20keyIndex%20%3D%200%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20your%20network%20key%20Index%20number%20(needed%20only%20for%20WEP)%0A%0Aint%20status%20%3D%20WL_IDLE_STATUS%3B%0AWiFiServer%20server(80)%3B%0A%0Avoid%20setup()%20%7B%0A%20%20Serial.begin(9600)%3B%20%20%20%20%20%20%2F%2F%20initialize%20serial%20communication%0A%20%20pinMode(LED_BUILTIN%2C%20OUTPUT)%3B%20%20%20%20%20%20%2F%2F%20set%20the%20LED%20pin%20mode%0A%20%20pinMode(11%2C%20OUTPUT)%3B%20%20%2F%2FR%0A%20%20pinMode(9%2C%20OUTPUT)%3B%20%20%20%2F%2FG%0A%20%20pinMode(7%2C%20OUTPUT)%3B%20%20%20%2F%2FB%0A%0A%20%20%2F%2F%20attempt%20to%20connect%20to%20Wifi%20network%3A%0A%20%20while%20(status%20!%3D%20WL_CONNECTED)%20%7B%0A%20%20%20%20Serial.print(%22Attempting%20to%20connect%20to%20Network%20named%3A%20%22)%3B%0A%20%20%20%20Serial.println(ssid)%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20print%20the%20network%20name%20(SSID)%3B%0A%0A%20%20%20%20%2F%2F%20Connect%20to%20WPA%2FWPA2%20network.%20Change%20this%20line%20if%20using%20open%20or%20WEP%20network%3A%0A%20%20%20%20status%20%3D%20WiFi.begin(ssid%2C%20pass)%3B%0A%20%20%7D%0A%20%20server.begin()%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20start%20the%20web%20server%20on%20port%2080%0A%20%20printWifiStatus()%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20you’re%20connected%20now%2C%20so%20print%20out%20the%20status%0A%7D%0A%0A%0Avoid%20loop()%20%7B%0A%20%20WiFiClient%20client%20%3D%20server.available()%3B%20%20%20%2F%2F%20listen%20for%20incoming%20clients%0A%0A%20%20if%20(client)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20if%20you%20get%20a%20client%2C%0A%20%20%20%20Serial.println(%22new%20client%22)%3B%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20print%20a%20message%20out%20the%20serial%20port%0A%20%20%20%20String%20currentLine%20%3D%20%22%22%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20make%20a%20String%20to%20hold%20incoming%20data%20from%20the%20client%0A%20%20%20%20while%20(client.connected())%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20loop%20while%20the%20client’s%20connected%0A%20%20%20%20%20%20if%20(client.available())%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20if%20there’s%20bytes%20to%20read%20from%20the%20client%2C%0A%20%20%20%20%20%20%20%20char%20c%20%3D%20client.read()%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20read%20a%20byte%2C%20then%0A%20%20%20%20%20%20%20%20Serial.write(c)%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20print%20it%20out%20the%20serial%20monitor%0A%20%20%20%20%20%20%20%20if%20(c%20%3D%3D%20’%5Cn’)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20if%20the%20byte%20is%20a%20newline%20character%0A%0A%20%20%20%20%20%20%20%20%20%20%2F%2F%20if%20the%20current%20line%20is%20blank%2C%20you%20got%20two%20newline%20characters%20in%20a%20row.%0A%20%20%20%20%20%20%20%20%20%20%2F%2F%20that’s%20the%20end%20of%20the%20client%20HTTP%20request%2C%20so%20send%20a%20response%3A%0A%20%20%20%20%20%20%20%20%20%20if%20(currentLine.length()%20%3D%3D%200)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20HTTP%20headers%20always%20start%20with%20a%20response%20code%20(e.g.%20HTTP%2F1.1%20200%20OK)%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20and%20a%20content-type%20so%20the%20client%20knows%20what’s%20coming%2C%20then%20a%20blank%20line%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20client.println(%22HTTP%2F1.1%20200%20OK%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20client.println(%22Content-type%3Atext%2Fhtml%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20client.println()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20the%20content%20of%20the%20HTTP%20response%20follows%20the%20header%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20client.print(%22Click%20%3Ca%20href%3D%5C%22%2FR%5C%22%3Ehere%3C%2Fa%3E%20to%20light%20red%3Cbr%3E%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20client.print(%22Click%20%3Ca%20href%3D%5C%22%2FG%5C%22%3Ehere%3C%2Fa%3E%20to%20light%20green%3Cbr%3E%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20client.print(%22Click%20%3Ca%20href%3D%5C%22%2FB%5C%22%3Ehere%3C%2Fa%3E%20to%20light%20blue%3Cbr%3E%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20client.print(%22Click%20%3Ca%20href%3D%5C%22%2FW%5C%22%3Ehere%3C%2Fa%3E%20to%20light%20white%3Cbr%3E%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20client.print(%22Click%20%3Ca%20href%3D%5C%22%2Fo%5C%22%3Ehere%3C%2Fa%3E%20to%20light%20off%3Cbr%3E%22)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20The%20HTTP%20response%20ends%20with%20another%20blank%20line%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20client.println()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20break%20out%20of%20the%20while%20loop%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0A%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%20%20%20%20%2F%2F%20if%20you%20got%20a%20newline%2C%20then%20clear%20currentLine%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20currentLine%20%3D%20%22%22%3B%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%20else%20if%20(c%20!%3D%20’%5Cr’)%20%7B%20%20%2F%2F%20if%20you%20got%20anything%20else%20but%20a%20carriage%20return%20character%2C%0A%20%20%20%20%20%20%20%20%20%20currentLine%20%2B%3D%20c%3B%20%20%20%20%20%20%2F%2F%20add%20it%20to%20the%20end%20of%20the%20currentLine%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Check%20client%20request%0A%20%20%20%20%20%20%20%20if%20(currentLine.startsWith(%22GET%20%2FR%22))%20%7B%20%20%2F%2F%20GET%20%2FF%20to%20light%20red%0A%20%20%20%20%20%20%20%20%20%20led(1%2C0%2C0)%3B%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(currentLine.startsWith(%22GET%20%2FG%22))%20%7B%20%20%2F%2F%20GET%20%2FG%20to%20light%20green%0A%20%20%20%20%20%20%20%20%20%20led(0%2C1%2C0)%3B%20%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(currentLine.startsWith(%22GET%20%2FB%22))%20%7B%20%20%2F%2F%20GET%20%2FB%20to%20light%20blue%0A%20%20%20%20%20%20%20%20%20%20led(0%2C0%2C1)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(currentLine.startsWith(%22GET%20%2FW%22))%20%7B%20%20%2F%2F%20GET%20%2FW%20to%20light%20white%0A%20%20%20%20%20%20%20%20%20%20led(1%2C1%2C1)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(currentLine.startsWith(%22GET%20%2FO%22))%20%7B%20%20%2F%2F%20GET%20%2FO%20to%20light%20off%0A%20%20%20%20%20%20%20%20%20%20led(0%2C0%2C0)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20%2F%2F%20close%20the%20connection%3A%0A%20%20%20%20client.stop()%3B%0A%20%20%20%20Serial.println(%22client%20disonnected%22)%3B%0A%20%20%7D%0A%7D%0A%0Avoid%20printWifiStatus()%20%7B%0A%20%20%2F%2F%20print%20the%20SSID%20of%20the%20network%20you’re%20attached%20to%3A%0A%20%20Serial.print(%22SSID%3A%20%22)%3B%0A%20%20Serial.println(WiFi.SSID())%3B%0A%0A%20%20%2F%2F%20print%20your%20WiFi%20shield’s%20IP%20address%3A%0A%20%20IPAddress%20ip%20%3D%20WiFi.localIP()%3B%0A%20%20Serial.print(%22IP%20Address%3A%20%22)%3B%0A%20%20Serial.println(ip)%3B%0A%0A%20%20%2F%2F%20print%20the%20received%20signal%20strength%3A%0A%20%20long%20rssi%20%3D%20WiFi.RSSI()%3B%0A%20%20Serial.print(%22signal%20strength%20(RSSI)%3A%22)%3B%0A%20%20Serial.print(rssi)%3B%0A%20%20Serial.println(%22%20dBm%22)%3B%0A%20%20%2F%2F%20print%20where%20to%20go%20in%20a%20browser%3A%0A%20%20Serial.print(%22To%20see%20this%20page%20in%20action%2C%20open%20a%20browser%20to%20http%3A%2F%2F%22)%3B%0A%20%20Serial.println(ip)%3B%0A%7D%0A%0Avoid%20led(int%20R%2C%20int%20G%2C%20int%20B)%20%7B%0A%20%20digitalWrite(11%2C%20R)%3B%0A%20%20digitalWrite(9%2C%20G)%3B%0A%20%20digitalWrite(7%2C%20B)%3B%0A%7D%0A” message=”” highlight=”” provider=”manual”/]





