November 10, 2014

AVR External Interrupt

Lagi khusyuk belajar µC AVR nih, dan setelah ini bakal ada new category di blog ini, yaitu AVR. Stay updated ya… :)
Post pertama tentang AVR adalah, tentang bagaimana menggunakan external interrupt. Contoh paling mudah, adalah membuat program yang akan menyalakan LED jika ada interrupt pada pin INT1. Berikut garis besar langkahnya…

  1. Setup port direction.
  2. Setup external interrupt configuration register.
  3. Definisi interrupt service router untuk vektor INT1_vect.
  4. Polesan sedikit pada function loop().
Langsung wae…
Kode program dibawah tidak menggunakan function dari Arduino seperti: pinMode(), digitalWrite(), atau attachInterrupt(), tetapi menggunakan operasi pada register secara langsung. Mengapa? Latihan membiasakan membuat kode yang ringkas dan cepat. Dan jika Anda bingung, berarti Anda harus mencari datasheet Atmega328p dan mulai membaca bagian External Interrupts.
#define pinTriggerWheel 3 // PD3
#define pinIndikator 5 // PB5

volatile boolean trigger;

void setup()
{
  /* CONFIG PORT
  *************
  Konfigurasi port dilakukan dengan manipulasi
  Direction Data Register. Port AVR ada macam-macam 
  tergantung jenis, utk Atmega328p INT1 ada di port-D3
  sedangkan onboard LED ada di port-B5.

  Maka masing-masing port harus dikonfigurasi di DDRD dan DDRB.
  */
  // PD3 pin mode input -- INT1
  // di set input, kare memang port ini akan menerima input
  // trigger dari luar, seperti push-button.
  DDRD &= ~_BV(pinTriggerWheel);

  // PB5 pin mode output -- onboard LED
  // di set output, karena program akan menyalakan LED
  // yang terpasang pada port ini
  DDRB |= _BV(pinIndikator);

  /* INTERRUPT
  ************
  Konfigurasi ext. intr.
  */
  // clear ext. intr. ctrl. reg. A
  EICRA = 0;

  // konfigurasi: interrupt akan ter-trigger saat
  // sinyal rising edge (dari 0, ke V+) terlihat di
  // pinTriggerWheel
  EICRA |= _BV(ISC11);

  // clear ext. intr. mask
  EIMSK = 0;

  // enable intr. mask untuk INT1 di-set apabila ingin
  // melakukan sesuatu jika ada trigger INT1
  EIMSK |= _BV(INT1);

  // flag bahwa ada trigger yang terjadi
  trigger = false;
}

void loop()
{
  if(trigger)
  {
    // matikan LED
    PORTB &= ~_BV(pinIndikator);

    // clear software flag
    trigger = false;
  }
  // nunggu 10 ms
  delay(10);
}

/* Interrupt Service Routine
   Yang dieksekusi saat INT1 ter-trigger
***************************************/
ISR(INT1_vect)
{
  // set software flag
  trigger = true;

  // menyalakan LED
  PORTB |= _BV(pinIndikator);
}