workshop/of/arduino

ArduinoとPCでシリアル送受信

ArduinoとPCやその他デバイスの通信(データのやり取り)を行うには,シリアル通信を 利用します.このページではOpenframeworksとArduinoの通信に関して基礎を学習します. 例えば,ArduinoのA0値をPC側で監視する事例を通じて,解説していきます.

Firmataを 利用することで,これから解説するようなやり方を学習せずともPCとの通信はできるように なりますが,機種依存や時間制御困難といった初心者では解決が難しい問題に直面することが多くあります. Firmataはシリアル通信の基礎を身につけた上で,高速なプロトタイピングを行う上での一つの ツールとして考えてください.最終的な商品開発や基盤最小化において,このようなツールは結果として邪魔になります.
では,下記から本題に入ります.

1バイトのデータ形式は楽ちん

シリアル通信とは1Byte単位でのデータ送信/受信プロトコル(規格)です.通信速度や誤り検出(パリティチェック), Start Bit, Stop Bit等 こまかな設定項目が用意されていますが,一般的にArduinoの初期設定は 通信速度:9600 bit/s,誤り検出無し,stop bitとなっています.まずみなさんが頻繁に設定変更する ものは通信速度だけですので,他は気にしなくてよいです.

Arduino UNO等では,analogRead()によって取得できる値は0-1023(10bit)の範囲と なります.ではこれをコンピュータ側へ送信するためにはどうすればよいでしょうか? もっとも簡単で基本的なやり方は,値を1バイト形式(フォーマット)にして送受信することです. つまり,0-1023を0-255に変更し,Arduino側で1バイトずつ送信することで,PC側は0-255の範囲で A0の値を取得することができます.具体的には下記のようなコードだけで済みます.

// Arduinoで送信
int a = analogRead(0);
a = map(a, 0, 1023, 0, 255);
Serial.write(a);

// Openframeworksで受信
int a = serial.read();
cout << a << endl;

0-1023のデータを送るには

上記やり方で簡単にデータを取得できるようになりましたが,例えば元々の0-1023の範囲でデータを取得 するにはどうすればよいでしょうか?個人的には0-255で問題がなければ極力一つのデータは1バイトで扱う 方がよいですが,学習のために実践してみましょう.

シリアル通信は1Byte単位での送信となるので,0-1023の範囲の値は10bitの為,1Byteではデータ範囲が不足 します.なので,2Byte(16Bit)利用すれば1023までのデータ範囲を送信することが可能になります. 同じプログラム内であれば,Int型をコピーすれば良いだけですが,シリアル通信では少し面倒になります. ここで2進数による考えが重要になります.

  • 1023 : 00000011 11111111
  • 1023は2進数では上記のようになります.つまり2Byteを利用してデータを送信する場合は先にどちらか一方 のデータを送信し,次のもう一方のデータを送信します.受信した側は,2Byte受け取った後にそのバイトを つなげることで実際のデータを読み取ることができます.一般的には1023を送る場合,下位バイト(11111111)を 先に送信し,続いて上位バイト(00000011)を送信します.次に受け取る側では例えばa = 0b11111111, b = 0x00000011 を受信したとします.これを上位バイトと下位バイトをあわせるにはどうすればよいでしょうか?aは下位バイトに あたるので,bの下にaをつなげれば良いことになります.しかし int c = b + a;としても,4+255となってしまうだけです. この上位バイトと下位バイトの”足しあわせ”の計算にはビットシフトと言われる計算を行います.つまり 次のように計算ができます

      int b = 0b00000011;
      int a = 0b11111111;
      b = b << 8;
      int c = b + a;
      printf("%d\n", c);
    

    b << 8とは,値bを左方向に8ビットシフトすることを意味しています.つまり,intが2Byteで構成される型である とすれば,b = 0b0000000000000011であったものが,8ビット左にシフトすることで b = 0b0000001100000000となります.これにより a = 0b0000000011111111を足すことで, 0b0000001111111111を取得できます. といわけで,こんなかんじで一手間かかるので,精度や解像度が必要な場合を除き,基本的にはデータは0-255で構成されていること が望ましいわけです.

    2Byteを正しく受け取る

    0-1023のデータは上記の方法で送受信ができるようになりました.一方でシリアル通信とは非常に簡素な プロトコルであり,例えば取得したデータが上位バイト or 下位バイト といった情報自体は受け手からは 2Byteだけの情報では判別が不能です.これを実現するには様々なやり方がありますが,もっともシンプル なスタートバイトを利用するやり方を紹介します.つまり,下位バイト→上位バイトの順にデータを送信する のですが,上位バイト送信前にスタートバイトを送信するわけです.スタートバイトには0-255の範囲でなんでも 構いません.では例えばスタートバイトを255に決めてみましょう.するとどうでしょう. スタートバイト(255)と下位バイト(0-255)の両方で255が出現する為スタートバイトの 区別がつかなくなってしまいます.この問題を回避するには上位バイトに下位バイト1ビットシフトする等の やり方が考えられますが,ここまでの処理は行わなくとも,データ長を基準にすることでほぼ問題 なくデータは取得可能です.

    Serial.print, Serial.printlnはデバッグの為に利用します


    Copyright (c) 2015 Tetsuaki BABA all rights reserved.