UNODUE
概要
Ethernet Shieldを利用したTCP/IP通信の実験です。標準で付属のEthernetライブラリを利用します。スケッチはArduinoソフトウェアについてくるDhcpAddressPrinter、WebClient、WebServerをベースに少し修正しています。
Arduino Uno と Arduino Due の両方で動作することを確認しました。Arduino Dueの場合も、ICSPピンが正しく刺さるように(デジタルピンやアナログピンの番号が同じとなるように)Ethernet Shieldを取り付ければ動作するようです。
目的
Ethernetライブラリの使い方と動作を少しずつ見ていきます。最終的にはTCPの簡単なクライアントプログラムとサーバプログラムを作成します。
- 共通編
- IPアドレスを設定する。
- DHCPサーバからIPアドレスを取得する。
- IPアドレスを指定する。
- クライアント編
- サーバ編
実験
共通編
クライアント・サーバのどちらを利用するにもIPアドレスを設定する必要があります。ここではIPアドレスの設定方法を確認します。
IPアドレスを設定する
EthernetClassクラスのEthernetというオブジェクト(変数)に、MACアドレスやIPアドレスなどを保持します。EthernetというオブジェクトはEthernetClassライブラリの中で事前に定義されています。シリアル通信に利用するSerialというオブジェクトと同様と考えることができます。
IPアドレスは自分で指定することも、DHCPサーバから取得することもできます。
DHCPサーバからIPアドレスを取得する。
Ethernet.begin()という関数を利用してIPアドレスを設定します。この関数はパラメータによって動作が異なります。DHCPサーバからIPアドレスを取得するときは、この関数にMACアドレスだけを渡します。IPアドレスの取得に成功すると1が返り、失敗すると0が返ります。
MACアドレスはEthernet Shieldの裏に記載されています。Ethernet ShieldをArduino本体に装着する前にMACアドレスをメモしておかないと、後で苦労するかもしれません。隙間から見えなくもありませんが。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
#include <SPI.h>
#include <Ethernet.h>
// MACアドレスの定義
byte mac_address[] = {
0x90, 0xA2, 0xDa, 0x0D, 0xD2, 0xEF
};
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
// DHCPサーバを用いてIPアドレス、サブネットマスク、ゲートウェイサーバ、DNSサーバを設定する。
if (Ethernet.begin(mac_address) > 0) {
Serial.print("IP Address: ");
Serial.println(Ethernet.localIP());
Serial.print("Subnet Mask: ");
Serial.println(Ethernet.subnetMask());
Serial.print("Gateway IP Address: ");
Serial.println(Ethernet.gatewayIP());
Serial.print("DNS Server Address: ");
Serial.println(Ethernet.dnsServerIP());
}
}
void loop() {
// put your main code here, to run repeatedly:
}
|
MACアドレスはbyte型の配列で6バイト分を設定します。Ethernet Shieldに割り当てられているアドレスを設定してください。
Ethernet.localIP()は設定されているIPアドレスを取得する関数、Ethernet.subnetMask()は設定されているサブネットマスクを取得する関数、Ethernet.gatewayIP()は設定されているゲートウェイのIPアドレスを取得する関数、Ethernet.dnsServerIP()は設定されているDNSサーバのIPアドレスを取得する関数です。すべてIPAddressクラスを返却します。
IPアドレスクラスはSerial.print()に直接渡すことができます。ドット付きの10進表記で出力されます。
DHCPサーバからIPアドレスを取得した場合は定期的にアドレスの再取得(再リース)を行う必要があります。これは、Ethernet.maintain()という関数を使います。
IPアドレスを指定する
IPアドレスを自分で設定するときもEthernet.begin()を使います。MACアドレス、IPアドレス、DNSサーバアドレス、ゲートウェイアドレス、サブネットマスクを設定することができます。DNSサーバアドレス、ゲートウェイアドレス、サブネットマスクは省略することもできます。省略した場合は以下の値が設定されます。
項目 |
デフォルト値 |
DNSサーバアドレス |
IPアドレスの第4オクテットを1にしたIPアドレス。 |
ゲートウェイアドレス |
IPアドレスの第4オクテットを1にしたIPアドレス。 |
サブネットマスク |
255.255.255.0 |
表の下から順に同時に省略することができます。例えば、サブネットマスクとゲートウェイアドレスを同時に省略することはできますが、DNSサーバを省略してゲートウェイアドレスを指定するということはできません。詳しくはEthernet.begin()のリファレンスを参照してください。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
#include <SPI.h>
#include <Ethernet.h>
// MACアドレスの定義
byte mac_address[] = {
0x90, 0xA2, 0xDa, 0x0D, 0xD2, 0xEF
};
// IPアドレスの定義
byte IP_address[] = {
192, 168, 11, 200
};
// DNSサーバアドレスの定義
byte dns_address[] = {
192, 168, 11, 1
};
// ゲートウェイアドレスの定義
byte gateway_address[] = {
192, 168, 11, 1
};
// サブネットマスクの定義
byte subnet[] = {
255, 255, 255, 0
};
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
// MACアドレス、IPアドレス、DNSサーバ、
// ゲートウェイサーバ、サブネットマスクを設定する。
Ethernet.begin(mac_address, IP_address, dns_address, gateway_address, subnet);
Serial.print("IP Address: ");
Serial.println(Ethernet.localIP());
Serial.print("Subnet Mask: ");
Serial.println(Ethernet.subnetMask());
Serial.print("Gateway IP Address: ");
Serial.println(Ethernet.gatewayIP());
Serial.print("DNS Server Address: ");
Serial.println(Ethernet.dnsServerIP());
}
void loop() {
// put your main code here, to run repeatedly:
}
|
IPアドレスやサブネットマスクは、byte型の配列で4バイト分を設定します。各自の環境に合わせて設定してください。IPAddressクラスの変数を使うこともできます。この場合は、例えば、以下のように設定します。
1
|
IPAddress IP_address(192, 168, 11, 200);
|
クライアント編
簡単なWebクライアントを作成する
TCPのクライアントは以下の手順で実現することができます。
- IPアドレス等設定
- クライアント用オブジェクト作成
- サーバに接続
- データの送受信
上記で、EthernetClientクラスのメソッドは実際には、「2」で作成したオブジェクトのメソッドを呼び出します。例えば、「client」というEthernetClient型のオブジェクトを「2」で作成したとすると、EthernetClient::connect()は、スケッチ上では、client.connect()となります。
以下にhttp://www.arduino.cc/にアクセスして、トップページを取得するサンプルプログラムを示します。当然ですが取得できるのはHTML本体です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
#include <SPI.h>
#include <Ethernet.h>
byte mac_address[] = {
0x90, 0xA2, 0xDa, 0x0D, 0xD2, 0xEF
};
EthernetClient client;
void setup() {
Serial.begin(9600);
if (Ethernet.begin(mac_address) == 0) {
Serial.println("Failed to configure Ethernet using DHCP.");
for(;;)
;
}
Serial.print("connecting...");
if (client.connect("www.arduino.cc", 80)) {
Serial.println("done.");
// Make a HTTP request:
client.println("GET / HTTP/1.1");
client.println("Host: www.arduino.cc");
client.println("Connection: close");
client.println();
}
else {
Serial.println("failed.");
}
}
void loop()
{
if (client.available()) {
char c = client.read();
Serial.print(c);
}
if (!client.connected()) {
Serial.println();
Serial.println("disconnecting.");
client.stop();
for(;;)
;
}
}
|
EthernetClient()型の変数clientを定義します。setup()とloop()の両方で利用するため、グローバル変数として定義しています。
setup()では、前述した方法でEthernet ShieldにIPアドレス等を割り当てています。DHCPサーバ経由でIPアドレスを取得しているので、直接IPアドレスを指定したい場合は、適宜修正してください。
EthernetClient::connect()を使ってサーバに接続します。引数は接続先のホスト名とポートです。ホスト名ではなくIPアドレスで指定する場合は、IPAddress型の変数を指定します。
次に、EthernetClient::print()を用いてサーバに文字列を送信します。今回は、HTTP/1.1のGETメソッドと必要なほぼ最小限のヘッダ情報を送信しています。
その後、loop()内で、EthernetClient::available()で受信データがあるかを確認し、データがある場合は、EthernetClient::read()でデータを受信します。最後に、EthernetClient::connected()でコネクションの有無を確認しています。
サーバ編
TCPのサーバは以下の手順で実現することができます。
- IPアドレス等設定
- サーバ用オブジェクト作成
- クライアントからの接続準備(listen相当)
- クライアントからの接続待機(accept相当)
- データの受送信
以下に、Webサーバとしてアナログ入力の値をWebブラウザに表示するためのスケッチを示します。このスケッチは、チュートリアルにあるスケッチです。
EthernetServer型の変数serverを定義します。setup()とloop()の両方で利用するため、グローバル変数として定義しています。
setup()では、前述した方法でEthernet ShieldにIPアドレス等を割り当てています。IPアドレスを直接指定しているため、DHCPサーバ経由でIPアドレスを取得したい場合は、適宜修正してください。ただし、サーバ用途では毎回IPアドレスが変更されるのは不便なので、IPアドレスを直接指定するのがいいと思います。
EthernetServer::begin()を使ってクライアントからの接続準備を行います。引数はありません。
次に、EthernetServer::available()を使ってクライアントからの接続を待機します。接続がある場合は否ゼロの値が返却されます。返却されるのはEthernetClient型のオブジェクトです。
EthernetServer::available()を呼び出した際に返却されたEthernetClient型のオブジェクトを利用して、クライアントとのデータの受送信を行います。
EthernetServerクラスにもEthernetServer::write()というメソッドがありますが、これは、現在接続されているすべてのクライアントに対してデータを送信するためのメソッドです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
#include <SPI.h>
#include <Ethernet.h>
// MACアドレスの定義
byte mac_address[] = {0x90, 0xA2, 0xDA, 0x0D, 0xD2, 0xEF};
// IPアドレスの定義
byte ip_address[] = {192, 168, 11, 200};
// サーバ用オブジェクト作成
EthernetServer server(80);
void setup() {
Serial.begin(9600);
// MACアドレス、IPアドレスを設定する。
Ethernet.begin(mac_address, ip_address);
// クライアントからの接続準備
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
}
void loop() {
// クライアントからの接続待機
EthernetClient client = server.available();
if (client) {
Serial.println("new client");
boolean currentLineIsBlank = true;
// データの受送信
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);
if (c == '\n' && currentLineIsBlank) {
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("<meta http-equiv=\"refresh\" content=\"5\">");
for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
int sensorReading = analogRead(analogChannel);
client.print("analog input ");
client.print(analogChannel);
client.print(" is ");
client.print(sensorReading);
client.println("<br />");
}
client.println("</html>");
break;
}
if (c == '\n') {
currentLineIsBlank = true;
}
else if (c != '\r') {
currentLineIsBlank = false;
}
}
}
delay(1);
client.stop();
Serial.println("client disonnected");
}
}
|
まとめ
Ethernetクラス、EthernetClientクラス、EthernetServerクラスの関係は以下の通りです。
クラス |
用途 |
Ethernet |
IPアドレス等を設定する。 |
EthernetClient |
サーバへの接続要求を取り扱う。 クライアント・サーバ間のデータ送受信を行う。 |
EthernetServer |
クライアントからの接続要求を取り扱う。 |
以下に簡単な関連図を示します。
バージョン
Hardware: | Arduino Uno/Arduino Due |
Software: | Arduino 1.0.4/Arduino 1.5.2 |
最終更新日
November 1, 2022