今回はセンサーの話ではなく、センサーで読んだ値をどうするかという話になります。ここまでは、SDカードに記録したり(第5回)、PCやLCDに表示したり(第3・18回)することでArduinoに接続したセンサーの出力値を読んできました。しかし、例えば三軸試験装置などのように、Windows PC上に記録・制御ソフトウェアをつくり、そこにセンサーの値を読み込みたい場合があります。当然、Windows PCにSPIやI2C接続用のデジタルセンサーを直接つなぐことはできません(やろうにも、そもそもどこにつなぐ?って話です)。この場合、以下の図のように、Arduinoなどのマイコン(ボード)を介して、センサーとWindows PCをつなぐことができます。つまり、まずArduinoでデジタル値としてセンサー出力を読み込み、その数値をPCに転送します。
ここで、マイコンとPCの通信にはUART(Universal Asynchronous Receiver/Transmitter)という非同期シリアル通信を使い、USBに変換してPCに入力します。実は第3回でやったことと同じなのですが、第3回では、Arduino IDEの「シリアルモニタ」に数字が表れるだけで、ただ文字が現れるのを見るだけでした。第30回では、Windows Visual Studioを使って、Arduinoを介してデジタルセンサーの値をPCで読んだり、PCから値を入力してArduinoを介してDAC(デジタル-アナログ変換:第9回)から任意の電圧を出力する方法を紹介します。この第29回では、その前準備としてUART通信に慣れるため、Arduino同士のUART通信を説明をします。
ハードウェアシリアルとソフトウェアシリアル
Arduino UNOのデジタルピン0と1を見ると、製品によってはそれぞれRXD・TXD(RX・TXと意味は同じ)と書いてあります。これらのピンはチップ内でUART通信を行うハードウェアに接続されており、「ハードウェアシリアル」と呼ばれます。ArduinoをUSBケーブルでPCと接続したとき、実はこれで通信が行われています。一方、他のデジタルピンを、あたかもUARTハードウェアにつながっているかのようにRXやTXとしてふるまうようにさせるライブラリがArduinoには標準で存在し(SoftwareSerial)、これはソフトウェアによりUARTを可能にしているので、このようなUARTはソフトウェアシリアルといいます。Arduinoのモデルによって、RXとして割り当てられるデジタルピンに制約がある(ピン13はダメ、など)ようで、これについては他のリファレンスを見て下さい。
2台のArduino間の通信
先に述べたように、Arduinoを介してWindows PCでデジタルセンサーのデータを読むという本題に入る前に、2台のArduino間でUART通信によりデータを交換することを考えます。このことにそれほどの実用性はないのですが、この前置きには二つの意味があります。一つは、これまでI2CやSPIといったシリアル通信を使うセンサーを紹介してきましたが、UARTによりデータを交換することで機能するモジュール(後の回で紹介するLPWAのSigfox通信モジュールなど)もあるので、その模擬試験としての意味で、もう一つは、Arduino – PCの通信は途中にUSB変換が介在するため、UARTの基本がわかりづらいことです。まあ、面倒ならここは読まなくてもいいです。
ここでは、Arduino AのアナログピンA0にかかる電圧値をArduino Aで読み、UARTでArduino Bに送り、Arduino Bに接続したLCDに表示します。もちろん、LCDをArduino Aに直接接続すればArduino Bは要らないわけですが、ここは練習なので。UARTはGNDに加え、送信線TXと受信線RXを使います。ここでポイントなのが、第12回で説明したように、Arduino AのTXとRXは、Arduino BのRXとTXにそれぞれ接続することです。糸電話で、二人とも同じ糸でつながれたコップを口に当てていては、話ができませんよね。TXとRXのイメージは、以下の絵(西村紫6歳に加筆)です。
まずは、デジタルピン0と1を使った「ハードウェアシリアル版」です。以下のように接続します。
スケッチはArduino A・Bそれぞれ以下のようにします。UART通信はバイト単位でデータを送信し、受信もバイト単位となります。つまり、00~FFの256段階の値をやりとりするわけですが、これを送る・読むにはSerial.write()・Serial.read()という関数を使います。これは、例えば「3,056」mVという値を送る場合、値として”3” (0x03), “0” (0x00), “5” (0x05), “6” (0x06)を送ることになります(3056は256より大きいので、それ自体を一つの数値として送ることはできません)。一方、文字列として”3” (ASCIIコード表で51番、つまり0x33), “0” (0x30), “5” (0x35), “6” (0x36)をまとめてやりとりすることがソフトウェア上可能です。この場合、Serial.print()・Serial.readString()という関数を使います(最後に改行文字を加える場合はSerial.println()を使うことは以前にも説明済みです)。どちらのやり方がよいかは場合によるのでしょうが、文字を送りたい場合もあるので、後者のほうが汎用性があるかもしれません。ここでは文字列として通信を行います。なお、シリアルでデータを送る場合、受信バファー(64バイト)に蓄積され、そこから1バイトずつ読まれて消えていくのですが、そこに残っているバイト数はSerial.available()で読めます。つまり、while(!Serial.available())というのは「もう読み込むものがないうちは」という条件で、逆にwhile(Serial.available())というのは「まだ受信バファーに読まれていないデータが残っているうちは」という条件です。
Arduino A:
Arduino B:
次に、デジタルピン2と3を使った「ソフトウェアシリアル版」です。
スケッチはArduino A・Bそれぞれ以下のようにします。SoftwareSerialというライブラリはArduino IDEに標準でインストールされているはずです。スケッチ内で、どのピンをTX・RXとするのか指定しなくてはならないことに注意が必要です。ハードウェアシリアル版のスケッチからの変更箇所を赤で示します。
Arduino A:
Arduino B:
どちらでやっても、LCDに電圧値が表示されると思います。値だけでなく、メッセージなどを文字列として通信することももちろん可能です。