Dalam banyak proyek berbasis ESP8266, sering kali perangkat perlu menjalankan program utama sambil tetap mampu merespons suatu peristiwa secara cepat dan efisien. Untuk memenuhi kebutuhan tersebut, mekanisme interrupt menjadi solusi yang umum digunakan karena memungkinkan sistem bereaksi segera tanpa harus menunggu loop utama selesai. Interrupt pada ESP8266 sendiri terbagi menjadi dua jenis utama, yaitu interrupt perangkat keras yang dipicu oleh kejadian eksternal seperti perubahan logika pada pin GPIO, serta interrupt perangkat lunak yang dipicu oleh instruksi internal seperti timer. Dengan memanfaatkan interrupt, Anda dapat membuat ESP8266 tetap responsif meskipun sedang menjalankan proses lain di latar belakang. Pada konteks penggunaan GPIO, ESP8266 menyediakan kemampuan untuk mendeteksi perubahan level logika pada hampir semua pin, sehingga memudahkan Anda memantau tombol, sensor, atau sinyal eksternal lainnya.
Untuk mengimplementasikannya di Arduino IDE, fungsi attachInterrupt() digunakan sebagai konfigurasi awal yang menentukan pin, rutin layanan interrupt (ISR), dan mode pemicu yang diinginkan. Setiap ISR dirancang untuk bekerja secepat mungkin karena ia menghentikan jalannya program utama sementara fungsinya dijalankan. Dengan memahami cara kerja interrupt pada ESP8266, Anda dapat membangun sistem yang lebih efisien, responsif, dan mampu menangani peristiwa penting secara real-time.
Dalam banyak aplikasi, diperlukan agar ESP8266 dapat menjalankan fungsi utamanya sambil tetap memantau suatu kondisi atau peristiwa secara paralel. Salah satu metode yang umum digunakan untuk memenuhi kebutuhan tersebut adalah penerapan interrupt. Secara umum, terdapat dua kategori interrupt:
1. Interrupt perangkat keras – Dipicu oleh kejadian eksternal, seperti perubahan pada pin GPIO, misalnya ketika sebuah tombol ditekan.
2. Interrupt perangkat lunak – Dipicu oleh instruksi yang berasal dari perangkat lunak, seperti interrupt dari timer sederhana atau watchdog timer yang aktif ketika waktu penghitungannya berakhir.
Interrupt GPIO ESP8266
Anda dapat mengonfigurasi ESP8266 untuk menghasilkan interrupt ketika pin GPIO mengubah level logikanya. Semua pin GPIO pada papan ESP8266 dapat dikonfigurasi untuk bertindak sebagai input permintaan interrupt, kecuali GPIO16.
Memasang Interrupt ke Pin GPIO
Pada Arduino IDE, konfigurasi interrupt untuk masing-masing pin dilakukan menggunakan fungsi `attachInterrupt()`. Fungsi ini memiliki sintaks dasar sebagai berikut.
attachInterrupt(GPIOPin, ISR, Mode);
Fungsi ini menerima tiga parameter utama, yaitu:
1. GPIOPin – Menentukan pin GPIO yang akan digunakan sebagai sumber interrupt, sehingga ESP8266 mengetahui pin mana yang harus dipantau.
2. ISR (Interrupt Service Routine) – Nama fungsi yang akan dijalankan secara otomatis ketika interrupt terdeteksi.
3. Mode – Menentukan kondisi pemicu interrupt. Terdapat lima konstanta bawaan yang dapat digunakan, yaitu:
- LOW: Interrupt dipicu ketika status pin berada pada level LOW.
- HIGH: Interrupt dipicu ketika status pin berada pada level HIGH.
- CHANGE: Interrupt dipicu pada setiap perubahan nilai pin, baik dari HIGH ke LOW maupun LOW ke HIGH.
- FALLING: Interrupt dipicu ketika pin berubah dari HIGH ke LOW.
- RISING: Interrupt dipicu ketika pin berubah dari LOW ke HIGH.
Interrupt Service Routine
Interrupt Service Routine (ISR) adalah fungsi yang dipanggil setiap kali terjadi interrupt pada pin GPIO. Sintaksnya seperti di bawah ini:
void ICACHE_RAM_ATTR ISR() {
Statements;
}
ISR dalam ESP8266 adalah jenis fungsi khusus yang memiliki beberapa aturan unik yang tidak dimiliki sebagian besar fungsi lainnya.
1. ISR tidak boleh memiliki parameter apa pun, dan tidak boleh mengembalikan apa pun.
2. ISR harus sesingkat dan secepat mungkin karena memblokir eksekusi program normal.
3. ISR harus memiliki atribut ICACHE_RAM_ATTR, sesuai dengan dokumentasi ESP8266.
Baca juga: Referensi Lengkap Pinout ESP8266 NodeMCU: Gambar dan Fungsi Tiap Pin
Apa itu ICACHE_RAM_ATTR?
Atribut `ICACHE_RAM_ATTR` digunakan untuk menandai suatu fungsi agar hasil kompilasinya ditempatkan di Internal RAM (IRAM) milik ESP8266. Tanpa atribut ini, kode secara default akan disimpan di memori Flash, yang memiliki kecepatan akses jauh lebih lambat dibandingkan RAM internal.
Pada kasus Interrupt Service Routine (ISR), eksekusi yang cepat dan responsif sangat penting. Jika ISR harus diambil terlebih dahulu dari Flash, prosesnya akan mengalami penundaan, sehingga dapat menyebabkan gangguan pada pemrosesan interrupt. Oleh karena itu, penempatan ISR di IRAM menjadi sangat krusial untuk menjaga performa sistem.
Pemasangan Perangkat Keras
Sambungkan push button ke pin GPIO12 (D6) pada ESP8266. Untuk pin ini, Anda tidak perlu menambahkan resistor pull-up eksternal karena pull-up internal akan diaktifkan melalui kode.
Contoh Kode: Interrupt Sederhana
Contoh sketsa berikut memperlihatkan bagaimana interrupt digunakan serta cara yang tepat untuk menulis rutinitas layanan interrupt. Program ini mengawasi GPIO12 (D6) untuk mendeteksi sinyal FALLING, yaitu perubahan dari logika HIGH ke LOW saat tombol ditekan. Ketika kondisi tersebut terdeteksi, fungsi isr akan dipicu. Di dalam fungsi tersebut, program menghitung jumlah penekanan tombol.
struct Button {
const uint8_t PIN;
uint32_t numberKeyPresses;
bool pressed;
};
Button button1 = {D6, 0, false};
void ICACHE_RAM_ATTR isr() {
button1.numberKeyPresses++;
button1.pressed = true;
}
void setup() {
Serial.begin(115200);
pinMode(button1.PIN, INPUT_PULLUP);
attachInterrupt(button1.PIN, isr, FALLING);
}
void loop() {
if (button1.pressed) {
Serial.printf("Button has been pressed %u times\n", button1.numberKeyPresses);
button1.pressed = false;
}
}
Setelah sketsa berhasil diunggah, buka Serial Monitor dengan baud rate 115200. Setiap kali tombol ditekan, Anda akan melihat output seperti berikut.
Penjelasan Kode
Pada bagian awal sketsa, Anda mendefinisikan sebuah struktur bernama Tombol. Struktur ini berisi tiga elemen, yaitu nomor pin, jumlah penekanan tombol, dan status tekanannya. Sebagai catatan, struktur merupakan wadah yang mengelompokkan beberapa variabel dengan tipe berbeda namun masih berhubungan secara logis dalam satu nama.
struct Button {
const uint8_t PIN;
uint32_t numberKeyPresses;
bool pressed;
};
Setelah itu, buat sebuah instance dari struktur Tombol dan memberikan nilai awal, yaitu menetapkan pin D6 sebagai pin yang digunakan, mengatur jumlah penekanan tombol menjadi 0, serta menetapkan status tekanannya ke kondisi false sebagai nilai awal.
Button button1 = {D6, 0, false};
Potongan kode berikut berfungsi sebagai rutin layanan interrupt. Seperti dijelaskan sebelumnya, setiap ISR pada ESP8266 perlu diberi atribut ICACHE_RAM_ATTR. Di dalam ISR tersebut, kita hanya menambah nilai KeyPresses sebanyak 1 dan mengubah status tombol menjadi true untuk menandai bahwa tombol telah ditekan.
void ICACHE_RAM_ATTR isr() {
button1.numberKeyPresses++;
button1.pressed = true;
}
Pada bagian setup, dimulai dengan mengaktifkan komunikasi serial dengan komputer, kemudian menyalakan pull-up internal pada pin GPIO D6. Setelah itu, konfigurasikan ESP8266 agar memantau pin D6 dan memicu rutin layanan interrupt isr setiap kali terjadi perubahan dari logika HIGH ke LOW, yaitu pada tepi FALLING.
void setup() {
Serial.begin(115200);
pinMode(button1.PIN, INPUT_PULLUP);
attachInterrupt(button1.PIN, isr, FALLING);
}
Di dalam fungsi loop, program hanya perlu mengecek apakah tombol terdeteksi ditekan. Jika iya, jumlah total penekanan akan dicetak, kemudian status tombol dikembalikan menjadi false agar interrupt berikutnya tetap dapat diproses.
void loop() {
if (button1.pressed) {
Serial.printf("Button has been pressed %u times\n", button1.numberKeyPresses);
button1.pressed = false;
}
}
Mengelola Masalah Switch Bounce
Salah satu kendala yang sering muncul saat menggunakan interrupt adalah pemicu yang terjadi berulang untuk satu kejadian yang sama. Jika Anda memperhatikan output serial pada contoh sebelumnya, Anda akan melihat bahwa meskipun tombol ditekan satu kali, penghitung dapat bertambah beberapa kali.
Untuk memahami sumber masalahnya, Anda perlu melihat bentuk sinyalnya. Saat Anda memonitor tegangan pada pin menggunakan signal analyzer ketika tombol ditekan, Anda akan melihat pola sinyal seperti ini:
Meskipun secara kasatmata tombol tampak melakukan satu kali kontak, mekanisme internalnya menghasilkan beberapa transisi cepat sebelum mencapai kondisi stabil. Transisi berulang inilah yang memicu beberapa interrupt secara beruntun. Perilaku ini merupakan karakteristik fisik dari sakelar mekanis dan dikenal sebagai switch bouncing, yaitu fenomena di mana kontak listrik berosilasi beberapa kali sebelum menetap, serupa dengan bola yang memantul berulang kali sebelum berhenti. Waktu yang dibutuhkan hingga sinyal mencapai kestabilan sangat singkat bagi manusia, tetapi bagi ESP8266 durasi tersebut tergolong panjang. Dalam rentang mikrodetik ini, mikrokontroler mampu mengeksekusi banyak instruksi, sehingga setiap fluktuasi kecil pada sinyal teridentifikasi sebagai interrupt terpisah. Proses untuk menyingkirkan efek pantulan ini dikenal sebagai debouncing. Ada dua metode yang bisa digunakan:
- Debouncing perangkat keras: menambahkan rangkaian RC untuk memperhalus perubahan sinyal.
- Debouncing perangkat lunak: mengabaikan interrupt lain selama jangka waktu tertentu setelah interrupt pertama terjadi.
Contoh Kode: Debouncing Interrupt
Pada bagian ini, sketsa sebelumnya ditulis ulang untuk menunjukkan cara menerapkan debouncing interrupt melalui pemrograman. Dengan pendekatan ini, ISR hanya dijalankan satu kali untuk setiap penekanan tombol, bukan berulang kali seperti pada contoh sebelumnya. Bagian kode yang mengalami perubahan ditandai dengan warna hijau.
struct Button {
const uint8_t PIN;
uint32_t numberKeyPresses;
bool pressed;
};
Button button1 = {D6, 0, false};
//variables to keep track of the timing of recent interrupts
unsigned long button_time = 0;
unsigned long last_button_time = 0;
void ICACHE_RAM_ATTR isr() {
button_time = millis();
if (button_time - last_button_time > 250)
{
button1.numberKeyPresses++;
button1.pressed = true;
last_button_time = button_time;
}
}
void setup() {
Serial.begin(115200);
pinMode(button1.PIN, INPUT_PULLUP);
attachInterrupt(button1.PIN, isr, FALLING);
}
void loop() {
if (button1.pressed) {
Serial.printf("Button has been pressed %u times\n", button1.numberKeyPresses);
button1.pressed = false;
}
}
Jika Anda mengamati ulang keluaran serial saat tombol ditekan, terlihat bahwa rutinitas layanan interrupt (ISR) kini dieksekusi hanya satu kali untuk setiap event penekanan tombol, menandakan bahwa mekanisme debouncing perangkat lunak telah bekerja sebagaimana mestinya.
Penjelasan Kode:
Mekanisme perbaikan ini bekerja dengan cara membandingkan timestamp saat ini yang diperoleh dari fungsi `millis()` dengan waktu terakhir ISR dijalankan. Jika selang waktu sejak pemanggilan ISR terakhir kurang dari 250 ms, ESP8266 akan mengabaikan interrupt dan langsung melanjutkan eksekusi utama. Jika selang waktu lebih dari 250 ms, blok kode di dalam pernyataan `if` akan dijalankan: penghitung tombol ditingkatkan dan variabel `last_button_time` diperbarui, sehingga ISR memiliki referensi waktu terbaru untuk evaluasi saat interrupt berikutnya terjadi.
Baca juga: Cara Menggunakan Layar LCD I2C dengan ESP8266
Siap Untuk Membuat Proyek Impianmu Menjadi Kenyataan?
Klik di sini untuk chat langsung via WhatsApp dan dapatkan dukungan langsung dari tim ahli kami!










0 Komentar