Arduinoと有線LANで通信する(W5100 1)

こちらで、ENC28J60チップを使ったLANモ ジュールを紹介しましたが、
今回はW5100チップを使ったArduino用のLANモジュールを使った、
RaspberryとArduino+W5100の通信を紹介します。
全体のイメージはこんな感じです。
Raspberry側は普通のLANを使います。




W5100チップはUNO用の純正Etnernetシールドでも使われています。
私が使ったのは写真のようなワイヤーで接続するタイプです。
ENC28J60($2.82)よりも少し高めの$6.03でした。




このモジュールについては、こ ちらのページに詳 しく紹介されていますが、IDE標準の「Ethernet.h」で動きました。
まずは、Raspberryがサーバー、Arduinoがクライアントの動作を試してみました。

【Raspberry側】

以下のコード(server.c)をコンパイルして実行します。
クライアントから受信した文字列を大文字に変換して送り返す単純なものです。
コンパイルは単純に「cc server.c」で、実行は「./a.out」です。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>
#include <limits.h>

#define PORT 9876 //クライアントプログラムとポート番号を合わせてください

int main(int argc, char **argv){
  int i;
  int srcSocket; //自分
  int dstSocket; //相手
  // sockaddr_in 構造体
  struct sockaddr_in srcAddr;
  struct sockaddr_in dstAddr;
  socklen_t dstAddrSize;
  // 各種パラメータ
  int numrcv;
  char buf[1024];
  int loopMax;
  int loopCnt;

  time_t start_time=0, end_time;
  double dtime;

  loopMax=INT_MAX;
  if (argc == 2) {
    loopMax=atoi(argv[1]);
  }

  // sockaddr_in 構造体のセット
  bzero((char *)&srcAddr, sizeof(srcAddr));
  srcAddr.sin_port = htons(PORT);
  srcAddr.sin_family = AF_INET;
  srcAddr.sin_addr.s_addr = INADDR_ANY;
   
  // ソケットの生成(ストリーム型)
  srcSocket = socket(AF_INET, SOCK_STREAM, 0);
  // ソケットのバインド
  bind(srcSocket, (struct sockaddr *)&srcAddr, sizeof(srcAddr));
  // 接続の許可
  listen(srcSocket, 5);
 
  for(loopCnt=0;loopCnt<loopMax;loopCnt++) {
//  while(1){
    // 接続の受付け
    printf("接続を待っています\nクライアントプログラムを動かして下さい\n");
    dstAddrSize = sizeof(dstAddr);
    dstSocket = accept(srcSocket, (struct sockaddr *)&dstAddr, &dstAddrSize);
    printf("%s から接続を受けました\n",inet_ntoa(dstAddr.sin_addr));
    if (start_time == 0) time( &start_time );
       
    while(1) { // クライアントがSocketをクローズしてからこちらもクローズする
      //パケットの受信
      memset(buf,0,sizeof(buf));
      numrcv = read(dstSocket, buf, 1024);
      printf("numrcv=%d\n",numrcv);
      if(numrcv ==0 || numrcv ==-1 ){ // client close socket
        close(dstSocket); break;
      }
      printf("Recv=[%s]",buf);
      for (i=0; i< numrcv; i++){ // bufの中の小文字を大文字に変換
        if(isalpha(buf[i])) buf[i] = toupper(buf[i]);
      }
      // パケットの送信
      write(dstSocket, buf, numrcv);
      printf("->Send=[%s]\n",buf);
    } // end while
  } // end for
  time( &end_time );
  dtime=difftime( end_time, start_time );
  printf("loop=%d difftime=%f[sec] %f[min]\n",loopMax,dtime,dtime/60);
  return(0);
}

プログラムを起動すると以下の表示となります。


【Arduino側】

W5100とArduinoの接続はこちらで紹介されてい る以下の通りです。

W5100 GND -> Arduino Gnd pin
W5100 VCC -> Arduino 5V pin
W5100 SS -> Arduino pin 10
W5100 SCK -> Arduino pin 13
W5100 MOSI -> Arduino pin 11
W5100 MISO -> Arduino pin 12

Arduino側のスケッチは以下の通りです。
こちらで紹介 しているENC28J60のスケッチから青字の部分だけ変更して動きました。
(というかこのスケッチがEthernetシールドを使うときの標準です)
相手側(今回はRaspberry)とポート番号(今回は9876番を使用)とIPアドレスを合わせて下さい。
ここが合っていないと正しく通信できません。
赤字の部分はRaspberryのIPアドレスに変更してください。
サーバー側(Raspberry側)のプログラムが動いていないときは、接続をリトライします。

/*
 * W5100 Ethernet Module TcpClient example.
 */

#include <SPI.h>
#include <Ethernet.h>

EthernetClient client;
unsigned long next;
bool connect;

void EthernetBegin() {
  uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05};

  while(1) {
    Serial.print("begin....");
    int Ret = Ethernet.begin(mac);
    Serial.print(Ret);
    Serial.print("...");
    if (Ret) {
      Serial.println("ok....");
      Serial.print("localIP: ");
      Serial.println(Ethernet.localIP());
      Serial.print("subnetMask: ");
      Serial.println(Ethernet.subnetMask());
      Serial.print("gatewayIP: ");
      Serial.println(Ethernet.gatewayIP());
      Serial.print("dnsServerIP: ");
      Serial.println(Ethernet.dnsServerIP());
      break;
    } // end if
    Serial.println("faild....");
    delay(1000);
  } // end while
}

void setup() {

  Serial.begin(9600);
  Serial.println("Client Start");
  connect = 0;
  next = 0;
}

void loop() {
  static int num = 0;
  char smsg[30];
  uint8_t rmsg[30];

  if ( (millis() - next) > 0) {
    if (!connect) EthernetBegin();
    next = millis() + 5000;
    Serial.print("Client connect....");
    // replace hostname with name of machine running tcpserver.pl
    if (client.connect(IPAddress(192,168,111,20),9876)) {
      connect = 1;
      Serial.print("Client Connected....");
      sprintf(smsg,"data from arduino %05d",num);
      num++;
      client.print(smsg);

      // wait for responce
      while(client.available()==0) {
        if (next - millis() < 0) {
          connect = 0;
          goto close;
        } // end if
      } // end while

      int size;
      while((size = client.available()) > 0) {
        Serial.print("Receive Size=");
        Serial.println(size);
        size = client.read(rmsg,size);
        Serial.write(smsg,size);
        Serial.write("->");
        Serial.write(rmsg,size);
        Serial.println("");
      } // end while

close:
      //disconnect client
      Serial.println("Client disconnect");
      client.stop();
    } else {
      Serial.println("Client connect failed");
      connect = 0;
    }
  }
}

このスケッチを実行するとArduinoのシリアルモニターに以下が表示されます。
Arduinoから送った「data from arduino」の文字が「DATA FROM ARDUINO」となって返ってきます。
その後ろの5桁の数字はパケットの送信回数です。



Raspberry側は以下の様に表示されます。




次は、Raspberryがクライアント、Arduinoがサーバーの動作を試して みます。