M5Stackを学ぶ 番外編(ボタンとチャタリング)

2024/07/05に公開

はじめに

2回目にして早くも番外編ですが、以前今使用しているM5Stackを使用していた時に、ボタンにチャタリングのような不具合が発生し、ボタンが埋まってしまったような感じで、大量にのLINEが送信されてしまったことがあったので今回は各ボタンの動作確認と、チャタリングしているのかをコードを書いて検証していきたいと思います。

1,ボタンの確認

私が使用しているM5Stack Basicはボタンが3つあり、各Aボタン、Bボタン、Cボタンとなっています。

確認方法としては、ボタンを押した際に画面が切り替われば、それぞれのボタンが正常に作動していることとしようと思います。コードはこちら

#include <M5Stack.h>

enum Screen { SCREEN_A, SCREEN_B, SCREEN_C };
Screen currentScreen = SCREEN_A;

void displayCurrentScreen(void);

void setup() {
  M5.begin();
  displayCurrentScreen();
}

void loop() {
  M5.update(); // ボタンの状態を更新

  if (M5.BtnA.wasPressed()) {
    currentScreen = SCREEN_A;
    displayCurrentScreen();
  }
  if (M5.BtnB.wasPressed()) {
    currentScreen = SCREEN_B;
    displayCurrentScreen();
  }
  if (M5.BtnC.wasPressed()) {
    currentScreen = SCREEN_C;
    displayCurrentScreen();
  }
}

void displayCurrentScreen() {
  M5.Lcd.clear();
  switch (currentScreen) {
    case SCREEN_A:
      M5.Lcd.setCursor(0, 20);
      M5.Lcd.setTextSize(3);
      M5.Lcd.println("This is Screen A");
      break;
    case SCREEN_B:
      M5.Lcd.setCursor(0, 20);
        M5.Lcd.setTextSize(3);
      M5.Lcd.println("This is Screen B");
      break;
    case SCREEN_C:
      M5.Lcd.setCursor(0, 20);
      M5.Lcd.setTextSize(3);
      M5.Lcd.println("This is Screen C");
      break;
  }
}

各ボタンを押したときにそれぞれAボタンなら画面に「This is Screen A」、Bボタンなら「This is Screen B」、Cボタンも同様の動きをするようなコードになっています。ちなみに、テキストサイズは色々試してみた結果setTextSize(3)くらいがちょうどいい感じになりました。

以下が結果です。

Aボタン

Bボタン

Cボタン

ボタンの確認はこれで問題なさそうですね。

2,チャタリングの確認

チャタリングは面倒ですが、組み込みではとても大切な部分なので、確認や何かを作る際にチャタリング吸収などの対策をするのとしないのとでは、システムとしての安心感がまるで違います。頑張りましょう。

今回は、ボタンの状態変化を検知し、短時間でのオン・オフの繰り返しがあればチャタリングとみなしてカウントするやり方を取ってテストしていこうと思います。

コードはこちら

#include <M5Stack.h>

// ボタンの状態
bool lastBtnA = false;
bool lastBtnB = false;
bool lastBtnC = false;

// チャタリングカウンタ
int chatterCountA = 0;
int chatterCountB = 0;
int chatterCountC = 0;

// チャタリング検出のための閾値(ミリ秒)
unsigned long chatterThreshold = 50; 

// ボタンの状態変化を記録するためのタイムスタンプ
unsigned long lastChangeTimeA = 0;
unsigned long lastChangeTimeB = 0;
unsigned long lastChangeTimeC = 0;

void setup() {
  M5.begin();
  M5.Lcd.println("Button Chattering Test");
  M5.Lcd.setCursor(0, 20);
  M5.Lcd.setTextSize(3);
  M5.Lcd.printf("Chatter Count A: %d\n\n", chatterCountA);
  M5.Lcd.printf("Chatter Count B: %d\n\n", chatterCountB);
  M5.Lcd.printf("Chatter Count C: %d\n\n", chatterCountC);
}

void loop() {
  M5.update(); // ボタンの状態を更新

  // ボタンAのチャタリング検出
  if (M5.BtnA.isPressed() != lastBtnA) {
    unsigned long currentTime = millis();
    if (currentTime - lastChangeTimeA < chatterThreshold) {
      chatterCountA++;
      M5.Lcd.setCursor(0, 40);
      M5.Lcd.printf("Chatter Count A: %d\n", chatterCountA);
    }
    lastChangeTimeA = currentTime;
    lastBtnA = M5.BtnA.isPressed();
  }

  // ボタンBのチャタリング検出
  if (M5.BtnB.isPressed() != lastBtnB) {
    unsigned long currentTime = millis();
    if (currentTime - lastChangeTimeB < chatterThreshold) {
      chatterCountB++;
      M5.Lcd.setCursor(0, 60);
      M5.Lcd.printf("Chatter Count B: %d\n", chatterCountB);
    }
    lastChangeTimeB = currentTime;
    lastBtnB = M5.BtnB.isPressed();
  }

  // ボタンCのチャタリング検出
  if (M5.BtnC.isPressed() != lastBtnC) {
    unsigned long currentTime = millis();
    if (currentTime - lastChangeTimeC < chatterThreshold) {
      chatterCountC++;
      M5.Lcd.setCursor(0, 80);
      M5.Lcd.printf("Chatter Count C: %d\n", chatterCountC);
    }
    lastChangeTimeC = currentTime;
    lastBtnC = M5.BtnC.isPressed();
  }

  // 少しの待ち時間を入れる(ディスプレイの更新頻度を減らすため)
  delay(10);
}

オシロスコープとかはないので、細かいことはできませんが、ボタンの動作確認(前に起こっていたのはボタンが埋まって更新され続けるような不具合)程度ならこれで十分だと考えました。結果は以下になります。

連打してみましたが、問題ありませんでした。ちなみにちょっと頑張ると、、、

このように数を増やせます。正常に動いていそうですね。(テキストの重複には目を瞑る)

これでボタン関連の確認は大丈夫でしょう!

3,おわりに

2回目から番外編という形でマイコンのボタンテストを行いましたが、これでも全然雑というか色々足りていないので、本格的にやりたい方はオシロスコープなどを使用して、検証することをお勧めします。

こんな感じに脱線することが多々ありますが、温かい目で読んでいただけると嬉しく思います。

では、また次回お会いしましょう。お疲れさまでした。

Discussion