Jak utworzyć przerwanie timera w Arduino?


9

Próbuję utworzyć przerwanie opóźnienia czasowego w Arduino. Chciałbym użyć funkcji interrupts (), ponieważ jest to wewnętrzne przerwanie.

Przykład: Powiedzmy, że chciałbym, aby kontrolka mrugała i wyłączała się, podając jedynie czas przerwania.

Istnieje przykładowy kod, ale wykorzystuje on zewnętrzne przerwania (attachInterrupt ()). Chciałbym nadal używać wewnętrznych przerwań.


2
Myślę, że Kortuk pokazał też, że attachInterrupt jest abstrakcyjną rzeczą, nie
dołączasz

Ten artykuł może ci pomóc. engblaze.com/…
Seth Archer Brown

Odpowiedzi:


10

Blog Noah Stahl ma przykład migania diody LED za pomocą Timera2 . Dzięki temu i karcie danych powinieneś być w stanie dostosować ją do dowolnego przerwania, którego chcesz użyć - tj. Przerwania, którego normalnej funkcji najbardziej możesz sobie pozwolić na rezygnację lub na modyfikację. Timer2 jest zwykle używany do niektórych funkcji PWM.

Jego przykład przytacza ATmega2560; Mogę potwierdzić, że działa również z ATmega328p. Rozejrzyj się po jego stronie, aby znaleźć bardziej przydatne przykłady przerwań Arduino.

Edytować:

Oto moja lekko zredagowana - głównie w komentarzach - wersja kodu Noego. Wywołaj Timer2init () z funkcji Arduino setup () po zainicjowaniu powiązanej struktury danych lub sprzętu, ponieważ odmierzanie czasu i przerwanie rozpocznie się po wykonaniu tej czynności.

F / ex, użyłem go do multipleksowania 3-cyfrowego 7-segmentowego wyświetlacza, więc przed zainicjowaniem timera zainicjowałem rejestry we / wy wyświetlacza i wyczyściłem dane wyświetlania w miejscu, w którym będzie go szukał ISR.

W komentarzach znajduje się tabela niektórych przydatnych danych dotyczących czasu z arkusza danych i moich własnych obliczeń, które mogą posłużyć jako odniesienie do ustanowienia innego schematu pomiaru czasu.

Makro ISR () zajmuje się tworzeniem kodu wejścia i wyjścia przerwań dla ISR zamiast wejścia i wyjścia normalnej funkcji oraz powiązaniem go z odpowiednim wektorem przerwań. Reszta tej funkcji to 1) kod, który ma być uruchamiany przy każdym przerwaniu, oraz 2) kod kodu, aby zresetować licznik czasu dla następnego przerwania.

Jak napisano, powinno to zostać przeniesione do szkicu .pde lub .ino (lub pliku .cpp, jeśli używasz Eclipse, f / ex). Szkic musi # zdefiniować LEDPIN, a setup () musi wywołać Timer2init (). Funkcja pętli może być pusta lub nie; dioda LED powinna zacząć migać podczas pobierania (no dosłownie po wywołaniu Timer2init ()).

/*
 * 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: Wspomniany komentarz był moją obserwacją kilku komentatorów tutaj i nie był skierowany do ciebie osobiście i nie był potrzebny. Przepraszam i usunąłem go.) Rozszerzyłem swoją odpowiedź, jak zasugerowałeś i mam nadzieję, że to jest teraz nie tylko demonstracyjny, ale także pouczający. Zawiera komentarze, które napisałem w kodzie na własny użytek (co oznacza: jeśli będę w stanie je zrozumieć za 6 miesięcy, ktoś też będzie w stanie to zrobić), a także kilka instrukcji „jak używać” w odpowiedź. Dziękuję za twoje sugestie.
JRobert,

Należy pamiętać, że przedskale 32 i 128 nie są dostępne dla timera 0 i timera 1 (przynajmniej z atmega328).
tuupola

Dobrze wiedzieć - dzięki. Używam tego dla Timera 2 (jak dotąd) i jest to po prostu drop-in.
JRobert

5

Funkcja attachInterrupt () faktycznie dołącza przerwanie do zmiany stanu zewnętrznego na pinie, nie ma żadnych innych opcji.

Na tej samej stronie opcje trybu są wymienione jako:

Tryb określa, kiedy ma zostać uruchomione przerwanie. Cztery wartości warunkowe są wstępnie zdefiniowane jako prawidłowe wartości:

  • LOW, aby uruchomić przerwanie, gdy pin jest niski,
  • ZMIEŃ, aby wywołać przerwanie za każdym razem, gdy pin zmienia wartość
  • RISING, aby uruchomić, gdy pin przechodzi z niskiego do wysokiego,
  • SPADAJĄ, gdy pin przechodzi z wysokiego do niskiego.

Przepraszam, że jestem nosicielem złych wieści, to jedna z pierwszych rzeczy, których szukałem.


Myślę, że ma na myśli, że chce użyć wewnętrznego timera zamiast zewnętrznego urządzenia ... ale nie znam zbyt dobrze Arduino, więc nie mogę powiedzieć, czy to możliwe
clabacchio

@ clabacchio, mówię, że jedyną opcją jest użycie zewnętrznego wyzwalacza, nie ma wewnętrznej funkcji timera.
Kortuk

Ach, dobrze :) ale czy przynajmniej tablice Arduino mają jakieś timery?
clabacchio

Tak, w ten sposób osiągają takie rzeczy jak opóźnienie.
Kortuk

1
@ icarus74 ATMega328 naprawdę ma 3 timery (jeden to 16b, a dwa to 8b), ale wszystkie z nich są używane przez Arduino. Jeden służy do funkcji takich jak delay () i millis (), a wszystkie trzy są używane do PWM (więcej informacji można znaleźć w funkcji „init ()”, plik „wiring.c” w Arduino IDE).
vasco

2

Ten artykuł na temat PWM rozwieje wiele twoich wątpliwości dotyczących używania zegarów Arduino. W Arduino są dwa 8-bitowe timery i jeden 16-bitowy. Nie ma interfejsu API wysokiego poziomu, aby podłączyć funkcję ISR bezpośrednio do timerów, który jest dostarczany z Arduino SDK (tj. Jako standardowa biblioteka), ale nieco niższa metoda ustawiania rejestrów funkcji specjalnych i arytmetyki bitów / operacje na nich. Istnieje jednak biblioteka użytkownika o nazwie Timer jeden .


W rzeczywistości istnieje kilka różnych kombinacji timerów, w zależności od tego, o którym mowa w Arduino. Odpowiedź jest myląca.
Niby So

@ Wydaje się, że chcesz opracować? Jeśli mówisz o sprzęcie Arduino, zwróć uwagę, że odpowiedź jest w kontekście pytania, a także godziny, w której pytanie jest zadawane.
icarus74

Arduino Mega (oparty na ATmega1280) został wydany 26 marca 2009 r., A Mega 2560 (ATmega2560) został wydany 24 września 2010 r., Oba na długo przed zadaniem tego pytania. Oba mikrokontrolery mają więcej niż 2x 8 bitów i 1x 16 bitów timera / licznika określonych w odpowiedzi.
Pozornie

Większość interakcji, które widziałem do tej pory, ma jednoznaczne odniesienie do Arduino, co oznacza podobne do Duemilanove lub Uno, tj. Płyt opartych na serii 328. Inne płyty zawsze były jednoznacznie zakwalifikowane przez UP seria nr. lub Mega, Nano, Micro itp. W każdym razie pokornie zaakceptuję poprawkę. W tym kontekście wyjaśnienie jest lepsze.
icarus74

1

Arduino używa wszystkich trzech timerów w ATMega328. Timer1(16 bitów) służy do funkcji takich jak delay()i millis()do wyjścia PWM na pinach 5 i 6. Pozostałe dwa timery - Timer0i Timer2są używane do wyjścia PWM na pinach 3, 9, 10, 11.

Tak więc nie ma funkcji Arduino dla przerwania timera. Ale jest na to sposób. Możesz użyć tego kodu, aby włączyć przerwanie timera na Timer2:

ISR(TIMER2_OVF_vect) {
  // Interrupt routine.
}

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

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

Napisałem ten kod bez testowania, więc możliwe, że popełniłem błąd. W takim przypadku sprawdź arkusz danych, s . 156 .

Jeśli chcesz zmienić częstotliwość timera (prescaler), po prostu zmień rejestr TCCR2A. Aby uzyskać więcej informacji, zajrzyj do arkusza danych na stronie 153. Ale jeśli zmienisz częstotliwość timera, zmienisz również częstotliwość sygnału PWM na dwóch pinach wyjściowych!


AFAIK na ATmega328 Timer0i Timer2są 8-bitowe i tylko Timer116-bitowe.
tuupola

Nie, to nie jest poprawne. To Timer0, a nie Timer 1, służy do opóźnień () i millis () oraz do wyjścia PWM na pinach 5 i 6. Timer0 jest 8-bitowym timerem. Patrz np. Zegary Arduino i Przerwania .
Peter Mortensen,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.