シリアル通信でデジタル出力

# はじめに

ここでは、Arduino UNOでシリアル通信とデジタル出力を組み合わせた実験をします。

目次へ戻るには [ここ](https://qiita.com/hsgucci/items/085680123f758c8c3eb4#%E5%AE%9F%E9%A8%93%E6%89%8B%E9%A0%86) をクリック

※本ページは実験のテキストです。

# デジタル出力とシリアル通信

[Lチカ(デジタル出力)の解説](https://qiita.com/hsgucci/items/8ae1fc4bb542893d130b) では、デジタル出力の機能を説明しました。
Arduinoの特定のピンを5VにしたりGNDにしたりすることで、LEDを点灯/消灯できました。

[シリアル通信をしてみよう（Serial）](https://qiita.com/hsgucci/items/eee5894e3651d0a8cb75) では、パソコンとマイコンとの間をシリアル通信でデータ送受信しました。

今回は、両者を組み合わせてみます。
シリアル通信でキーを入力し、キーに応じてLEDを点灯/消灯する、というプログラムを作成します。

具体的には、

- シリアル通信で `q` を送信したらLEDを点灯
- シリアル通信で `a` を送信したらLEDを消灯

の様に動作させます。
具体的には、以下のようなイメージです。
![serial_led.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256470/3f53d21b-b356-40dd-36a6-91de900bc523.png)


# スケッチを書き込む

それでは、プログラミングしてみます。
メニューバーから[ファイル]-[新規ファイル]をクリックし、新しいプログラムを書く準備をしてください。

以下のプログラムを打ち込み、コンパイル/実行してみましょう。
ファイル名は `Serial_led.ino` としました。

```cpp: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に書き込み終わったら、シリアルモニタを開いて文字を送信し、動作を確認しましょう。
![serial_led.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256470/3f53d21b-b356-40dd-36a6-91de900bc523.png)

きちんと図のように動いていますか？

このプログラムで **<font color=blue>「パソコンからの指令でArduinoマイコンを操作した」</font>** ことになります。
この手法を応用すれば、

・キーボード入力でモータを回す/停止させる
・複数のモータを１つのキーで同時に操作する
・キーボードをゲームコントローラの十字キーの様に使うことで、前後移動や旋回をさせる

といった使い方もできるので、ロボットの遠隔操作なども可能になります。

# プログラム解説
以降は，スケッチの内容を解説していきます。

## setup関数
電源投入またはリセット後に一度だけ実行されるのがsetup関数でした。
いわゆる「初期化」の作業です。

```cpp:setup関数
void setup() {
  // LED_BUILTINのデジタルピンを出力モードに設定
  pinMode(LED_BUILTIN, OUTPUT);

  Serial.begin( 9600 );     // シリアル通信を初期化する。通信速度は9600bps

  Serial.println( "Hello Arduino!" );   // 最初に1回だけメッセージを表示する
}
```

setup関数では、大別して２つの作業をしています。

- デジタル出力の初期化：`pinMode()`
- シリアル通信の初期化：`Serial.begin()`

両者を連携させるので、それぞれきちんと初期化しておく必要がありますね。

`Serial.print`で "Hello Arduino!" を出力しているのは、
プログラムがきちんと動作していることを確認するためのメッセージです。

パソコンも、電源投入直後にはメーカーのロゴマークなどが表示されますが、
あれと同様に「ちゃんと動いてるよ～」というアピールです。

## loop関数

何度も繰り返して呼び出されるのがloop関数です。

```cpp:loop関数(1)
void loop() {
  char key;     // 受信データを格納するchar型の変数

  // 受信データがあった時だけ、処理を行う
  if ( Serial.available() ) {       // 受信データがあるか？
    key = Serial.read();            // 1文字だけ読み込む
    Serial.write( key );            // 1文字送信。受信データをそのまま送り返す。
```
loop関数の冒頭では、[シリアル通信をしてみよう（Serial）](https://qiita.com/hsgucci/items/eee5894e3651d0a8cb75) と同じ記述をしています。

- パソコンからデータが来たかどうかを、`Serial.available`関数でチェック
- データがあったら、`Serial.read`関数で取り出す
- パソコン側に何も表示されないのは寂しいので、`Serial.write`関数で送り返す

ブロッキング関数である`Serial.read`をいきなり呼び出すのではなく、
まずは`Serial.available`で様子見/偵察するのが重要な作法です。


```cpp:loop関数(2)
    // 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文的には「デフォルトで何をさせる？」「デフォで何をする？」という使い方だったのが、
「～するのがデフォ」のような「定番」という意味にまで派生しています。

　参考：[「デフォ」は若者言葉？死語？](https://eigobu.jp/magazine/defo)

key変数と比較したいキーボードの文字は，`'q'` `'a'`の様にシングルクォーテーション`'`で囲みます。
`q` `a`と何も付けずに書くと、コンパイラは変数q・変数aがいると勘違いしてしまいます。
`'q'`と書けば「ああ、ASCIIコードでのq、すなわち16進数の0x71ね」と解釈してくれます。

　参考：[ASCIIコード表](http://e-words.jp/p/r-ascii.html)

つまり、

```
if( key == 'q' )
```
こう書くことは、

```
if( key == 0x71 )
```
これと同じ意味になります。
`'a'`に関しても同様に，実際の値は16進数で0x61です。



# まとめ

- `key` にはキーボードの文字が入っている
- `switch( key )` と書けば、文字に応じて違う処理をさせることができる

# おわりに
これでシリアル通信によってLEDを操作することができました。


次はブレッドボードの使い方を解説します。

[目次](https://qiita.com/hsgucci/items/085680123f758c8c3eb4#%E5%AE%9F%E9%A8%93%E6%89%8B%E9%A0%86) へ戻って次の作業を行ってください。