Tombolmu terpicu dua kali. Ini penyebabnya, dan ini cara memperbaikinya.
Atau lihat semua pelajaran.
- 465komponen di meja kerja
- 43board sedang berjalan
- 1.00xwaktu nyata, di semua board
Saklar taktil adalah kubah logam kecil yang ditekan ke sebuah kontak, dan kubah itu tidak langsung mendarat lalu diam. Kubah itu mendarat, memantul sepersekian milimeter, mendarat lagi, dan mengulanginya beberapa kali sebelum tenang, seperti koin yang dijatuhkan tidak langsung berhenti saat pertama menyentuh meja. Secara listrik, kontaknya terbuka dan tertutup beberapa kali di beberapa milidetik pertama saat ditekan, dan lagi saat dilepas, sebelum akhirnya stabil. Sketch yang hanya menghitung edge di pin itu akan salah hitung, karena satu tekanan bisa terbaca sebagai dua, tiga, atau lebih.
Mokxi memodelkan ini, bukan menyembunyikannya. Setiap tombol tekan di meja kerja memantul secara default, dengan profil bernama typical: tiga sampai delapan transisi, stabil di antara 1 dan 5 milidetik setelah tekanan dimulai. Itu mendekati saklar taktil sungguhan, dan artinya rangkaian di atas bukan demonstrasi bug yang dibuat-buat; itulah bug-nya, terjadi dengan cara yang sama seperti di meja belajarmu.
Yang ditunjukkan simulator
Program yang berjalan di atas adalah contoh interrupt bawaan Uno. Program ini memasang interrupt handler di pin 2 yang terpicu di setiap edge turun (setiap saat pin turun dari 5 V ke 0 V) dan menambah satu ke penghitung, sengaja tanpa logika debounce sama sekali. Buka rangkaiannya di editor, buka Serial Monitor, lalu tekan tombolnya sekali, dengan mantap, seperti kamu menekan tombol apa pun. Hitungan yang tercetak setelah satu tekanan sangat sering dua atau tiga, bukan satu, dan LED bawaan board, yang berganti sesuai ganjil-genapnya hitungan, kadang berakhir di keadaan yang tidak kamu duga. Tidak ada yang rusak. Saklarnya memantul, handler melihat setiap pantulan sebagai tekanan terpisah, dan menghitung semuanya dengan setia, karena memang itulah yang diminta kodenya.
Inilah seluruh pelajarannya dalam satu kalimat: yang menghasilkan tekanan tambahan adalah saklarnya, bukan kodenya, dan perbaikannya ada di kode karena saklarnya tidak bisa dibuat benar-benar bersih.
Tiga cara memperbaikinya
Perbaikan pertama, dan yang paling murah, adalah jendela debounce di software: setelah ada perubahan di pin, abaikan perubahan berikutnya selama waktu singkat, cukup lama untuk menutupi waktu stabilnya dan cukup singkat agar tekanan kedua yang sungguhan tidak pernah dikira pantulan. Antara 5 sampai 20 milidetik sudah cukup longgar untuk saklar biasa.
Perbaikan kedua ada di hardware: kapasitor kecil yang dipasang melintasi saklar. Kapasitor ini memperlambat naik turunnya tegangan cukup jauh sehingga pantulannya tidak pernah mencapai transisi logika penuh, jadi pin benar-benar hanya melihat satu edge yang bersih. Cara ini berhasil di meja kerja karena kapasitor sungguhan butuh waktu nyata untuk terisi dan kosong, dan berhasil di Mokxi karena alasan yang sama: kapasitor di sini berintegrasi terhadap waktu dengan respons RC eksponensial yang nyata, bukan berganti seketika, jadi versi kecil dari perbaikan ini benar-benar bekerja di simulator, bukan cuma secara teori.
Yang ketiga adalah debounce di dalam interrupt handler itu sendiri, yang butuh satu aturan tambahan: handler harus mengerjakan sesedikit mungkin, karena handler berjalan sambil menahan interrupt lain. Catat waktunya lalu keluar; lakukan pengambilan keputusannya, termasuk jendela debounce, di loop().
Versi millis()
Program toggle bawaan Uno adalah perbaikan software itu, lengkap, di pin 2 yang sama dengan demonstrasi pantulan. Program ini menyimpan bacaan terakhir dan waktu terakhir bacaan itu berubah, dan hanya bertindak atas perubahan setelah DEBOUNCE_MS, dua puluh lima milidetik, berlalu sejak perubahan sebelumnya. Tekan tombolnya sekali saat program ini berjalan, maka lampu di pin 13 menyala; tekan lagi, maka lampunya mati, tepat sekali per tekanan, dan itulah intinya.
Perhatikan apa yang sebenarnya dibandingkan kodenya. Kode ini tidak menghitung berapa lama tombol ditahan; kode ini mengukur berapa lama sejak perubahan terakhir yang diterima, di edge mana pun, saat ditekan atau dilepas. Perbedaan itulah yang membuat jendelanya simetris: pantulan tepat setelah ditekan diabaikan, begitu pula pantulan tepat setelah dilepas, dengan aturan dua puluh lima milidetik yang sama untuk keduanya tanpa perlu membedakan edge yang mana.
const int BUTTON_PIN = 2;
const int LAMP_PIN = 13;
const unsigned long DEBOUNCE_MS = 25;
int lastReading = HIGH;
unsigned long lastChange = 0;
bool lampOn = false;
void loop() {
int reading = digitalRead(BUTTON_PIN);
unsigned long now = millis();
if (reading != lastReading && now - lastChange >= DEBOUNCE_MS) {
lastChange = now;
lastReading = reading;
if (reading == LOW) {
lampOn = !lampOn;
digitalWrite(LAMP_PIN, lampOn ? HIGH : LOW);
}
}
}Soal resistor pull-up
Demonstrasi pantulan maupun perbaikannya menyambung tombol langsung ke pin 2 tanpa resistor eksternal, karena sketch-nya menyalakan pull-up internal pin itu dengan INPUT_PULLUP. Pull-up itu menahan pin di 5 V sampai tombol menyambungkannya ke ground, itulah sebabnya pin terbaca LOW saat tombol ditahan, bukan HIGH. Detail ini sering membingungkan orang saat pertama kali melihatnya, karena terasa kebalikan dari yang seharusnya dilakukan tombol.
Alternatifnya adalah pull-up eksternal sungguhan, resistor 10 kilohm dari pin ke 5 V, dengan tombol yang menarik net yang sama ke ground saat ditekan. Secara listrik keduanya ide yang sama; yang internal hanya lebih lemah (sekitar 35 kilohm) dan tidak butuh komponen tambahan. Halaman tentang resistor pull-up merakit versi eksternalnya dari nol, dan layak dibaca kalau pull-up internal terasa muncul begitu saja.
Kenapa profil default diatur seperti itu
typical, tiga sampai delapan transisi yang stabil dalam 1 sampai 5 milidetik, sengaja meniru saklar taktil biasa, jenis yang ada di hampir setiap kit breadboard, bukan kasus terburuk yang dipilih supaya masalahnya terlihat lebih parah dari aslinya. Ada juga profil worst, hingga dua puluh transisi selama 10 sampai 20 milidetik, lebih mirip saklar yang sudah aus atau limit switch bertuas panjang yang sudah sering dipakai, dan layak dipakai untuk menguji jendela debounce setelah kasus biasanya beres: perbaikan yang disetel untuk pantulan 5 milidetik tanpa sisa ruang masih bisa gagal pada saklar yang bergetar selama 15.
Pertanyaan
Berapa lama delay debounce yang pas?
Antara 5 sampai 20 milidetik cukup untuk saklar taktil biasa, dan itu juga rentang waktu stabil profil pantulan default Mokxi. Terlalu singkat, sebagian pantulan lolos; terlalu lama, tekan dua kali dengan cepat mulai terasa tidak responsif.
Apakah aku butuh kapasitor kalau sudah debounce di software?
Tidak. Keduanya adalah alternatif yang menyelesaikan masalah yang sama di tempat berbeda, dan memakai keduanya tidak salah, hanya berlebihan. Pilih yang cocok dengan rangkaianmu: software tidak butuh biaya tambahan, hardware tetap bekerja walaupun kode yang membaca pin tidak pernah diubah.
Kenapa interrupt-ku masih terpicu dua kali setelah aku menambahkan pengecekan debounce?
Hampir selalu karena pengecekan jendela debounce-nya ada di dalam interrupt handler bersama pekerjaan yang lambat, atau karena waktunya dibandingkan dengan nilai tersimpan yang salah. Batasi handler hanya untuk membaca waktu dan memasang penanda, lalu lakukan perbandingannya di loop().
Apakah INPUT_PULLUP juga butuh resistor eksternal?
Tidak. Mode itu menyalakan resistor pull-up yang ada di dalam ATmega328P itu sendiri, jadi tombol hanya butuh dua kabel: satu ke pin, satu ke GND.
Kapasitor berapa yang bisa men-debounce saklar biasa secara hardware?
Sekitar 100 nanofarad melintasi saklar, sering dipasangkan dengan resistor seri kecil untuk membatasi arus pengosongan saat tekanan pertama, adalah titik awal yang umum; nilai yang tepat tergantung saklarnya dan sebaiknya dicek di meja kerja dengan komponen aslinya, bukan percaya pada satu angka untuk semua saklar.
Apakah debounce hanya masalah untuk tombol?
Tidak. Setiap kontak mekanis memantul, termasuk relay, saklar toggle, dan limit switch di motor atau pintu. Perbaikannya sama: jendela waktu setelah perubahan pertama, atau kapasitor melintasi kontaknya, mana yang cocok dengan rangkaian yang membacanya.
Lanjutkan
Rakit versi nyatanya
Buka editor, ubah sebuah nilai, dan lihat angkanya ikut berubah. Tidak ada yang perlu dipasang, dan tidak perlu akun.