semaver
New member
Zamanlayıcı, metre ve kesintiler
Bu ekstra baskıda zamanlayıcıların konusu ortaya çıkıyor. Bunlar gecikme () işlevinin basit çağrısından daha fazlasıdır.
İşlev Gecikme () Şimdiye kadar zaman ölçümü açısından sadık ve sürekli ortağımızız. Varsayılan olarak Arduino Kütüphanesi'nde mevcuttur ve milisaniye beklemeye izin verir. Peki daha ne istiyorsun? Anonim sistemlerin geliştirilmesinde – bu arada, sadece gerçek sorular için değil – zamanın ölçümü merkezi bir rol oynar. Gecikme () Ancak, sofistike uygulama alanları için değil, yaklaşık bir araçtır.
Basit işlevler ne yapar Gecikme () VEYA Millis ()?
- Sınırlı çözünürlük: Milisaniye cinsinden bir doğruluk, insan algısı ölçeğinde bekleme süreleri için iletilmiş görünebilir. Bu çözüm teknik olaylar bağlamında yetersizdir. Arduino kartlarında bir atne veya ATY CPU ile, genellikle 8 MHz veya 16 MHz saat frekanslarıyla yaparız. 16 MHz'de tek bir sert saat 0.0000000625 sn. Bu, milisaniyeye (0.001 sn) kıyasla 1: 16.000 faktördür. Bir atga, her milisaniye boyunca binlerce makine kontrolünü ayrıntılı olarak ele alır. Bu nedenle, bu boyutların tepki süreleri kabul edilebilir olmaktan uzaktır.
- Aktif bekle: Gönderen bir gecikme sırasında Gecikme (42) Arduino'nun taslağı aktif olarak beklediği için kınanır. Milisaniye cinsinden seçilen bekleme süresi genellikle slogana göre yaklaşık bir tahminin sonucudur: “Muhtemelen başlatma yaklaşık 2 saniye sürer. Ama sadece güvenlik için 3 saniye kullanıyoruz”. Bu verimsizliğe yol açar.
- Esneklik eksikliği: Timerne'nin kullanımı Gecikme () Sadece bekleme sürelerini entegre etmeye hizmet eder. Diğer hizmetler, özellikle bir koruma köpek zamanlayıcısı gibi periyodik tetikleyiciler, sadece yetersiz veya yetersizdir.
Bir AVR işlemcisi bu tür brüt zaman ölçümünden memnun kalırsa, Arduino kartlarındaki birçok fonksiyonel uzlaşmayı kabul etmeliyiz. Dijital kapılardaki dürtü genişliğinin modülasyonu, kesin faaliyetlerin (iş döngüleri) kesin aktivitelerini ayarlamak için zamanlayıcının yüksek çözünürlüğünü gerektirir. Örneğin, dijital bir çıkışta ortalama 2.765643 V çıkış voltajına ihtiyacınız varsa, bu yalnız olabilir Gecikme () VEYA Millis () rol yapmak.
Benim gibi otobüs sistemleri için2C veya SPI, mikrosaniye alanında tipik ve gereklidir. Bir program bu veri yolu sistemlerinden bağlanan bileşenleri kontrol etmek istiyorsa, büyük milisaniyelerin çözümü şov için bir sınır olacaktır. Son olarak, daha az önemli olmayan, hizmetkotların kontrolü veya tonal üretim için zaman koşulları gereklidir, sadece milisaniye-tetikleyici tarafından uygulanmayan zamanlayıcı uygulamak mümkün değildi.
Önceki deneyimlerden Arduino kartlarının PWM, otobüs sistemleri, hizmetçi kontrolü ve tonların üretimi için mükemmel destek sağladığını bildiğimiz için iki soru ortaya çıkıyor:
- Bir AVR işlemci, gerekli zamansal çözünürlükleri dahili olarak nasıl uygular?
- Bir geliştirici olarak bu işlevlerden de öncü olabilir miyiz?
Bahsedilen faaliyetler için, AV mikrodenetleyicisi çeşitli zamanlayıcıları 8 veya 16 bit genişliğinde atanan sayım kayıtları ile entegre eder. Bu kayıtlar başlangıç değeri 0 ile başlar. Artış veya sayım otomatik ve periyodik olarak. İlgili kayıtlar gerçekleştirilirse, bir zamanlayıcı taşma kesintisi etkinleştirilir.
Yaygın bir hata, Arduino CPU'nun zamanlayıcılara öncülük etmesidir. Bir Arduino veya Atmel AVR mikrodenetleyicisinin zamanlayıcıları CPU veya MCU'dan bağımsızdır. Bu gerçeği aşağıdaki tartışmalarda aklınızda bulundurmalısınız.
Mümkün olan maksimum çözünürlüğü korumak için, ilk yaklaşım, proses beldesinde senkronize olan sayaç (yani artışları) güncellemelerini gerçekleştirmek olabilir. Bununla birlikte, bunun belirleyici bir kusur vardır. 16 MHz'lik varsayılan saat frekansı ile, 16 mikrosaniyeden sonra, yaklaşık 4,1 milisaniye sonra 16 bit kayıttan sonra 8 BIT zamanlayıcının taşmasına ulaşılacaktır.
Bu, kısa vadeli zaman aralıkları için açıkça avantajlıdır. Ya daha uzun süreleri karşılamak istersek? Bunu etkinleştirmek için, mikrodenetleyiciler seçilmiş kişilere sözde sunar. Bunlar, sistemin kaç saat döngüsünü bir sayma kaydı eklemesi gerektiğini yapılandırır. Olası değerler 8, 64, 256 veya 1024'tür
Aralıklarla tam olarak planlamak için, zamanlayıcı kayıtları 0 başlamalarına izin vermek yerine karşı okumalarla başlamak için kullanılabilir. Geldikten sonra, bir LED'i her 0,5 saniyede bir açmak ve kapatmak istiyoruz. Bu nedenle zamanlayıcının istenen frekansı 2 Hz olacaktır. Bir zamanlayıcı taşmasının aktivasyonunda bir saat etkinleştirilir. Bu tam olarak nasıl elde edilebilir?
Aşağıdaki parametrelerle ilgileniyoruz:
- biraz Bit yazarkasa boyutunu, 16 Bit Zamanlayıcı için yaklaşık 16'yı tanımlar.
- MaxCount maksimum sayı değerine karşılık gelirbiraz.
- Reçete Yapılandırılabilir prescal değeri yukarıda açıklanmışsa, yani saat döngüsü sayısı zamanlayıcı kaydında daha fazla artışla yapılır.
- Cpufreq CPU'nun frekansını temsil eder. Döngü döngüsü daha sonra hesaplanır 1 / cpufreq.
- İnit Sayma kaydının başlangıç değeridir.
- saymak Bir kekik üfleyicisini etkinleştirmek için gerekli sayıda artıştır. Uygulanır: Count = MaxCount – InitCount.
- delta Zamanlayıcı taşması tetiklenene kadar istenen zaman aralığını açıklar. Ayrıca tanımlanabilir: Deltat = 1 / timerfreq (Saniyede istenen taşma zamanlayıcısı sayısı).
=> Count = Deltat * CPUFREQ / INGOR
=> MaxCount – InitCount = Deltat * CPUFRQ / Prescal
=> İnitCount = MaxCount – Deltat * Cpufreq / Integral
Örnek Hesaplama: Bir zamanlayıcı taşma kesintisi her 0,5 saniyede bir gerçekleşmelidir.
- 16 -Bit Zamanlayıcı kullanıyoruz: biraz = 16 => MaxCount = 216 = 65536.
- Yarım saniye boyunca bir zamanlayıcı taşmasına ihtiyacımız var. delta = 0.5 sn = 1 / TimerFreq
- Arduino kartının saatinin sıklığı Cpufreq = 16 MHz = 16.000.000 Hz
- Bir reçete değeri bulundukça Reçete = 256 önce.
Zamanlayıcı kaydı başlangıçta 34.286 ile başlamalıdır, böylece zamanlayıcı taşana kadar-65.636 tam olarak yarım saniye geçer. Kesinti hizmet rutininin her yürütülmesinde, sayaç 34.286 ile tekrar başlatılır.
Karşılık gelen bir taslak aşağıdaki gibi görünebilir. Daha sonra listelenen kayıtlara geliyoruz.
#define ledPin 13
void setup()
{
pinMode(ledPin, OUTPUT); // Ausgabe LED festlegen
// Timer 1
noInterrupts(); // Alle Interrupts temporär abschalten
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 34286; // Timer nach obiger Rechnung vorbelegen
TCCR1B |= (1 << CS12); // 256 als Prescale-Wert spezifizieren
TIMSK1 |= (1 << TOIE1); // Timer Overflow Interrupt aktivieren
interrupts(); // alle Interrupts scharf schalten
}
// Hier kommt die selbstdefinierte Interruptbehandlungsroutine
// für den Timer Overflow
ISR(TIMER1_OVF_vect)
{
TCNT1 = 34286; // Zähler erneut vorbelegen
digitalWrite(ledPin, digitalRead(ledPin) ^ 1); // LED ein und aus
}
void loop()
{
// Wir könnten hier zusätzlichen Code integrieren
}
Zamanlayıcıların Dünyası
Bir Arduino'nun sadece tek bir zamanlayıcısı değil, birkaç zamanlayıcısı vardır. Şaşırtıcı olmamalı, ancak zamanlayıcılar bir mikrodenetleyicinin çeşitli görevleri için temel temel bileşenlerdir.
- Zamanlayıcı 0 (8 bit) gibi işlevler için kullanılır Gecikme (),, Millis (),, Micros ()
- Kütüphane hizmetçisi tarafından kullanılan zamanlayıcı 1 (16 bit)
- Toni kitapçısı tarafından kullanılan zamanlayıcı 2 (8 bit)
- Zamanlayıcı 3 (16 bit) sadece mega
- Zamanlayıcı 4 (16 bit) sadece mega
- Zamanlayıcı 5 (16 bit) sadece mega
- Pin PWM 5 ve 6 zamanlayıcı 0 tarafından kontrol edilir
- Pin PWM 9 ve 10 zamanlayıcı 1 tarafından kontrol edilir
- PIN PWM 3 ve 11 Timer 2 tarafından kontrol edilir
- PIN PWM 4 ve 13 zamanlayıcı 0 tarafından kontrol edilir
- Pin PWM 11 ve 12 zamanlayıcı 1 tarafından kontrol edilir
- PIN PWM 9 ve 10 zamanlayıcı 2 tarafından kontrol edilir
- Pin PWM 2, 3 ve 5 zamanlayıcı tarafından kontrol edilir
- Pin PWM 6, 7 ve 8 zamanlayıcı 4 tarafından kontrol edilir
- Pin PWM 44, 45 ve 45 zamanlayıcı 5 tarafından kontrol edilir
- Arduino'nun pim 11'i aynı zamanda SPI veriyolunun PWM ve Pin-in-Pin Master-Out Becerileri ile bir pim. Sonuç olarak, her iki işlev de aynı anda kullanılamaz.
- En azından zamanlayıcı 2, ton üretimi için kullanılmaktadır. Bu nedenle, pimler 3, 11 (arduino) veya 9, 10 (Arduino mega), fonksiyon olduğu sürece PWM için kullanılamaz Ton () Kullanımda.
- Hizmetçileri bağlarken, zamanlayıcılar kendilerini sadece bu göreve ayırmalıdır, bu nedenle Dijital Pim sayısı PMW desteği ile azalır.
Yukarıdaki taslakta görebileceğiniz gibi, zamanlayıcının işlevselliği çeşitli kayıtlar aracılığıyla kontrol edilir. Μ sembolü, ilgili zamanlayıcı sayısını temsil eder: 0, 1, 2, …,. . Bu nedenle tcntµ, zamanlayıcı kontel µ kaydıdır. Zamanlayıcı 1 için sayım kaydı sonuç olarak 0 TCNT0 zamanlayıcısı için TCNT1'dir.
Basitlik nedenlerinden ötürü, sonraki tartışmalar ve örneğin iki eskiz, zamanlayıcı 1'e atıfta bulunur. Ayrıca, tüm ayrıntıların bir listesi dışında, ancak ilgili özelliklere odaklanıyorum.
TCCR1A (zamanlayıcı sayaç/kontrol kaydı): PWM10 ve PWM11 bayrakları, zamanlayıcı 1'in PWM'yi kontrol etmesi durumunda çözünürlüğü belirlemenizi sağlar. Başlangıç noktası anlaşmadır Tccr1a = 0;:
- PWM yok: no-op
- 8 -Bit PWM: TCCR1A |= (1 << PWM10);
- 9 -Bit PWM: TCCR1A |= (1 << PWM11);
- 10 -bit PWM: TCCR1A |= (1 << PWM 10); TCCR1A |= (1 << PWM11);
- Önyargı yok: TCCR1B = 0; TCCR1B |= (1 << CS10);
- İntegral = 8: TCCR1B = 0; TCCR1B |= (1 << CS11);
- INGOR = 64: TCCR1B = 0; TCCR1B |= (1 << CS10); TCCR1B |= (1 << CS11);
- INGOR = 256: TCCR1B = 0; TCCR1B |= (1 << CS12);
- İntegral = 1024: TCCR1B = 0; TCCR1B |= (1 << CS10); TCCR1B |= (1 << CS12);
TCNT1 (zamanlayıcı/sayaç kaydı): yani gerçek sayaç.
OCR1 (Çıkış Karşılaştırma Kayıt): TCNT1 sayaçı eşit derecede OCR1 içeriğiyse, bir zamanlayıcı kesinti karşılaştırır.
ICR1 (Giriş Edinme Kayıt, Yalnızca 16 Bit Kayıt için): Giriş edinme pimlerinin iki tarafı arasındaki zamanın harici devrelerden oluşan ölçümü. Bir motorun devrim sayısını ölçmek için de kullanılabilir. Ayrıca TCCR1A ayarlarından da etkilenir.
Timsk1 (zamanlayıcı/karşı mask kaydı): Zamanlayıcılar burada önlenebilir veya izin verilebilir.
- Güvenli Çıktı Kesme karşılaştırın: TIMSK1 |= (1 << OCIE1A)
- Zamanlayıcı taşma kesintisinin onaylanması (16 bit): TIMSK1 |= (1 << TOIE1)
- Zamanlayıcı taşma kesintisinin onaylanması (16 bit): TIMSK1 |= (1 << TOIE0)
Alternatif CTC yöntemi
Bir zamanlayıcı kaydının kesinti taşımını etkinleştirmek yerine, üst çizimde olduğu gibi, CTC adı verilen alternatif seçenek vardır (eşleşmede Conscel Timer). Bunda mikrodenetleyici, sayaç kaydının içeriğinin zamanlayıcıya ait OCR içeriği ile aynı olup olmadığını karşılaştırır (Çıktı Karşılaştırma Kayıt). Bu durumda, bir zamanlayıcı karşılaştırması etkinleştirilir ve kayıt 0'a geri yüklenir. Bir kez daha bir kesinti yapılmalıdır.
256 Başkan ve 16 MHz saat frekansı ile yukarıdaki formülü saymak için kullanabiliriz: Count = Deltat * CPUFREQ / Prescal = 0.5 * 16.000.000 / 256 = 31.256.
Bu durumda, yukarıdaki taslak değişecektir:
#define ledPin 13
void setup()
{
pinMode(ledPin, OUTPUT); // Ausgabe LED festlegen
// Timer 1
noInterrupts(); // Alle Interrupts temporär abschalten
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0; // Register mit 0 initialisieren
OCR1A = 31250; // Output Compare Register vorbelegen
TCCR1B |= (1 << CS12); // 256 als Prescale-Wert spezifizieren
TIMSK1 |= (1 << OCIE1A); // Timer Compare Interrupt aktivieren
interrupts(); // alle Interrupts scharf schalten
}
// Hier kommt die selbstdefinierte Interruptbehandlungsroutine
// für den Timer Compare Interrupt
ISR(TIMER1_COMPA_vect)
{
TCNT1 = 0; // Register mit 0 initialisieren
digitalWrite(ledPin, digitalRead(ledPin) ^ 1); // LED ein und aus
}
void loop()
{
// Wir könnten hier zusätzlichen Code integrieren
}
Özet
Bu ekstra, Atmel Aile İşlemcilerindeki (ATMEGA, ATTINE) sofistike zamanlayıcıların işlevleriyle ilgilidir. Bu şimdi konuyu daha iyi anlamalıdır. Bunu daha ayrıntılı olarak daha ayrıntılı olarak bilmek istiyorsanız, sizi bu gibi Atmel üreticisinin belgelerine yönlendiriyorum.
Ses sentezi, PWM veya Servomotors gibi gelişmiş uygulamalarda bu işlevselliğin pratik uygulaması hakkında daha fazla bilgi edinebilirsiniz. Bu Adofruit makalesi bir başka yararlı okumadır.
Ama aynı zamanda deneylerinizle öğrendiklerinizi derinleştirmek de iyi bir fikirdir.
()