Wie erstelle ich einen Timer-Interrupt mit Arduino?

Ich versuche, mit Arduino einen Zeitverzögerungs-Interrupt zu erstellen. Ich möchte die Funktion interrupts() verwenden, da es sich um einen internen Interrupt handelt.

Beispiel: Nehmen wir an, ich möchte ein Licht blinken lassen, nur mit dem Timing des Interrupts.

Es gibt Beispielcode, aber er verwendet externe Interrupts (attachInterrupt()). Ich möchte weiterhin die internen Interrupts verwenden.

Ich denke, der Punkt, den auch Kortuk gezeigt hat, ist, dass AttachInterrupt eine abstrakte Sache ist, Sie hängen keine externe Komponente an :)
Dieser Artikel könnte Ihnen helfen. engblaze.com/…

Antworten (4)

Noah Stahls Blog enthält ein Beispiel für das Blinken einer LED mit Timer2 . Damit und mit dem Datenblatt sollten Sie in der Lage sein, es an jeden Interrupt anzupassen, den Sie verwenden möchten – dh den Interrupt, dessen normale Funktion Sie am ehesten aufgeben können oder zu ändern bereit sind. Timer2 wird normalerweise für einige PWM-Funktionen verwendet.

Sein Beispiel zitiert den ATmega2560; Ich kann bestätigen, dass es auch mit einem ATmega328p funktioniert. Sehen Sie sich auf seiner Website nach weiteren nützlichen Beispielen für Arduino-Interrupts um.

Bearbeiten:

Hier ist meine leicht bearbeitete – hauptsächlich in den Kommentaren – Version von Noahs Code. Rufen Sie Timer2init() aus der Arduino-Funktion setup() auf, nachdem Sie alle zugehörigen Datenstrukturen oder Hardware initialisiert haben, da das Timing – und das Unterbrechen – beginnt, sobald Sie dies tun.

Zum Beispiel habe ich es verwendet, um eine 3-stellige 7-Segment-Anzeige zu multiplexen, also habe ich vor der Initialisierung des Timers die Anzeige-E / A-Register initialisiert und die Anzeigedaten an der Stelle gelöscht, an der die ISR danach suchen wird.

In den Kommentaren befindet sich eine Tabelle mit einigen nützlichen Timing-Daten aus dem Datenblatt und meinen eigenen Berechnungen als Referenz, um ein anderes Timing-Schema einzurichten.

Das ISR()-Makro kümmert sich darum, einen Interrupt-Eingangs- und -Ausgangscode für einen ISR anstelle des Eingangs und Ausgangs einer normalen Funktion zu erzeugen und ihn mit dem richtigen Interrupt-Vektor zu verknüpfen. Der Rest dieser Funktion ist 1) der Code, der bei jedem Interrupt ausgeführt werden soll, und 2) der Codecode zum Zurücksetzen des Timers für den nächsten Interrupt.

Wie geschrieben, sollte dies in einer .pde- oder .ino-Skizze (oder einer .cpp-Datei, wenn Sie Eclipse, f/ex verwenden) abgelegt werden. Die Skizze muss #define LEDPIN und setup() muss Timer2init() aufrufen. Die Schleifenfunktion kann leer sein oder nicht; Die LED sollte beim Download anfangen zu blinken (na ja, buchstäblich, nachdem Timer2init() aufgerufen wurde).

/*
 * 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: Der Kommentar, auf den Sie sich beziehen, war meine Beobachtung mehrerer Kommentatoren hier und richtete sich nicht an Sie persönlich und war unnötig. Ich entschuldige mich und habe ihn entfernt.) Ich habe meine Antwort erweitert, wie Sie vorgeschlagen haben, und ich hoffe, dass dies der Fall ist jetzt nicht nur demonstrativ, sondern auch lehrreich. Es enthält Kommentare, die ich für meinen eigenen Gebrauch in den Code geschrieben habe (was bedeutet: Wenn ich sie in 6 Monaten verstehen kann, wird es jemand anderes auch können), sowie ein paar "How to use"-Anweisungen in der Antworten. Vielen Dank für Ihre Vorschläge.
Beachten Sie, dass Prescales von 32 und 128 für Timer0 und Timer1 nicht verfügbar sind (zumindest mit atmega328).
Das ist gut zu wissen - danke. Ich benutze dies für Timer2 (bisher) und es ist im Grunde ein Drop-In.

Die Funktion attachmentInterrupt() hängt tatsächlich einen Interrupt an eine externe Zustandsänderung an einem Pin an, sie hat keine anderen Optionen.

Auf derselben Seite sind die Modusoptionen wie folgt aufgeführt:

mode definiert, wann der Interrupt ausgelöst werden soll. Als gültige Werte sind vier Konstanten vordefiniert:

  • LOW , um den Interrupt auszulösen, wenn der Pin niedrig ist,
  • CHANGE , um den Interrupt auszulösen, wenn der Pin seinen Wert ändert
  • RISING , um auszulösen, wenn der Stift von niedrig nach hoch geht,
  • FALLING , wenn der Pin von High auf Low wechselt.

Tut mir leid, der Überbringer schlechter Nachrichten zu sein, das war auch eines der ersten Dinge, nach denen ich gesucht habe.

Ich denke, er meint, dass er einen internen Timer anstelle eines externen Geräts verwenden möchte ... aber ich kenne Arduino nicht sehr gut, daher kann ich nicht sagen, ob es möglich ist
@clabacchio, ich sage, dass die einzige Möglichkeit darin besteht, einen externen Trigger zu verwenden, es gibt keine interne Timer-Funktion.
Ah, gut :) aber haben die Arduino-Boards wenigstens Timer?
Ja, so erreichen sie Dinge wie Verzögerung.
@Kortuk, vielleicht ist dies ein Problem des Verständnisses der Bedeutung, die Sie zu vermitteln versuchen. Der AVR uC auf Arduino, dh ATmega328, verfügt jedoch über einen integrierten 8-MHz-Oszillator, sodass kein externer Trigger erforderlich ist. Die Systemuhr speist die 3 verschiedenen Timer (Timer0, Timer1, Timer2) und einzelne Multiplikatoren. Ich habe mich zwar in letzter Zeit nicht näher damit befasst, aber soweit ich mich erinnere, verwendet Arduino eine davon für die Timing-/Verzögerungsfunktionen und eine andere für PWM, wobei ein Timer ungenutzt bleibt. Der Benutzer kann sich tatsächlich in den kostenlosen einklinken (der ein 8-Bit-Timer ist) oder sogar mit anderen Timern verketten.
@ icarus74, Das klingt vernünftig, ich habe geantwortet, dass Arduino keine eingebaute Funktion hat, die ich finden könnte, um die Verwendung eines Interrupts basierend auf seinem Timer zu ermöglichen. Ich erkläre ausdrücklich, dass Sie den Timer nicht für einen Interrupt verwenden können, da das Arduino-Paket eingerichtet ist. Es würde für mich Sinn machen, dass ein Benutzer seinen eigenen Interrupt einrichten könnte, indem er eine Bibliothek schreibt, erkläre einfach, was ich weiß, dass es verfügbar ist.
@icarus74 ATMega328 hat wirklich 3 Timer (einer ist 16b und zwei sind 8b), aber alle werden von Arduino verwendet. Einer wird für Funktionen wie delay() und millis() verwendet und alle drei werden für PWM verwendet (weitere Informationen finden Sie in der Funktion 'init()', Datei 'wiring.c' in Arduino IDE).

Dieser Artikel über PWM wird viele Ihrer Zweifel bezüglich der Verwendung von Arduino-Timern ausräumen. Es gibt zwei 8-Bit-Timer und einen 16-Bit-Timer auf Arduino. Es gibt keine High-Level-API, um die ISR-Funktion direkt mit den Timern zu verknüpfen, die mit dem Arduino SDK (dh als Standardbibliothek) geliefert werden, sondern eine etwas niedrigere Methode zum Setzen von Special-Function-Registers und Bit-Arithmetik / Operationen an ihnen. Es gibt jedoch eine von Benutzern beigesteuerte Bibliothek namens Timer one .

Es sind tatsächlich mehrere verschiedene Timer-Kombinationen möglich, je nachdem, auf welches Arduino verwiesen wird. Antwort ist irreführend.
@SeeminglyAlso, möchten Sie das näher erläutern? Wenn Sie über Arduino-Hardware sprechen, beachten Sie, dass die Antwort im Kontext der Frage steht und auch der Zeitpunkt, zu dem die Frage gestellt wird.
Der Arduino Mega (ATmega1280-basiert) wurde am 26. März 2009 und der Mega 2560 (ATmega2560) am 24. September 2010 veröffentlicht, beide lange bevor diese Frage gestellt wurde. Beide Mikrocontroller haben mehr als die in der Antwort angegebenen 2x 8-Bit- und 1x 16-Bit-Timer/Zähler.
Die meisten Interaktionen, die ich bisher gesehen habe, haben einen eindeutigen Bezug zu Arduino, um so etwas wie Duemilanove oder Uno zu meinen, dh die auf der 328-Serie basierenden Boards. Andere Boards wurden schon immer ausdrücklich durch die uP-Serien-Nr. oder Mega, Nano, Micro etc. Jedenfalls nehme ich die Korrektur demütig entgegen. In diesem Zusammenhang ist eine Klarstellung besser.

Arduino verwendet alle drei Timer in ATMega328. Timer1(16 Bit) wird für Funktionen wie delay()und millis()für die PWM-Ausgabe an den Pins 5 und 6 verwendet. Die anderen beiden Timer — Timer0und Timer2werden für die PWM-Ausgabe an den Pins 3, 9, 10, 11 verwendet.

Es gibt also keine Arduino-Funktion für den Timer-Interrupt. Aber es gibt einen Weg. Sie können diesen Code verwenden, um den Timer-Interrupt zu aktivieren Timer2:

ISR(TIMER2_OVF_vect) {
  // Interrupt routine.
}

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

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

Ich habe diesen Code ohne Tests geschrieben, daher ist es möglich, dass ich einen Fehler gemacht habe. In diesem Fall siehe Datenblatt, S. 156 .

Wenn Sie die Timer-Frequenz (Prescaler) ändern möchten, ändern Sie einfach das Register TCCR2A. Weitere Informationen finden Sie im Datenblatt auf Seite 153. Wenn Sie jedoch die Frequenz des Timers ändern, ändern Sie auch die Frequenz des PWM-Signals an zwei Ausgangspins!

AFAIK auf ATmega328 Timer0und Timer2sind 8 Bit und nur Timer116 Bit.
Nein, das ist nicht richtig. Es ist Timer0, nicht Timer1, der für delay() und millis() und für die PWM-Ausgabe an den Pins 5 und 6 verwendet wird. Timer0 ist ein 8-Bit-Timer. Siehe zB Arduino Timers and Interrupts .