Mengontrol 10 Tombol Secara Efisien dengan Satu Interrupt pada Arduino UNO
Komponen dan perlengkapan
Berikut adalah komponen yang diperlukan untuk proyek ini:
Arduino UNO (atau mikrokontroler lainnya)
Breadboard
Kabel jumper (21 buah)
Tombol tactile (10 buah)
Aplikasi dan layanan online
Arduino IDE digunakan untuk menulis dan mengunggah kode ke papan Arduino.
Tentang proyek ini
Interrupt sangat berguna. Selain terkadang membuat kode menjadi lebih sederhana, interrupt dapat digunakan untuk pengaturan waktu yang tepat atau untuk membangunkan Arduino dari mode tidur.
Bayangkan Anda memiliki antarmuka pengguna, misalnya pengendali jarak jauh, yang berjalan dengan baterai. Anda mungkin ingin mengatur Arduino (atau ATmega mandiri) ke mode power-down untuk menghemat daya. Saat Arduino memasuki mode power-down, ia hanya dapat dibangunkan oleh interrupt eksternal. Chip ATmega328P yang digunakan pada Arduino Uno hanya memiliki dua interrupt pin eksternal (INT0 dan INT1 pada pin 2 dan 3). Karena antarmuka pengguna kemungkinan besar memiliki lebih dari dua tombol, ini menjadi masalah.
Cara standar untuk menyelesaikan hal ini adalah dengan menghubungkan semua tombol secara normal, tetapi juga menghubungkannya ke pin interrupt dengan dioda. Namun, hal ini secara signifikan membingungkan rangkaian.
Selain interrupt eksternal standar, ATmega328P juga memiliki interrupt perubahan pin. Ada pustaka untuk menangani mereka dan mereka adalah solusi yang baik untuk masalah ini.
Namun, selama kompetisi pemrograman, saya menemukan cara untuk melakukannya menggunakan interrupt eksternal standar tanpa komponen elektrik tambahan.
Rangkaian
Kami memiliki beberapa tombol. Saya menggunakan sepuluh, yang pas dengan breadboard saya. (Saya juga tidak memiliki lebih banyak.) Anda dapat memiliki satu tombol per pin, yang berarti hingga 20 pada Uno dan hingga 70 pada Mega! (Jika Anda benar-benar membutuhkan 70 tombol, saya merekomendasikan penggunaan multiplexing, Anda tidak membutuhkan seluruh Mega untuk itu.)
Setiap tombol memiliki satu sisi yang terhubung ke pin sembarang. (4-13 dalam kasus saya) Sisi lain dari semua tombol terhubung bersama-sama ke satu pin yang mampu interrupt. (2 dalam kasus saya)
Kode
Kode dilampirkan di bawah ini. Untuk membuat contoh ini berfungsi, unggah ke papan Anda. Buka serial monitor Anda. Saat Anda menekan tombol, nomornya akan muncul. Seperti yang Anda lihat, fungsi loop tidak digunakan sama sekali.
Bagaimana cara kerjanya?
Tentu saja, ada sebuah interrupt. Dalam kasus saya, itu terpasang pada pin 2. Ini dikonfigurasi sebagai FALLING.
Untuk menghindari penggunaan dioda, Arduino merangkaian ulang sirkuit secara langsung. Ada dua konfigurasi yang mungkin: Mode umum dan Mode terpisah.
Mode umum
Sebagian besar waktu, sirkuit akan berada dalam mode umum. Pin interrupt akan dikonfigurasi sebagai INPUT_PULLUP dan sisanya akan menjadi OUTPUT dan LOW.
void configureCommon() { pinMode(commonPin, INPUT_PULLUP); for (int i = 0; i < sizeof(buttonPins) / sizeof(int); i++) { pinMode(buttonPins[i], OUTPUT); digitalWrite(buttonPins[i], LOW); } }
Dalam mode umum, menekan tombol apapun akan menarik pin interrupt kita ke bawah dan memicu interrupt kita. Setelah itu terjadi, rutinitas layanan interrupt kita akan mengonfigurasi ulang pin untuk mode terpisah.
Mode terpisah
Setelah interrupt kita terpicu, kita dengan beralih cepat ke mode terpisah.
Mode terpisah adalah kebalikan dari mode umum. Pin interrupt akan menjadi OUTPUT dan LOW dan sisanya akan menjadi INPUT_PULLUP.
void configureDistinct() { pinMode(commonPin, OUTPUT); digitalWrite(commonPin, LOW); for (int i = 0; i < sizeof(buttonPins) / sizeof(int); i++) { pinMode(buttonPins[i], INPUT_PULLUP); } }
Dalam mode terpisah, hanya pin yang sesuai dengan tombol yang benar-benar ditekan yang akan ditarik ke bawah. Kita dengan mudah dapat memeriksa semua pin untuk mengetahui mana yang memicu interrupt.
Setelah selesai, Arduino dapat beralih kembali ke mode umum dan menunggu interrupt lain. Atau, tergantung pada aplikasi Anda, ia dapat tetap dalam mode terpisah dan memproses input pengguna seperti biasanya, beralih kembali ke mode umum sebelum Arduino masuk ke mode tidur.
Contoh yang lebih kompleks
Mari kita coba sesuatu yang sedikit lebih kompleks. Kami akan melayani servo dan memetakan setiap tombol ke sudut yang berbeda. (1=0°, 2=20°... 10=120°) Kami juga akan menyediakan daya Arduino dengan beberapa baterai.
Dalam contoh ini, kami menempatkan Arduino ke mode power-down setelah lima detik tidak aktif untuk menghemat daya. Anda dapat menemukan beberapa tutorial tentang mode tidur online. Selain itu, kami menyediakan daya servo melalui transistor untuk mematikannya saat tidak digunakan.
Kode untuk contoh ini juga dilampirkan di bawah ini.
Kode lengkap
Serial logger
const int commonPin = 2; const int buttonPins[] = {4,5,6,7,8,9,10,11,12,13}; unsigned long lastFire = 0; void setup() { configureCommon(); attachInterrupt(digitalPinToInterrupt(commonPin), pressInterrupt, FALLING); Serial.begin(9600); } void loop() { } void pressInterrupt() { if (millis() - lastFire < 200) { return; } lastFire = millis(); configureDistinct(); for (int i = 0; i < sizeof(buttonPins) / sizeof(int); i++) { if (!digitalRead(buttonPins[i])) { press(i); } } configureCommon(); } void configureCommon() { pinMode(commonPin, INPUT_PULLUP); for (int i = 0; i < sizeof(buttonPins) / sizeof(int); i++) { pinMode(buttonPins[i], OUTPUT); digitalWrite(buttonPins[i], LOW); } } void configureDistinct() { pinMode(commonPin, OUTPUT); digitalWrite(commonPin, LOW); for (int i = 0; i < sizeof(buttonPins) / sizeof(int); i++) { pinMode(buttonPins[i], INPUT_PULLUP); } } void press(int button) { Serial.println(button + 1); }