スイッチライブラリ

このライブラリはスイッチを使うためのものです。 チャタリングの回避とスイッチを押したときのレベルの変化(HIGHからLOWもしくは、LOWからHIGH)の検出ができます。

使い方

基本的な使い方

2番のデジタルピン(D2)にタクトスイッチをつける場合は図のようにD2, GNDとスイッチの端子をつなぎます。マイコン内蔵のプルアップ抵抗を使うので、外付けの抵抗は不要です。

スケッチではSwitchesライブラリを読み込み、変数を宣言をして使います。 スイッチの状態を知るには変数名が sw なら sw() とします。 sw() とするとスイッチのつながったピンの電圧を調べ、 前回に HIGH で今回が LOW のとき(スイッチを押したとき)に 戻り値が真(TRUE)になります。下のスケッチではスイッチを押したときLEDを1秒間点灯します。スイッチを押しっぱなしにしても点灯を繰り返しません。
#include 

Switches sw(2);

void setup()
{
  pinMode(13, OUTPUT);
}

void loop()
{
  if (!sw())
    return;

  digitalWrite(13, HIGH);
  delay(1000);
  digitalWrite(13, LOW);
}

使い方

宣言

宣言の方法は4通りあります。 一つ目の方法ではピンの番号などは、init()関数を使って宣言後に設定します。配列にするときなどに使います。

Switches sw1;

void setup()
{
  sw1.init(2);
}
2つ目はピンの番号を引数にとります。内蔵プルアップが有効で、ピンの電圧がHからLに変化したときにsw2()の値がtrueになります。
Switches sw2(2);
3つ目はピンの番号と、内蔵プルアップの有効/無効を引数にとります。 プルアップを有効にするにはtrueを、無効にするにはfalseとします。
Switches sw3(3, false);
4つ目はピンの番号と、内蔵プルアップの有効/無効、変数名の関数の値がtrueになる条件を引数にとります。プルアップを有効にするには二つ目の引数をtrueに、無効にするにはfalseにします。3つ目の引数で変数名の関数の値がtrueになる条件を指定します。
Switches sw4(4, true, SWITCH_LEVEL);
のとき3つ目の引数によってsw4()がtrueになる条件は次のようになります:
引数条件
SWITCH_LEVELピンがHのとき
SWITCH_NLEVELピンがLのとき
SWITCH_HtoLピンの値がHからLに変化したとき(省略時)
SWITCH_LtoHピンの値がLからHに変化したとき

init(int Pin, bool pullup, int mode)

init関数で、ピンの番号、内蔵プルアップの有効(true)/無効(false)(デフォルト:true)、変数名の関数の値がtrueになる条件(デフォルト:SWITCH_HtoL, 宣言時と同じ)を指定します。次の例ではいずれも内蔵プルアップが有効で、HからLになったときに sw1(), sw2(), sw3()の値が真(true)になります:

Switches sw1, sw2, sw3;

sw1.init(2, true, SWITCH_HtoL);
sw2.init(3);
sw3.init(4, true);

setInterval(int t)

setInterval関数で、チャタリング防止のための読み込み間隔をミリ秒単位で指定します。 デフォルトは20[ms]です。このライブラリでは、変数名の関数が連続で 呼び出されたときにもチャタリングで誤動作しないように、前回に呼び出したときから 一定時間経過してからピンの値を呼んでいます。その時間をsetInterval関数で指定します。例:

Switches sw1(2);

sw1.setInterval(50);  // set interval to 50[ms]

read()

read関数は、設定によらずピンの値をそのまま読んで返します。つまりピンの値がHなら、HIGH (true), Lなら LOW (false)を返します。

注意事項

このライブラリは下記の「チャタリングを回避する方法(2)」をとっています。 そのため、変数名の関数を呼び出している間隔が長いと、その間の変化がわからないことがあります。

ダウンロードとインストール

次のzipファイルをダウンロードします。Arduino IDEの「スケッチ」→「ライブラリを使用」→「ライブラリをインストール」でダウンロードしたファイルを指定してインストールします。

チャタリングと回避方法

機械的なスイッチは動作時にチャタリングがどうしても発生します。 チャタリングは、スイッチ内の接点同士の接触が安定するまでの 数ミリ秒から数10ミリ秒ぐらいの短い時間に、スイッチが ON/OFF を繰り返す現象です。

チャタリングが気にならない場合

次のスケッチは、スイッチを押している間にLEDを点灯するスケッチの一部です:

void loop()
{
  if (digitalRead(2) == LOW) {
     digitalWrite(13, HIGH);
  } else {
     digitalWrite(13, LOW);
  }
}
この場合にはチャタリングが発生しても、LEDの点滅が速く目には見えないので気になりません。

次のスケッチのように、スイッチを押して何か長い処理を実行する場合も問題になりません:

void loop()
{
  if (digitalRead(2) == HIGH)
     return;
  }

  for(int i=0; i<10; i ++) {
    digitalWrite(13, HIGH);
    delay(100);
    digitalWrite(13, LOW);
    delay(100);
  }
}

チャタリングが問題になる場合

スイッチを押すたびに、LEDの点灯と消灯を切り替えるスケッチを考えたとします:

bool osw = HIGH;
bool LED = LOW;

void setup()
{
  pinMode(13, OUTPUT);
}

void loop()
{
  bool sw = digitalRead(2);

  if (osw == HIGH && sw == LOW) {
     LED = !LED;
     digitalWrite(13, LED);
  }
  osw = sw;
}
このスケッチでは、2番ピンにつないだスイッチの値を読み、直前の値 osw が HIGHで、今の値swがLOWなら、LED変数の値を反転 (!LEDでLEDの値が0(LOW)なら1(HIGH)に1なら0になる)しています。一見よさそうに見えるのですが、実際にスケッチを動かすと、チャタリングのためにスイッチを押しても思ったように点灯、消灯ができません。

同様にスイッチを押した回数を数えるスケッチもうまく動きません:

bool osw = HIGH;
int count = 0;

void setup()
{
}

void loop()
{
  bool sw = digitalRead(2);

  if (osw == HIGH && sw == LOW) {
     count ++;
  }
  osw = sw;
}

チャタリングを回避する方法(1)

チャタリングを回避するにはスイッチとArduinoの間に抵抗2本とコンデンサ1つからなるローパスフィルタを入れるハードウェア的な解決方法と、スイッチの値を読むタイミングで解決するソフトウェア的な方法があります。ここでは後者を紹介します。

チャタリングの問題は接点が安定しないために、ArduinoからみたときにHIGH(H)/LOW(L)を実際の操作よりも短時間に繰り返すことにあります。 そこで実際の操作よりも短時間で、接点が安定するよりも長い時間の間隔でスイッチの値を読むという方法が知られています。

たとえばスイッチを押すと

HHHHHHHHHHHHHHHHHHHHHLHLHHLHLHLHLHLLLLLLLLLLLLLLLLLLLLLLLL
という順番でピンの値が変化したとします。スイッチを押していないとき、押しているときをはさんでチャタリングが含まれています。
|             |             |             |             |
HHHHHHHHHHHHHHHHHHHHHLHLHHLHLHLHLHLLLLLLLLLLLLLLLLLLLLLLLL
< ------安定期----- >< チャタリング >< -----安定期------ >
ここで上の縦棒の時だけ読み込むようにすれば、チャタリングの影響はありません。 たまたまチャタリングの間に読み込んだとしても、操作よりも高速なH/Lの変化は現れません。

読み込みの間隔はスイッチによるのですが、20ミリ秒ぐらいでいいでしょう。 もう少し短くてよいスイッチもあれば、100ミリ秒ぐらい必要なものもあります。 スケッチにdelay(20);を加えるだけです。

bool osw = HIGH;
bool LED = LOW;

void setup()
{
  pinMode(13, OUTPUT);
}

void loop()
{
  bool sw = digitalRead(2);

  if (osw == HIGH && sw == LOW) {
     LED = !LED;
     digitalWrite(13, LED);
  }
  osw = sw;

  delay(20);
}
同様にスイッチを押した回数を数えるスケッチにも一行加えるだけです:
bool osw = HIGH;
int count = 0;

void setup()
{
}

void loop()
{
  bool sw = digitalRead(2);

  if (osw == HIGH && sw == LOW) {
     count ++;
  }
  osw = sw;

  delay(20);
}
ただし、プログラム全体の動作タイミングは変わります。

チャタリングを回避する方法(2)

動作のタイミングを大きく変えたくない場合には millis() 関数を使う方法があります。 Arduinoの「スケッチの例」にある「02.Digital」のBlinkWithoutDelayのように一定時間が経過しているときだけ、スイッチの処理をします。 スイッチライブラリも、この方法をとっています。

たとえばスイッチを押したときに点灯と消灯を切り替えるなら:

unsigned long prev = 0;
bool osw = HIGH;
bool LED = LOW;

void setup()
{
  pinMode(13, OUTPUT);
  prev = millis();
}

void loop()
{
  unsigned long cur = millis();

  if (cur - prev > 20) {
    bool sw = digitalRead(2);
    prev = cur;

    if (osw == HIGH && sw == LOW) {
       LED = !LED;
       digitalWrite(13, LED);
    }
    osw = sw;
  }
}
同様にスイッチを押した回数を数えるスケッチの場合には:
unsigned long prev = 0;
bool osw = HIGH;
int count = 0;

void setup()
{
  prev = millis();
}

void loop()
{
  unsigned long cur = millis();

  if (cur - prev > 20) {
    bool sw = digitalRead(2);

    if (osw == HIGH && sw == LOW) {
       count ++;
    }
    osw = sw;
    prev = cur;
  }
}


Arduinoのすすめ
Copyright (c) 2014, 2016, Noriaki Mitsunaga