本篇為『物聯網系統開發系列』之運用 ARDUINO 乙太網路擴充板建立簡單網頁伺服器,筆者建立這個新專欄,主要是未來物聯網時代推瀾下,希望能夠透過文章,來推廣筆者在物聯網開發的實務經驗與技術分享<p>文\曹永忠、吳佳駿、許智誠、蔡英德</p>
<p>(曹永忠, 吳佳駿, 許智誠, &amp; 蔡英德, 2017a, 2017b, 2017c; 曹永忠, 許智誠, &amp; 蔡英德, 2015a, 2015b, 2015c, 2015d, 2015e),所以第二篇文章就要介紹 Arduino 開發板累加上乙太網路擴充板(Ethernet Shield),讓創客神器Arduino開發板可以連上網際網路(曹永忠, 許智誠, &amp; 蔡英德, 2015f),可以成為物聯網開發中最簡單使用的開發版。</p>
<p>本系列希望貢獻筆者一些經驗,讓非資訊、電機、電子等 Makers 可以學到在物聯網開發中,一些程式開發的技巧、原理、法則與穩固的技術,因本系列文章主要讀者為初學者,內容程度為基礎入門程度,深入之處不足,但請高手們給筆者賜教,也請讀者關注本系列。</p>
<h3>Arduino Ethernet Shield 簡介</h3>
<p>W5100 主要特色是把 TCP/IP Protocols (TCP, UDP, ICMP, IPv4 ARP, IGMP, PPPoE, Ethernet) 做在硬體電路上,減輕了單晶片(MCU)的負擔 (也就是 Arduino 開發板的負擔)(曹永忠 et al., 2015b, 2015c)。Arduino 程式只要使用 Ethernet Library<strong><sup>1</sup></strong> 便可以輕易完成連至網際網路的動作,不過 W5100 也不是沒有缺點,因為它有一個限制,就是最多只允許同時4 個 socket 連線。</p>
<blockquote>
<p><strong>1.</strong>可到 Arduino.cc 的官網:<a href="http://www.arduino.cc/en/reference/ethernet" target="_blank">http://www.arduino.cc/en/reference/ethernet</a>,下載函式庫與相關範例。</p>
</blockquote>
<p>Arduino Ethernet Shield 使用加長型的 Pin header (如圖 1.(a) &amp; 圖 1.(b)),可以直接插到 Arduino 控制板上 (如圖 1.(c) &amp; 圖 1.(d) &amp; 圖 1.(e)),而且原封不動地保留了 Arduino 控制板的 Pin Layout,讓使用者可以在它上面疊其它的擴充板(如圖 1.(c) &amp; 圖 1.(d) &amp; 圖 1.(e))。比較新的 Ethernet Shield 增加了 micro-SD card 插槽(如圖 1.(a)),可以用來儲存檔案,你可以用 Arduino 內建的 SD library 來存取板子上的 SD cardEthernet Shield 相容於 UNO 和 Mega 2560 控制板。</p>
<p style="text-align: center;"><img src="https://cdn2-techbang.pixfs.net/system/images/397117/original/3b489b316cceecea0b86046fc7c53f2b.jpg?1496210424" alt="" /><br /><strong>▲圖1 Ethernet Shield (W5100)</strong></p>
<p style="text-align: left;">Arduino 開發板跟 W5100 以及 SD card 之間的通訊都是透過 SPI bus (通過 ICSP header)。以 UNO開發板 而言,SPI bus 腳位位於 pins 11, 12 和 13,而 Mega 2560開發板 則是 pins 50, 51 和 52。UNO 和 Mega 2560 都一樣,pin 10 是用來選擇 W5100,而 pin 4 則是用來選擇 SD card。這邊提到的這幾支腳位都不能拿來當 GPIO 使用,請讀者勿必避開這兩個 GPIO 腳位。</p>
<p style="text-align: left;">另外,在 Arduino Mega 2560 開發板上,pin 53 是 hardware SS pin,這支腳位也必須保持為<span style="text-decoration: underline;"><strong> OUTPUT</strong></span>,不然 SPI bus 就不能動作。在使用的時候要注意一件事,因為 W5100 和 SD card 共享 SPI bus,所以在同一個時間只能使用其中一個設備。如果你程式裏會用到 W5100 和 SD card 兩種設備,那在使用對應的 library 時就要特別留意,要避免搶 SPI bus 資源的情形。假如你確定不會用到其中一個設備的話,你可以在程式裏明白地指示 Arduino開發板,方法是: 如果不會用到 SD card,那就把 pin 4 設置成<span style="text-decoration: underline;"><strong> OUTPUT&nbsp;</strong></span>並把狀態改為 high,如果不會用到 W5100,那麼便把 pin 10 設置成<span style="text-decoration: underline;"><strong> OUTPUT&nbsp;</strong></span>並把狀態改為 high。</p>
<p style="text-align: left;">如圖 2所示,Ethernet Shield 狀態指示燈 (LEDs)功能列舉如下:</p>
<ul>
<li>PWR: 表示 Arduino 控制板和 Ethernet Shield 已經上電<br />LINK: 網路指示燈,當燈號閃爍時代表正在傳送或接收資料<br />FULLD: 代表網路連線是全雙工<br />100M: 表示網路是 100 MB/s (相對於 10 Mb/s)<br />RX: 接收資料時閃爍<br />TX: 傳送資料時閃爍<br />COLL: 閃爍時代表網路上發生封包碰撞的情形 (network collisions are detected)<br />資料來源:<a href="http://www.arduino.cc/en/Main/ArduinoEthernetShield" target="_blank">http://www.arduino.cc/en/Main/ArduinoEthernetShield</a></li>
</ul>
<p style="text-align: center;"><img src="https://cdn0-techbang.pixfs.net/system/images/397118/original/e87af06fe2d6f8db544ea48f63ffc972.jpeg?1496210424" alt="" /><br /><br /><strong>▲圖2 W5100指示燈</strong></p>
<h3 style="text-align: left;">簡單 Web Server</h3>
<p>首先,組立 W5100 以太網路模組是非常容易的一件事,如下圖所示,只要將 W5100 以太網路模組堆疊到任何 Arduino 開發板之上就可以了。</p>
<p style="text-align: center;"><img src="https://cdn2-techbang.pixfs.net/system/images/397119/original/e52f5eee7e61cc64bf2654d3bdf8dabf.jpeg?1496210425" alt="" /><br /><strong>▲圖3 將 Arduino 開發板與 W5100 以太網路模組堆疊組立</strong></p>
<p style="text-align: left;">之後,在將組立好的 W5100 以太網路模組,如下圖所示,只要將USB線差到 Arduino 開發板,再將 RJ 45的網路線一端插到 W5100 以太網路模組,另一端插到可以上網的集線器(Switch HUB)的任何一個區域網路接口(Lan Port)就可以了。</p>
<p style="text-align: center;"><img src="https://cdn2-techbang.pixfs.net/system/images/397120/original/d59ef66533357b5228df7ba7b8c98730.jpeg?1496210425" alt="" /><br /><strong>▲圖4 接上電源與網路線的 W5100 以太網路模組堆疊卡</strong></p>
<p style="text-align: left;">我們遵照前幾章所述,將 Arduino 開發板的驅動程式安裝好之後,我們打開 Arduino 開發板的開發工具:Sketch IDE 整合開發軟體,攥寫一段程式,如下表所示之 WebServer 測試程式,我們就可以讓 W5100 以太網路模組堆疊卡變成一台簡易的網頁伺服器運作了。</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="558">
<p class="a"><span style="text-decoration: underline;"><strong>W5100 以太網路模組(WebServer)</strong></span></p>
</td>
</tr>
<tr>
<td width="558" valign="top">
<p class="a">/*</p>
<p class="a">&nbsp; Web Server</p>
<p class="a">&nbsp;</p>
<p class="a">&nbsp;A simple web server that shows the value of the analog input pins.</p>
<p class="a">&nbsp;using an Arduino Wiznet Ethernet shield.</p>
<p class="a">&nbsp;</p>
<p class="a">&nbsp;Circuit:</p>
<p class="a">&nbsp;* Ethernet shield attached to pins 10, 11, 12, 13</p>
<p class="a">&nbsp;* Analog inputs attached to pins A0 through A5 (optional)</p>
<p class="a">&nbsp;</p>
<p class="a">&nbsp;created 18 Dec 2009</p>
<p class="a">&nbsp;by David A. Mellis</p>
<p class="a">&nbsp;modified 9 Apr 2012</p>
<p class="a">&nbsp;by Tom Igoe</p>
<p class="a">&nbsp;</p>
<p class="a">&nbsp;*/</p>
<p class="a">&nbsp;</p>
<p class="a">#include &lt;SPI.h&gt;</p>
<p class="a">#include &lt;Ethernet.h&gt;</p>
<p class="a">&nbsp;</p>
<p class="a">// Enter a MAC address and IP address for your controller below.</p>
<p class="a">// The IP address will be dependent on your local network:</p>
<p class="a">byte mac[] = {</p>
<p class="a">&nbsp; 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF</p>
<p class="a">};</p>
<p class="a">IPAddress ip(192, 168, 30, 200);</p>
<p class="a">IPAddress dnServer(168, 95, 1, 1);</p>
<p class="a">// the router's gateway address:</p>
<p class="a">IPAddress gateway(192, 168, 30, 254);</p>
<p class="a">// the subnet:</p>
<p class="a">IPAddress subnet(255, 255, 255, 0);</p>
<p class="a">&nbsp;</p>
<p class="a">// Initialize the Ethernet server library</p>
<p class="a">// with the IP address and port you want to use</p>
<p class="a">// (port 80 is default for HTTP):</p>
<p class="a">EthernetServer server(80);</p>
<p class="a">&nbsp;</p>
<p class="a">void setup() {</p>
<p class="a">&nbsp; // Open serial communications and wait for port to open:</p>
<p class="a">&nbsp; Serial.begin(9600);</p>
<p class="a">&nbsp; while (!Serial) {</p>
<p class="a">&nbsp;&nbsp;&nbsp; ; // wait for serial port to connect. Needed for Leonardo only</p>
<p class="a">&nbsp; }</p>
<p class="a">&nbsp;</p>
<p class="a">&nbsp;</p>
<p class="a">&nbsp; // start the Ethernet connection and the server:</p>
<p class="a">&nbsp; Ethernet.begin(mac, ip, dnServer, gateway, subnet);</p>
<p class="a">&nbsp; server.begin();</p>
<p class="a">&nbsp; Serial.print("server is at ");</p>
<p class="a">&nbsp; Serial.println(Ethernet.localIP());</p>
<p class="a">}</p>
<p class="a">&nbsp;</p>
<p class="a">&nbsp;</p>
<p class="a">void loop() {</p>
<p class="a">&nbsp; // listen for incoming clients</p>
<p class="a">&nbsp; EthernetClient client = server.available();</p>
<p class="a">&nbsp; if (client) {</p>
<p class="a">&nbsp;&nbsp;&nbsp; Serial.println("new client");</p>
<p class="a">&nbsp;&nbsp;&nbsp; // an http request ends with a blank line</p>
<p class="a">&nbsp;&nbsp;&nbsp; boolean currentLineIsBlank = true;</p>
<p class="a">&nbsp;&nbsp;&nbsp; while (client.connected()) {</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (client.available()) {</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char c = client.read();</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Serial.write(c);</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // if you've gotten to the end of the line (received a newline</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // character) and the line is blank, the http request has ended,</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // so you can send a reply</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (c == '\n' &amp;&amp; currentLineIsBlank) {</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // send a standard http response header</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.println("HTTP/1.1 200 OK");</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.println("Content-Type: text/html");</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.println("Connection: close");&nbsp; // the connection will be closed after completion of the response</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.println("Refresh: 5");&nbsp; // refresh the page automatically every 5 sec</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.println();</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.println("&lt;!DOCTYPE HTML&gt;");</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;client.println("&lt;html&gt;");</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // output the value of each analog input pin</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int analogChannel = 0; analogChannel &lt; 6; analogChannel++) {</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int sensorReading = analogRead(analogChannel);</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.print("analog input ");</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.print(analogChannel);</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.print(" is ");</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.print(sensorReading);</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.println("&lt;br /&gt;");</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.println("&lt;/html&gt;");</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (c == '\n') {</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // you're starting a new line</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; currentLineIsBlank = true;</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (c != '\r') {</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // you've gotten a character on the current line</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; currentLineIsBlank = false;</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p class="a">&nbsp;&nbsp;&nbsp; }</p>
<p class="a">&nbsp;&nbsp;&nbsp; // give the web browser time to receive the data</p>
<p class="a">&nbsp;&nbsp;&nbsp; delay(1);</p>
<p class="a">&nbsp;&nbsp;&nbsp; // close the connection:</p>
<p class="a">&nbsp;&nbsp;&nbsp; client.stop();</p>
<p class="a">&nbsp;&nbsp;&nbsp; Serial.println("client disconnected");</p>
<p class="a">&nbsp; }</p>
<p class="a">}</p>
</td>
</tr>
</tbody>
</table>
<p style="text-align: right;">程式範例原始碼網址:<a href="https://github.com/brucetsao/arduino_RFProgramming" target="_blank">https://github.com/brucetsao/arduino_RFProgramming</a></p>
<p style="text-align: left;">如下圖所示,讀者可以看到本次實驗- WebServer 測試程式結果畫面。</p>
<p style="text-align: center;"><img src="https://cdn1-techbang.pixfs.net/system/images/397121/original/b4514f9217f250a773368b67ee0bb8c1.jpeg?1496210426" alt="" /><br /><br /><strong>▲圖5 WebServer 測試程式結果畫面</strong></p>
<p style="text-align: center;">下一頁還有更精采的教學喔 !</p>
<p style="text-align: center;"><!-- pagebreak --></p>
<h3 style="text-align: left;">使用 DHCP 架設 Web Server</h3>
<p>首先,組立 W5100 以太網路模組是非常容易的一件事,如下圖所示,只要將 W5100 以太網路模組堆疊到任何 Arduino 開發板之上就可以了。</p>
<p style="text-align: center;"><img src="https://cdn0-techbang.pixfs.net/system/images/397122/original/c15830b6c92913ed2cf91d6c382f1d83.jpeg?1496210426" alt="" /></p>
<p style="text-align: center;"><strong>▲圖6 將 Arduino 開發板與 W5100 以太網路模組堆疊組立</strong></p>
<p>之後,在將組立好的 W5100 以太網路模組,如下圖所示,只要將 USB 線差到 Arduino 開發板,再將 RJ 45的網路線一端插到 W5100 以太網路模組,另一端插到可以上網的集線器(Switch HUB)的任何一個區域網路接口(Lan Port)就可以了。</p>
<p style="text-align: center;"><img src="https://cdn0-techbang.pixfs.net/system/images/397123/original/da2a925a3f34416984a441f0501bc561.jpeg?1496210426" alt="" /><br /><strong>▲圖7 接上電源與網路線的 W5100 以太網路模組堆疊卡</strong></p>
<p style="text-align: left;">我們遵照前幾章所述,將 Arduino 開發板的驅動程式安裝好之後,我們打開 Arduino 開發板的開發工具:Sketch IDE 整合開發軟體,攥寫一段程式,如下表所示之 WebServer 測試程式一,我們就可以讓 W5100 以太網路模組堆疊卡變成一台簡易的網頁伺服器運作了。</p>
<p>表 2 WebServer 測試程式一</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="558">
<p class="a">WebServer測試程式一(WebServer_dhcp)</p>
</td>
</tr>
<tr>
<td width="558" valign="top">
<p class="a">/*</p>
<p class="a">&nbsp; Web Server</p>
<p class="a">&nbsp;</p>
<p class="a">&nbsp;A simple web server that shows the value of the analog input pins.</p>
<p class="a">&nbsp;using an Arduino Wiznet Ethernet shield.</p>
<p class="a">&nbsp;</p>
<p class="a">&nbsp;Circuit:</p>
<p class="a">&nbsp;* Ethernet shield attached to pins 10, 11, 12, 13</p>
<p class="a">&nbsp;* Analog inputs attached to pins A0 through A5 (optional)</p>
<p class="a">&nbsp;</p>
<p class="a">&nbsp;created 18 Dec 2009</p>
<p class="a">&nbsp;by David A. Mellis</p>
<p class="a">&nbsp;modified 9 Apr 2012</p>
<p class="a">&nbsp;by Tom Igoe</p>
<p class="a">&nbsp;</p>
<p class="a">&nbsp;*/</p>
<p class="a">&nbsp;</p>
<p class="a">#include &lt;SPI.h&gt;</p>
<p class="a">#include &lt;Ethernet.h&gt;</p>
<p class="a">&nbsp;</p>
<p class="a">// Enter a MAC address and IP address for your controller below.</p>
<p class="a">// The IP address will be dependent on your local network:</p>
<p class="a">byte mac[] = {</p>
<p class="a">&nbsp; 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF</p>
<p class="a">};&nbsp;</p>
<p class="a">IPAddress ip(192, 168, 30, 200);</p>
<p class="a">&nbsp;</p>
<p class="a">//IPAddress ip&nbsp; = Ethernet.localIP() ;</p>
<p class="a">IPAddress dnServer(168, 95, 1, 1);</p>
<p class="a">// the router's gateway address:</p>
<p class="a">IPAddress gateway(192, 168, 30, 254);</p>
<p class="a">// the subnet:</p>
<p class="a">IPAddress subnet(255, 255, 255, 0);</p>
<p class="a">&nbsp;</p>
<p class="a">// Initialize the Ethernet server library</p>
<p class="a">// with the IP address and port you want to use</p>
<p class="a">// (port 80 is default for HTTP):</p>
<p class="a">EthernetServer server(80);</p>
<p class="a">&nbsp;</p>
<p class="a">void setup() {</p>
<p class="a">&nbsp; // Open serial communications and wait for port to open:</p>
<p class="a">&nbsp; Serial.begin(9600);</p>
<p class="a">&nbsp;//ip = Ethernet.localIP() ;</p>
<p class="a">&nbsp;&nbsp;&nbsp; Serial.println("now program Start") ;</p>
<p class="a">&nbsp;</p>
<p class="a">&nbsp; while (!Serial) {</p>
<p class="a">&nbsp;&nbsp;&nbsp; ; // wait for serial port to connect. Needed for Leonardo only</p>
<p class="a">&nbsp; }</p>
<p class="a">&nbsp;</p>
<p class="a">&nbsp; // 啟用 Ethernet 連線,預設會以 DHCP 取得 IP 位址</p>
<p class="a">&nbsp; if (Ethernet.begin(mac) == 0) {</p>
<p class="a">&nbsp;&nbsp;&nbsp; Serial.println("無法取得 IP 位址");</p>
<p class="a">&nbsp;&nbsp;&nbsp; // 無法取得 IP 位址,不做任何事情</p>
<p class="a">&nbsp;&nbsp;&nbsp; for(;;)</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;</p>
<p class="a">&nbsp; }</p>
<p class="a">&nbsp; // 輸出 IP 位址</p>
<p class="a">&nbsp; Serial.print("IP 位址:");</p>
<p class="a">&nbsp; Serial.println(ip);</p>
<p class="a">&nbsp;</p>
<p class="a">//&nbsp;&nbsp; Ethernet.begin(mac, ip, dnServer, gateway, subnet);</p>
<p class="a">&nbsp;&nbsp; Ethernet.begin(mac);&nbsp;&nbsp;&nbsp; // use this statement , will request DHCP server for ip</p>
<p class="a">&nbsp;</p>
<p class="a">&nbsp; server.begin();</p>
<p class="a">&nbsp; Serial.print("server is at ");</p>
<p class="a">&nbsp; Serial.println(Ethernet.localIP());</p>
<p class="a">}</p>
<p class="a">&nbsp;</p>
<p class="a">&nbsp;</p>
<p class="a">void loop() {</p>
<p class="a">&nbsp; // listen for incoming clients</p>
<p class="a">&nbsp; EthernetClient client = server.available();</p>
<p class="a">&nbsp; if (client) {</p>
<p class="a">&nbsp;&nbsp;&nbsp; Serial.println("new client");</p>
<p class="a">&nbsp;&nbsp;&nbsp; // an http request ends with a blank line</p>
<p class="a">&nbsp;&nbsp;&nbsp; boolean currentLineIsBlank = true;</p>
<p class="a">&nbsp;&nbsp;&nbsp; while (client.connected()) {</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (client.available()) {</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char c = client.read();</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Serial.write(c);</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // if you've gotten to the end of the line (received a newline</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // character) and the line is blank, the http request has ended,</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // so you can send a reply</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (c == '\n' &amp;&amp; currentLineIsBlank) {</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // send a standard http response header</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.println("HTTP/1.1 200 OK");</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.println("Content-Type: text/html");</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;client.println("Connection: close");&nbsp; // the connection will be closed after completion of the response</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.println("Refresh: 5");&nbsp; // refresh the page automatically every 5 sec</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.println();</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.println("&lt;!DOCTYPE HTML&gt;");</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.println("&lt;html&gt;");</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // output the value of each analog input pin</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int analogChannel = 0; analogChannel &lt; 6; analogChannel++) {</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int sensorReading = analogRead(analogChannel);</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.print("analog input ");</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.print(analogChannel);</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.print(" is ");</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.print(sensorReading);</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.println("&lt;br /&gt;");</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; client.println("&lt;/html&gt;");</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (c == '\n') {</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // you're starting a new line</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; currentLineIsBlank = true;</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (c != '\r') {</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // you've gotten a character on the current line</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; currentLineIsBlank = false;</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p class="a">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p class="a">&nbsp;&nbsp;&nbsp; }</p>
<p class="a">&nbsp;&nbsp;&nbsp; // give the web browser time to receive the data</p>
<p class="a">&nbsp;&nbsp;&nbsp; delay(1);</p>
<p class="a">&nbsp;&nbsp;&nbsp; // close the connection:</p>
<p class="a">&nbsp;&nbsp;&nbsp; client.stop();</p>
<p class="a">&nbsp;&nbsp;&nbsp; Serial.println("client disconnected");</p>
<p class="a">&nbsp; }</p>
<p class="a">}</p>
</td>
</tr>
</tbody>
</table>
<p style="text-align: right;">程式範例原始碼網址:<a href="https://github.com/brucetsao/arduino_RFProgramming">https://github.com/brucetsao/arduino_RFProgramming</a></p>
<p style="text-align: left;">如下圖所示,讀者可以看到本次實驗- WebServer 測試程式一結果畫面。</p>
<p style="text-align: center;"><img src="https://cdn2-techbang.pixfs.net/system/images/397124/original/061382729e23c5604a265364a098e067.jpeg?1496210427" alt="" /><br /><strong>▲圖8 WebServer 測試程式一結果畫面</strong></p>
<p style="text-align: center;">最後一頁是作者介紹及後續文章發展唷 !</p>
<p style="text-align: center;"><!-- pagebreak --></p>
<h3 class="23421">後續</h3>
<p>本篇為『物聯網系統開發系列』系列之運用 ARDUINO 乙太網路擴充板建立簡單網頁伺服器,主要內容是要讓讀者使用創客神器 Arduino 開發板,透過乙太網路擴充板(Ethernet Shield)的網際網路連線之強大功能,可以讓 Arduino 開發板可以建立網頁伺服器的功能,進而透過 DNS Mapping(網域名稱對應)與 Port Mapping 的功能,透過路由器的通訊埠轉發(Port Forwarding),建立一個物聯網的端點,進而透過創客神器 Arduino 開發板連接許多感測器模組,將這些內容送到網際網路或雲端平台,乃是筆者本篇內容想傳達的創作概念。</p>
<p>筆者本系列是針對非資訊、電機、電子等 Makers 攥寫的物聯網系統開發系列,這四、五年來在物聯網系統開發領域寫書、發表文章、辦展、授課,常遇到許多學子訓練不足,以交作業的心態來學習,並沒有把程式底子打好。</p>
<p>後續筆者還會繼續發表『物聯網系統開發系列』系列的文章,在未來我們可以創造出更優質,更具未來性的物聯網(Internet of Thing:IOT)產品開發相關技術。</p>
<p>敬請期待更多的文章。</p>
<h3>作者介紹</h3>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="553" valign="top">
<p><strong>曹永忠 (Yung-Chung Tsao)</strong><strong> </strong><strong>,</strong>目前為自由作家暨專業 Maker,專研於軟體工程、軟體開發與設計、物件導向程式設計,商品攝影及人像攝影。長期投入創客運動、資訊系統設計與開發、企業應用系統開發、軟體工程、新產品開發管理、商品及人像攝影等領域,並持續發表作品及相關專業著作。</p>
<p>Email:<a href="mailto:[email protected]">[email protected]<br /></a>Line ID:dr.brucetsao</p>
<p><img src="https://cdn1-techbang.pixfs.net/system/images/397125/original/2feaa56eeb5577fd0b3a6748ae84c889.jpeg?1496210427" alt="" /></p>
<p><br />作者網站:<a href="https://www.cs.pu.edu.tw/~yctsao/">https://www.cs.pu.edu.tw/~yctsao/<br /></a>臉書社群(Arduino.Taiwan):<a href="https://www.facebook.com/groups/Arduino.Taiwan/">https://www.facebook.com/groups/Arduino.Taiwan/<br /></a>Github網站:<a href="https://github.com/brucetsao/">https://github.com/brucetsao/<br /></a>原始碼網址:<a href="https://github.com/brucetsao/eHUE_Bulb2">https://github.com/brucetsao/eHUE_Bulb2<br /></a>Youtube:<a href="https://www.youtube.com/channel/UCcYG2yY_u0m1aotcA4hrRgQ">https://www.youtube.com/channel/UCcYG2yY_u0m1aotcA4hrRgQ</a></p>
<p>&nbsp;</p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="553" valign="top">
<p><strong>吳佳駿 (Chia-Chun Wu)</strong>,國立中興大學資訊科學與工程學系博士,現任教於國立金門大學工業工程與管理學系專任助理教授,目前兼任國立金門大學計算機與網路中心資訊網路組組長,主要研究為軟體工程與應用、行動裝置程式設計、物件導向程式設計、網路程式設計、動態網頁資料庫、資訊安全與管理。</p>
<p>Email: <a href="mailto:[email protected]">[email protected]</a></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="553" valign="top">
<p><strong>許智誠 (Chih-Cheng Hsu)</strong>,美國加州大學洛杉磯分校(UCLA) 資訊工程系博士,曾任職於美國IBM等軟體公司多年,現任教於中央大學資訊管理學系專任副教授,主要研究為軟體工程、設計流程與自動化、數位教學、雲端裝置、多層式網頁系統、系統整合。</p>
<p>Email: <a href="mailto:[email protected]">[email protected]</a></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="553" valign="top">
<p><strong>蔡英德 (Yin-Te Tsai)</strong>,國立清華大學資訊科學系博士,目前是靜宜大學資訊傳播工程學系教授、靜宜大學計算機及通訊中心主任,主要研究為演算法設計與分析、生物資訊、軟體開發、視障輔具設計與開發。</p>
<p>Email:<a href="mailto:[email protected]">[email protected]</a></p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<blockquote>
<p>參考文獻:</p>
<p class="EndNoteBibliography">曹永忠, 吳佳駿, 許智誠, &amp; 蔡英德. (2017a). <em>Ameba</em><em>程式設計(</em><em>物聯網基礎篇):An Introduction to Internet of Thing by Using Ameba RTL8195AM</em> (初版 ed.). 台湾、彰化: 渥瑪數位有限公司.</p>
<p class="EndNoteBibliography">曹永忠, 吳佳駿, 許智誠, &amp; 蔡英德. (2017b). <em>Ameba</em><em>程序设计(</em><em>物联网基础篇):An Introduction to Internet of Thing by Using Ameba RTL8195AM</em> (初版 ed.). 台湾、彰化: 渥瑪數位有限公司.</p>
<p class="EndNoteBibliography">曹永忠, 吳佳駿, 許智誠, &amp; 蔡英德. (2017c). 【物聯網系統開發】THINGSPEAK 平台基本篇. <em>智慧家庭.</em>&nbsp; Retrieved from <a href="http://www.techbang.com/posts/51161-internet-system-development-thingspeak-platform-review">http://www.techbang.com/posts/51161-internet-system-development-thingspeak-platform-review</a></p>
<p class="EndNoteBibliography">曹永忠, 許智誠, &amp; 蔡英德. (2015a). <em>Arduino</em><em>云 </em><em>物联网系统开发(</em><em>入门篇):Using Arduino Yun to Develop an Application for Internet of Things (Basic Introduction)</em> (初版 ed.). 台湾、彰化: 渥瑪數位有限公司.</p>
<p class="EndNoteBibliography">曹永忠, 許智誠, &amp; 蔡英德. (2015b). <em>Arduino</em><em>程式教學(</em><em>無線通訊篇):Arduino Programming (Wireless Communication)</em> (初版 ed.). 台湾、彰化: 渥瑪數位有限公司.</p>
<p class="EndNoteBibliography">曹永忠, 許智誠, &amp; 蔡英德. (2015c). <em>Arduino</em><em>编程教学(</em><em>无线通讯篇):Arduino Programming (Wireless Communication)</em> (初版 ed.). 台湾、彰化: 渥瑪數位有限公司.</p>
<p class="EndNoteBibliography">曹永忠, 許智誠, &amp; 蔡英德. (2015d). <em>Arduino</em><em>雲 </em><em>物聯網系統開發(</em><em>入門篇):Using Arduino Yun to Develop an Application for Internet of Things (Basic Introduction)</em> (初版 ed.). 台湾、彰化: 渥瑪數位有限公司.</p>
<p class="EndNoteBibliography">曹永忠, 許智誠, &amp; 蔡英德. (2015e). 【Maker 實戰】實作 Arduino Ethernet Shield 應用,透過網路監控居家亮度.&nbsp;&nbsp; Retrieved from <a href="http://www.techbang.com/posts/25109-future-of-humanity-through-network-monitoring-internet-home-brightness">http://www.techbang.com/posts/25109-future-of-humanity-through-network-monitoring-internet-home-brightness</a></p>
<p class="EndNoteBibliography">曹永忠, 許智誠, &amp; 蔡英德. (2015f). 創客神器ARDUINO到底是什麼呢?.&nbsp;&nbsp; Retrieved from <a href="http://makerdiwo.com/archives/1893">http://makerdiwo.com/archives/1893</a></p>
<p>&nbsp;</p>
</blockquote>
<p style="text-align: left;">&nbsp;</p>
<p>&nbsp;</p><a href="http://www.facebook.com/TKbang">加入T客邦Facebook粉絲團</a><img src="http://feeds.feedburner.com/~r/techbang/~4/syhGKHaNc8A" height="1" width="1" alt=""/>