スポンサーリンク
ものづくり・DIY

Arduinoでタクトスイッチを読む|プルアップ抵抗とINPUT_PULLUPのしくみ、チャタリング対策まで

INPUT_PULLUPで配線を減らす

ボードの中のプルアップ抵抗を使う

Arduino Unoなどのマイコンには、入力端子ごとにプルアップ抵抗が内蔵されていて、スケッチから有効にできます。pinMode で端子を INPUT_PULLUP に設定すると、外付けの抵抗なしでプルアップの回路ができあがります。内蔵の抵抗は数十kΩ程度で、値は機種によって違いますが、ボタンを読む用途には十分です。

スポンサーリンク

配線は、ボタンの片側をデジタル端子(ここでは2番)に、もう片側をGNDにつなぐだけです。部品が減り、5Vの配線も不要になるので、ブレッドボードの上がすっきりします。入門では、まずこの方法から始めるのがおすすめです。

配線の手順

  1. USBケーブルを抜き、ボードに電源が入っていない状態にする。
  2. タクトスイッチをブレッドボードの中央の溝をまたぐように挿す。
  3. スイッチの対角の足の一方に、ボードのデジタル2番からジャンパー線をつなぐ。
  4. もう一方の足から、ボードのGNDへジャンパー線をつなぐ。
  5. 配線を指でたどり、5VとGNDが直接つながっていないことを確かめてからUSBをつなぐ。
INPUT_PULLUPの配線(1. 電源を切る、2. スイッチを置く、3. 2番につなぐ、4. GNDにつなぐ、5. たどって確認)
抵抗なしでボタンを読む最小構成。

押されたら基板のLEDを点けるスケッチ

ボタンの状態を読み、押されている間だけ基板上のLEDを点けるスケッチは、次のようになります。

const int buttonPin = 2;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  int state = digitalRead(buttonPin);
  if (state == LOW) {          // 押されているとLOW
    digitalWrite(LED_BUILTIN, HIGH);
  } else {
    digitalWrite(LED_BUILTIN, LOW);
  }
  Serial.println(state);
  delay(10);
}

ポイントは、押されているときに LOW になることです。プルアップでは値が「逆」になるので、条件を state == LOW と書きます。慣れないうちは混乱しやすいので、bool pressed = (digitalRead(buttonPin) == LOW); のように「押されているか」を表す変数を作ってから使うと、後のスケッチが読みやすくなります。

シリアルモニタを開くと、押していないときは1、押すと0が流れていくはずです。値が勝手に揺れる場合は、INPUT_PULLUP の書き間違いや、別の端子番号に配線していないかを確かめます。

スポンサーリンク

外付けの抵抗で組む場合

内部プルアップがあるのに外付けの抵抗を学ぶ意味は、他のマイコンや部品を使うときに同じ考え方が出てくるからです。外付けのプルダウンで組むなら、ボタンの片側を5Vに、もう片側をデジタル2番につなぎ、同じ2番の列から10kΩの抵抗を通してGNDへつなぎます。スケッチでは pinMode(buttonPin, INPUT); とし、押されているときが HIGH になります。

外付けと内部のプルアップを同時に使う必要はありません。外付けのプルダウン抵抗を付けたまま INPUT_PULLUP にすると、内部の抵抗と外付けの抵抗が引っ張り合い、押していないときの電圧が中途半端になることがあります。回路とスケッチの設定は、どちらか一方にそろえます。

押した瞬間を検出する

「押されている」と「押された」は違う

上のスケッチは、押している間ずっと反応します。しかし実際の作品では、「1回押すごとにLEDの点灯と消灯を切り替える」「押した回数を数える」など、押した瞬間だけを捉えたい場面がよくあります。loop は1秒間に何千回も回るので、押している間の状態をそのまま使うと、1回の押下で何百回も数えてしまいます。

前回の状態と比べる

押した瞬間を捉えるには、前回 loop を回ったときの状態を覚えておき、今回と比べます。前回がHIGH(押していない)で、今回がLOW(押している)なら、ちょうど押された瞬間です。このように状態が切り替わる境目を「エッジ」と呼びます。

const int buttonPin = 2;
int lastState = HIGH;
bool ledOn = false;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  int state = digitalRead(buttonPin);
  if (lastState == HIGH && state == LOW) {  // 押された瞬間
    ledOn = !ledOn;
    digitalWrite(LED_BUILTIN, ledOn ? HIGH : LOW);
  }
  lastState = state;
}

逆に、前回がLOWで今回がHIGHなら、ボタンが離された瞬間です。押した瞬間で処理を始め、離した瞬間で終える、という組み合わせもよく使います。押した回数を数えたいときは、押された瞬間の条件の中で変数に1を足し、シリアルモニタへ表示すると、数え方が正しいかを目で確かめられます。

スポンサーリンク

動きを確かめるコツ

エッジの検出がうまく動いているかは、LEDだけでは分かりにくいことがあります。押された瞬間に Serial.println("pressed"); のような文字を出すようにしておくと、1回押したときに何回表示されるかで、スケッチの動きを確かめられます。1回押して1回だけ表示されれば正しく、2回、3回と表示されるなら、何かが余分に反応しています。

これで1回押すごとに点灯と消灯が切り替わる……はずですが、実際に試すと、うまく切り替わらないことがあります。押したのに点いたり消えたりを素早く繰り返して、元の状態に戻ってしまうのです。シリアルモニタで確かめると、1回の押下で表示が何回も出ることがあります。原因は次に説明するチャタリングです。

次のページへチャタリングの原因と対策
スポンサーリンク
  1. 秋の戸口に並ぶかぼちゃの明かりとかぶ、麦束
  2. 資料を手に落ち着いて話し合う二人
  3. ノートパソコンと資料、外付け記憶装置がある机
  4. 冬の木で越冬する卵のうやミノムシ、テントウムシ
  5. 青い折り鶴と三角に折った紙、無地の折り紙