AVRのIOピンに押しボタンスイッチで入力する

スイッチが押されると、LEDがON/OFFとトグルする簡単なコードを書きました。

スイッチはPC5, LEDはPD4に接続してあります。
PC5はプルアップしてあり、スイッチによりGNDに短絡されると、割り込み(PCINT1_vect)が入り、PD4の出力がXOR演算でトグルされます。
初期化では、ポートのIN/OUT、1/0の設定、割り込み関係のレジスタの設定がなされます。

ポイントは、スイッチのチャタリングをソフトウェアで吸収することです。
スイッチを押したり/離したりするときのバタつきが納まるまで10ms待ちます。さらに、押している最中のバタつきを無視するために、「前は離されていて、今は押されている」というときのみボタンが押されたと判定します。押している最中のバタつきは、「前は押されていて、今は押されている」という状況になり、排除されます。
今回のように「押したらLEDをトグルする」という処理をするときにはこのような判定が必要ですが、「押している間だけLEDをON」という処理ならば、チャタリングで一瞬LEDがOFFになっても気づかないので、必要ありません。


#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

volatile int8_t last;

SIGNAL(PCINT1_vect){
  _delay_ms(10);
  int8_t now = PINC & (1 << PINC5);
  if ((last != 0) & (now == 0)){
    PORTD ^= (1 << PORTD4);
  }
  last = now;
}


int main(void){
  //button: pc5(PCINT13)
  //led: pd4
  DDRB = 0xFF;//direction 1 out, 0 in
  DDRC = 0b11011111;//in: pc5
  DDRD = 0xFF;
  PORTB = 0x00;//off
  PORTC = (1 << PORTC5);//pullup: pc5
  PORTD = 0b00010000;

  last = 1;

  ///INT.
  PCICR |= 1 << PCIE1;//allow int. for pin group 1(8-14)
  PCMSK1 |= (1 << PCINT13);//PCMSK1 = 0x30

  sei(); // allow interrupts

  while(1){
  }
  return 0;
}

割り込みを有効にする前にlast = 1;としないと、ボタンを初めて押した時にボタンが効きません。初期化と同時に代入するのでも良いです。