「Arduinoの基礎 - Ethernet」の版間の差分
ページの作成:「== 概要 == <br><br> == Ethernetシールド == ==== DHCPの利用 ==== ArduinoでEthernetシールド等を使用する場合、プログラムで明示的にIPアド…」 |
|||
| 151行目: | 151行目: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<br><br> | <br> | ||
==== Arduinoの遠隔操作 ==== | |||
Arduinoのメリットの1つに、各種シールドと開発環境における各種ライブラリの存在が挙げられる。<br> | |||
<br> | |||
例えば、Arduino UnoをLANに接続するには、Ethernetシールドのみ準備することで、Arduino Unoにネットワーク機能を追加することができる。<br> | |||
そして、そのネットワーク機能はハードウェアの違いを意識せずに、Ethernetライブラリを使用することで実現できる。<br> | |||
さらに、プログラミングインターフェイスとして、ソケットよりも抽象化されたサーバオブジェクトとクライアントオブジェクトが用意されている。<br> | |||
<br> | |||
このセクションでは、ArduinoとEthernetシールドを使用したLED遠隔操作ソフトウェアを作成する。<br> | |||
ホストPC上のソフトウェアONボタンまたはOFFボタンを押下することで、Arduinoに接続されたLEDを制御する。<br> | |||
また、ArduinoとホストPCは、有線LANケーブルを使用してルータまたはハブに接続する。<br> | |||
<br> | |||
Arduinoのソースコードでは、TCPポート8888番をリスニングしており、データ"S:1"を受信するとLEDを点灯、"S:0"を受信するとLEDを消す。<br> | |||
ホストPCのソフトウェアでは、ONボタンを押下した時はArduinoにデータ"S:1"を送信、OFFボタンを押下した時にデータ"S:0"を送信する。<br> | |||
このようなクライアントとサーバ間のデータ通信の取り決めのことを、プロトコルという。<br> | |||
<br> | |||
次に、ArduinoにEthernetシールドを接続する。<br> | |||
下図に、Ethernetシールドの表面と裏面、接続図を示す。<br> | |||
<br> | |||
下図に、ArduinoとLEDの接続を示す。<br> | |||
8番ピンのデジタル出力を使用している。<br> | |||
ここでは、抵抗は470[Ω]を使用しており、流れる電流は<math>I = \frac{5 \mbox{[V]} - 2.1 \mbox{[V]}}{470 [\Omega]} = 6 \mbox{[mA]}</math>である。<br> | |||
<br> | |||
以下に、Arduino Unoのソースコードを示す。<br> | |||
<br> | |||
データ"S:1"でLEDを点灯、データ"S:0"でLEDを消す。<br> | |||
その他のデータを受信した場合、クライアントがそのデータを捨てる。<br> | |||
1バイトずつにデータを取得するため、下図のような状態遷移となる。<br> | |||
<br> | |||
MACアドレスは、一意性のある6バイトを設定する。(ここでは、0xDE 0xAD 0xBE 0xEF 0xF0 0x0Dとしている)<br> | |||
ネットワークアドレスは192.168.1.0/24を想定しており、ArduinoのIPアドレスは192.168.1.10と固定する。<br> | |||
また、ポート番号は、TCP 50000番とする。<br> | |||
<syntaxhighlight lang="c++"> | |||
#include <EthernetServer.h> | |||
#include <Ethernet.h> | |||
#include <EthernetClient.h> | |||
#include <Dhcp.h> | |||
#include <Dns.h> | |||
#include <EthernetUdp.h> | |||
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xF0, 0x0D }; | |||
byte ip[] = { 192, 168, 1, 10 }; | |||
EthernetServer server(50000); | |||
const int STATE_INIT = 0; | |||
const int STATE_1 = 1; | |||
const int STATE_2 = 2; | |||
const int STATE_3 = 3; | |||
const int PIN_LED = 8; | |||
void setup() | |||
{ | |||
Ethernet.begin( mac, ip ); | |||
server.begin(); | |||
pinMode( PIN_LED, OUTPUT ); | |||
digitalWrite( PIN_LED, LOW ); | |||
} | |||
void loop() | |||
{ | |||
EthernetClient client = server.available(); | |||
int state = STATE_INIT; | |||
int i; | |||
if(client) | |||
{ | |||
while(client.connected()) | |||
{ | |||
while( ( i = client.read() ) != -1 ) | |||
{ | |||
if( state == STATE_INIT ) | |||
{ | |||
if( i == 'S' ) | |||
{ | |||
state = STATE_1; | |||
} | |||
else | |||
{ | |||
client.stop(); | |||
break; | |||
} | |||
} | |||
else if( state == STATE_1 ) | |||
{ | |||
if( i == ':' ) | |||
{ | |||
state = STATE_2; | |||
} | |||
else | |||
{ | |||
state = STATE_INIT; | |||
client.stop(); | |||
break; | |||
} | |||
} | |||
else if( state == STATE_2 ) | |||
{ | |||
if( i == '1' ) | |||
{ | |||
switch_led(1); | |||
client.print("OK"); | |||
} | |||
else if( i == '0' ) | |||
{ | |||
switch_led(0); | |||
client.print("OK"); | |||
} | |||
state = STATE_INIT; | |||
client.stop(); | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
void switch_led(int on) | |||
{ | |||
digitalWrite( PIN_LED, on ? HIGH : LOW ); | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
__FORCETOC__ | __FORCETOC__ | ||
[[カテゴリ:Arduino]] | [[カテゴリ:Arduino]] | ||
2020年12月3日 (木) 02:09時点における版
概要
Ethernetシールド
DHCPの利用
ArduinoでEthernetシールド等を使用する場合、プログラムで明示的にIPアドレスを指定するのではなく、
DHCPで自動的にIPアドレスの割り当てを行う方法を記載する。
Arduinoの標準のEthernetライブラリを使用することで、簡単に実現できる。
これは、Ethernet.begin()を呼び出す時、MACアドレスのみを指定することで(IPアドレスは指定しない)、DHCPからIPアドレスを自動で取得できる。
ここでは、Arduino UnoにEthernetシールドを接続している。
以下の例では、シリアルポートに結果を出力するために、Serial.begin()やprintln()を呼び出している。
#include <Ethernet.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xF0, 0x0D };
void setup()
{
Serial.begin(9600);
Ethernet.begin(mac);
Serial.println(Ethernet.localIP());
}
void loop()
{
}
Webサーバの実装
このセクションでは、Arduinoの標準のEthernetライブラリを使用して、単純なWebサーバを実装する。
簡単なWebサーバの実装例はExampleに含まれている。
以下の例では、URIを確認して、HTTPステータスコード 200 OKおよび404 File Not Foundを返している。
Webサーバが必要な評価試験において、以下のようなサンプルコードを動作させるとよい。
IPアドレスはDHCPから自動で取得しており、手動で設定する場合は、Ethernet.begin()で指定する。
また、IPアドレスはシリアルポートに出力しており、
WebブラウザからこのWebサーバに接続する時は、シリアルモニタに表示されたIPアドレスへリクエストを送る。
リクエストラインのみを確認するので、その行だけ特別にバッファ(変数reqLine)にコピーしている。
クライアントからのリクエストを読み込みんだ後、バッファを確認してメソッドとURIを取得する。
もし、長いリクエストが来た場合、途中まで読み込む。
Content-Lenghをセットしない代わりに、データ区切りとしてConnection closeする。
効率は悪いが、単一クライアントのみ接続が可能なので、1つずつのリクエスト処理は短くする必要がある。
#include <Ethernet.h>
byte mac[] = { 0xDE,0xAD,0xBE,0xEF,0xF0,0x0D };
EthernetServer server(80);
void setup()
{
Serial.begin(9600);
Ethernet.begin(mac);
Serial.println(Ethernet.localIP());
server.begin();
}
void loop()
{
EthernetClient client = server.available();
if(client)
{
Serial.println("*** New Client ***");
boolean currentLineIsBlank = true;
boolean requestLineRead = false;
char reqLine[64] = {0};
char *p = reqLine;
char *method = NULL;
char *uri = NULL;
const char delims[2] = " ";
while(client.connected())
{
char c = client.read();
// Serial.write( c );
// Query
if(!requestLineRead && (p - reqLine ) < (sizeof(reqLine) - 1) && c != '\r' && c != '\n' )
{
*p = c;
p++;
}
if(c == '\n' && currentLineIsBlank)
{
// Parse Query
p = strtok(reqLine, delims);
while( p )
{
if(!method)
{
method = p;
}
else if(!uri)
{
uri = p;
}
p = strtok(NULL, delims);
}
// Send Response
if(!strcmp(method, "GET") && !strcmp(uri, "/pic"))
{
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/plain");
client.println("Connection: close");
client.println();
client.println("OK!");
}
else
{
client.println("HTTP/1.1 404 Not Found");
client.println("Content-Type: text/plain");
client.println("Connection: close");
client.println();
client.println("File Not Found");
}
break;
}
if(c == '\n')
{
currentLineIsBlank = true;
if(!requestLineRead)
{
requestLineRead = true;
}
}
else if(c != '\r')
{
currentLineIsBlank = false;
}
}
delay( 10 );
client.stop();
Serial.println("Client disconnected");
}
}
Arduinoの遠隔操作
Arduinoのメリットの1つに、各種シールドと開発環境における各種ライブラリの存在が挙げられる。
例えば、Arduino UnoをLANに接続するには、Ethernetシールドのみ準備することで、Arduino Unoにネットワーク機能を追加することができる。
そして、そのネットワーク機能はハードウェアの違いを意識せずに、Ethernetライブラリを使用することで実現できる。
さらに、プログラミングインターフェイスとして、ソケットよりも抽象化されたサーバオブジェクトとクライアントオブジェクトが用意されている。
このセクションでは、ArduinoとEthernetシールドを使用したLED遠隔操作ソフトウェアを作成する。
ホストPC上のソフトウェアONボタンまたはOFFボタンを押下することで、Arduinoに接続されたLEDを制御する。
また、ArduinoとホストPCは、有線LANケーブルを使用してルータまたはハブに接続する。
Arduinoのソースコードでは、TCPポート8888番をリスニングしており、データ"S:1"を受信するとLEDを点灯、"S:0"を受信するとLEDを消す。
ホストPCのソフトウェアでは、ONボタンを押下した時はArduinoにデータ"S:1"を送信、OFFボタンを押下した時にデータ"S:0"を送信する。
このようなクライアントとサーバ間のデータ通信の取り決めのことを、プロトコルという。
次に、ArduinoにEthernetシールドを接続する。
下図に、Ethernetシールドの表面と裏面、接続図を示す。
下図に、ArduinoとLEDの接続を示す。
8番ピンのデジタル出力を使用している。
ここでは、抵抗は470[Ω]を使用しており、流れる電流はである。
以下に、Arduino Unoのソースコードを示す。
データ"S:1"でLEDを点灯、データ"S:0"でLEDを消す。
その他のデータを受信した場合、クライアントがそのデータを捨てる。
1バイトずつにデータを取得するため、下図のような状態遷移となる。
MACアドレスは、一意性のある6バイトを設定する。(ここでは、0xDE 0xAD 0xBE 0xEF 0xF0 0x0Dとしている)
ネットワークアドレスは192.168.1.0/24を想定しており、ArduinoのIPアドレスは192.168.1.10と固定する。
また、ポート番号は、TCP 50000番とする。
#include <EthernetServer.h>
#include <Ethernet.h>
#include <EthernetClient.h>
#include <Dhcp.h>
#include <Dns.h>
#include <EthernetUdp.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xF0, 0x0D };
byte ip[] = { 192, 168, 1, 10 };
EthernetServer server(50000);
const int STATE_INIT = 0;
const int STATE_1 = 1;
const int STATE_2 = 2;
const int STATE_3 = 3;
const int PIN_LED = 8;
void setup()
{
Ethernet.begin( mac, ip );
server.begin();
pinMode( PIN_LED, OUTPUT );
digitalWrite( PIN_LED, LOW );
}
void loop()
{
EthernetClient client = server.available();
int state = STATE_INIT;
int i;
if(client)
{
while(client.connected())
{
while( ( i = client.read() ) != -1 )
{
if( state == STATE_INIT )
{
if( i == 'S' )
{
state = STATE_1;
}
else
{
client.stop();
break;
}
}
else if( state == STATE_1 )
{
if( i == ':' )
{
state = STATE_2;
}
else
{
state = STATE_INIT;
client.stop();
break;
}
}
else if( state == STATE_2 )
{
if( i == '1' )
{
switch_led(1);
client.print("OK");
}
else if( i == '0' )
{
switch_led(0);
client.print("OK");
}
state = STATE_INIT;
client.stop();
break;
}
}
}
}
}
void switch_led(int on)
{
digitalWrite( PIN_LED, on ? HIGH : LOW );
}