はじめに
ここでは、Arduino UNOで シリアル通信 の実験をしてみます。
目次へ戻るには ここ をクリック
※本ページは実験のテキストです。
シリアル通信とは
シリアル(serial)とは「連続した」という意味があります。
連続殺人犯は「serial killer」と言います。
下図のように、1本だけの通信線を使い、HIGH/LOWの電圧レベルを連続的(=シリアル)に変化させて、
意味のあるデータを送信/受信する通信方式がシリアル通信です。
昔は、複数本の通信線を使えるので1本よりも多くのデータが送れることから
「シリアル通信よりもパラレル通信の方が高速」と言われていました。
しかし、あまりに高速な通信になりすぎると、パラレルの通信線は互いにアンテナになり、
高周波数の電磁波を送受信し、データにゴミが乗ってしまいます。これがクロストーク(混信)です。
一方、シリアル通信は単線なので、影響はありません。
したがって現在では「パラレル通信には限界があったので、シリアル通信の方が高速」と言われています。
USB(ユニバーサル シリアル バス)、シリアルATAなど、様々な規格はシリアル通信を行っています。
RS-232C
Arduinoで利用するシリアル通信は、「RS-232C」と呼ばれる規格です。
正式名称はEIA-232Dですが、誰もこの呼び名は使っていません。
図のように、古いパソコンにはRS-232Cポートが標準装備されていたのですが、
最近は、使われることもなくなって失われてしまいました。
なので「レガシーシリアル」(時代遅れの/遺産的なシリアル規格)などと呼ばれています。
しかし、一般人には使われなくなりましたが、マイコン開発には現役です。
USBシリアル変換
物理的なRS-232Cポートは失われましたが、今はUSBで置き換えられています。
USBそのものの通信規格は、デバイスディスクリプタだとかエンドポイントだとか複雑なため、
今までRS-232C規格を使っていたマイコン技術者がUSB規格に乗り換えるのは至難の業でした。
そこで、USBポートに接続して今までのRS-232Cと同じ通信規格の使えるICが登場しました。
代表的な製品は以下の2社です。
・FTDI社 FT232シリーズ
https://www.ftdichip.com/FTProducts.htm
・Sillicon Labs社 CP210xシリーズ
https://www.silabs.com/products/interface/usb-bridges
具体的には、以下のURLにあるような製品がマイコン開発・電子工作に使われています。
http://akizukidenshi.com/catalog/c/cusb232/
見かけ上はUSB接続ですが、中身は実はRS-232Cという製品も多くあります。
Arduinoも同様です。
昔あった「Arduino Duemilanove」という製品では、FTDIのICが使われていました。
Arduino UNOでは、USBポートのすぐ近くにあるATmega16U2マイコンがUSBシリアル変換をしています。
USBシリアル変換のおかげで、RS-232Cとして簡単に通信が行えるのです。
通信プログラム
それでは、シリアル通信を試してみます。
メニューバーから[ファイル]-[新規ファイル]をクリックし、新しいプログラムを書く準備をしてください。
以下のプログラムを打ち込み、コンパイル/実行してみましょう。
void setup() {
Serial.begin( 9600 ); // シリアル通信を初期化する。通信速度は9600bps
Serial.println( "Hello Arduino!" ); // 最初に1回だけメッセージを表示する
}
void loop() {
char key; // 受信データを格納するchar型の変数
// 受信データがあった時だけ、処理を行う
if ( Serial.available() ) { // 受信データがあるか?
key = Serial.read(); // 1文字だけ読み込む
Serial.write( key ); // 1文字送信。受信データをそのまま送り返す。
}
}
プログラムを実行しても、LEDが光るなどの効果はありません。
動作を確認するためには、シリアルモニタを使う必要があります。
シリアルモニタの使い方
シリアルモニタは、図のボタンをクリックすることで起動します。
シリアルモニタが起動すると、図のように Hello Arduino! と表示されるはずです。
次に、上部にある小さいテキストボックスに a と打ち込んでから、右の[送信]ボタンをクリックしましょう。
すると、Hello Arduino!という文字の下に、a という文字が表示されます。
先ほど入力したa は消えました。
同様に、様々な文字を送信して試してみてください。
一度にたくさんの文字を送信することも可能です。
つまり、 Arduinoマイコンに文字を送ると、送った文字が返ってきている のです。
プログラム解説
次は、プログラムを読んでいきましょう。
まずはsetup
関数です。
void setup() {
Serial.begin( 9600 ); // Arduionoとシリアルモニタの通信速度はどちらも9600bpsにする必要がある
Serial.println( "Hello Arduino!" ); // C言語のprintfのように、メッセージを出したいときに使う。
}
Serial.begin
関数で、シリアル通信を使う準備をします。
引数にある 9600 というのは、9600bps(bit per second)です。
つまり、1秒間に9600ビット分のデータを送れる通信速度に設定する、という意味です。
マイコンでよく使われる通信速度は、
・9600bps
・57600bps
・115200bps
です。数字が大きくなるほど、
多くのデータを送れるスピードだということです。
注意すべき点は、
パソコン側とマイコン側の通信速度は必ず同じにしなければならない
です。
図のように、シリアルモニタの通信速度と、プログラムで書いたマイコンの速度とを同じにしないと、
データが正常に伝送されず、文字化けしてしまいます。
Serial.println
関数は、シリアルモニタ上にメッセージを表示する関数です。
Arduinoなどのマイコンにはディスプレイが搭載されていないので、
C言語で最初に学ぶメッセージ表示関数printf
は使えません。
その代わりとして、シリアルモニタ上にprintするのです。
Serial.print
の後ろにln
が付いているのは、「改行コード(CR)を自動追加する」を意味しています。
printf
関数で例えれば、"\n"を自分で書く代わりに、勝手に関数が追加してくれる、ということです。
printf("hogehoge"); // Serial.printだと改行されない
printf("hogehogen\n") // Serial.printlnだと暗黙に\nが付加されて改行される
Serial.print
とSerial.println
は非常によく使われます。
メッセージを表示するだけでなく、変数の中身を表示することもできます。
次はloop
関数を見ていきましょう。
void loop() {
char key; // 受信データを格納するchar型の変数
// 受信データがあった時だけ、処理を行う
if ( Serial.available() ) { // 受信データがあるか?
key = Serial.read(); // 1文字だけ読み込む
Serial.write( key ); // 1文字送信。受信データをそのまま送り返す。
}
}
まず注目すべきはSerial.read
とSerial.write
の関数です。
Serial.read
とSerial.write
は、受信と送信の対の関係になります。
シリアルからreadしたデータをkeyに格納し、keyをwriteしているので、
「受信データをそのまま送信する」という作業をしています。
ポイントは、if ( Serial.available() ) { }
です。
シリアルモニタから何かデータが送られてきた時だけ、if文の中を実行するように書いています。
これは ブロッキング関数をみだりに使わない という狙いがあります。
ブロッキング関数
ブロッキング関数とは、
「その関数を実行すると、処理が完了するまではプログラムがそこで停止する」
という関数です。
例えば、以下のように書くとわかりやすいです。
void loop1() {
char key; // 受信データを格納するchar型の変数
// 受信データがあった時だけ、処理を行う
if ( Serial.available() ) { // 受信データがあるか?
key = Serial.read(); // データが無いときは呼ばれない
Serial.write( key );
}
// LED点滅
digitalWrite(13, HIGH);
delay(50);
digitalWrite(13, LOW);
delay(50);
}
void loop2() {
char key; // 受信データを格納するchar型の変数
key = Serial.read(); // データが来るまで待ち続ける
Serial.write( key ); // データが1個も来ないと,ここから下へは行かない
// LED点滅
digitalWrite(13, HIGH);
delay(50);
digitalWrite(13, LOW);
delay(50);
}
loop1
では,受信データがあったときだけif文の中が読み込まれるので,
LEDは50ミリ秒で点滅を繰り返します.
Serial.read()がブロッキング関数です.
loop2
では,Serial.read()
が1文字受け取るまで,ずっと待ち続けます.
したがって,その下のdigitalWrite
の方へはプログラムが流れません.
LEDはずっと消えたままになります.
プログラムのメインストリーム(主流)にブロッキング関数を書いてしまうと,
プログラム全体が停止してしまうので気をつけましょう.
if文の様なサブストリーム(支流)に書くべきなのです.
まとめ
Serial.begin()
で初期化と速度設定をする
Serial.available()
で受信データがあるかどうかチェックする
Serial.read()
で実際にデータを受信する
Serial.write()
でデータを送信する
Serial.read()
はブロッキング関数なので,if文の中に書くようにする.
おわりに
これでシリアル通信の動作確認ができました。
次はシリアル通信を使ってデジタル出力を制御してみます。
目次 へ戻って次の作業を行ってください。