ソフトウェアシリアル通信の動作確認
というわけで今日もいじるよ、ながてぃ~の。
わ「いじるのじゃ!」
Arduinoプログラミング
Arduinoプログラミングに使う言語はC/C++を拡張したようなもので、プログラミングになじみがない人でも簡単に作成できるように配慮されている。Arduinoでできることはリファレンスを参照すればなんとなく想像できた。一つ一つのプログラムはスケッチと呼ばれていて、それぞれのスケッチは主にsetup関数とloop関数によって構成されている。
スケッチを実行する時に始めに一度だけ呼び出されるsetup関数では変数などの初期化を行って、loop関数内には実際の処理を記述するようになっている。loop関数はその名の通り、Arduinoに電源が入っている間、永遠に実行される。loop関数の一回の実行は基本一瞬で終わってしまうようなので、適宜delay関数を使って、実行を遅らせてやる必要があるっぽい。
ところで、Processingというデザイナー向けの環境(言語?)があるがArduino IDEはこれに非常に酷似している。スケッチの拡張子もかつてはProcessingのものと同じ.pdeであったというし(現在は.ino)、何か関係があるのだろうか。……と思ったら、Arduino公式サイトにThe microcontroller on the board is programmed using the Arduino programming language (based on Wiring) and the Arduino development environment (based on Processing).
という記述があった。なるほど!
シリアル通信ってなんぞ?
Arduinoだけで完結するようなシステムに憧れないこともないことはないが、初めはやっぱりPCの画面上にもArduinoからの情報を表示したいし、逆にArduinoに対してデータを送りたい。というかそういう機能がないと何かとデバッグしづらい。
そんなわがままかつ自然な欲求を満たしてくれるのがこのシリアル通信機能である。Arduino本体と開発環境(Windows PC)などはUSBケーブルで接続されていると思うが、このケーブルを介してデータのやり取りをすることが可能なのだ。
Arduino上のマイコンにはUSBケーブルを通じてプログラムを書き込んでいるが、同じUSBケーブルを使って他のデバイスと通信することもできる。面白いものだ。そして、このシリアル通信を実現するためのピンが、Arduino上のDigital 0ピン(RX)、Digital 1ピン(DX)なのだ。
ちなみにArduinoから見るとRXが受信でDXが送信であり、それぞれの状況はArduino上のRX、TXとラベル付けされたLEDを観察することでなんとなく知ることができる(あーLEDが全然光ってないから通信していないんだなーとか)。
シリアル通信するプログラムの作成
さて、シリアル通信を簡単に行えるようにArduino IDEには標準でSerial Monitorがついている。IDEの右上の方にある虫眼鏡アイコンがそれだ。こいつを使えば特に苦労することなく、USBケーブルを介したPC – Arduino間のシリアル通信を体験することができる。
ネットワークプログラミングの基本を学ぶとき、まずは受信したデータをそのまま送り返すようなプログラムを作成することが多い。これはEchoサーバなどと呼ばれるような機能であり、データ受信とデータ送信という通信の基本実装を確かめられる。さながら通信プログラム版「Hello,World」といったところである。
わ「今回もシリアル通信を介して送られてきたデータをそのまま送り返すようなプログラム作りんす。ソースコードはこんな感じじゃ!コード表示スタイルのやっつけっぷりはみなかったことにしてくりゃれ」
char incoming = 0; // 今読んでいるバイト
char processFlag = false; // 表示処理フラグ
void setup()
{
Serial.begin(9600);
pinMode(13, OUTPUT);
}
void loop()
{
incoming = Serial.read(); // 受信バッファから1バイト読み込む
if(processFlag) // 表示処理中か
{
if(incoming < 0) // バッファにデータがないならSerial.read()は-1
{
// 出力おわり
Serial.println();
digitalWrite(13, LOW);
processFlag = false;
}
else
{
Serial.print(incoming); // バッファから読み込んだ文字を表示
}
}
else if(!(incoming < 0)) // 文字列を受信したか(=バッファにデータがあるか)
{
digitalWrite(13, HIGH);
Serial.println("Characters are coming!!");
delay(500); // 一呼吸
Serial.print(" ");
Serial.print(incoming);
processFlag = true;
}
delay(500);
}
わ「スケッチを実行して、シリアルモニターを立ち上げんす。次に、上のテキストボックスに適当な文字列(1バイト文字が良い)を入力し、隣のボタンを押すのじゃ。そうすると中央の領域に入力した文字列がポンポン表示されるのが分かろ」
動作を簡単に説明する。スケッチを実行すると、Arduinoはシリアルポートにデータが到着するのを待ち続ける。データが到着する(シリアルモニター、つまりPCからデータが送信される)と届いたデータを1バイトずつ、定期的に返送する。
観察していて気づいたのは、PCからArduinoには高速でデータが送られているはずなのに、プログラム上でreadするタイミングに制限がないことである。もしかしたら、マイコン上において、受信したデータはバッファ上に一時的に保持しておき、readしたタイミングで取り出すようにしているのかもしれない(憶測)。
ただ、いろいろ調べていて気づいたのが、単純にEchoさせるだけなら以下のコードでいいっぽいwなん……だと……
void setup() {
Serial.begin(9600);
}
void loop() {
if (Serial.available())
Serial.write(Serial.read());
}
なんだろう、この当社比80%カット感w一応ポイントを解説しておくとArduinoのシリアル通信ポートにデータが到着しているかどうかってSerial.available()関数でとれるみたいね。
ソフトウェアによるシリアル通信
先にも書いたように、Arduinoにはシリアル通信用にRX、TXという特別なピンがついている。これらのピンは、マイコン(私のながてぃ~の。の場合はATMEGA328P-PU)のRX、TXピンに直結されているらしい。つまり、マイコンはハードウェアとしてシリアル通信の機能を備えている。
が、ながてぃ~の。にはシリアル通信ポートが1対しか用意されていない。直前の記事にも書いたように、これでは2種類以上のデバイスと通信したいときに都合が悪い。
そこで考えられるのが、特別なピン以外のDigitalポートを使ってシリアル通信機能を実現する方法だ。となると、プログラムがやたら煩雑になりそうであるが、実はこの機能、Arduino標準ライブラリSoftwareSerialとして用意されていた。
#include
SoftwareSerial softSerial(2,3);
使い方はごく簡単で、始めにSoftwareSerial.hをincludeした後、SoftwareSerial softSerial(R,T);として仮想ポートを宣言するだけである。宣言するときのRはRX、TはTX相当で、上のサンプルコードだとDigital 2ピンを受信ポートとして、Digital 3ピンを送信ポートとして使う意味になる。
softSerial.begin(9600); // Serial.begin(9600);
あとは通常のシリアル通信プログラムでSerialと書いていた部分を先ほど宣言したポート名で書くだけだ。
わ「の、簡単じゃろ♪」
実際に先ほどのプログラム(80%カットしていない方)をソフトウェアシリアル通信に置き換えてみた。
動作確認をする上ではシリアルモニターを使いたかったので図のように、Digital 0ピンと2ピンを、Digital 1ピンを3ピンとそれぞれ接続した。お察しの通り、これだけじゃあんまりソフトウェアシリアル通信を使う意味がない。あくまでソフトウェアシリアル通信機能の性能確認のためである。PC側に出力している途中で1-3ジャンパピン(つまり送信データバイパス部分)を抜き差しするとシリアルモニタ側の表示が途切れる。このことから、ちゃんとソフトウェア側でシリアル通信している(3ピンから信号が出ている)ことがわかる。