ArduinoにはCC3000等のWiFiシールドもあるが、当然有線のEthernetシールドもある。
Ethernetシールドの使い方も簡単で、ライブラリを拾ってきて少しコードを書くだけである。上記シールドはWizNetのW5200と言うタイプのチップが搭載されたシールドである。
ライブラリは幾つか存在するが、Seeed Studioのライブラリが手直し不要ですんなり動作する(他のライブラリは一部手直ししないとコンパイルが通らない)。
https://github.com/Seeed-Studio/Ethernet_Shield_W5200
Arduino IDEでインポート後、各種サーバーやクライエント等のサンプルスケッチが入る。下記ライブラリは手直しが必要だが、サンプルスケッチにTweet投稿が含まれている(動作未確認)
https://github.com/Wiznet/WIZ_Ethernet_Library
WiFiの時に作成した、簡易WebサーバーとOLEDディスプレイでブラウザから入力した文字列を表示するスケッチも、ライブラリを変更してsetup処理を少し変えるだけで動作した。
しかし、ArduinoのEthernetシールドには一点大きな難点がある。電源投入後、ネットワーク接続に失敗し、リセットボタンを一度押下しないとリンクがつながらない症状が出る事がある(筆者の環境では必ず失敗した)。ソフト的なリセットを行ってもArduino本体は再起動するがシールドは再起動しないため効果が無く、ソフト的な対策が出来ない点がまた難点となっている。
正常動作時はLINK LEDが光るが、失敗時はLEDが光らないか起動時に一瞬だけ光る。
W5100チップ搭載等多数のArduino用Ethernetシールドがこの問題を抱えているらしく、原因はArduinoの起動時のリセットシーケンスにある様だが、検索すると多数の関連記事や投稿が見つかる。
http://todotani.cocolog-nifty.com/blog/2010/06/arduino-etherne.html
http://www.hobbyist.co.nz/?q=ethernet-shield-w5100
http://marco.guardigli.it/2010/11/arduino-wiznet-ethernet-shield-proper.html
http://forum.arduino.cc/index.php?topic=28175.45
対策として多く挙げられているのがコンデンサと抵抗を追加し、起動時のリセット時間を伸ばす方法であるが、残念ながら筆者手持ちのW5200搭載シールドでは効果がなかった。
電源投入後一回だけリセットボタンを押せば動作するが、下記方法で簡単に対策する事が出来た。
必要なものはケーブル一本のみ。
EthernetシールドのResetピンを曲げるか切断し、Arduinoとの接続を外す。そして、シールドのResetピンとお好きな空きピンをジャンパーで接続する。ここではリセットピンとA3ピンを接続した(下記写真ではリセットピンを少し外にずらしてある)。
後は、起動時にA3ピンを一瞬LOWにする事でEthernetシールドにリセットがかかり正常に動作する様になる。これで電源投入後手動リセットせずとも毎回正常にリンクする様になった。
W5100やW5200のチップはMACアドレスを記憶する機能がない為、スケッチでMACアドレスを指定し設定する。外部インターネットに繋がないのであればローカル用MACアドレスを指定するか、衝突しないアドレスを適当に指定する(ローカル用にランダムに生成してくれるサイトもある)。外部インターネットに繋ぐ場合は割り当てられているグローバル用MACアドレスを指定するか、IEEEに申請して取得するか(有償)、使用していないLANデバイスのMACアドレスを使用する等して衝突しない様にする。
A3リセット処理を含んだ簡単なWebサーバースケッチは以下の通り。
//https://github.com/Seeed-Studio/Ethernet_Shield_W5200 #include <Wire.h> #include <SPI.h> #include <EthernetV2_0.h> #include "utility/w5200.h" #include "U8glib.h" #include <avr/wdt.h> #define LISTEN_PORT 80 char in_buffer[48]; int in_size = 0; char req_page[32]; char in_ch; char last_ch; char subch[24]; char decch[24]; char *cmd; char oledstrbuff[6][16]; EthernetServer server(LISTEN_PORT); byte mac[] = { 0x02, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; IPAddress ip(192,168,1, 177); IPAddress gateway(192,168,1, 1); IPAddress subnet(255, 255, 0, 0); #define W5200_CS 10 #define SDCARD_CS 4 U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0); // I2C / TWI void oled_drawstr(int line,char *text){ strcpy(oledstrbuff[line],text); u8g.firstPage(); do { u8g.setFont(u8g_font_6x10); u8g.setFontRefHeightExtendedText(); u8g.setDefaultForegroundColor(); u8g.setFontPosTop(); for (int i=0;i<6;i++) u8g.drawStr(0,10*i,oledstrbuff[i]); } while (u8g.nextPage()); } //bend or clip reset pin on Ethernet shield, connect reset and A3 pin with jumper void resetEther() { delay(100); digitalWrite(17,LOW); delay(100); digitalWrite(17,HIGH); } void setup(void) { pinMode(17,OUTPUT); digitalWrite(17,HIGH); resetEther(); //reset ethernet shield oled_drawstr(0,"Booting"); pinMode(SDCARD_CS,OUTPUT); digitalWrite(SDCARD_CS,HIGH);//Deselect the SD card oled_drawstr(1,"Connect Net..."); while (Ethernet.begin(mac) == 0) { oled_drawstr(2,"Connect Fail"); } oled_drawstr(1,"Connect Net OK"); delay(500); while (! displayConnectionDetails()) { delay(1000); } Serial.begin(9600); server.begin(); } void loop(void) { EthernetClient client = server.available(); if (client) { if (client.available() > 0) { in_ch = client.read(); if (in_size < 47 && in_ch != '\r' && in_ch != '\n') in_buffer[in_size++] = in_ch; if (in_ch == '\r') { in_buffer[in_size] = '\0'; Serial.println(in_buffer); cmd = getparam(in_buffer, ' ', 0); if (strcmp(cmd, "GET") == 0) strcpy(req_page, getparam(in_buffer, ' ', 1)); in_size = 0; if (last_ch == '\r') //double linefeed, end of request replypage(&client); } if (in_ch == '\r' || in_ch == '\n') last_ch = '\r'; else last_ch = ' '; } } } //return n-th char array separated with specified character char *getparam(char *txt, char seperator, int index) { int strcnt = 0; int indcnt = 0; memset(subch, 0, 24); for (int i = 0; i < strlen(txt); i++) { if (txt[i] == seperator) { indcnt++; if (indcnt > index) break; } else if (indcnt == index) { subch[strcnt++] = txt[i]; } } return &subch[0]; } char *decodechar(char *txt){ memset(decch,0,24); int deccnt = 0; char hexbuf[3] = {0,0,0}; for (int i=0;i<strlen(txt);i++){ if (txt[i] == '+'){ decch[deccnt++] = ' '; }else if (txt[i] == '%'){ hexbuf[0] = txt[i+1]; hexbuf[1] = txt[i+2]; decch[deccnt++] = strtol(hexbuf,NULL,16); i+=2; }else{ decch[deccnt++] = txt[i]; } } return decch; } void replypage(EthernetClient *pclient) { if (strcmp(getparam(req_page, '=', 0), "/?t") == 0) { char char_param[10]; strcpy(char_param,decodechar(getparam(req_page, '=', 1))); oled_drawstr(5, char_param); } Serial.println("Sending page"); pclient->println("HTTP/1.1 200 OK"); pclient->print("Content-Type: text/html"); pclient->println("\n"); pclient->println("<html><title>Arduino Web</title><body>"); // char buffer[96]; // sprintf(buffer, "Requested : %s", req_page); // pclient->fastrprint(buffer); pclient->println("<BR><form method=\"GET\" action=\"/\">"); pclient->println("<input type=\"text\" maxlength=\"8\" name=\"t\">"); pclient->println("<input type=\"submit\" value=\"Go\"></form>"); pclient->println("</body></html>"); delay(1000); pclient->flush(); pclient->stop(); Serial.println("Client close"); } bool displayConnectionDetails(void) { ip = Ethernet.localIP(); char ipadd[16]; sprintf(ipadd,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]); oled_drawstr(3, "IP Address:"); oled_drawstr(4, &ipadd[0]); return true; }
Arduino用 W5200 Ethernet Shield イーサネットシールド
[GPG] 小型I2C 128×64 OLED ディスプレイ Arduino等の電子工作用 (ホワイト)
It’s great to read something that’s both enjoyable and provides prgaamtisdc solutions.