2015年8月28日金曜日

AVRのPin Change Interruptとチャタリング対策

タクトスイッチの入力も割り込みで処理することを考えてみた。

Timer割り込みで処理しようかと思っていたが、調べるとAVRにはPin Change Interruptという外部割り込みの仕組みがあるようだ。

PORTB、PORTC、PORTDの入力状態が変化すると、それぞれPCINT0、PCINT1、PCINT2の割り込みがかかる。

ブレッドボード図

タクトスイッチの入力をPORTDで受けて、PORTBに接続したLEDで表示する。PC0につないだ黄色のLEDはデバッグ用だ

Atmel StudioのプロジェクトはGithubで公開しました。
https://github.com/ryood/Pin_Change_Interrupt_Test

大まかな処理の流れとしては、以下のとおり。

  1. タクトスイッチの状態が変化(ユーザーがなんかボタンを押す)
  2. Pin Change割り込みが発生(PCINT2)
  3. タクトスイッチの入力状態をprevSwitchに記録して1ms後にTimer0割り込みを発生させる
  4. 1ms後にTimer0割り込みが発生したらprevSwitchと現在のタクトスイッチの入力状態を比較して、同じだったらチャタリングではないとしてLEDの表示状態を変更する。

細かいこと

トグル動作

トグルスイッチとして動作させるために、prevSwitchとは別にsdataという8bitの変数を設けてXORでトグル動作させている。
sdata ^= prevSwitch;
PINxの処理

prevSwitchと現在の入力状態(PIND)を比較するときに、一旦テンポラリ変数にPINDの状態を代入している。

これは
if (prevSwitch == ~PIND)
という書き方では比較がちゃんと動作しないため。PINxの読み取りにはウエイトをかけないとダメなせいかな?わかんねー(^q^;

チャタリングの持続時間

デバッグ用にPin Change Interruptがかかった時に黄色のLEDが点滅するようにしているので、ある程度チャタリングの発生状況が視認できるようにしている。

黄色のLEDが不安定な感じのときにも赤色LEDはそこそこトグル動作をしているが1msだと短すぎるかもしれない。

トグル動作がおかしいとイライラするので、1msよりもう少し長い時間にした方がいいかも。

起動時のLEDチェック

起動時にLEDの接続がうまくいっているか確認するためにちょっとした処理を入れてみた。
// LED Check PORTB = 0xFF;
PORTC = (1 << PC0);
for (int i = 0; i < 8; i++) {
PORTB &= ~(1 << i);
_delay_ms(100);
}
PORTC = 0x00;
LED全点灯から一つづつ消灯していくという処理。

ブレッドボードでの実験では素子数が多くなると不具合の原因がよくわからなくなりがちなのでなかなか便利です(^q^/