プロローグ
スイッチの特性によりON/OFF動作で接触部の金属が瞬間的にビヨヨーンと何度か跳ね返るため思ったように動作しないことらしい。
正式には「バウンシング」というようだが、一般的には「チャタリング」も多く使われていてYouTubeで「チャタリング」で検索すると、マウスがシングルクリックがダブルクリックになってしまうような現象がよくヒットする。
このチャタリングを解消する方法としては、回路にコンデンサを追加したりするハードウェア的な方法やプログラムで何とかするソフトウェア的な方法や、はたまたマウスの誤動作なら呉556的なものをシュッとする方法もあるようだが、ここではもちろんプログラムで何とかする方法を試すことにする。
回路
前回の内部プルアップ抵抗を使ったタクトスイッチでLEDを光らせるやつを流用する。
ソースコード
スイッチをトグル動作(押すたびにONとOFFが切り替わる)にした方がチャタリングが再現しやすそうなので、トグル動作にしてみる。
ここへきてONとOFFが逆なのがややこしくてたまらない。
#include <stdio.h>
#include <wiringPi.h>
#define LED_PIN_BCM 17
#define BUTTON_PIN_BCM 18
int main(void) {
if (wiringPiSetupPinType(WPI_PIN_BCM) == -1) {
printf("setup wiringPi failed.");
return 1;
}
// pull up
pullUpDnControl(BUTTON_PIN_BCM, PUD_UP);
int prev = HIGH; // 前回スイッチ状態 (HIGH=Not Pressed)
int current = HIGH; // 今回スイッチ状態
int alt = HIGH; // 点灯状態 (HIGH=Off)
pinMode(LED_PIN_BCM, OUTPUT);
pinMode(BUTTON_PIN_BCM, INPUT);
digitalWrite(LED_PIN_BCM, alt); // Led off
while (1) {
// 今回状態を前回状態へ
prev = current;
// スイッチ状態を取得
current = digitalRead(BUTTON_PIN_BCM);
// スイッチの切り替わりを検出 (LOW=Pressed)
if (prev == HIGH && current == LOW) {
// 点灯切り替え
alt = !alt;
printf("switch on. prev:%d current:%d Led %s.\n", prev, current, alt == LOW ? "on" : "off");
digitalWrite(LED_PIN_BCM, alt);
}
}
return 0;
}
実行
$ gcc ./toggle_swicth1.c -o toggle_swicth1 -lwiringPi
$ ./toggle_swicth1
時々、ON→OFFにしようとしてONのままになったりその逆だったりになる。
思ったほどには起きないが、一度起きると何度も続けて起きる感じがある。
チャタリング発生時は標準出力に出している switch on. ... がワンプッシュで2回出ていてOFFになったのがまたONに戻っている。
チャタリング対策
スイッチが押された時と離された時にも20ミリ秒の待機を入れる。
#include <stdio.h>
#include <wiringPi.h>
#define LED_PIN_BCM 17
#define BUTTON_PIN_BCM 18
#define DELAY_MS 20
int main(void) {
if (wiringPiSetupPinType(WPI_PIN_BCM) == -1) {
printf("setup wiringPi failed.");
return 1;
}
// pull up
pullUpDnControl(BUTTON_PIN_BCM, PUD_UP);
int prev = HIGH; // 前回スイッチ状態 (HIGH=Not Pressed)
int current = HIGH; // 今回スイッチ状態
int alt = HIGH; // 点灯状態 (HIGH=Off)
pinMode(LED_PIN_BCM, OUTPUT);
pinMode(BUTTON_PIN_BCM, INPUT);
digitalWrite(LED_PIN_BCM, alt); // Led off
while (1) {
// 今回状態を前回状態へ
prev = current;
// スイッチ状態を取得
current = digitalRead(BUTTON_PIN_BCM);
// スイッチの切り替わり(ON)を検出 (LOW=Pressed)
if (prev == HIGH && current == LOW) {
// 点灯切り替え
alt = !alt;
printf("switch on. prev:%d current:%d Led %s.\n", prev, current, alt == LOW ? "on" : "off");
digitalWrite(LED_PIN_BCM, alt);
delay(DELAY_MS);
// スイッチの切り替わり(OFF)を検出
} else if (prev == LOW && current == HIGH) {
printf("switch off. prev:%d current:%d Led %s.\n", prev, current, alt == LOW ? "on" : "off");
delay(DELAY_MS);
}
}
return 0;
}
まぁ直った。とりあえず再現しなくなった。
エピローグ
タクトスイッチにも飽きてきたけれどもうちょっとやる。
