Arduino ile bir zamanlayıcı kesintisi nasıl oluştururum?


9

Arduino ile zaman gecikmesi kesintisi yaratmaya çalışıyorum. İnterrupts () işlevini kullanmak istiyorum, çünkü bu dahili bir kesmedir.

Örnek: Diyelim ki, sadece kesintinin zamanlamasıyla bir ışık yanıp sönmesini istiyorum.

Örnek kod var, ancak harici kesmeler kullanıyor (attachInterrupt ()). Dahili kesintileri kullanmaya devam etmek istiyorum.


2
Bence Kortuk'un da gösterdiği nokta, attachInterrupt'ın soyut bir şey olduğu, herhangi bir dış bileşen
takmamanızdır

Bu makale size yardımcı olabilir. engblaze.com/…
Seth Archer Brown

Yanıtlar:


10

Noah Stahl'ın blogunda Timer2 ile bir LED yanıp sönme örneği var . Bununla ve veri sayfasıyla, kullanmak istediğiniz kesmeye - yani normal işlevinden vazgeçmeyi ya da değiştirmeye istekli olduğu kesime - adapte edebilmelisiniz. Timer2 genellikle bazı PWM işlevleri için kullanılır.

Onun örneği ATmega2560; ATmega328p ile de çalıştığını doğrulayabilirim. Daha kullanışlı Arduino kesme örnekleri için sitesinin etrafına bakın.

Düzenle:

İşte Nuh'un kodunun hafifçe düzenlenmiş - çoğunlukla yorumlarda - sürümü. İlgili veri yapılarını veya donanımları başlattıktan sonra Arduino setup () işlevinden Timer2init () yöntemini çağırın, çünkü zamanlama - ve kesinti - bir kez yaptığınızda başlayacaktır.

F / ex, 3 basamaklı 7 segmentli bir ekranı çoğaltmak için kullandım, böylece zamanlayıcıyı başlatmadan önce, ekran G / Ç kayıtlarını başlattım ve ekran verilerini ISR'nin arayacağı yere boşalttım.

Veri sayfasındaki bazı yararlı zamanlama verilerinin yorumlarında ve başka bir zamanlama şemasını ayarlamak için referans için kendi hesaplamalarımda bir tablo var.

ISR () makrosu, normal bir işlevin giriş ve çıkışı yerine bir ISR için kesme giriş ve çıkış kodu oluşturmaya ve onu uygun kesme vektörü ile ilişkilendirmeye özen gösterir. Bu işlevin geri kalanı 1) her kesmede çalıştırılacak kod ve 2) bir sonraki kesme için zamanlayıcıyı sıfırlamak için kod kodudur.

Yazıldığı gibi, bu bir .pde veya .ino çizimine (veya eclipse, f / ex kullanıyorsanız bir .cpp dosyasına) bırakılmalıdır. Çizim LEDPIN #define gerekir ve setup () Timer2init () çağırmak gerekir. Döngü işlevi boş olabilir veya olmayabilir; indirme sırasında LED yanıp sönmeye başlamalıdır (kelimenin tam anlamıyla Timer2init () çağrıldıktan sonra).

/*
 * From sample interrupt code published by Noah Stahl on his blog, at:
 * http://arduinomega.blogspot.com/p/arduino-code.html
 * 
 */


/*** FUNC

Name:           Timer2init

Function:       Init timer 2 to interrupt periodically. Call this from 
                the Arduino setup() function.

Description:    The pre-scaler and the timer count divide the timer-counter
                clock frequency to give a timer overflow interrupt rate:

                Interrupt rate =  16MHz / (prescaler * (255 - TCNT2))

        TCCR2B[b2:0]   Prescaler    Freq [KHz], Period [usec] after prescale
          0x0            (TC stopped)     0         0
          0x1                1        16000.        0.0625
          0x2                8         2000.        0.500
          0x3               32          500.        2.000
          0x4               64          250.        4.000
          0x5              128          125.        8.000
          0x6              256           62.5      16.000
          0x7             1024           15.625    64.000


Parameters: void

Returns:    void

FUNC ***/

void Timer2init() {

    // Setup Timer2 overflow to fire every 8ms (125Hz)
    //   period [sec] = (1 / f_clock [sec]) * prescale * (255-count)
    //                  (1/16000000)  * 1024 * (255-130) = .008 sec


    TCCR2B = 0x00;        // Disable Timer2 while we set it up

    TCNT2  = 130;         // Reset Timer Count  (255-130) = execute ev 125-th T/C clock
    TIFR2  = 0x00;        // Timer2 INT Flag Reg: Clear Timer Overflow Flag
    TIMSK2 = 0x01;        // Timer2 INT Reg: Timer2 Overflow Interrupt Enable
    TCCR2A = 0x00;        // Timer2 Control Reg A: Wave Gen Mode normal
    TCCR2B = 0x07;        // Timer2 Control Reg B: Timer Prescaler set to 1024
}



/*** FUNC

Name:       Timer2 ISR

Function:   Handles the Timer2-overflow interrupt

Description:    Maintains the 7-segment display

Parameters: void

Returns:    void

FUNC ***/

ISR(TIMER2_OVF_vect) {
    static unsigned int led_state = 0; // LED state

    led_state = !led_state;         // toggles the LED state
    digitalWrite(TOGGLE_PIN, led_state);

    TCNT2 = 130;     // reset timer ct to 130 out of 255
    TIFR2 = 0x00;    // timer2 int flag reg: clear timer overflow flag
};

(@Kortuk: Bahsettiğiniz yorum, burada birkaç yorumcuyu gözlemlememdi ve kişisel olarak sizi hedeflemedi ve gereksizdi. Özür dilerim ve kaldırdım.) Önerdiğim gibi cevabımı genişlettim ve umarım şimdi sadece gösterici değil, aynı zamanda öğretici de. Kendi kullanımım için koda yazdığım yorumları (yani: Ondan 6 ay sonra anlayabiliyorsam, başka biri de yapabilir) ve ayrıca birkaç "nasıl kullanılır" talimatını içerir. Cevap. Önerileriniz için teşekkürler.
JRobert

Zamanlayıcı0 ve zamanlayıcı1 (atmega328 ile en az) için 32 ve 128 ön ölçeklerinin mevcut olmadığını unutmayın.
tuupola

Bunu bilmek güzel - teşekkürler. Ben Timer2 (şimdiye kadar) için kullanın ve temelde bir damla.
JRobert

5

AttachInterrupt () aslında bir pim üzerine harici bir durum değişikliği için bir kesme takılarak olan fonksiyon, herhangi bir diğer seçenekleri yoktur.

On aynı sayfada modu seçenekleri olarak listelenmiştir:

modu kesmenin ne zaman tetiklenmesi gerektiğini tanımlar. Dört aday, geçerli değerler olarak önceden tanımlanmıştır:

  • Pim azaldığında kesmeyi tetiklemek için DÜŞÜK ,
  • Pim her değer değiştirdiğinde kesmeyi tetiklemek için DEĞİŞTİR
  • Pim alçaktan yükseğe çıktığında tetiklemek için yükseliyor ,
  • DÜŞME pimi yüksekten en düşüğe doğru gittiğinde için.

Kötü haberlerin taşıyıcısı olduğum için üzgünüm, bu da ilk aradığım şeylerden biri.


Sanırım harici bir cihaz yerine dahili bir zamanlayıcı kullanmak istediği anlamına geliyor ... ama
Arduino'yu

@clabacchio, tek seçeneğin harici bir tetikleyici kullanmak olduğunu söylüyorum, dahili zamanlayıcı işlevi yok.
Kortuk

Ah, güzel :) ama en azından Arduino kartlarında zamanlayıcı var mı?
clabacchio

Evet, gecikme gibi şeyleri böyle yaparlar.
Kortuk

1
@ icarus74 ATMega328 gerçekten 3 zamanlayıcıya sahip (biri 16b ve ikisi 8b) ama hepsi Arduino tarafından kullanılıyor. Bunlardan biri delay () ve millis () gibi işlevler için kullanılır ve üçü de PWM için kullanılır (Arduino IDE'deki 'init ()' fonksiyonunda 'wiring.c' dosyasında daha fazla bilgi bulabilirsiniz).
vasco

2

PWM hakkındaki bu makale, Arduino zamanlayıcılarının kullanımıyla ilgili şüphelerinizin çoğunu temizleyecektir. Arduino'da iki adet 8 bit zamanlayıcı ve bir adet 16 bit zamanlayıcı vardır. ISR işlevini doğrudan zamanlayıcılara bağlamak için yüksek düzeyli bir API yoktur; bu, Arduino SDK (yani standart bir kütüphane olarak) ile birlikte gönderilir, ancak Özel Fonksiyon Kayıtları ve bit-aritmetik / üzerlerinde işlemler. Ancak Timer one adlı kullanıcı katkısı olan bir kütüphane vardır .


Aslında hangi Arduino'nun atıfta bulunduğuna bağlı olarak birkaç farklı zamanlayıcı kombinasyonu vardır. Cevap yanıltıcıdır.
Görünüşe göre

@SeeminglySo, özen göstermeye özen gösteriyor musunuz? Arduino donanımı hakkında konuşuyorsanız, cevabın soru bağlamında ve aynı zamanda sorunun sorulduğu zamanda olduğunu unutmayın.
icarus74

Arduino Mega (ATmega1280 tabanlı) 26 Mart 2009'da piyasaya sürüldü ve Mega 2560 (ATmega2560) bu soru sorulmadan çok önce 24 Eylül 2010'da piyasaya sürüldü. Her iki mikro denetleyicinin de yanıtta belirtilen 2x 8 bit ve 1x 16 bit zamanlayıcı / sayacı vardır.
Görünüşe göre

Şimdiye kadar gördüğüm etkileşimlerin çoğu, Duemilanove veya Uno'nun yani 328 serisi tabanlı kartlar gibi Arduino'ya açık bir referansa sahiptir. Diğer kartlar her zaman açıkça UP serisi no. veya Mega, Nano, Mikro vb. Her neyse, düzeltmeyi alçakgönüllülükle kabul edeceğim. Bu bağlamda, bir açıklama daha iyidir.
icarus74

1

Arduino, ATMega328'de üç zamanlayıcıyı da kullanıyor. Timer1(16 bit), 5 ve 6 numaralı pinlerdeki PWM çıkışı gibi delay()ve için işlevler için kullanılır millis(). Diğer iki zamanlayıcı - Timer0veTimer2 pim 3, 9, 10, 11'deki PWM çıkışı için kullanılır.

Bu nedenle, zamanlayıcı kesmesi için Arduino işlevi yoktur. Ama, bir yolu var. Aşağıdaki durumlarda zamanlayıcı kesmesini etkinleştirmek için bu kodu kullanabilirsiniz Timer2:

ISR(TIMER2_OVF_vect) {
  // Interrupt routine.
}

void setup() {
  // Enable Timer2 interrupt.
  TIMSK2 = (0<<OCIE2A) | (1<<TOIE2);
}

void loop() {
  // Your main loop.
}

Bu kodu test etmeden yazdım, bu yüzden bir hata yaptım. Bu durumda, veri sayfasını kontrol edin , s.156 .

Zamanlayıcı frekansını (ön ölçekleyici) değiştirmek istiyorsanız, kaydı değiştirmeniz yeterlidir TCCR2A. Daha fazla bilgi için veri sayfası sayfasına bakınız. 153. Ancak zamanlayıcı frekansını değiştirirseniz, iki çıkış pimindeki PWM sinyalinin frekansını da değiştirebilirsiniz!


ATmega328'de AFAIK Timer0ve Timer28 bit ve sadece Timer116 bit.
tuupola

Hayır, bu doğru değil. Timer0, Timer1 değil, delay () ve millis () ve pim 5 ve 6'daki PWM çıkışı için kullanılır. Timer0, 8 bitlik bir zamanlayıcıdır. Bkz. Örneğin Arduino Zamanlayıcıları ve Kesintileri .
Peter Mortensen
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.