5.3 デジタル入力とLED点滅 その2

delayを使わずに
デジタル入力でボタンが押されたことを検知して
LEDの点滅パターンを変えることを考えてみます。

§5.2のプログラムを以下のように変えてみます。

int buttonState = 0; 
int count = 0;
int check = 0;
int state = 0;

unsigned long preMillis = 0;  
unsigned long interval = 200;

unsigned long btn_preMillis = 0;  
unsigned long btn_interval = 100;

void setup() {
  pinMode(P1_0, OUTPUT);      
  pinMode(P1_6, OUTPUT);      

  pinMode(P1_3, INPUT_PULLUP);     
}

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

  if(curMillis - btn_preMillis > btn_interval) {

    buttonState = digitalRead(P1_3);
  
    if (buttonState == LOW) {
      if (check == 0) {
        count++;
        check = 1;
        state = 0;
        digitalWrite(P1_0, LOW);
        digitalWrite(P1_6, LOW);
      }  
    }
    else check = 0;
    
    btn_preMillis = curMillis;
  }


  if(curMillis - preMillis > interval) {
     switch (count % 4) {
       case 0:
         if( state % 2 ==0 )
           digitalWrite(P1_0, LOW);
         else 
           digitalWrite(P1_0, HIGH);
         break;    
    
       case 1:
         if( state % 2 ==0 )
           digitalWrite(P1_6, LOW);
         else 
           digitalWrite(P1_6, HIGH);
         break;    
       
       case 2:
         if( state % 2 ==0 ) {
           digitalWrite(P1_0, LOW);
           digitalWrite(P1_6, LOW);
         }
         else {
           digitalWrite(P1_0, HIGH);
           digitalWrite(P1_6, HIGH);
         }
         break;    
       
       case 3:
         if( state % 2 ==0 ) {
           digitalWrite(P1_0, LOW);
           digitalWrite(P1_6, HIGH);
         }
         else {
           digitalWrite(P1_0, HIGH);
           digitalWrite(P1_6, LOW);
         }
         break;    
     }
     state++;
     preMillis = curMillis;
  }
  

}

このプログラムではdelayを使っていません。
§4.1や4.2で扱った、現在時刻と前回処理を行った時刻の差を利用して
200msごとの処理を作り出しています。

  if(curMillis - preMillis > interval) {
     switch (count % 4) {
       case 0:

の部分です。 intervalには最初に200を代入していますので
200ms毎にif文の{ }の中のswitch文に処理が移ります

さらに各case文の中で

       case 0:
         if( state % 2 ==0 )
           digitalWrite(P1_0, LOW);
         else 
           digitalWrite(P1_0, HIGH);
         break;    

としています。stateの中身が奇数が偶数かで処理を切り替えています。

このswitch-case文の後で

     state++;
     preMillis = curMillis;

としていることから、200ms毎に
このswitch-case文の処理を行うたびに
stateの値は1ずつ増加していきます。
ですので、

偶数の処理→奇数の処理→偶数の処理→奇数の…

と200ms毎に切り替わるわけです。

さらに、ボタンの処理は

  if(curMillis - btn_preMillis > btn_interval) {

    buttonState = digitalRead(P1_3);
  
    if (buttonState == LOW) {
      if (check == 0) {
        count++;
        check = 1;
        state = 0;
        digitalWrite(P1_0, LOW);
        digitalWrite(P1_6, LOW);
      }  
    }
    else check = 0;

としてあります。
LEDの処理を行う200ms毎の処理とは別にbtn_intervalの時間毎に
このif文の{ }の中の処理を行います

btn_intervalは最初で100にしてあるので
ボタンの処理は100ms毎に行うことになります。
100ms毎に行う処理は§5.2とほぼ同じです。

ボタンを押される(LOWになる)たびにcountを1ずつ増加させます。
そして、ボタンを押したままにしているかどうかを
checkの中身を0にしたり1にしたりすることで、判別します。

さらに、ボタンを押されたときにstateの中身を0にします。
つまり、ボタンを押されるたびに、偶数回と奇数回の切り替えを行うための
変数であるstateを0に戻しているわけです。

ちなみに、この100ms毎の処理を100ms毎でなく常に行うようにすると
複数回ボタンを押されたと検出されて、
countの値が1ずつ増加しなくなってしまうことがあります。

これは、ボタンが押されているときにおきるチャタリングに起因すると考えられます。
一般にボタンの処理を行うときにはチャタリング対策が求められます。
チャタリング対策については、また別の機会に解説したいと思います。

ここでは、ボタンを押された処理は、一定時間毎に行った方が良い
と考えておいてください。

0 件のコメント:

コメントを投稿