Tinkercad Circuits で Arduino 入門4～デジタル入力～

# 概要

第4回目です。[前回](https://qiita.com/code0327/items/b2922d7f325fa1b1de30)は、Arduinoのデジタル出力ポートにLEDを接続し、**プログラムによりポート出力（HIGH/LOW）を変えること**でLEDの点灯を制御を実現しました。

- [Tinkercad Circuits](https://www.tinkercad.com/) 

今回は、Arduino に **押しボタンスイッチ** を接続して、**<font color='red'>スイッチ操作により LED の点灯/消灯をコントロールする</font>**ための勉強（＝**デジタル入力機能**の勉強）をしていきます。前回と同様に、一部、基礎的な電気回路の勉強を含みます。

![2020-04-27_13h27_59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/20168f7a-db4a-14ae-8d79-79cfe0a0bb9a.png)

# デジタル入力ポート

Arduino の **デジタル【出力】ポート**は、**<font color='red'>デジタル【入力】ポートとしても利用できます</font>** 。<br>![2020-04-15_11h23_29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/f82bcc96-85cc-6b42-773c-cbbbb0616d5b.png)

デジタル**入力**ポートでは、 **ポート（ピン／端子）に印加されている電圧を HIGH または LOW の2値で読み取ることができます** 。例えは、デジタル入力ポートに $5\mathrm{V}$ が与えられているときに、プログラムでポート値を読み取ると  **HIGH**（$=1$）が得られます。一方で、$0\mathrm{V}$ のときに読み取ると **LOW**（$=0$）が得られます。

じゃあ「$3\mathrm{V}$ なら？」は、次回以降で説明します。気になる人は「`デジタル入力　閾値　Arduino`」でググってみましょう。<br>![2020-04-27_13h39_52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/a053e457-5d58-2ab8-686a-304849b527a8.png)

これを、[Tinkercad Circuits](https://www.tinkercad.com/) のシミュレーションで確かめてみましょう。

「8番ポートに $5\mathrm{V}$ を与えているとき ビルトインLED が **点灯し**、$0\mathrm{V}$ を与えているとき **消灯** する」というシステムをつくってみます。

[Tinkercad Circuits](https://www.tinkercad.com/)  にアクセス、ログインして「**新しい回路**」を作成します。まず、Arduino UNO を配置し、コードエディタを開いて、次のようにブロックプログラムを構成します（なお、初期配置されているLED点滅のブロックは「ゴミ箱」にドロップ＆ドロップして削除してください）。</br>![2020-04-20_16h38_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/bb706909-7f71-676e-50c1-90444f72b407.png)

まずは、上記のブロックの意味を読み解いてから、実際に手を動かしてみましょう。日本語環境では、**HIGH** は **高**、**LOW** は **低** と読み替えてください。

なお、まだ、この時点ではシミュレーションを開始しても意図する動作はしません（まだスイッチも配置していないので当然ですよね）。回路の接続が必要です。

## ちょっとだけ寄り道

なお、上記のブロックプログラムを **コード（Arudino言語）** で記述すると、次のようになります。既に学習済みの **C言語** に非常に似ています。**少しづつ、コードにも慣れていきましょう**。

```cpp:8番ピンにHIGHが入力されているときLEDが点灯.ino
void setup() // 電源投入後の最初の1回だけ実行
{
  pinMode(8, INPUT);   // 8番ポートを入力として使うことを設定
  pinMode(13, OUTPUT); // ビルトインLEDはボード内部で13番ピンと接続されている
}

void loop() // setup() のあとに呼び出されて、以降、繰り返して実行
{
  if (digitalRead(8) == HIGH) {
    digitalWrite(13, HIGH); // 13番ピン（ボード内部でビルトインLEDと接続）を HIGH に設定
  } else {
    digitalWrite(13, LOW);
  }
  delay(10); // Delay a little bit to improve simulation performance
}
```

C言語をしっかりと勉強した人ほど「`main()` がないじゃないか！」と混乱するかもしれません。その場合、裏側に次のようなコードが隠れていると思ってください。

```cpp:見えないところに記述されているプログラム
main() {
  setup();   // 最初に呼び出される
  while(1){  // 無限ループ
    loop();  // 無限ループのなかで loop() が繰り返し呼び出される
  }
}
```

## 寄り道、終了

ブロックプログラミングした後は、次のように <font color='red'>**常に** 8番ポートに $5\mathrm{V}$ が与えられるように**配線**してみましょう</font>。Arduinoの「$5\mathrm{V}$ 端子」は、その名のとおり「（プログラムとは無関係に）常に $5\mathrm{V}$ を出力する端子」です。<br>![2020-04-20_16h45_08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/da4c459e-8351-678c-9229-b5e19da2fab6.png)

「シミュレーションを開始」のボタンを押すか、キーボードの**[S]**キーを押してシミュレーションを実行すると、**<font color='red'>ビルトインLEDの点灯（点灯しっぱなし）</font>**が確認できると思います。確認できたらシミュレーションを停止します。

今度は、次のように配線を変えて、<font color='blue'>8番ポートに**常に** $0\mathrm{V}$（GNDレベル）を与える</font>ようにして、シミュレーションを開始してみましょう。**<font color='blue'>ビルトインLEDの消灯</font>** が確認できると思います。<br>![2020-04-20_16h52_58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/e971114e-7879-bc05-9f3e-1101d75c952a.png)

# スイッチを使ってHIGH/LOWの入力を切り替える

今度は、**押しボタンスイッチ**（プッシュスイッチやタクトスイッチとも呼ばれます）を使って「**<font color='red'>スイッチを押しているときにビルトインLEDが点灯し、スイッチを離すと消灯する</font>**」というシステムをつくっていきたいと思います。

Tinkercad の 押しボタンスイッチは、**4つ端子を持っていて**その内部回路は次のようになっています。たとえば、**端子1a** と **端子1b** は **<font color='red'>ボタンの押下に無関係に、常につながっていること</font>**に注意してください。<br>![2020-04-20_16h18_08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/9ddff742-ef55-ab25-2f40-4eb86702a548.png)

## ありがちな間違い

「スイッチを押しているときに $5\mathrm{V}$ が入力されて、指を離しているときに $0\mathrm{V}$ が入力される回路」と言われると、次のような回路が思い浮かぶと思います。<br>![2020-04-20_17h20_53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/72f2a3f2-c885-de03-c6a3-2bbe2366e693.png)

しかし、**<font color='red'>この回路は、デジタル入力回路としては「間違い」です</font>**。実際に、シミュレーションを実行して確認してもらえば分かりますが、**ボタンを押しても、押さなくともLEDは ずっと点灯のまま** です。

このように動作する原因は、**<font color='red'>スイッチを押していないときの 8番ポート入力が「$0\mathrm{V}$」ではなく「ハイインピーダンス（Hi-Z）」という状態になるため</font>**です。押しボタンスイッチの内部回路をみてください、**<font color='blue'>スイッチを押してないとき 8番ポートからの配線は途中で途切れている（＝空中につながっている）、つまり、 8番ポートには何もつながっていない状態</font>**になります。

この「$5\mathrm{V}$」でもなく「$0\mathrm{V}$」でもない **第3の状態** である「ハイインピーダンス」については、電子回路などの別科目で習うのでそれまで待つか、どうしても気になる人は「`ハイインピーダンス　マイコン`」や「`ハイインピーダンス　デジタル回路`」などでググってください。とりあえず、いまは**<font color='red'>「端子に何も接続しないこと（端子からの配線が途中で途切れている）」と「端子に0Vを入力すること」は同じではない</font>**ということが分かればOKです。

## 正しいデジタル入力回路のつくりかた

では、どのように押しボタンスイッチによる回路を構成すればよいかというと、次のように構成します。まずは、実際に回路を再構成してシミュレーションを実行してみてください。ボタン押したときLEDが点灯して離すと消灯することが確認できると思います。回路例は[こちら](https://www.tinkercad.com/things/0iUarfUa9zx)。<br>![2020-04-20_17h42_48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/cf633f96-4484-a444-6698-5d319e7be2a4.png)

なぜ、上記の回路で解決するのでしょうか？ボタンを押しているときと、指を離しているときの等価回路は次のようになります。「ボタンを押している状態のスイッチは $0\,\Omega$ の抵抗」、「指を離している状態のスイッチは $\infty\, \Omega$ の抵抗」に置き換えることができます（回路中の **D8** は デジタル8番ポート の意味です）。<br>![2020-04-20_19h35_31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/bb38c66d-7a73-1cc4-24cb-89258421b03c.png)

デジタル8番ポートに入力される電圧 $V_{\mathrm{in}}$ は、中学で学習したように次の抵抗分圧の計算式で求めることができます。

$$ V_{\mathrm{in}} = \frac{R2}{R1+R2}\cdot V$$

ボタンを**<font color='red'>押しているとき</font>**（$R1=0\,\Omega$ のとき）の 8番ポート入力 $V_{\mathrm{in}}$は、次のように $5\mathrm{V}$ (＝**<font color='red'>HIGH</font>**) になります。

$$ V_{\mathrm{in}} = \frac{R2}{R1+R2}\cdot V = \frac{2k}{0 + 2k}\cdot 5 \fallingdotseq  5 \, [\mathrm{V}]$$

一方で、ボタンから**<font color='blue'>指を離しているとき**</font>（$R1=\infty\,\Omega$ のとき）のポート入力 $V_{\mathrm{in}}$は、次のように $0\mathrm{V}$ (＝**<font color='blue'>LOW</font>**) になります。**<font color='red'>このとき、8番ポートは、抵抗 $R2$ を経由して GND に接続している状態です（どこにもつながっていないわけではない）**</font>。

$$ V_{\mathrm{in}} = \frac{R2}{R1+R2}\cdot V = \frac{2k}{\infty + 2k}\cdot 5 \fallingdotseq 0[\mathrm{V}]$$

ところで、抵抗 $R2$ を、その用途から **プルダウン抵抗** とよびます。この抵抗値が小さすぎるとボタンを押したときに電源からGNDに向かって大電流が流れてしまいます。また、抵抗値が大きすぎるとハイインピーダンスと同じになってしまう、ということで $1$ ～ $10\,\mathrm{k}\Omega$ 程度に設定します。

# 演習7：ブロックとコードの対応確認

コードエディタのモードを「**ブロック + テキスト**」に変更し、ブロックで構成したプログラムと、プログラムコード（テキスト）で記述したプログラムがどのように対応しているのか確認してみましょう。<br>![2020-04-20_19h21_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/d8f81d11-ac1a-9373-02ad-9d9ce522cb50.png)

# 演習8：ボタンを押しているときだけLEDが消灯

ボタンを**押しているときだけLEDが【消灯】する**ようにしてみましょう（ここまでとは逆の動作す。回路は変更せずにプログラム変更だけで対応可能です）。ただし、現在の回路／プログラミングを修正するのではなく、**練習のためにもう一度、ゼロから新規作成してみましょう**（解説を読んですっかり理解したように思っても、ゼロから作成しようと思うと案外できないものです）。

# 演習9：チルトセンサーと圧電ブザーによる転倒検出装置

Tinkercad Circuits では **<font color='red'>傾きや振動</font>** を検出できる「SW-200D」というセンサーが用意されています。コンポーネントパネルでは「**チルトセンサー**」として表示されています。このセンサーは、実際に販売されているもので「`Tilt Switch sw200d`」などをキーワードに検索すると詳細（原理）を見ることができます。<br>

![2020-04-27_15h21_44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/d469cdd3-56d6-6a87-a074-dc7359f012dd.png)

このセンサは、傾きを検出するもので、垂直にしていると**非導通**、ある程度の傾きを与えると**導通**するスイッチになります。シミュレーションの**実行中**に、チルトセンサーをクリックするとスライドバーが表示されるので、それを操作して傾きを与えることができます（動作を理解するために、実際に以下の回路をつくってみることをお勧めします。抵抗は $330\Omega$ です）。<br>![2020-04-27_15h52_31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/f4dcc287-b627-504d-182c-2f9841b6f8c0.png)


また、Tinkercad Circuits には **圧電ブザー** が用意されており、Arduino を使って **<font color='red'>音を鳴らすことができます</font>**。音を再生するためには「**ピンX、トーンXXでスピーカーを XX 秒再生**」というブロックを使用します（<font color='red'>**圧電ブザーは、単に電池と接続して電圧を与えても音は鳴りません</font>**）。

圧電ブザーを Arduino のデジタル出力ピンと、GNDに接続して（一応、極性があります）、次のようにブロックを組んでシミュレーションを実行すると「**1秒間音がなって、1秒間音が止まる**」という動作を繰り返します。回路のサンプルは[こちら](https://www.tinkercad.com/things/2MnICQjSJ1U)。
<br>![2020-04-27_16h29_44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/3cba220a-eb35-bf15-be17-739d91bf12bb.png)

ここで注意すべきは「音再生ブロック」ではプログラムが終了待機しない点です。つまり、**音の再生が終わってから次のブロックに進むわけではなく、音の再生をはじめた瞬間に次のブロックに進みます。**よって、上記のサンプルのように「**<font color='red'>2秒</font>を待機**」にしないと「**1秒間音がなって、1秒間音が止まる**」という動作になりません。

以上の **傾きセンサー** と **圧電ブザー** を組み合わせて、転倒検出装置（転倒しているとき（傾いているとき）音が鳴って知らせるような回路）を構成してみましょう。


- 解答例は[こちら](https://www.tinkercad.com/things/dKzmo9dlfVU)（TinkerCadに飛びます）

# EX演習1：

ここまでは、**ボタンを押しつづけているとき**に点灯させるという動作でした。言い換えれば、この回路は、LED点灯させつづけるためには**ずっとボタンを押し続ける必要があります**。

これを**ボタンを押すたびに点灯／消灯が切り替わる**ようにするためにはどうしたらよいでしょうか？

仮にスライドスイッチを使えば比較的簡単にできます。<br>![2020-04-27_15h08_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/5ea6576c-3425-51a3-1bb4-4c642b6345e4.png)

一方で、**押しボタンスイッチ**を使って実現しようとすると、プログラムでうまく対応する必要があります（現在までに紹介していないブロックも必要とします）。

どのようにすれば、目的の動作ができるか試行錯誤してみましょう。

<!-- - 解答例は、[こちら](https://www.tinkercad.com/things/aFTLKANaL5u)（TinkerCadに飛びます）。
  - チャタリングが発生しないことを仮定しています。 -->