Pin değiştirme kesintisinin doğru kullanımı


10

Basılan düğmeleri algılamak için pim değiştirme kesintilerini kullanmaya çalışıyorum. Şimdiye kadar bu tür kesintilerle hiç çalışmadım ve bazı problemler var, bu yüzden bunun doğru kullanım olup olmadığından emin olmak istiyorum.

Veri sayfasını doğru bir şekilde anladıysam, bir pin değiştirme kesintisi kullanmak için aşağıdakiler yapılmalıdır:

  1. PCMSK kaydında hangi PIN'leri kontrol etmek istediğinizi ayarlayın
  2. Pin değiştirme kesinti kontrolü (PCICR) için PIN kaydını etkinleştirin
  3. Kesmeleri etkinleştir
  4. İlgili kesinti vektörünü kullanın

Proje: Basit Moodlamp, 4 Düğme ile kontrol edilen renkler.

Kurmak:

  • Atmega168A-PU
  • 4 mini basma düğmesi anahtarı
  • 3 Watt RGB LED'imi kontrol etmek için MOSFETS

İşte ben beklendiği gibi çalışmıyor kod kullanıyorum:

#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);
        }
}

Not: Düğmeler kaldırılmalıdır. Bu adımı adım adım denediğim için ve LED'i açmak için gerekli olmamalı, burada görmezden geldim.

Soru: Kesmeleri kullanmaya çalıştığım yol doğru mu?

Kurulumumla ilgili sorunlar:

  • 1-3 arasındaki düğmeler tamamen yok sayılır.
  • Button4, atmega sıfırlamasını tetikliyor

Kontrol ettiğim şeyler:

  • Düğmeler hiçbir şekilde sıfırlama PIN'ine bağlı değildir
  • Düğmeler basılırsa GND'ye düzgün şekilde bağlanır
  • Düğmeler basılmazsa GND'ye bağlı değildir
  • Kesintisiz olarak kullanırsanız düğmeler güzel çalışır, örneğin:

    eğer (! (PINC & BUTTON4)) {PORTB ^ = MAVİ; }

  • 16MHZ harici kristal / dahili kristal
  • Yönlendirmedeki hatalar
  • Atmega'da PWR ve GND arasında 100nF kapasitör kullanıyorum
  • VCC (7), GND (8), GND (22), AVCC (20) bağlı (AREF'e ihtiyacım olmadığı için bağlı değil)

Sen PCIE1 bayrağı (değil PCIe2) ve PCINT1_vect (değil PCINT2) ihtiyaç
microtherion

Neden PCIE1? Ben C Kayıt kullanıyorum, bu yüzden saymak A (PCIE0), B (PCIE1), C (PCIE2) olurdu? Her neyse, PCIE1 nad PCINT1_vect ile denedim ve düğmelere basarsam hiçbir tepki yok.
echox

1
Bu tür görevlerde ortogonalite varsaymak biraz riskli olabilir. Bu özel durumda, ATmega168'in A bağlantı noktası olmaması dışında neredeyse doğru olacaksınız . Her durumda, veri sayfası ve pinout'a gittim. Başka bir ipucu, PCIE2 kullandığınız, ancak PCMSK1'de bit ayarladığınızdır; bu doğru olmayabilir (Ne yazık ki, gözden geçirilmiş çiziminizin neden hala çalışmadığını bilmiyorum).
microtherion

Teşekkürler, ayrıca kendi kendini inşa donanımına bağlı hata ayıklama yazılımı kombinasyonunun o kadar kolay olmadığını
anlıyorum

Yanıtlar:


14

Pim değiştirme kesintileri genellikle düğme eylemlerini algılamanın iyi bir yolu değildir. Bunun nedeni, mekanik düğmelerin zıplamasıdır ve çok fazla anlamsız kesinti elde edersiniz ve yine de yine de zıplatma yapmanız gerekir.

Daha iyi bir yol, her 1 ms (1 kHz hızı) gibi periyodik bir kesinti yapmaktır. Çoğu işlemcide bu uzun bir süre, bu yüzden kesmede harcanan zaman oranı küçük olacaktır. Her kesmede düğme durumunu örneklemeniz yeterlidir. Yeni durumu arka arkaya 50 ms gördüyseniz yeni bir düğme durumu bildirin. 50 ms çoğu düğmeden sekiyor, ancak insanlar gecikmeyi fark etmeyecek veya umursamayacak kadar kısa.

Bu şekilde, aynı periyodik 1 ms kesmede birden fazla düğmeyi de kullanabileceğinizi unutmayın. Tek ihtiyacınız olan her düğme için bir sayaç.

Başlangıç ​​zamanı hakkında daha fazla bilgi:

Bazen, bu durumda olduğu gibi, birileri 50 ms'nin çok uzun bir bekleme süresi olduğunu söylüyor. Bu, insanlar tarafından basılan sıradan düğmeler için geçerli değildir. Belki de kronometre gibi zamanlama açısından kritik uygulamalarda bir sorun olabilir, ancak şimdiye kadar bir tane ile karşılaşmadım. Bunu 1980'lerin başında test ettim ve diğer birçok insanda da var.

Tipik buton sıçrama zamanının yaklaşık 10 ms olduğu ve hemen hemen tümünün 25 msn ayarlandığı doğrudur. Kalkış süresini sınırlayan faktör insan algısıdır. 50 ms insanların aramadıkları zaman bir gecikme fark etmeye başladığı yerden biraz daha kısadır. O zaman bile, sinir bozucu olması çok daha uzun sürüyor. Bazı durumlarda, bir insanın özellikle araması durumunda 50 ms ve 0 ms gecikme arasındaki farkı tespit etmesi mümkündür , ancak bu bir düğmeye basmaktan ve bir şeylerin gerçekleştiğinden ve gecikmeyi düşünmediğinden oldukça farklıdır.

50 ms, bu nedenle, gecikme, sıradan uygulamalarda algılama sınırının altında, rahatsızlık sınırının çok altında ve çoğu anahtarın hemen çıkma süresinin oldukça üzerinde olduğu için iyi bir ayrılma süresidir. Neredeyse bu kadar uzun süre sıçrayan anahtarlar buldum, bu yüzden de algılanacak bir şey olmadığı için algılama sınırına da basabilirsiniz.

50 msn açılma süresini kullanarak bellenimden kaldırılmış düğmelerle birçok ürün yaptım. Bir kez bir müşteri bir gecikme fark bile bahsetmedi. Hepsi düğmeleri sorunsuz çalışarak kabul etti.


1
50ms bazı vakalar için çok uzun olabilir (genellikle, 10-20ms insan algısının sınırıdır ve bu, kalkış için yeterli olmalıdır), ancak burada açıklanan yöntem gitmenin yoludur.
Laszlo Valko

1
@Laszlo: Hayır, 50 ms normal vaka için çok uzun değil. Cevabımın eklenmesine bakın.
Olin Lathrop

Benim için iyi çalışan 50 ms denedim :-) Hala neden pin değiştirme kesintisinin (zıplayan şeylerin yanında) çalışmıyor, ama bu işe yarar :-) Teşekkürler.
echox

1

Pim değiştirme kesintileri, yoklamadan yoklamaktan daha iyi bir yoldur. Kesme genellikle D-Flip Flop veya D-Latch gibi bazı mantıklardan geçer. Bu doğru olmasına rağmen, bu geri çekme rutinini daha yüksek seviyeli derleyicilerle uygulamak daha zordur. Kesme gerçekleştiğinde, kesme bayrağı temizlenmez ve bir gecikme gerçekleşene kadar kesme izni temizlenir. Gecikme meydana geldiğinde, pimin durumu kontrol edilir ve kesmeyi hala tetikleyen belirli bir durumda ise düğmenin durumu değiştirilir ve kesme bayrağı temizlenir ve kesme izni ayarlanır. İnisiye neden olan durumda değilse, interrupt izni ayarlanır ve durum aynı kalır. Bu işlemciyi diğer görevler için boşaltır. Periyodik olarak programdaki atık zamanını kesintiye uğratır.


-1

"Pin değiştirme kesintileri genellikle düğme eylemlerini algılamak için iyi bir yol değildir."

Yanlış. PC INT en iyi seçenektir. Bir düğmenin durumunu kontrol etmek için yoklama kullanırsanız, çoğu zaman hiçbir şey yapılmaz. Çok değerli CPU zamanı harcıyorsunuz. PC INT, eylemlerin yalnızca istek üzerine gerçekleştirilmesine izin verir.

"Bunun nedeni, mekanik düğmelerin zıplaması ve birçok anlamsız kesinti elde etmeniz ve yine de yine de zıplatma yapmanız gerekiyor."

Zıplatma hakkında düzeltin. Yine de, ASLA bir kesme rutininin içinde bir düğmeyi / anahtarı açmamalısınız (aynı sebep: CPU zamanını boşa harcamayın). ISR'lerin gerçekten kısa ve verimli, kod bakımından olması gerekiyor. Sadece donanım açmayı kullanın. Yazılımınızı temiz tutun!

Donanımın yeniden başlatılması daha uygundur, buraya bakın / RC debouncing + Schmitt trigger referans için . PC INT ile sayısız kez kullandım, asla başarısız olmadı.

Yani evet, bir düğme durumu almak için PC INT'yi kullanabilirsiniz (ve kullanmalısınız). Ama aynı zamanda uygun donanım sökmeyi de kullanmalısınız.


2
Yazılımın kaldırılması geçerli bir yaklaşımdır ve çoğu zaman biraz fazladan CPU ek yükü önemsizdir. Genellikle donanımdan çıkmanız gerektiğini söylemek en iyi ihtimalle tartışmalıdır. Her durumda donanımın yeniden başlatılmasını kullanmanız gerektiğini söylemek yanlıştır.
Olin Lathrop

Çoğu uygulamada, kontrolör ana döngüyü çalıştırarak çoğu zaman boşta çalışır. Ayrıca, bir IO durum kontrolü gerçekleştirmek ve bir değişkeni potansiyel olarak artırmak için gereken CPU süresi minimumdur. Yazılımda basit bir açılma uygulaması neredeyse "ücretsiz", donanım maliyeti para için gelir. Ve birkaç kuruşa gülmeyin, montaj da paraya mal olur ve orta ila yüksek hacimli bir ürün çalıştırırsanız ihmal edilemez. ISR zamanının kısa tutulması gerektiği doğrudur, ancak bu durumda bu bir argüman değildir. PC INT ISR sıçraması nedeniyle arka arkaya 50 kez ateşlenirse muhtemelen daha kritiktir.
Rev1.0

@ Nelson, 'CPU zamanının israfı' bazı uygulamalarda önemlidir, diğer uygulamalarda önemli değildir. Cevabınızı CPU zamanının kritik olduğu durumlar için onaylamalısınız.
user1139880
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.