Program Resource

開発者向け各種コード、アルゴリズム、リソース情報ライブラリ もしくはねふぁの覚え書き

ArduinoにはCC3000等のWiFiシールドもあるが、当然有線のEthernetシールドもある。

DSC03686

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処理を少し変えるだけで動作した。

DSC03711

DSC03712

しかし、ArduinoのEthernetシールドには一点大きな難点がある。電源投入後、ネットワーク接続に失敗し、リセットボタンを一度押下しないとリンクがつながらない症状が出る事がある(筆者の環境では必ず失敗した)。ソフト的なリセットを行ってもArduino本体は再起動するがシールドは再起動しないため効果が無く、ソフト的な対策が出来ない点がまた難点となっている。

正常動作時はLINK LEDが光るが、失敗時はLEDが光らないか起動時に一瞬だけ光る。

DSC03713

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ピンを接続した(下記写真ではリセットピンを少し外にずらしてある)。

DSC03714

後は、起動時にA3ピンを一瞬LOWにする事でEthernetシールドにリセットがかかり正常に動作する様になる。これで電源投入後手動リセットせずとも毎回正常にリンクする様になった。

DSC03715

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 イーサネットシールド
Arduino用 W5200 Ethernet Shield イーサネットシールド
[GPG] 小型I2C 128x64 OLED ディスプレイ Arduino等の電子工作用 (ホワイト)
[GPG] 小型I2C 128×64 OLED ディスプレイ Arduino等の電子工作用 (ホワイト)


EthernetシールドでArduinoを有線LAN接続」 に1件のコメント

  1. Rajat より:

    It’s great to read something that’s both enjoyable and provides prgaamtisdc solutions.

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


*