Kesme rutininde millis () ve micros () kullanma


13

İçin belgeler attachInterrupt()diyor:

... millis()saymak için kesintilere dayanır, bu yüzden asla bir ISR'nin içinde artmaz. Yana delay()çalışmalarına kesmeleri gerektiren bir ISR içinde denir, eğer çalışmaz. micros()başlangıçta çalışır, ancak 1-2 ms sonra düzensiz davranmaya başlayacaktır. ...

Nasıl gelmez micros()farklılık millis()(kendi hassasiyet için elbette hariç)? Yukarıdaki uyarı, micros()bir kesme rutininin içinde kullanmanın her zaman kötü bir fikir olduğu anlamına mı geliyor ?

Bağlam - Düşük darbe doluluk oranını ölçmek istiyorum , bu yüzden giriş sinyalim değiştiğinde ve geçerli saati kaydettiğimde rutinimi tetiklemem gerekiyor.

Yanıtlar:


16

Diğer cevaplar çok iyi, ama nasıl micros()çalıştığını açıklamak istiyorum . Her zaman donanım TCNT0tarafından sürekli olarak güncellenen geçerli donanım zamanlayıcısını (muhtemelen ) okur (aslında, 64 ön ölçekleyici nedeniyle her 4 µs'de bir). Daha sonra bir zamanlayıcı taşma kesintisi (256 ile çarpılır) ile güncellenen Zamanlayıcı 0 taşma sayısını ekler.

Böylece, bir ISR'nin içinde bile, micros()güncellemeye güvenebilirsiniz . Ancak çok uzun süre beklerseniz taşma güncellemesini kaçırırsınız ve sonra döndürülen sonuç aşağı iner (yani 253, 254, 255, 0, 1, 2, 3 vb.)

Bu micros()- diğer işlemciler için tanımları kaldırmak için biraz basitleştirilmiştir:

unsigned long micros() {
    unsigned long m;
    uint8_t oldSREG = SREG, t;
    cli();
    m = timer0_overflow_count;
    t = TCNT0;
    if ((TIFR0 & _BV(TOV0)) && (t < 255))
        m++;
    SREG = oldSREG;
    return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
}

Yukarıdaki kod taşmaya izin verir (TOV0 bitini kontrol eder), böylece kesmeler kapalıyken taşma ile başa çıkabilir ancak sadece bir kez - iki taşma işlemesi için bir hüküm yoktur.


TLDR;

  • ISR içinde gecikme yapmayın
  • Onları yapmanız gerekiyorsa, o zaman zamanla yapabilirsiniz, micros()ancak yapamazsınız millis(). Ayrıca delayMicroseconds()bir olasılık.
  • 500 µs'den fazla geciktirmeyin, aksi takdirde zamanlayıcı taşmasını kaçırırsınız.
  • Kısa gecikmeler bile gelen seri verileri kaçırmanıza neden olabilir (115200 baud'da her 87 µs'de yeni bir karakter elde edersiniz).

Micros () 'da kullanılan aşağıdaki ifadeyi anlayamıyorum. Lütfen biraz açıklayabilir misiniz? ISR yazıldığından, ISR girilir girilmez TOV0 bayrağı silinecek ve bu nedenle aşağıdaki koşul gerçekleşmeyebilir !. eğer ((TIFR0 & _BV (TOV0)) && (t <255)) m ++;
Rajesh

micros()bir ISR değil. Bu normal bir işlevdir. TOV0 bayrağı, zamanlayıcı taşmasının gerçekleşip gerçekleşmediğini (ancak henüz işlenmediğini) görmek için donanımı test etmenizi sağlar.
Nick Gammon

Test kesintilerle yapıldığından, test sırasında bayrağın değişmeyeceğini biliyorsunuz.
Nick Gammon

Yani micros () fonksiyonu içinde cli () sonra, herhangi bir taşma meydana gelirse, bu kontrol edilmesi mi demek istiyorsun? Bu mantıklı. Aksi takdirde, mikrolar bir işlev olmasa da, TIMER0_OVF_vect ISR, TIFR0'daki TOV0'ı şüphem budur.
Rajesh

Ayrıca TCNT0 neden 255'ten az olup olmadığını görmek için 255 ile karşılaştırılır? Cli () 'den sonra TCNT0 255' e ulaşırsa ne olur?
Rajesh

8

Bir kesme rutini kullanmak veya içinde yanlış değildir .millis()micros()

İse yanlış bunları kullanmak için yanlış.

Buradaki en önemli şey, bir kesme rutinindeyken "saat geçmiyor". millis()ve micros()değişmeyecek ( micros()başlangıçta değişecek , ancak bir milisaniyelik bir kene gereken sihirli milisaniye noktasının ötesine geçtikten sonra hepsi ayrı düşüyor.)

Böylece kesinlikle ISR'nizdeki geçerli saati arayabilir millis()veya micros()öğrenebilirsiniz, ancak o zamanın değişmesini beklemeyin.

Sağladığınız teklifte uyarılan zamanda değişiklik olmaması. ne kadar zaman geçtiğini bilmek değişime delay()dayanır millis(). Değişmediği için delay()asla bitemez.

Yani esasen millis()ve ISR'nizde nemicros() zaman kullanırsanız kullanın, ISR'nizin çağrıldığı zamanı size söyleyecektir .


3
Hayır, micros()güncellemeler. Her zaman donanım zamanlayıcı kaydını okur.
Nick Gammon

4

Alıntılanan ifade bir uyarı değildir , sadece işlerin nasıl çalıştığına dair bir ifadedir.

Düzgün yazılmış bir kesme rutini kullanarak millis()veya micros()içinde özünde yanlış olan hiçbir şey yoktur .

Öte yandan, yanlış yazılmış bir kesme rutini içinde herhangi bir şey yapmak tanım gereği yanlıştır.

İşini yapmak için birkaç mikrosaniyeden fazla süren bir kesme rutini, her durumda, yanlış yazılmıştır.

Kısacası: Bir düzgün yazılmış kesme rutin yol açmayacak ya da karşılaşma sorunları millis()veya micros().

Düzenleme: " Arduino micros işlevinin incelenmesi " web sayfasında açıklandığı gibi "neden micros ()" düzensiz davranmaya başlar "ile ilgili olarak , micros()sıradan bir Uno kod işlevsel olarak eşdeğerdir

unsigned long micros() {
  return((timer0_overflow_count << 8) + TCNT0)*(64/16);
}

Bu timer0_overflow_count, zamanlayıcı-0 sayma kaydından gelen en düşük üç bayt ve bir bayttan oluşan dört baytlık işaretsiz bir uzun döndürür .

timer0_overflow_countTarafından milisaniye başına bir kez hakkında artırılır TIMER0_OVF_vectkesme yürütücüsü gibi bir açıklandığı Arduino Millis fonksiyonu incelenmesine web sayfası.

Bir kesme işleyicisi başlamadan önce, AVR donanımı kesintileri devre dışı bırakır. (Örneğin) bir kesme işleyicisi, kesintiler hala devre dışı bırakılmış beş milisaniye boyunca çalışacaksa, en az dört zamanlayıcı 0 taşması kaçırılır. [Arduino sistemindeki C kodunda yazılan kesintiler yeniden girilmez (aynı işleyici içinde birden çok çakışan yürütmeyi doğru şekilde işleyebilir), ancak zaman alıcı bir işleme başlamadan önce kesmeleri yeniden etkinleştirebilen bir yeniden birleştirici montaj dili işleyicisi yazılabilir.]

Başka bir deyişle, zamanlayıcı taşmaları “birikmez”; bir önceki taşma kesintisinden önce bir taşma meydana geldiğinde, millis()sayaç bir milisaniyeyi kaybeder ve buna karşılık tutarsızlık da bir milisaniyede yanlış timer0_overflow_countyapar micros().

Kesme işlemi için bir üst süre limiti olarak "500 μs'den daha kısa" ile ilgili olarak, "zamanlayıcı kesintisinin çok uzun süre engellenmesini önlemek için", 1024 μs'nin (örn. 1020 μs) biraz altına kadar çıkabilir ve millis()yine de işe yarayabilir. saati. Bununla birlikte, 5 μs'den fazla bir sümüklü böcek, 10 μs'den fazla tembel, 20 μs'den fazla salyangoz benzeri bir kesme işleyicisi görüyorum.


"İşlerin nasıl yürüdüğünü", özellikle neden micros()"düzensiz davranmaya başlayacağınızı" biraz açıklayabilir misiniz? Peki "düzgün yazılmış kesme rutini" ile ne demek istiyorsun? Ben "500us daha kısa" (zamanlayıcı kesmeyi çok uzun süre engellenmesini önlemek için), "iletişim için değişken değişkenler kullanmak" ve "kütüphane kodunu çağırmak" mümkün olduğunca, yani başka bir şey var demek olduğunu varsayalım.
Petr Pudlák

@ PetrPudlák, bakınız düzenleme
James Waldby - jwpat7
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.