【Arduino】LAN通信モジュール(W5500 Lite)を使う

it

LAN通信するためのモジュールW5500を使ってみました。
W5500 Liteとの接続相性のいいT-LITEとの合体を試してみました。
代表的なマイコン同士のTCP/IPでのTelnet通信と、Webサーバーを作ってセンサの読み取り結果を表示しました。

W5500 Lite

簡単紹介

SPIをTCP/IPに変換することで、マイコン同士のLAN通信できる。
LOLIN のT-LITE(ESP32)と相性がよく合体して配線不要で使用できる。

購入時にはピンヘッダが取り付けられています。
LOLINのT-Liteと合体して使う際、T-Lite側をピンヘッダにしたかったので当記事ではピンソケットに換装して使っています。

ピン配置

LOLINのT-Liteと合体して使いやすいですが、SPI信号のMOSIとMISOのピン番号を入れ替える必要があります。
こちらで紹介しています。

外観

使ってみた

◆まとめ

・手軽に使うにはLOLINのT-LITEとの相性がいい。
・Webサーバー化でき、マイコンの読み取ったセンサ情報をリアルタイムに更新できた。

◆開発環境

Arduino環境で開発しました。
複数のマイコンを使用していますが、主にLOLINのT-LITEを使用しました。
ボードライブラリはEspressif の「esp32 by Espressif Systems」、ボードは「ESP32 DevModule」を使いました。

同名のモジュールライブラリWIZnetの「WIZnet-ArduinoEthernet」がインストールされている場合、ライブラリフォルダから除外してコンパイルしないと動作しないことがあります。

◆T-LITEと合体

取り付け方向を間違わないように注意が必要ですが、ピンヘッダとピンソケットを接続するだけです。
ピンヘッダ1本余るのが気になりますが、作業は簡単です。

合体した状態です。
面積のない基板同士の合体なので厚みが勝り、思ったより小さくならない印象です。

本来はW5500-Lite側にピンヘッダが取り付けられています。
個人的にマイコン側をピンヘッダにしたかったので、W5500-Liteのピンヘッダをピンソケットに換装しました。

画像左側が作業後、右が作業前(購入時)です。

ピンヘッダを取り外す作業ははんだ作業に自信がないとモジュールを破損することがあります。

◆プロトコル

TCP/IPサーバ、TCP/IPクライアント

初期化は若干コード量が多いです。
サーバ側、クライアント側ともに電文の送受信はUARTのような使用感で使えます。

Webサーバー

簡単なメッセージサーバーを作りました。
センサーの状態をリアルタイムでブラウザに表示する簡単なメッセージサーバーを作りました。センサーの状態をリアルタイムでブラウザに表示することもできます。

◆いろんなマイコンで使ってみる

代表的なマイコンでW5500-LITEを使ってみました。
今回試してみたのは以下一覧で、すべての基板でW5500-Liteを使うことができました。

・LOLIN T-Lite (ESP32-WROOM32)
・XIAO RP2040
・XIAO SAMD21(SAMD21)

こちらはXIAO SAMD21で使った結果です。

準備

Arduino環境の作成

◆開発環境

Arduino環境の準備はこちらの記事で紹介しています。

◆ボードライブラリ

この記事では省略しましたが多種マイコンボードでも使用できます。
各ボードに対応するボードライブラリを一覧にしました。
ボード名は当サイトの該当記事にリンクしています。

ボード名選択するボード
T-LITEesp32 > ESP32 Dev Module
XIAO RP2040RaspberryPi Pico/RP2040/RP2350 > Seeed XIAO RP2040
XIAO SAMD21Seeed SAMD Boards > Seeed XIAO

◆モジュールライブラリ

Ethernetライブラリを使います。
追加のインストールは不要です。

注意

…\Document\Arduino\libraries フォルダに、Ethernet フォルダがある場合期待通りの動作をしないことがあります。

当サイトではWiznetの製品を使った記事を書いています。
その過程でWiznetサイトからEthernetのモジュールライブラリをインストールしますが、その状態で当記事のサンプルを実行すると動作をしないことがあります。

以下手順で一時的にライブラリを除外してから実施することで解消できます。

フォルダ : C:\Users\<ユーザアカウント>\OneDrive\Documents\Arduino\libraries
に移動し、「Ethernet」フォルダをデスクトップ(とりあえず)に移動します。

「Ethernet」ライブラリが必要になったら逆の手順で元のフォルダへ移動します。

そのほかの「Ethernet」ライブラリでも同じことが起きる可能性があるので、うまく動作しない場合は試してみる価値あります。

◆ピンヘッダピンソケット交換

T-Lite(ピンヘッダ装着)と合体するために、W5500-Lite側をピンソケットに付け替えます。
半田と作業にコツが必要です。

作業の概要
ピンヘッダを1本ずつ抜き取り、スルーホールに残ったはんだをバキュームで吸い取ります。

①ピンヘッダをプライヤでつまみ、半田を溶かします。
 ピンヘッダは軽く引き圧をかけておくことで、半田が溶けるとスルっと抜けます。
 力で引き抜こうとすると基板が破損します。

②1ピン引き抜いた様子です。

③順番に全部抜きます。

④半田バキュームをスタンバイした状態で、反対側から半田を溶かして吸い取ります。

スルーホールがきれいに清掃できたらピンソケットを取り付けます。

スケッチ

TCP Client

説明

T-LiteとW5500-Liteを合体させてTCP Clientにします。
TeratermからUSB-UARTからT-Liteに送信した電文を、LANを経由して反対のマイコン(サーバ側)に送信し、USB-UARTからTeratermに出力します。

当サイトで紹介した適当なTCP Serverと通信します。
サーバー側のIP設定は以下の内容で起動します。
IP Address : 192.168.1.20/24
Port : 5000

今回サーバーには、当サイトで紹介した[W5100S-EVB-Pico]を使用します。

こちらで紹介したTCP Serverも使用することができます。

T-Liteのコンパイルに使うボードライブラリは「ESP32 Dev Module」を使います。
デフォルトピンのままのSPIピン配置は、W5500-Liteのピン配置に対しMOSIとMISOが逆です。
スケッチの先頭で、ピン配置を変更する処理を加えます。

//ピン定義
#define PIN_MOSI      (19)
#define PIN_MISO      (23)

void setup() {

  //SPIに使用するピン配置を定義
  SPI.begin(PIN_SCK, PIN_MISO, PIN_MOSI, PIN_CS);

配線

ジャンパワイヤによる配線はありません。

スケッチ

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

#define PIN_CS        (5)
#define PIN_RESET     (4)
#define PIN_DC        (33)
#define PIN_MOSI      (19)
#define PIN_MISO      (23)
#define PIN_SCK       (18)


byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 10);

IPAddress server(192, 168, 1, 20);
#define PORTNO 5000

EthernetClient client;

void setup() {

  SPI.begin(PIN_SCK, PIN_MISO, PIN_MOSI, PIN_CS);

  Ethernet.init(PIN_CS);
  Ethernet.begin(mac, ip);
  
  Serial.begin(115200);
  while (!Serial) {
    ;
  }

  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1);
    }
  }

  while (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
    delay(500);
  }

  delay(1000);
  Serial.println("connecting...");

  if (client.connect(server, 5000)) {
    Serial.println("connected");
  } else {
    Serial.println("connection failed");
  }
}

void loop()
{
  if (client.available() != 0)
  {
    char cClient = client.read();
    Serial.print(cClient);
  }

  while (Serial.available() > 0)
  {
    char cCOM = Serial.read();
    if (client.connected() == true)
    {
      client.print(cCOM);
    }
  }

  if (client.connected() == false) 
  {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
 
    while (true)
    {
      delay(1);
    }
  }
}

結果

パソコンとT-LiteをUSBケーブルで接続。
パソコンとW5100S-EVB-PicoをUSBケーブルで接続。
W5500-LiteとW5100S-EVB-PicoをLANケーブルで接続します。

T-Lite はCOM27、W5100S-EVB-PicoはCOM29で認識されました。
Teratermを使いそれぞれのポートで開きます。

初めにCOM27側(T-Lite)のTeratermから”hello”と入力すると、COM29側のTeratermに”hello”と表示されました。
次にCOM29側(W5100S-EVB-Pico)のTeratermから”abc”と入力すると、COM27側のTeratermに”abc”と表示されました。
(LocalEchoはOffです)

それぞれUART経由からマイコンを通り、LANを経て反対のマイコンに通信できました。

TCP Server

説明

TCP SeverとしてTCP Clientと通信します。
今回Clientには、PC(Windows11)を使います。

パソコンから優先LANケーブルをW5500-Liteに接続し、Teratermを使い電文の送受信をします。
パソコン側のネットワーク設定は以下にしました。

Windows側
IP : 192.168.1.10/24

T-Liteのコンパイルに使うボードライブラリは「ESP32 Dev Module」を使います。
デフォルトピンのままのSPIピン配置は、W5500-Liteのピン配置に対しMOSIとMISOが逆です。
スケッチの先頭で、ピン配置を変更する処理を加えます。

//ピン定義
#define PIN_MOSI      (19)
#define PIN_MISO      (23)

void setup() {

  //SPIに使用するピン配置を定義
  SPI.begin(PIN_SCK, PIN_MISO, PIN_MOSI, PIN_CS);

スケッチ

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

#define SOCKET_PORT   (5000)
#define PIN_CS        (5)
#define PIN_RESET     (4)
#define PIN_DC        (33)
#define PIN_MOSI      (19)
#define PIN_MISO      (23)
#define PIN_SCK       (18)

byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xEE
};

IPAddress ip(192, 168, 1, 20);
IPAddress myDns(192, 168, 1, 10);
IPAddress gateway(192, 168, 1, 10);
IPAddress subnet(255, 255, 255, 0);

EthernetServer server(SOCKET_PORT);

void setup()
{
  SPI.begin(PIN_SCK, PIN_MISO, PIN_MOSI, PIN_CS);

  Ethernet.init(PIN_CS);
  
  Ethernet.begin(mac, ip, myDns, gateway, subnet);

  Serial.begin(115200);
  
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1);
    }
  }

  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());

  server.begin();
  Serial.println("Server Start");
}

void loop()
{
  EthernetClient client = server.available();

  if (client.available() != 0)
  {
    char cClient = client.read();
    Serial.print(cClient);
  }

  if(Serial.available() > 0)
  {
    char cCOM = Serial.read();
    server.print(cCOM);
  }

}

結果

T-Lite(W5500-Lite)側はArduinoのシリアルモニタを使いました。
パソコンとの有線LANはTeratermを使いTCP/IP ソケット通信でW5500-Liteと接続しました。


Teraterm(192.168.1.20)に”Hello”+Enter と入力すると、Arduinoシリアルモニタに”Hello”と表示されました。
Arduinoシリアルモニタに”World”と入力するとTeratermに”World”と表示されました。

Web Server

説明

T-LiteとW5500-Liteを使いWebServerを作りました。
ブラウザ上に”こんにちは”と表示します。

スケッチ

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

#define SOCKET_PORT   (80)
#define PIN_CS        (5)
#define PIN_MOSI      (19)
#define PIN_MISO      (23)
#define PIN_SCK       (18)

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xEE };

IPAddress ip(192, 168, 1, 200);
IPAddress myDns(192, 168, 1, 100);
IPAddress gateway(192, 168, 1, 100);
IPAddress subnet(255, 255, 255, 0);

EthernetServer server(SOCKET_PORT);

void setup() {
  Serial.begin(115200);
  delay(1000);

  SPI.begin(PIN_SCK, PIN_MISO, PIN_MOSI, PIN_CS);

  Ethernet.init(PIN_CS);
  Ethernet.begin(mac, ip, myDns, gateway, subnet);

  Serial.print("IP Address: ");
  Serial.println(Ethernet.localIP());

  server.begin();
}

void loop() {
  EthernetClient client = server.available();

  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (c == '\n') break;
      }
    }

    client.println("HTTP/1.1 200 OK");
    client.println("Content-Type: text/html; charset=UTF-8");
    client.println("Connection: close");
    client.println();
    client.println("<h1>こんにちは</h1>");

    client.stop();
  }
}

結果

ブラウザのアドレスバーに”192.168.1.200″と入力すると下図表示がされました。

Web Server(XIAO SAMD21)

説明

W5500-LiteとXIAO SAMD21を組み合わせたWebServerを作りました。
ブラウザ上にはXIAO SAMD21のADCで読み取った値とグラフを表示します。

XIAO SAMD21のADCにはアナログ入力としてESP32-WROOM32 NodeMCUのDAC出力を入力します。
入力信号は約2秒かけて0 -> 3.3V, 約2秒かけて3.3 -> 0Vへ変化します。
こちらはあらかじめ以下ページで用意したものを使います。


XIAO SAMD21は入力電圧を読み取り、結果をWebサーバー上に反映させます。
Webサーバーは約100msごとに更新します。

配線

※D3の青配線(RST)は不要です。

スケッチ

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

#define SOCKET_PORT   (80)
#define PIN_CS        (D2)

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xEE };

IPAddress ip(192, 168, 1, 200);
IPAddress myDns(192, 168, 1, 100);
IPAddress gateway(192, 168, 1, 100);
IPAddress subnet(255, 255, 255, 0);

EthernetServer server(SOCKET_PORT);

unsigned long lastRead = 0;
int sensorValue = 0;

void setup() {
  Serial.begin(115200);
  delay(1000);

  Ethernet.init(PIN_CS);
  Ethernet.begin(mac, ip, myDns, gateway, subnet);

  Serial.print("IP Address: ");
  Serial.println(Ethernet.localIP());

  server.begin();
}

void loop() {
  // 100msごとにA0を読み取る
  if (millis() - lastRead >= 100) {
    lastRead = millis();
    sensorValue = analogRead(A0);
  }

  EthernetClient client = server.available();

  if (client) {
    String req = client.readStringUntil('\n');

    // ---- JSONデータ要求(AJAX用) ----
    if (req.indexOf("GET /data") >= 0) {
      client.println("HTTP/1.1 200 OK");
      client.println("Content-Type: application/json");
      client.println("Connection: close");
      client.println();
      client.print("{\"value\":");
      client.print(sensorValue);
      client.println("}");
      client.stop();
      return;
    }

    // ---- 通常のWebページ ----
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (c == '\n') break;
      }
    }

    client.println("HTTP/1.1 200 OK");
    client.println("Content-Type: text/html; charset=UTF-8");
    client.println("Connection: close");
    client.println();
    client.println("<html><head><meta charset='UTF-8'>");
    client.println("<title>A0 Monitor</title>");
    client.println("<style>");
    client.println("body{font-family:sans-serif;}");
    client.println("#val{font-size:32px;}");
    client.println("</style>");
    client.println("</head><body>");

    client.println("<h1>A0 アナログ値</h1>");
    client.println("<div id='val'>--</div>");
    client.println("<canvas id='graph' width='400' height='100' style='border:1px solid #ccc;'></canvas>");

    // JavaScript
    client.println("<script>");
    client.println("let ctx = document.getElementById('graph').getContext('2d');");
    client.println("let data = new Array(100).fill(0);");

    client.println("function update(){");
    client.println(" fetch('/data').then(r=>r.json()).then(j=>{");
    client.println("   document.getElementById('val').innerText = j.value;");
    client.println("   data.push(j.value); data.shift();");
    client.println("   draw();");
    client.println(" });");
    client.println("}");

    client.println("function draw(){");
    client.println(" ctx.clearRect(0,0,400,100);");
    client.println(" ctx.beginPath();");
    client.println(" ctx.moveTo(0,100-data[0]/10);");
    client.println(" for(let i=1;i<100;i++){ ctx.lineTo(i*4,100-data[i]/10); }");
    client.println(" ctx.stroke();");
    client.println("}");

    client.println("setInterval(update,100);"); // 100msごと更新
    client.println("</script>");

    client.println("</body></html>");

    client.stop();
  }
}

結果

ブラウザのアドレスバーに”192.168.1.200″と入力すると下図表示がされました。
計測器の画面のように値とグラフが更新されました。
グラフは1秒間に10回程度更新され左にスクロールしていきます。

コメント

タイトルとURLをコピーしました