Penggunaan pin interupsi yang benar

10

Saya mencoba menggunakan pin change interrupt untuk mendeteksi tombol yang ditekan. Sampai sekarang saya belum pernah bekerja dengan interupsi semacam ini dan ada beberapa masalah, jadi saya ingin memastikan apakah ini penggunaan yang benar.

Jika saya mendapatkan datasheet dengan benar, hal-hal berikut harus dilakukan untuk menggunakan interupsi perubahan pin:

  1. Tetapkan PIN mana yang ingin Anda kendalikan dalam register PCMSK
  2. Mengaktifkan register PIN untuk kontrol interupsi penggantian pin (PCICR)
  3. Aktifkan interupsi
  4. Gunakan vektor interupsi yang sesuai

Proyek: Moodlamp Sederhana, Warna dikontrol melalui 4 Tombol.

Mempersiapkan:

  • Atmega168A-PU
  • 4 sakelar tombol tekan mini
  • MOSFET untuk mengontrol LED RGB 3 Watt saya

Berikut adalah kode yang saya gunakan yang tidak berfungsi seperti yang diharapkan:

#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#define BUTTON1 (1<<PC5) 
#define BUTTON2 (1<<PC4) 
#define BUTTON3 (1<<PC3) 
#define BUTTON4 (1<<PC2) 

#define GREEN   (1<<PB1) 
#define BLUE    (1<<PB2) 
#define RED     (1<<PB3) 

void init() {

        // enable LED
        DDRB |= GREEN;
        DDRB |= BLUE;
        DDRB |= RED;

        // button pullups
        PORTC |= BUTTON1;
        PORTC |= BUTTON2;
        PORTC |= BUTTON3;
        PORTC |= BUTTON4;

        // pin change interrupts for buttons
        PCMSK1 |= PCINT13;
        PCMSK1 |= PCINT12;
        PCMSK1 |= PCINT11;
        PCMSK1 |= PCINT10;

        // enable pin change for buttons
        PCICR |= PCIE2;

        sei();

}

ISR(PCINT2_vect) {

                PORTB = BLUE;
}


void ledTest() {

                PORTB ^= RED;
                _delay_ms(250);
                PORTB ^= RED;
                _delay_ms(250);
                PORTB ^= RED;
                _delay_ms(250);
                PORTB ^= RED;


                PORTB ^= BLUE;
                _delay_ms(250);
                PORTB ^= BLUE;
                _delay_ms(250);
                PORTB ^= BLUE;
                _delay_ms(250);
                PORTB ^= BLUE;

                PORTB ^= GREEN;
                _delay_ms(250);
                PORTB ^= GREEN;
                _delay_ms(250);
                PORTB ^= GREEN;
                _delay_ms(250);
                PORTB ^= GREEN;
}

int main() {

        init();
        ledTest();

        _delay_ms(500);
        PORTB |= GREEN;

        while(1) {
                _delay_ms(100);
        }
}

Catatan: Tombol-tombol harus didebound. Karena saya mencoba langkah ini selangkah demi selangkah dan tidak seharusnya mater untuk menyalakan LED, saya mengabaikannya di sini.

Pertanyaan: Apakah cara saya mencoba menggunakan interupsi itu benar?

Masalah dengan pengaturan saya:

  • Buttons1-3 benar-benar diabaikan.
  • Button4 memicu reset atmega

Hal-hal yang saya periksa:

  • Tombol tidak terhubung dengan PIN reset
  • Tombol terhubung dengan benar ke GND jika ditekan
  • Tombol tidak terhubung ke GND jika tidak ditekan
  • Tombol berfungsi dengan baik jika saya menggunakannya tanpa gangguan, misalnya:

    if (! (PINC & BUTTON4)) {PORTB ^ = BIRU; }

  • Kristal eksternal 16MHz / kristal internal
  • Kesalahan dalam perutean
  • Saya menggunakan kapasitor 100nF antara PWR dan GND pada atmega
  • VCC (7), GND (8), GND (22), AVCC (20) terhubung (karena saya tidak perlu AREF, tidak terhubung)
echox
sumber
Anda perlu bendera PCIE1 (tidak PCIE2) dan PCINT1_vect (tidak PCINT2)
microtherion
Mengapa PCIE1? Saya menggunakan Daftar C, jadi jika saya hitung itu akan menjadi A (PCIE0), B (PCIE1), C (PCIE2)? Bagaimanapun, saya mencobanya dengan PCIE1 nad PCINT1_vect dan tidak ada reaksi jika saya menekan tombol.
echox
1
Agak riskan untuk menganggap ortogonalitas dalam penugasan semacam itu. Dalam kasus khusus ini, Anda akan hampir benar, kecuali bahwa ATmega168 tidak memiliki port A. Dalam hal apapun, saya pergi dengan datasheet dan pinout. Tip-off lainnya adalah Anda menggunakan PCIE2, tetapi mengatur bit di PCMSK1; itu tidak mungkin benar (Sayangnya, saya tidak tahu mengapa sketsa yang direvisi masih tidak berfungsi).
microtherion
Terima kasih, saya juga mengerti bahwa kombinasi perangkat lunak debug yang tergantung pada perangkat keras yang dibangun sendiri tidak semudah itu ;-)
echox

Jawaban:

14

Pin change interrupt biasanya bukan cara yang baik untuk mendeteksi aksi tombol. Ini karena tombol mekanis memantul, dan Anda akan mendapatkan banyak interupsi yang tidak berarti, dan kemudian Anda tetap harus melakukan debouncing.

Cara yang lebih baik adalah memiliki interupsi berkala, seperti setiap 1 ms (tingkat 1 kHz). Itu waktu yang lama pada kebanyakan prosesor, sehingga sebagian kecil dari waktu yang dihabiskan dalam interupsi akan kecil. Cukup sampel kondisi tombol setiap interupsi. Nyatakan status tombol baru jika Anda telah melihat status baru 50 ms berturut-turut. 50 ms lebih panjang dari sebagian besar tombol memantul, tetapi masih cukup pendek sehingga manusia tidak akan memperhatikan atau peduli dengan lag.

Perhatikan bahwa dengan cara ini Anda juga dapat menangani beberapa tombol dalam interupsi berkala 1 ms yang sama. Yang Anda butuhkan hanyalah satu penghitung untuk setiap tombol.

Lebih lanjut tentang waktu debounce:

Kadang-kadang, seperti dalam kasus ini, seseorang mengatakan 50 ms adalah waktu debounce terlalu lama. Ini tidak benar untuk tombol biasa yang ditekan oleh manusia. Mungkin ini masalah yang mungkin terjadi pada aplikasi yang sangat menentukan waktu seperti stopwatch, tapi sejauh ini saya belum pernah melihatnya. Saya melakukan tes pada awal 1980-an, dan banyak orang lain juga.

Memang benar bahwa waktu pentalan tombol tekan yang khas adalah sekitar 10 ms, dengan hampir semua settling sebesar 25 ms. Faktor pembatas waktu debounce adalah persepsi manusia. 50 ms sedikit lebih pendek daripada di mana orang-orang mulai melihat penundaan ketika mereka tidak mencarinya. Meski begitu, butuh waktu yang lebih lama untuk itu mengganggu. Dalam beberapa kasus dapat dimungkinkan bagi manusia untuk mendeteksi perbedaan antara 50 ms dan 0 ms keterlambatan jika mereka secara spesifik mencarinya , tetapi itu sangat berbeda dari menekan tombol dan melihat sesuatu terjadi dan tidak memikirkan penundaan.

Oleh karena itu 50 ms adalah waktu debounce yang baik karena keterlambatannya di bawah batas persepsi dalam aplikasi biasa, jauh di bawah batas gangguan, dan jauh di atas waktu bouncing sebagian besar sakelar. Saya telah menemukan sakelar yang memantul hampir selama itu, jadi sebaiknya Anda mendorong hingga batas persepsi karena tidak ada yang longgar.

Saya telah melakukan banyak produk dengan tombol firmware-deboelled menggunakan waktu debounce 50 ms. Tidak seorang pelanggan pun menyebutkan adanya penundaan. Mereka semua menerima bahwa tombol berfungsi dengan baik tanpa masalah.

Olin Lathrop
sumber
1
50 ms mungkin terlalu lama untuk beberapa kasus (biasanya, 10-20 ms adalah batas persepsi manusia, dan itu sudah cukup untuk melonggarkan), tetapi metode yang dijelaskan di sini adalah cara untuk pergi.
Laszlo Valko
1
@Laszlo: Tidak, 50 ms tidak terlalu panjang untuk kasus biasa. Lihat tambahan jawaban saya.
Olin Lathrop
Saya mencoba 50ms yang berfungsi dengan baik untuk saya :-) Saya masih ingin tahu mengapa interupsi penggantian pin tidak bekerja (di samping hal-hal yang memantul), tetapi ini bekerja :-) Terima kasih.
echox
1

Interupsi perubahan pin adalah cara yang lebih baik untuk melakukan debounce daripada polling. Interrupt biasanya melewati beberapa logika seperti D-Flip Flop, atau D-Latch. Meskipun ini benar, lebih sulit untuk mengimplementasikan rutin debounce ini dengan kompiler level yang lebih tinggi. Setelah interupsi terjadi, bendera interupsi tidak dihapus dan mengaktifkan interupsi dihapus sampai penundaan telah terjadi. Setelah penundaan telah terjadi, status pin dicentang dan jika masih dalam keadaan tertentu yang memicu interupsi, status tombol diubah dan bendera interupsi dihapus dan mengaktifkan interupsi diatur. Jika tidak dalam keadaan yang menyebabkan inisiat, interupsi diaktifkan diatur dan keadaan tetap sama. Ini membebaskan prosesor untuk tugas-tugas lain. Secara berkala mengganggu waktu yang terbuang dalam program.

Jim Vernay
sumber
-1

"Pin change interrupt biasanya bukan cara yang baik untuk mendeteksi aksi tombol."

Salah. PC INT adalah opsi terbaik. Jika Anda menggunakan polling untuk memeriksa keadaan tombol, tidak ada yang akan dilakukan sebagian besar waktu. Anda membuang banyak waktu CPU yang berharga. PC INT memungkinkan tindakan dilakukan hanya berdasarkan permintaan.

"Ini karena tombol mekanis terpental, dan kamu akan mendapatkan banyak interupsi yang tidak berarti, dan lagipula kamu masih harus melakukan debouncing."

Benar tentang memantul. Namun, Anda TIDAK PERNAH harus melonggarkan tombol / sakelar di dalam rutinitas interupsi (alasan yang sama: buang-buang waktu CPU). ISR dimaksudkan untuk menjadi sangat singkat dan efisien, bijaksana kode. Cukup gunakan debouncing perangkat keras. Jaga kebersihan perangkat lunak Anda!

Pelepasan hardware lebih mudah, lihat di sini / RC debouncing + pemicu Schmitt untuk referensi. Saya sudah menggunakannya berkali-kali dengan PC INT, tidak pernah gagal.

Jadi ya, Anda bisa (dan harus) menggunakan PC INT untuk mendapatkan status tombol. Tetapi Anda juga harus menggunakan debouncing perangkat keras yang tepat.

Nelson
sumber
2
Pelepasan perangkat lunak adalah pendekatan yang valid, dan sebagian besar waktu overhead CPU tambahan tidak relevan. Mengatakan bahwa Anda biasanya harus melakukan debounce pada perangkat keras dipertanyakan. Mengatakan Anda harus menggunakan debouncing perangkat keras dalam semua kasus hanya salah.
Olin Lathrop
Di sebagian besar aplikasi, pengontrol berjalan idle hampir sepanjang waktu, menjalankan loop utama. Juga, waktu CPU diperlukan untuk melakukan pemeriksaan status IO dan berpotensi menambah variabel minimal. Menerapkan debouncing sederhana dalam perangkat lunak datang hampir untuk "gratis", biaya perangkat keras. Dan jangan menertawakan beberapa sen, biaya perakitan juga mahal dan jika Anda menjalankan volume produk yang sedang hingga tinggi, hal itu tidak dapat diabaikan. Memang benar bahwa waktu ISR harus ditunda, tetapi itu bukan argumen dalam kasus ini. Mungkin lebih penting jika PC INT ISR menyala 50 kali berturut-turut karena terpental.
Rev1.0
@Nelson, 'buang waktu CPU' penting di beberapa aplikasi dan tidak di banyak aplikasi lainnya. Anda harus memenuhi syarat jawaban Anda untuk situasi di mana waktu CPU sangat penting.
user1139880