はじめに
ここでは、Arduino UNOでシリアル通信とデジタル出力を組み合わせた実験をします。
目次へ戻るには ここ をクリック
※本ページは実験のテキストです。
デジタル出力とシリアル通信
Lチカ(デジタル出力)の解説 では、デジタル出力の機能を説明しました。
Arduinoの特定のピンを5VにしたりGNDにしたりすることで、LEDを点灯/消灯できました。
シリアル通信をしてみよう(Serial) では、パソコンとマイコンとの間をシリアル通信でデータ送受信しました。
今回は、両者を組み合わせてみます。
シリアル通信でキーを入力し、キーに応じてLEDを点灯/消灯する、というプログラムを作成します。
具体的には、
- シリアル通信で
q
を送信したらLEDを点灯 - シリアル通信で
a
を送信したらLEDを消灯
の様に動作させます。
具体的には、以下のようなイメージです。
スケッチを書き込む
それでは、プログラミングしてみます。
メニューバーから[ファイル]-[新規ファイル]をクリックし、新しいプログラムを書く準備をしてください。
以下のプログラムを打ち込み、コンパイル/実行してみましょう。
ファイル名は Serial_led.ino
としました。
void setup() {
// LED_BUILTINのデジタルピンを出力モードに設定
pinMode(LED_BUILTIN, OUTPUT);
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文字送信。受信データをそのまま送り返す。
// keyの文字に応じて、行う処理を切り替える
switch( key ) {
// qキーが押された時の処理
case 'q':
digitalWrite(LED_BUILTIN, HIGH); // LED点灯(HIGHは電圧を5Vにする)
break;
// aキーが押された時の処理
case 'a':
digitalWrite(LED_BUILTIN, LOW); // LED消灯(LOWは電圧を0Vにする)
break;
// 上記以外の場合の処理(何もしない)
default:
break;
} //switch文の末尾
} // if文の末尾
} // loop関数の末尾
動作テスト
Arduinoに書き込み終わったら、シリアルモニタを開いて文字を送信し、動作を確認しましょう。
きちんと図のように動いていますか?
このプログラムで 「パソコンからの指令でArduinoマイコンを操作した」 ことになります。
この手法を応用すれば、
・キーボード入力でモータを回す/停止させる
・複数のモータを1つのキーで同時に操作する
・キーボードをゲームコントローラの十字キーの様に使うことで、前後移動や旋回をさせる
といった使い方もできるので、ロボットの遠隔操作なども可能になります。
プログラム解説
以降は,スケッチの内容を解説していきます。
setup関数
電源投入またはリセット後に一度だけ実行されるのがsetup関数でした。
いわゆる「初期化」の作業です。
void setup() {
// LED_BUILTINのデジタルピンを出力モードに設定
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin( 9600 ); // シリアル通信を初期化する。通信速度は9600bps
Serial.println( "Hello Arduino!" ); // 最初に1回だけメッセージを表示する
}
setup関数では、大別して2つの作業をしています。
- デジタル出力の初期化:
pinMode()
- シリアル通信の初期化:
Serial.begin()
両者を連携させるので、それぞれきちんと初期化しておく必要がありますね。
Serial.print
で "Hello Arduino!" を出力しているのは、
プログラムがきちんと動作していることを確認するためのメッセージです。
パソコンも、電源投入直後にはメーカーのロゴマークなどが表示されますが、
あれと同様に「ちゃんと動いてるよ~」というアピールです。
loop関数
何度も繰り返して呼び出されるのがloop関数です。
void loop() {
char key; // 受信データを格納するchar型の変数
// 受信データがあった時だけ、処理を行う
if ( Serial.available() ) { // 受信データがあるか?
key = Serial.read(); // 1文字だけ読み込む
Serial.write( key ); // 1文字送信。受信データをそのまま送り返す。
loop関数の冒頭では、シリアル通信をしてみよう(Serial) と同じ記述をしています。
- パソコンからデータが来たかどうかを、
Serial.available
関数でチェック - データがあったら、
Serial.read
関数で取り出す - パソコン側に何も表示されないのは寂しいので、
Serial.write
関数で送り返す
ブロッキング関数であるSerial.read
をいきなり呼び出すのではなく、
まずはSerial.available
で様子見/偵察するのが重要な作法です。
// keyの文字に応じて、行う処理を切り替える
switch( key ) {
// qキーが押された時の処理
case 'q':
digitalWrite(LED_BUILTIN, HIGH); // LED点灯(HIGHは電圧を5Vにする)
break;
// aキーが押された時の処理
case 'a':
digitalWrite(LED_BUILTIN, LOW); // LED消灯(LOWは電圧を0Vにする)
break;
// 上記以外の場合の処理(何もしない)
default:
break;
} //switch文の末尾
} // if文の末尾
} // loop関数の末尾
次は、switch
文でkey
の中身に応じて処理を選択しています。
'q'
のときには、digitalWrite
関数でHIGHを出力することで、LEDが点灯します。
'a'
のときには、digitalWrite
関数でLOWを出力することで、LEDが消灯します。
'q'
と'a'
以外が入っているときは、default:
に流れていきますが、特に何もすることなく無反応になります。
switch文は、defaultをきちんと書くのがマナーです。
「デフォルトの処理」、すなわち特別なケースに当てはまらなかった「失敗時の処理」という意味が本質です。
しかし日本では、特別ではない時=通常時 という意味合いで浸透したのが、ネットスラングの「デフォ」です。
switch文的には「デフォルトで何をさせる?」「デフォで何をする?」という使い方だったのが、
「~するのがデフォ」のような「定番」という意味にまで派生しています。
key変数と比較したいキーボードの文字は,'q'
'a'
の様にシングルクォーテーション'
で囲みます。
q
a
と何も付けずに書くと、コンパイラは変数q・変数aがいると勘違いしてしまいます。
'q'
と書けば「ああ、ASCIIコードでのq、すなわち16進数の0x71ね」と解釈してくれます。
参考:ASCIIコード表
つまり、
if( key == 'q' )
こう書くことは、
if( key == 0x71 )
これと同じ意味になります。
'a'
に関しても同様に,実際の値は16進数で0x61です。
まとめ
-
key
にはキーボードの文字が入っている -
switch( key )
と書けば、文字に応じて違う処理をさせることができる
おわりに
これでシリアル通信によってLEDを操作することができました。
次はブレッドボードの使い方を解説します。
目次 へ戻って次の作業を行ってください。