Mengenal fungsi interrupt() pada Arduino

Hallo, selamat datang. mungkin suatu saat kita memerlukan sebuah algoritma, dimana ketika mikrokontroller sedang mengeksekusi sebuah program, kita perlu menjeda program yang sedang berjalan sesegera mungkin kemudian mengeksekusi program yang lain agar kita bisa memberikan respon terhadap suatu input dengan cepat dan efektif. hal tersebut bisa dilakukan dengan menggunakan fasilitas pada pemrograman arduino yang disebut dengan interrupt.

Bayangkan kita sedang mengendarai mobil, kita menjalankan mobil dengan menekan gas, mengganti gigi, mengendalikan setir mobil dan mengerem, kita ibaratkan kegiatan-kegiatan itu adalah program utama yang sedang berjalan, lalu tiba-tiba ada mobil yang menabrak dari depan, akibatnya mobil kita akan melakukan respon cepat dengan mengeluarkan airbag, aksi mobil mengeluarkan airbag bisa diibaratkan sebagai program interrupt.

Interrupt akan menghentikan eksekusi program utama ketika ada kejadian yang mentriggernya, pada arduino UNO hanya ada 2 pin yang bisa dijadikan input untuk mentrigger interrupt yaitu pin 2 dan 3. Interrupt digunakan diberbagai kasus seperti :

  • Mendeteksi perubahan kondisi pin (Contoh saat kita menggunakan rotary encoder dan push button)
  • Watchdog timer (Contoh, Jika tidak ada respon dalam 8 detik, aktifkan interrupt)
  • Timer Interrupt (Contoh, Set nilai timer, jika hitungan timer sampai ke set point, interrupt akan aktif)
  • Transfer data SPI
  • Transfer data I2C
  • Transfer data USART
  • Konversi Analog ke Digital (ADC)
  • Set EEPROM
  • Set Memory Flash

Karena materi interrupt itu cukup advance dan kompleks (karena harus melakukan programming di register level) saya akan membatasi contoh penggunaan interrupt pada 3 kasus saja, yaitu External interrupt, Pin change interrupt, dan watchdog timer. Sekarang, ayo kita bahas fungsi-fungsi untuk menggunakan interrupt() yang umum digunakan pada pemrograman arduino :

digitalPinToInterrupt()

Fungsi digitalPinToInterrupt() berfungsi untuk mendeklarasikan sebuah GPIO arduino untuk dijadikan sebagai input dari program interrupt, hanya pin yang support interrupt saja yang bisa di deklarasikan dengan fungsi ini dan ini tergantung board yang digunakan, informasi lengkapnya bisa kita lihat di web ini. fungsi digitalPinToInterrupt dipanggil menggunakan sintax ini:

				
					digitalPinToInterrupt(pin)
				
			
Paramenter:
  • pin   : nomor pin yang dijadikan sebagai pin interrupt, biasanya pin di deklarasikan pada sebuah variabel kemudian nama variabelnya dipanggil pada parameter syntax

Jika pin yang tidak support interrupt maka fungsi akan memberikan nilai balik -1, dan interrupt tidak akan berfungsi, jadi selalu perhatikan kompatibilitas board apakan pin yang kita gunakan support interrupt atau tidak.

attachInterrupt()

Fungsi attachInterrupt() digunakan untuk mengatur external interrupt pada pin yang dideklarasikan oleh fungsi digitalPinToInterrupt() . berikut syntaxnya : 

				
					attachInterrupt(digitalPinToInterrupt(pin), ISR, mode);
				
			

Parameter :

  • pin    = nama variabel yang digunakan sebagai pin interrupt
  • ISR   = Interrupt Servive Routine, ini adalah sebuah fungsi yang didalamnya ada program interrupt. jadi ketika ada trigger pada interrupt, maka program utama akan langsung di jeda dan program yang ada pada ISR akan dieksekusi.
  • mode  = Kondisi yang kita tetapkan untuk memicu interrupt, ada 4 mode yang bisa kita gunakan :

              LOW  : Trigger Interrupt ketika kondisi pin LOW

              RISING  : Trigger Interrupt ketika terjadi perubahan kondisi pin dari LOW ke HIGH

              FALLING  : Trigger Interrupt ketika terjadi perubahan kondisi pin dari HIGH ke LOW

              CHANGE  : Trigger Interrupt ketika terjadi perubahan kondisi pin

 

detachInterrupt()

Fungsi detachInterrupt() berfungsi untuk menonaktifkan interrupt pada pin tertentu. berikut syntaxnya:

				
					detachInterrupt(digitalPinToInterrupt(pin))
				
			

Parameter pin disini adalah nomor pin yang dijadikan parameter pada fungsi attachInterrupt() yang ingin kita non-aktifkan.

noInterrupts() dan Interrupts()

Fungsi noInterrupts() berfungsi untuk menonaktifkan semua interrupt yang aktif pada program, sedangkan fungsi Interrupts() berfungsi mengaktifkan kembali interrupts yang sudah dinonaktifkan dengan fungsi noInterrupts(). fungsi ini biasa digunakan pada blok program kritikal yang perlu dieksekusi tanpa gangguan, urutannya, kita panggil dulu fungsi noInterrupts() kemudian jalan kan blok program kritikal kemudian aktifkan kembali interrupt dengan fungsi Interrupts(). berikut contoh program nya :

				
					void setup() {}

void loop() {
  noInterrupts();
  // critical, time-sensitive code here
  interrupts();
  // other code here
}
				
			

Perbedaan antara fungsi noInterrupts() dan detachInterrupt() adalah, fungsi noInterrupts() akan menonaktifkan semua interrupt dalam program, sedangkan fungsi detachInterrupt() hanya menonaktifkan interrupt pada pin yang kita tentukan saja.

ISR (Interrupt Service Routine)

ISR adalah fungsi khusus yang dieksekusi sebagai respon terhadap sebuah kejadian yang mentrigger interrupt, sederhananya, ISR adalah program yang ingin kita jalankan ketika terjadi interrupt. Karena program pada ISR harus dieksekusi dengan cepat maka ada beberapa hal yang perlu diperhatikan saat membuat program ISR :

  • Buat program yang singkat, seperti hanya mengubah kondisi logika, mengubah nilai variabel dll
  • Hindari penggunaan fungsi delay()
  • Hindari penggunaan fungsi serial
  • Jika program ISR isinya adalah merubah kondisi pin atau merubah nilai variabel, maka gunakan volatile pada variabel yang diubah pada ISR
  • Hindari mengaktifkan dan menonaktifkan interrupt didalam ISR

Sekarang kita bahas dulu kenapa kita perlu menggunakan volatite pada variabel yang nilainya akan diubah didalam ISR ?. Alasannya, karena volatile memungkinkan kita untuk mengakses variabel sacara global, dengan begitu, kita bisa mengubah nilai variabel yang dideklarasi pada program utama melalui program ISR. tanpa volatile, nilai variabel yang kita ubah didalam program ISR tidak akan berubah pada program utama, sehingga program interrupt menjadi tidak berfungsi.

Pada prosessor ATmega328p yang mana digunakan pada arduino UNO, ada 26 interrupt yang bisa digunakan, 26 interrupt ini disebut vektor interrupt, list dibawah sudah diurutkan berdasarkan prioritas, maksudnya jika ada 2 interrupt yang ditrigger bersamaan (misal INT0_vect dan WDT_vect)  yang pertama dijalankan adalah INT0_vect karena prioritasnya lebih tinggi. 

				
					1  Reset 
 2  External Interrupt Request 0  (pin D2)          (INT0_vect)
 3  External Interrupt Request 1  (pin D3)          (INT1_vect)
 4  Pin Change Interrupt Request 0 (pins D8 to D13) (PCINT0_vect)
 5  Pin Change Interrupt Request 1 (pins A0 to A5)  (PCINT1_vect)
 6  Pin Change Interrupt Request 2 (pins D0 to D7)  (PCINT2_vect)
 7  Watchdog Time-out Interrupt                     (WDT_vect)
 8  Timer/Counter2 Compare Match A                  (TIMER2_COMPA_vect)
 9  Timer/Counter2 Compare Match B                  (TIMER2_COMPB_vect)
10  Timer/Counter2 Overflow                         (TIMER2_OVF_vect)
11  Timer/Counter1 Capture Event                    (TIMER1_CAPT_vect)
12  Timer/Counter1 Compare Match A                  (TIMER1_COMPA_vect)
13  Timer/Counter1 Compare Match B                  (TIMER1_COMPB_vect)
14  Timer/Counter1 Overflow                         (TIMER1_OVF_vect)
15  Timer/Counter0 Compare Match A                  (TIMER0_COMPA_vect)
16  Timer/Counter0 Compare Match B                  (TIMER0_COMPB_vect)
17  Timer/Counter0 Overflow                         (TIMER0_OVF_vect)
18  SPI Serial Transfer Complete                    (SPI_STC_vect)
19  USART Rx Complete                               (USART_RX_vect)
20  USART, Data Register Empty                      (USART_UDRE_vect)
21  USART, Tx Complete                              (USART_TX_vect)
22  ADC Conversion Complete                         (ADC_vect)
23  EEPROM Ready                                    (EE_READY_vect)
24  Analog Comparator                               (ANALOG_COMP_vect)
25  2-wire Serial Interface  (I2C)                  (TWI_vect)
26  Store Program Memory Ready                      (SPM_READY_vect)
				
			

Contoh program External Interrupt Request

Project ini membutuhkan 1 LED, 2 resistor dan 1 push button. Algoritma nya, LED akan kita buat agar terus menyala kemudian ketika push button ditekan akan mengaktifkan interrupt, dan program interrupt akan mematikan LED. coba buat rangakaian dibawah ini :

				
					//Contoh External Interrupt - purwarupa3d

const int ledPin = 13;    // Pin LED
const int buttonPin = 2;  // Pin tombol

volatile boolean ledState = true; // Status LED (menyala = true, mati = false)

void ledOff() {
  ledState = false;          // membuat status LED menjadi false
  digitalWrite(ledPin, ledState); // Mengatur LED sesuai status baru
}

void setup() {
  pinMode(ledPin, OUTPUT);    // Mengatur pin LED sebagai output
  pinMode(buttonPin, INPUT); // Mengatur pin tombol sebagai input
  
  attachInterrupt(digitalPinToInterrupt(buttonPin), ledOff, LOW); // Mengatur interrupt pada saat pin tombol LOW
}

void loop() {
  while(ledState = true){   //Ketika nilai variabel ledState = true, jalankan 
  digitalWrite(ledPin, ledState); // Menyalakan LED
  }
}
				
			

Program ini masih bisa disimulasikan pada wokwi, jika ingin mencoba silakan klik disini. Coba upload dan jalankan program. begini algoritma yang akan terjadi :

  • Awalnya LED akan terus menyala.
  • Ketika tombol ditekan, program interrupt akan aktif karena kondisi pada baris program 17 terpenuhi (kondisi sinyal pada buttonPin = LOW)
  • program interrupt akan dieksekusi (mengubah nilai variabel ledState menjadi false)
  • program interrupt akan mematikan LED
  • LED akan terus mati selama tombol ditekan

Contoh program Pin Change Interrupt Request

Project ini membutuhkan 2 push button, 1 LED dan 3 Resistor. buat rangkaian seperti gambar dibawah ini:

				
					//pin change interrupt - purwarupa3d

#include <avr/sleep.h>

#define LED1 13
#define LED2 8
#define BUTTON1 5
#define BUTTON2 9

volatile bool buttonPressed = false;  // Variabel volatile untuk menandai interrupt

// ISR untuk pin change interrupt pada PCINT2
ISR(PCINT2_vect) {
  if (digitalRead(BUTTON1) == LOW) {
    buttonPressed = true;
  }
}

void setup() {
  pinMode(LED1, OUTPUT);   // Mengatur LED1 sebagai output
  pinMode(LED2, OUTPUT);   // Mengatur LED2 sebagai output
  pinMode(BUTTON1, INPUT);  // Mengatur tombol 1 sebagai input 
  pinMode(BUTTON2, INPUT);  // Mengatur tombol 2 sebagai input

  // Mengaktifkan pin change interrupt pada pin BUTTON
  // pin change interrupt (untuk pin D5)
  PCMSK2 |= bit (PCINT21);  // register set interrupt pin 5 
  PCIFR  |= bit (PCIF2);   // clear any outstanding interrupts
  PCICR  |= bit (PCIE2);   // enable pin change interrupts for D0 to D7
  //sei();  // Mengaktifkan interrupt global
}

void loop() {
  if (!buttonPressed) {
    // Blinking LED1 jika tombol tidak ditekan
    digitalWrite(LED2, LOW);
    digitalWrite(LED1, HIGH);
    delay(500);
    digitalWrite(LED1, LOW);
    delay(500);
  } else {
    // Menyalakan LED2 dan mematikan LED1 jika tombol ditekan
    digitalWrite(LED1, LOW);
    digitalWrite(LED2, HIGH);
  }

  if (digitalRead(BUTTON2) == LOW) {
    buttonPressed = false;
  }
}
				
			

Program diatas bisa disimulasikan di wokwi, klik disini jika ingin mencoba. algoritma yang terjadi pada program diatas adalah :

  • Ketika eksekusi, L-LED pada arduino akan blinking setiap 0,5 detik, karena control structure if bernilai true
  • Jika button 1 ditekan (button kiri pada wokwi) akan mengktifkan interrupt
  • Program ISR akan dieksekusi, didalamnya berisi perintah untuk mengubah nilai variabel buttonPressed menjadi false saat kondisi pin button1 = LOW
  • Ini mengakibatkan L-Led berhenti berkedip (blink) dan mengeksekusi baris program else, yaitu mematikan L-LED dan menyalakan LED 2
  • Namun, jika button 2 ditekan (button kanan pada wokwi), maka dia akan mengembalikan nilai variabel buttonPressed menjadi false, sehingga akan mengeksekusi baris program statement if.

Pada project diatas, kita memakai vektor interrupt PCINT2_vect,  artinya yang menjadi trigger interrupt adalah perubahan dari kondisi sinyal pada salah satu pin antara pin D0 sampai D7. vektor pin change interrupt dikelompokan menjadi 3 bagian :

  • PCINT0_vect  —> pin change interrupt untuk pin D8 – D13
  • PCINT1_vect  —> pin change interrupt untuk pin A0 – A5
  • PCINT2_vect —-> pin change interrupt untuk pin D0 – D7
Karena kita menggunakan pin D5 untuk mentrigger interrupt, maka vektor ISR yang digunakan adalah PCINT2_vect.

selanjutnya perhatikan baris program 27,28,29. baris program tersebut adalah konfigurasi spesifik pin yang akan kita gunakan untuk mentrigger interrupt, format konfigurasi nya mengikuti daftar dibawah ini :

				
					D0	  PCINT16 (PCMSK2 / PCIF2 / PCIE2)
D1	  PCINT17 (PCMSK2 / PCIF2 / PCIE2)
D2	  PCINT18 (PCMSK2 / PCIF2 / PCIE2)
D3	  PCINT19 (PCMSK2 / PCIF2 / PCIE2)
D4	  PCINT20 (PCMSK2 / PCIF2 / PCIE2)
D5	  PCINT21 (PCMSK2 / PCIF2 / PCIE2)
D6	  PCINT22 (PCMSK2 / PCIF2 / PCIE2)
D7	  PCINT23 (PCMSK2 / PCIF2 / PCIE2)
D8	  PCINT0  (PCMSK0 / PCIF0 / PCIE0)
D9	  PCINT1  (PCMSK0 / PCIF0 / PCIE0)
D10	  PCINT2  (PCMSK0 / PCIF0 / PCIE0)
D11	  PCINT3  (PCMSK0 / PCIF0 / PCIE0)
D12	  PCINT4  (PCMSK0 / PCIF0 / PCIE0)
D13	  PCINT5  (PCMSK0 / PCIF0 / PCIE0)
A0	  PCINT8  (PCMSK1 / PCIF1 / PCIE1)
A1	  PCINT9  (PCMSK1 / PCIF1 / PCIE1)
A2	  PCINT10 (PCMSK1 / PCIF1 / PCIE1)
A3	  PCINT11 (PCMSK1 / PCIF1 / PCIE1)
A4	  PCINT12 (PCMSK1 / PCIF1 / PCIE1)
A5	  PCINT13 (PCMSK1 / PCIF1 / PCIE1)
				
			

Misal kita ingin interrupt di trigger oleh pin D12, maka gunakan interrupt vektor PCINT0_vect. kemudian gunakan konfigurasi dibawah ini:

				
					 PCMSK0 |= bit (PCINT4);  
  PCIFR  |= bit (PCIF0); 
  PCICR  |= bit (PCIE0); 
				
			

Reset Arduino Otomatis dengan Watchdog Interrupt

Pada contoh project kali ini kita akan menggunakan watchdog interrupt, interrupt ini biasa digunakan untuk mengawasi jalannya program. misal, jika program terlalu lama memproses data, atau stuck pada baris program tertentu, interrupt akan aktif untuk melakukan antisipasi. salah satu kegunaan watchdog interrupt adalah kita bisa melakukan reset otomatis.  Saat terjadi stuck microkontroller, watchdog interrupt akan mengaktifkan timer untuk menghitung lama waktu tunggu yang kita inginkan, jika sudah mencapai batas waktu tunggu, watchdog interrupt akan menginisiasi sistem untuk melakukan restart secara otomatis. sekarang kita coba praktekan, gunakan rangkaian yang sama dengan project External Interrupt Request. 

				
					/*Reset Otomatis dengan watchdog interrupt - purwarupa3d*/
#include <avr/wdt.h>

byte LED = 13;
byte BUTTON = 2;

void interupsi(){
  wdt_disable();
}

void setup() {

pinMode (LED,OUTPUT);
pinMode (BUTTON, INPUT);

Serial.begin(9600);

digitalWrite (LED, HIGH);
delay(100);
digitalWrite (LED,LOW);
delay(100);
digitalWrite (LED, HIGH);
delay(100);
digitalWrite (LED,LOW);
delay(100);
}

void loop() {
wdt_enable(WDTO_8S);
Serial.println("Start");
attachInterrupt (digitalPinToInterrupt(BUTTON),interupsi,LOW);
delay(1000);
wdt_reset();
delay(10000);
Serial.println("Loop Berlanjut");
delay(500);
}
				
			

Program diatas bisa disimulasikan disini, upload program dan buka serial monitor. Algoritma yang terjadi pada program diatas yaitu :

  • Saat program selesai di upload, LED akan berkedip 2 kali 
  • Pada serial monitor akan muncul text “Start”, ini menandakan loop sudah dieksekusi
  • Biarkan program berjalan lebih dari 8 detik
  • Akan terlihat arduino akan reset secara otomatis, ditandai LED berkedip 2 kali, itu artinya void setup dieksekusi
  • Namun jika kita menekan tombol, maka arduino tidak akan reset otomatis dan baris program loop akan dilanjutkan, ini ditandai dengan muncul text “Loop Berlanjut” pada serial monitor.

Sekian tutorial tentang interrupt kali ini, Semoga bermanfaat.

Tinggalkan komentar