PASのブログ

PASの中の人が書く雑記ブログです。

スイッチの長押し判定 アナマル.14

予告と毎回やることが違いますが、今回はいよいよプログラミング編最後の「プログラムを記憶させる」部分をスタートします。

基板は完成しましたが、スイッチは配線で接続するのでケースに組み込む段階で発表しようと思います。

プログラムモードをどう表示するかを検討する。

当初から考えていたのは、LCD1602を使うことでした。
しかし、未定義の表示は「プログラムセットモードかそうで無いか」だけなのです。
そこで取り合えず、以前の記事で使った、Arduinoに最初から載っているLEDを使用します。

注意点としては、LED_BUILTINは、正論理です。

スイッチの長押しの仕組み。

現在の短押しの仕組みのおさらい。
スイッチの状態の、現在と、一つ前の状態をそれぞれ変数に保存する。

スイッチを離した瞬間に検知する。

検知した瞬間にプログラムを止める。(チャタリングを読み込まないため)

やるべき処理を実行する。

現在の状態を一つ前の状態にコピーする。

これを改造したいところですが、「離した瞬間にそれが長押しだったかどうかを調べる」というやり方では、例えば1秒以上が長押しだったとして、0.99秒ならアウトになるわけですので、二度手間です。
そこでこのように考えます。

長押しの仕組みを考える。

例えばですがこういうのはどうでしょうか?

スイッチを押した瞬間にカウンターをスタートさせる。

ボタンを押しっぱなしの間カウンターは増えていく。 

長押し時間として予め決めた回数カウントアップしたら「長押し」と判定する。

やるべき処理を実行する。

カウンターをクリアする。


もし、長押し時間回数以下でスイッチから手を離したら

カウンターをクリアする。

では一旦これで試します。

長押ししてPRGset関数へ飛ぶ。

直接関係ある部分だけ記述します。

//sw6
//プログラムセットモード実装
//抜粋
const int SW5 = A5;//プログラムセットボタン
unsigned int count = 0; // 1周ループしたら+1
unsigned int swcount = 0; // 1周ループしたら+1

void setup() {

  pinMode(SW5, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {

  a = count % 4;
  sw(a);
  count = count + 1;

  //mode切り替え処理
  val[4] = digitalRead(SW4); //スイッチの状態をval[num]に入れる
  if ((val[4] == 1) && (old_val[4] == 0))
  {
    delay(10);// 10ms待つ。
    if (mode == 1)
    {
      mode = 0;
    }
    else
    {
      digitalWrite(LED[4], HIGH);
      digitalWrite(LED[5], HIGH);
      digitalWrite(LED[6], HIGH);
      digitalWrite(LED[7], HIGH);
      mode = 1;
    }
  }
  old_val[4] = val[4];

  //SW5長押しでPRGsetモードへ。
  if (!(digitalRead(SW5)))
  {
    swcount = swcount + 1;
    if (swcount >= 50000)
    {
      PRGset();
    }

  }
  else
  {
    swcount = 0;
  }

}

void PRGset()
{

  while (1)
  {
    digitalWrite(LED_BUILTIN, HIGH);
  }
}

swcountという変数を立てて、一周回る度にカウントアップしています。

前回、countで体験したように、データ型はunsigned int(0-65535の整数)にしました。

長押しでPRGset関数に飛び、その中で無限ループを繰り返します。

ここで、試していただくとわかりますが、マニュアルモードのときの長押し時間と、プログラムモードのときの長押し時間が違います。
(マニュアルモードのときのほうが長い)

プログラム一周でswcountは+1されていきますが、通るルートが違うために、一周の時間が違うために起きます。
今回の場合は実用上支障がないのでこのままにしておきます。

PRGset関数からメインループに戻る。

では同様に、PRGset関数から抜けるのもSW5ボタンの長押しでやることにします。
ここで気をつけるのは、メインループから長押しをしている途中でPRGset関数に飛んだ瞬間には既に、「長押しをしている」状態です。
長押しするタイミングはloop()の中と、PRGset()の中です。
ですのでこうします。

一つ変数を作って、「一旦スイッチから手を離したらモードを切り替える」ことにします。今までも何度かやっている方法ですね。

ではソースの抜粋です。

int SW5mode = 0;//SW5の状態 0がloopで1がPRGset

void loop() {
  digitalWrite(LED_BUILTIN, LOW);
  if (digitalRead(SW5))
  {
    SW5mode = 0;
  }
  a = count % 4;
  sw(a);
  count = count + 1;

  //mode切り替え処理
  val[4] = digitalRead(SW4); //スイッチの状態をval[num]に入れる
  if ((val[4] == 1) && (old_val[4] == 0))
  {
    delay(10);// 10ms待つ。
    if (mode == 1)
    {
      mode = 0;
    }
    else
    {
      digitalWrite(LED[4], HIGH);
      digitalWrite(LED[5], HIGH);
      digitalWrite(LED[6], HIGH);
      digitalWrite(LED[7], HIGH);
      mode = 1;
    }
  }
  old_val[4] = val[4];

  //SW5長押しでPRGsetモードへ。
  if (SW5mode == 0)
  { if (!digitalRead(SW5))
    {
      swcount = swcount + 1;
      if (swcount >= 50000)
      {
        PRGset();
      }

    }
    else
    {
      swcount = 0;
    }
  }
}

void PRGset()
{
    digitalWrite(LED_BUILTIN, HIGH);

  while (1)
  {
    if (digitalRead(SW5))
    {
      SW5mode = 1;
    }

    //SW5長押しでメインループへ。
    if (SW5mode == 1)
    {
      if (!digitalRead(SW5))

      {
        swcount = swcount + 1;
        if (swcount >= 50000)
        {
          break;
        }

      }
      else
      {
        swcount = 0;
      }
    }
  }
}