Arduinoでスイッチのオン・オフを読み取る

Arduino

今回は、Arduino のデジタル入力端子を使用して、スイッチのオン/オフを読み取る実験を行います。

Arduino のデジタル入力

概要

Arduino には D0 ~ D13 という 14個のデジタル入力に使える端子があります。デジタル入力とは、端子にかかっている電圧を『 HIGH 』または『 LOW 』の2段階で判別することができる端子のことです。

単一電源( 5 V )で回路を作成した場合、入力端子にかかる電圧は 0 V ~電源電圧の 5 V までのいずれかの値をとることが考えられます。0 V なら LOW、5 V なら HIGH なのは当然として、その間の値をとる場合はどうなるでしょうか?単純に考えて、中間の 2.5 V を境界値として、それ以上なら『 HIGH 』、それ未満なら『 LOW 』とすればよさそうに思えます。この判断の境目となる電圧のことを『スレッショルド(Threshold、しきい値)』といいます。

※表記揺れが多く、『スレスホルド』『スレシホールド』などと表記する人もいます。こちらで発音が聞けます

ただ、『スレッショルドが 2.5 V 』というのにも少々問題があります。たとえば入力電圧が 2.45 ~ 2.55 V で細かく上下するような場合(ノイズなどによって細かく電圧が上下してしまうことはよくあります)、HIGH と LOW が頻繁に切り替わることになり、動作が安定しなくなる危険があります。

そこで、
『LOW の状態から電圧が上がってきた場合は、2.6 V より上がったところで HIGH に切り替わる』
『HIGH の状態から電圧が下がってきた場合は、2.4 V より下がったところで LOW に切り替わる』
という風にすれば、2.45 ~ 2.55 V で細かく電圧が上下する入力があっても HIGH/LOW がバタバタと切り替わることが少なくなります。

このように『その瞬間の電圧』だけで判断するのではなく『直前の状態から電圧が上がった/下がった』ことも含めて HIGH/LOW を判断するような性質を『ヒステリシス(Hysteresis)特性』といい、このような特性を持ったデジタル入力を『シュミットトリガ(Schmitt trigger)』といいます。

Arduino のデジタル入力端子はヒステリシス特性を持っており、旧来のデジタル回路より安定した動作が期待できます。

※具体的な特性についてはメーカーが公開しているデータシート(参考)を参照して下さい。当面、具体的な上昇時/下降時の電圧閾値を憶えておく必要はありません。

具体的な使用法

二極スイッチを使う

今回は、スイッチによってデジタル入力端子の電位を HIGH/LOW で判断することを試してみます。一番単純に考えると、スイッチによって端子の電位が 5 V または 0 V となるように切り替えればよいので、

このような回路を作ればよさそうです。スイッチによって input 端子が 5 V と GND のどちらに接続されるかを切り替えています。

※Arduino の出力端子を5VまたはGNDに直結するのは過大な電流が流れて素子を破損する危険があるため厳禁ですが、入力端子はハイインピーダンス(MΩ単位)で、 5 V や GND に直結しても微量の電流しか流れず、Arduino を破損することはありません。

実際、この回路でもちゃんと動作はするのですが、実はこれでは問題があります。

このように『2つの接点のどちらに接続するかを切り替える』タイプのスイッチのことを『双投スイッチ』といいます。手で操作するタイプの『スライドスイッチ』や『トグルスイッチ』には双投のものはいくらでもあるのですが、手で切り替えないタイプのスイッチには、
『光があたったらオン』
『磁石が近づいたらオン』
『水に濡れたらオン』
など、単純に『オン=つながっている/オフ=つながっていない』だけを切り替えるものも数多くあるのです。

というわけで『オン/オフ』だけスイッチ(『単投スイッチ』といいいます)を使って『HIGH/LOW』を判別させる方法を考えてみましょう。

※なぜ『単投』『双投』など『投げる』という字が使われているのか不思議ですが、英語で『スイッチを入れる』ことを『throw』ということから来ているのだそうです

スイッチ・オンでHIGH

まず、このような回路を考えてみます。こうすると、

スイッチがオンのとき input 端子は 5 V に接続されるので電位は 5 V → HIGH
スイッチがオフのとき input 端子はどこにも接続されないので電位は 0 V → LOW

となりそうな気がしてしまいますが、これでは上手く行きません。『どこにも接続されていない入力端子』は電位が不定で、0 V にはならないのです。

そこで、スイッチがオフのとき確実に 0 V となるように、input 端子を抵抗器を通じて GND に接続します。

スイッチがオフのとき、input 端子は抵抗器を経由して GND に接続します。input 端子はハイインピーダンスで GND に接続しても電流はほとんど流れません。電流がごく小さければ抵抗器の端子間電位差(電圧降下)も 0 V と見なせるので、input 端子の電位は GND と同じ 0 V となります。

スイッチがオンのとき、input 端子は 5 V と直結されるため、input 端子の電位は 5 V となります。

これで、確実に『スイッチがオンなら HIGH、スイッチがオフなら LOW』とすることができます。

このように、スイッチがオフのときに input 端子の電位を不定ではなく 0 V にすることを『プルダウン』といい、そのために接続した抵抗器のことを『プルダウン抵抗』といいます。

スイッチ・オンで LOW

スイッチと抵抗を逆にした回路もよく使われます。

スイッチがオフのとき、input 端子は抵抗器を通じて 5 V に接続されるので、input 端子の電位は 5 V = HIGHとなります。このように、オフのときに端子の電位が 5 V ( HIGH レベル)になるように接続することを『プルアップ』といい、プルアップに使われる抵抗器のことを『プルアップ抵抗』といいます。

スイッチがオンのとき、input 端子は GND に接続されるので電位は 0 V = LOW となります。

つまり回路では、スイッチがオンのときに input 端子は LOW、スイッチがオフのとき input 端子は HIGH と、オン/オフと HIGH / LOW の関係が逆になります。

逆なんてややこしいのは辞めておこう…と思ってしまいますが、Arduino の場合はこちらの使用法が前提のようです。

Arduino のデジタル入力端子には、実は『内部プルアップ抵抗』が用意されており、ソフトウェアから内部プルアップ抵抗を有効化すると外部のプルアップ抵抗を省略することができるのです。小さなスペースに組み込まなければならないときは、抵抗器ひとつといえども不要になるのはありがたいことです。設定方法は後述します。

というわけで、本サイトの制作例では、基本的にスイッチは『オンで LOW 』の回路を作成することにします。

プルアップ/プルダウン抵抗器の抵抗値

プルダウン抵抗の抵抗値は、

input 端子の内部抵抗(インピーダンス)よりは充分小さく

かつ

スイッチ・オン時に大きな電流が流れてしまわないようにある程度大きく

する必要があります。この2つの要求を満たすためには、数 kΩ ~ 数十 kΩ の抵抗値とするのが適切です。当サイトでは基本的に 10 kΩ の抵抗器を使用することにします。

電流制限抵抗

先ほど『入力端子はハイインピーダンス( MΩ 単位)で、5 V や GND に直結しても微量の電流しか流れず、Arduino を破損することはありません』と書きました。これ自体は間違いではないのですが、ソフトウェアの不具合により『入力のつもりだった端子が出力に設定されてしまった』場合はどうでしょうか。このときスイッチがオン状態だと、端子が 5 V または GND に直結して過大な電流が流れ、Arduino が破損する危険があります。

そこで、スイッチと input 端子間に電流の最大値を制限する抵抗器を追加することがあります。このような目的で追加された抵抗器を『電流制限抵抗』と呼びます。

この図は『スイッチ・オンで LOW、外部プルアップ抵抗付き』で描きましたが、他の回路でも考え方は同じです。

Arduino の出力端子の最大電流は 40 mA で、それ以上の電流が流れてしまうと Arduino が破損する恐れがあります。つまり最大電位差 5 V でも電流が 40 mA 以下になるような抵抗が必要なので、

\[R=\frac{E}{I}=\frac{5}{40\times 10^{-3}}=125\]

つまり 125 Ω 以上の抵抗値とすればいいことがわかります。

実際にはもう少し余裕を見て、かつプルアップ/プルダウン抵抗よりは充分小さい抵抗値として、数百 Ω ~ 1 kΩ 程度とするのが適切と思われます。

製作・実行

使用部品

今回は以下の部品を使用します。

部品名(型番)数量備考
ブレッドボード1小さなサイズでOK
タクトスイッチ1ブレッドボードに挿せるもの
抵抗器(1kΩ)14本帯なら茶黒赤、5本帯なら茶黒黒茶
ジャンパ線
(オス-オス)
2緑×1、黒×1がオススメ

今回初めて使う部品について説明します。

タクトスイッチ

タクトスイッチは小型の押しボタンスイッチです。ボタンを押すとON、離すとOFFとなります。

回路

今回の回路は下図の通りです。

LED 点滅の実験では出力として使用した D3 を、今回は入力端子として使用します。

電流制限抵抗として 1 kΩ の抵抗器を用い、プルアップは Arduino の内蔵プルアップ抵抗を利用することにして外付けにはしていません。おかげで非常にシンプルな回路になりました。

配線

配線は下図の通りです。

1. タクトスイッチをブレッドボードの適当な位置に挿します。このとき、足(端子)の『く』の字型の折れ曲がりが『左/右』ではなく『手前/奥』を向くようにします。手前/奥は逆でも大丈夫です。

2. 1kΩの抵抗器を挿します。抵抗器の2本の足は、左脚をタクトスイッチの右側の足と同じ列の穴、右足をまだ他の部品が刺さっていない列の穴 に挿します。抵抗器には極性はありませんので、どちらが右足/左足でも大丈夫です。

3. ジャンパ線(黒)の2つのピンを、それぞれ Arduino の GND 端子(2つあるのでどちらでも)とタクトスイッチの左側の足と同じ列の穴 に挿します。

4. ジャンパ線(緑)の2つのピンを、それぞれ Arduino の D3 端子抵抗器の右足と同じ列の穴 に挿します。

プログラム

PC で Arduino IDE を起動し、新規スケッチを作成して、以下の通りに入力します。

C++
#define INPUT_PIN 3

void setup() {
  pinMode(INPUT_PIN, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {
  int value;
  value = digitalRead(INPUT_PIN);
  Serial.println(value);
}

プログラムの解説

#defineで定数の定義
C++
#define INPUT_PIN 3

今回は D3 端子を入力として使います。端子番号を引数として指定する関数はいくつかあるのですが、数値をそのまま記述すると意味が判りにくいので、英単語の組合せの名前の定数として定義するとプログラムの可読性が改善します。

また、複数箇所で同じ値を指定する場合、#define で定数として定義しておけば、変更があった場合には #define の定義のみを変更すればよく、変更漏れが発生しません。

pinMode() で端子を入力に設定
C++
void setup() {
  pinMode(INPUT_PIN, INPUT_PULLUP);
  Serial.begin(9600);
}

setup() 関数の中では、まずD3端子を入力に設定しています。端子の入力/出力を設定するには、pinMode() 関数を使います。

pinMode() の書式は次の通りです。

void pinMode(int pin, int mode)
引数
名称意味
pinint設定対象の端子番号
modeint設定内容
返却値

なし

補足

引数 mode に設定可能な値は以下の3通りです。

指定する値意味
OUTPUT端子を出力に設定する
※アナログ出力、デジタル出力の区別はありません
INPUT端子を入力に設定する
INPUT_PULLUP端子を入力、かつプルアップに設定する

これらは内部的には int 値を定数として定義したもので、INPUT = 0、OUTPUT = 1、INPUT_PULLUP = 2となっていますが、プログラム中で 0、1、2 の整数値を記述するのは可読性を損なうので辞めた方がいいでしょう。

今回の実験では、入力端子であり内蔵プルアップ抵抗を使用するので INPUT_PULLUP を指定します。プルアップ抵抗を外付けする場合は INPUT を指定します。

シリアル通信の初期化
C++
void setup() {
  pinMode(INPUT_PIN, INPUT_PULLUP);
  Serial.begin(9600);
}

入力値をPCのシリアルモニタで表示するため、Arduino のシリアル通信を初期化しています。

端子の入力値を読み取る digitalRead()
C++
void loop() {
  int value;
  value = digitalRead(INPUT_PIN);
  Serial.println(value);
}

loop() 関数の中では、ひたすら『デジタル入力端子の入力値を読み取ってシリアル通信でPCに送信する』ということを繰り返しています。

デジタル入力端子の値を読み取るには、digitalRead() 関数を使用します。書式は以下の通りです。

int digitarRead(int pin)
引数
名前意味
pinint入力値を読み取る端子番号
返却値
意味
int入力端子から読み取った入力値
解説

digitalRead() 関数は、端子番号を指定して入力値を読み取ります。返却値は、端子の電位が HIGH のとき 1、電位が LOW のとき 0 です。

読み取り値の送信
C++
void loop() {
  int value;
  value = digitalRead(INPUT_PIN);
  Serial.println(value);
}

入力端子からの読み取り値を Serial.println() 関数で PC へ送信しています。値は PC のシリアルモニタで表示することができます。

コンパイル&実行

それでは、USB ケーブルを PC と Arduino に接続し、Arduino IDE の『 』ボタンをクリックしてスケッチをコンパイル&実行します。シリアルモニタを起動して値を観察しながら、ブレッドボード上のタクトスイッチを押したり離したりしてみましょう。

※シリアルモニタは自動スクロールをオンにしておきましょう

タクトスイッチのボタンを押すと『 0 』、離すと『 1 』が表示されることが判ります。

まとめ

  • スイッチを Arduino の入力端子に接続する場合、必要に応じてプルアップ/プルダウン抵抗を接続する。ただし内蔵プルアップ抵抗を有効にすれば、それとは別にプルアップ抵抗を外付けする必要はない
  • 端子の入力/出力を設定するには、pinMode() 関数を使う
  • デジタル入力端子からの入力値の読み取りは、digitalRead() 関数を使う

コメント

タイトルとURLをコピーしました