Magicode logo
Magicode
1
5 min read

タクトスイッチのチャタリング対策をしてみた

https://cdn.apollon.ai/media/notebox/1059ee7d-f49e-4614-9ed9-24788edf3e57.jpeg

はじめに

以前 、esp32でサンプルをもとにタクトスイッチを扱ったが、チャタリング対策がされていなかった。
以前の使い方ではチャタリング対策は不要だったが、必要が出てきたので、チャタリング対策を行った。

環境

チャタリングについて

こちらの記事がわかりやすかった。
スイッチのon/offの直後に、出力が振動してしまう現象のことを チャタリング と呼ぶ。 現実のスイッチは、on/off切り替え時に一発でピタッと接点がくっつくことがなく、跳ねたり擦れたりして、接地が振動してしまうため発生してしまう。
上記の記事より

チャタリングの現象確認

オシロスコープは持っていないので、ログで現象を確認した。
プログラムはarudiono-esp32のFunctionalInterruptを使った。
以下、変更した箇所のみ。
...
	void ARDUINO_ISR_ATTR isr() {
        const unsigned long now = millis();

        diff_times[numberKeyPresses] = now - falled_time_ms;
        numberKeyPresses += 1;
        pressed = true;
        falled_time_ms = now;
	}

	void checkPressed() {
		if (pressed) {
            for(int i = 0 ; i < numberKeyPresses; i++){
                Serial.printf("diff time %u ms\n", diff_times[i]);
            }

		    Serial.printf("Button on pin %u has been pressed %u times\n", PIN, numberKeyPresses);
			pressed = false;
		}
	}

private:
    const uint8_t PIN;
    volatile uint32_t numberKeyPresses = 0;
    volatile bool pressed = false;
    volatile unsigned long falled_time_ms = 0;
    volatile unsigned long diff_times[128] = {};
};

...

// ここを変えないとreboot祭りになってしまった。
Button* button1;

void setup() {
    Serial.begin(115200);
    button1 = new Button(BUTTON1);
}

void loop() {
	button1->checkPressed();
}
これを書き込んで、4回スイッチを押した結果が下記。
4回目押した際に、チャタリングっぽい挙動がでていた。
diff time 1187 ms
Button on pin 16 has been pressed 1 times
diff time 1187 ms
diff time 951 ms
Button on pin 16 has been pressed 2 times
diff time 1187 ms
diff time 951 ms
diff time 1065 ms
Button on pin 16 has been pressed 3 times
diff time 1187 ms
diff time 951 ms
diff time 1065 ms
diff time 1106 ms
Button on pin 16 has been pressed 4 times
diff time 1187 ms
diff time 951 ms
diff time 1065 ms
diff time 1106 ms
diff time 89 ms
diff time 0 ms
diff time 0 ms
Button on pin 16 has been pressed 7 times

チャタリングの対策方法について

チャタリングの対策方法に関しては、ハードウェアによる解決とソフトウェアによる解決がある。
今回は、パーツを増やしたくなかったのでソフトウェアによる解決について説明する。

ソフトウェアによるチャタリング対策

こちらの記事 に詳しく書いてある。
単純に一定時間待つディレイ方式や、チャタリング期間より長い周期でサンプルするサンプリング方式などがあるよう。
ただ、これらのやり方は、arudiono-esp32のFunctionalInterrupt のような立下りの割り込み処理とは相性が悪そう。
そこで、今回はこちらの記事を参考にしたチャタリング対策を取り入れてみた。
....
	void ARDUINO_ISR_ATTR isr() {
        const unsigned long now = millis();
        const unsigned long diff = now - falled_time_ms;
        diff_times[numberKeyPresses] = diff;

        if(diff > CHATTERING_TIME_MS){
            numberKeyPresses += 1;
            pressed = true;
        }

        falled_time_ms = now;
	}
自分の環境ではCHATTERING_TIME_MSを150ぐらいにするとちょうどよかった。チャタリングは数100μs~数ms程度らしい※が、結構大きめにしないとダメだった。 微細な振動のチャタリングというよりは、スイッチ自体が大きく跳ねたりしてるのかな?
diff time 64765 ms
Button on pin 16 has been pressed 1 times
diff time 64765 ms
diff time 488 ms
Button on pin 16 has been pressed 2 times
diff time 64765 ms
diff time 488 ms
diff time 417 ms
Button on pin 16 has been pressed 3 times
diff time 64765 ms
diff time 488 ms
diff time 417 ms
diff time 578 ms
Button on pin 16 has been pressed 4 times

終わりに

esp32のサンプルコードに対して、チャタリング対策を入れてみた。
ディレイ方式やサンプリング方式など、一般的なやり方とサンプルコードの実装方式が合わなかったので、別のやり方をとったが、自分が使う分には問題なさそう。

Discussion

コメントにはログインが必要です。