戻る

44 ダブルクリックと長押ながおしの検出けんしゅつ

回路かいろ

21番のプログラム例, 43番のプログラム例と回路は同じです。

Arduino と抵抗(1kΩ茶黒赤金, 1kΩから10kΩ(茶黒橙金)ぐらいならよい)とスイッチを用意します。図のスイッチはタクトスイッチです。回路図のように Arduinoの2番ピンとスイッチの片方の足、抵抗の片方の足の3つをつなぎます。 スイッチの反対の足はグラウンド(GND)へ、抵抗の反対の足は5Vへつなぎます。 スイッチの向きを90度間違えると動作しないので注意してください。

プログラム

動作どうさ

このプログラムを実行している間にスイッチを押すと、スイッチの押し方によってArduinoボード上のLEDの点滅が変わります。

プログラムを止めるにはCtrl+Cを使います。

解説かいせつ

全体の構成

このプログラムは大きく分けて二つの部分に分かれます。 一つはLEDを点滅させる部分、 もう一つはスイッチが押されたときに実行される部分です。 スイッチが押されたときの部分を灰色にすると次のようになります。

unsigned long p = 0;
unsigned long t = 0;
int l = 0;
int s = 0;

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

void loop()
{
 if (s == 1) {
  if(millis()-p > 200) {
   p = p + 200;
   l = !l;
  }
 }
 digitalWrite(13, l);

 if (digitalRead(2) == LOW) {
  t=millis();
  t = millis();
  delay(20);
  while (digitalRead(2) == LOW) {
   delay(5);
  }
  if (millis()-t < 500) {
    s=0;
    l=1;
    for (int i=0; i<20; i=i+1) {
     if (digitalRead(2)==LOW) {
      s=1;
      delay(20);
      while(digitalRead(2)==LOW) {
       delay(5);
      }
      p=millis();
      break;
     }
     delay(10);
    }
   } else {
    s=0;
    l=0;
   }
 }
}

LEDを点滅させる部分

それではLEDを点滅させる部分だけにしてプログラムをみていきましょう。
unsigned long p = 0;
unsigned long t = 0;
int l = 0;
int s = 0;

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

void loop()
{
 if (s == 1) {
  if(millis()-p > 200) {
   p = p + 200;
   l = !l;
  }
 }
 digitalWrite(13, l);
}
最初の4行は変数p, t, l, sを宣言して0にしています。unsigned longは、32ビットの長さの正の整数のみを扱う型を表します(Arduinoの「時計」に合わせています)。 setup()関数では13番ピンを出力にしています。 loop()関数でsが0の時にはif文ではなにもせず、digitalWriteでlの値を13番ピンに出力しています。lが0の時に13番ピンはLOWになり、そうでなければHIGHになります。つまりlが0ならLEDは消灯、1ならLEDは点灯です。

sが1の時にはif文の中が実行されます。millis()はArduinoの時計を読みます。iArduinoの時計は1/1000秒に1ずつ増えていきます。pには過去の時刻を記憶しておきます。そうすると millis()-p > 200 が成り立つのは0.2秒(200/1000秒)が経ったときに中のif文の{と}の間が実行されます。

p=p+200でpに200を足しています。これは、たとえば経過時間が250m秒だったときには、次には150ms後に、このif文の中を実行したいと考えているからです。 「!」は否定(NOT, ノット)の記号です。右側の式が0のときには1に、0以外の時(たとえば1)には0になります。これでlの値が0のときには1に変わり、1のときには0に変わります。

したがって、

と変数の値を変えればよいとわかります。

スイッチが押されたときに対応する部分

長押しかどうかの判断

スイッチが押されたときには次のif文の中括弧の中が実行されます。グレーの部分はスイッチから手が離されるまで待つ部分です。

 if(digitalRead(2)==LOW) {
  t=millis();
  delay(20);
  while(digitalRead(2)==LOW) {
   delay(5);
  }
  if(millis()-t < 500) {
    s=0;
    l=1;
    for(int i=0; i<20; i=i+1) {
     if (digitalRead(2)==LOW) {
      s=1;
      l=!l;
      delay(20);
      while(digitalRead(2)==LOW) {
       delay(5);
      }
      p=millis();
      break;
     }
     delay(10);
    }
   } else {
    s=0;
    l=0;
   }
  }
スイッチが押されると
  t=millis();
で時計を読んでtに代入します。そしてスイッチから手が離れると長押し(0.5秒(500ミリ秒)で判断する)ではないかを調べています。
  if(millis()-t < 500) {
先に、長押しと判断した場合に実行する部分を見ます。
   } else {
    s=0;
    l=0;
   }
sとlに0を代入しているだけと分かります。

2回押しかの判断

長押しでない場合には先ほどのif文の最初の中括弧で囲まれた範囲

    s=0;
    l=1;
    for(int i=0; i<20; i=i+1) {
     if (digitalRead(2)==LOW) {
      s=1;
      l=!l;
      delay(20);
      while(digitalRead(2)==LOW) {
       delay(5);
      }
      p=millis();
      break;
     }
     delay(10);
    }
が実行されます。最初にs=0でl=1の点灯になるようにしています。 if文をみないなら、20回繰り返すforループ(for文)があり、1回に10/1000秒待っていることが分かります。つまり0.2秒(200/1000秒)待つだけで何もしません。

forループの中のif文は次のようになっています。

     if (digitalRead(2)==LOW) {
      s=1;
      delay(20);
      while(digitalRead(2)==LOW) {
       delay(5);
      }
      p=millis();
      break;
     }
スイッチが押されるとsを1にして点滅モードにします。そして手が離されるのを待ち、pに今の時刻(millis())を代入しています。

スイッチから手が離されたら、これ以上待つ必要はないので、最後のbreak文でforループの繰り返しを中止します。break文は、break文の含まれるforループやwhileループなどを中止します。


戻る
(c) 2014-2015 N. Mitsunaga
サンプルプログラムの著作権は放棄します。fritzingで作成した図は、そちらのライセンスに従って再配布して構いません。