Both sides previous revisionPrevious revisionNext revision | Previous revision |
de:examples:timer:periodic_interrupt [2010/11/10 00:04] – Wember | de:examples:timer:periodic_interrupt [2020/07/20 09:00] (current) – external edit 127.0.0.1 |
---|
====== Periodische Interrupts ====== | ====== Periodische Interrupts ====== |
| |
//Necessary knowledge: [HW] [[en:hardware:homelab:controller]], [HW] [[en:hardware:homelab:digi]], [AVR] [[en:avr:interrupts]], [AVR] [[en:avr:timers]], [LIB] [[en:software:homelab:library:pin]], [LIB] [[en:software:homelab:library:delay]], [LIB] [[en:software:homelab:library:timer]], [PRT] [[en:examples:timer:software_delay]]// | //Notwendiges Wissen: [HW] [[en:hardware:homelab:controller]], [HW] [[en:hardware:homelab:digi]], [AVR] [[en:avr:interrupts]], [AVR] [[en:avr:timers]], [LIB] [[en:software:homelab:library:pin]], [LIB] [[en:software:homelab:library:delay]], [LIB] [[en:software:homelab:library:timer]], [PRT] [[en:examples:timer:software_delay]]// |
| |
===== Theorie ===== | ===== Theorie ===== |
| |
Das Ziel dieses praktischen Beispiels ist es den Gebrauch von Interrupts an Beispiel von Countern zu zeigen. Die Interrupts sind Programmteile welche auf Events die in einem Microcontroller stattfinden reagieren. Ihr Zweck ist normalerweise eine schnelle Antwort auf ein Event, können aber auch benutzt werden um mehrere parallele Prozesse zu beenden, präzise zeitlich abgestimmte Aktion auszuführen, und zur Energieeinsparung. | Ziel dieses praktischen Beispiels ist es, die Verwendung von Interrupts an Beispiel von Timern darzustellen. Interrupts sind Programmteile welche auf Ereignisse, die in einem Mikrocontroller stattfinden, reagieren. Normalerweise dienen sie dazu, schnell auf ein Event zu reagieren. Sie können jedoch auch dazu genutzt werden, um mehrere parallel ablaufende Vorgänge oder zeitlich abgestimmte Aktionen auszuführen, oder zur Energieeinsparung. |
Zum Beispiel ist es möglich eine LED mit Interrupts blinken zu lassen, so dass die Blinkfrequenz nicht von dem abhängig ist, was gerade in einem Programm passiert. | Es ist beispielsweise möglich eine LED durch Interrupts blinken zu lassen, so dass die Blinkfrequenz nicht von einem Programm abhängig ist. |
| |
===== Übung ===== | ===== Übung ===== |
| |
Das folgende Programm zeigt wie Counter eingestellt werden um einen Interrupt auszulösen. | Das folgende Programm zeigt wie Timer eingestellt werden, um einen Interrupt auszulösen. |
Es sind 2 LEDs des Digitalen I/O Moduls in diesem Programm, der Status der roten LED wird mit einer Softwareverzögerung periodisch geändert, der Status der grünen LED wird geändert wenn ein Interrupt stattfindet. Es gibt ein separates Beispiel für blinkende LEDs mit Softwareverzögerung, und wird daher nicht hier erklärt. Das Ziel ist der Gebrauch der Library für Counter und Interrupts. | Das Programm nutzt zwei LEDs des digitalen I/O Moduls. Der Status der roten LED wird mit einer Softwareverzögerung periodisch geändert, der Status der grünen LED wird geändert wenn ein Interrupt auftritt. Es gibt ein separates Beispiel für blinkende LEDs durch Softwareverzögerung, daher wird es an dieser Stelle nicht näher erläutert. Ziel ist es, die Bibliothek für Counter und Interrupts zu verwenden. |
| |
Zu Beginn des Programms wird der 16-Bit Counter/Timer 1 mit der Funktion //timer1_init_ctc// eingestellt. Mit dieser Funktion wird der Counter im CTC //clear timer on compare match// Modus gesetzt, damit ist der maximale Wert vom Benutzer einstellbar. In diesem Fall wird der maximale Wert so gesetzt dass er gleich dem Wert des ICR1 Indexes ist. | Zu Beginn des Programms wird der 16-Bit Timer 1 mit der Funktion //timer1_init_ctc// eingestellt. Dadurch wird der Timer in den CTC //clear timer on compare match// Modus gesetzt, wodurch sein maximaler Wert nicht 216 - 1 ist, sondern vom Benutzer eingestellt werden kann. In diesem Fall wird der maximale Wert so gesetzt dass er gleich dem Wert des ICR1 Indexes ist. |
Der Teiler des Counters ist 1024 und der Wert des ICR1 ist 14400, also bei einer Taktfrequenz von 14,7456MHz ist die Periode genau eine Sekunde. Es ist einfach mit folgender Formel zu rechnen: | Der Teiler des Timers ist 1024 und der Wert des ICR1 beträgt 14400. Bei einer Taktfrequenz von 14,7456MHz umfasst eine Periode somit genau eine Sekunde. Dieses kann mit folgender Formel berechnet werden: |
| |
f = 14745600 Hz / 1024 / 14400 = 1 | f = 14745600 Hz / 1024 / 14400 = 1 |
| |
Nachdem erlauben von Interrupts wenn der maximale Wert von Counter 1 erreicht ist, muss auch auf globelem Level, also im Microcontroller, ein Interrupts erlaubt werden. Um globale Interrupts zu erlauben gibt es die Funktion //sei// und zum verbieten //cli//. Die Headerdatei | Nachdem zugelassen wurde, dass ein Interrupt den maximalen Wert von Counter 1 erreicht, muss ein Interrupt auch global, also im Mikrocontroller, zugelassen werden. Dazu gibt es die Funktion //sei//, um sie zu untersagen die Funktion //cli//. Um den Programmteil für diese Funktionen und Interrupts festzulegen muss die Headerdatei //avr/interrupt.h// eingefügt werden. |
//avr/interrupt.h// muss für diese Funktionen und Interrupts eingefügt werden. | Ein Interrupt wird im Programm durch die Makrofunktion ISR definiert, deren Parameter der Name des Interruptvektors ist. Im folgenden Beispiel beträgt der Interruptvektor des maximal erreichbaren Wertes von Counter 1 //TIMER1_CAPT_vect//. |
Der Programmteil des Interrupts ist durch die Macrofunktion ISR definiert, dessen Parameter der Name des Interruptvektors ist. In diesem Set-up ist die maximalen Wert Interrupts ist | |
//TIMER1_CAPT_vect//. | |
| |
| |
<code c> | <code c> |
// | // |
// The HomeLab's example of blinking LED which blinks due to counter interruptings. | // HomeLab Beispiel für blinkende LED aufgrund von Counter-Interrupts. |
// For comparison to the LED blinking due to interrupts, | // Zum Vergleich blinkender LEDs aufgrund von Interrupts, |
// there is a software delay blinking LED working parallel. | // gibt es parallel eine durch Softwareverzögerung blinkende LED. |
// | // |
#include <homelab/pin.h> | #include <homelab/pin.h> |
| |
// | // |
// Determining the pins of the LEDs. | // Festlegung der Pins der LEDs. |
// | // |
pin led_red = PIN(C, 5); | pin led_red = PIN(C, 5); |
| |
// | // |
// Interruption | // Interrupt |
// | // |
ISR(TIMER1_CAPT_vect) | ISR(TIMER1_CAPT_vect) |
{ | { |
// Changing the state of the green LED. | // Status der grünen LED ändern. |
pin_toggle(led_green); | pin_toggle(led_green); |
} | } |
| |
// | // |
// Main program. | // Hauptprogramm. |
// | // |
int main(void) | int main(void) |
{ | { |
// Setting the pins of the LEDs as outputs. | // LED Pins als Output setzen. |
pin_setup_output(led_red); | pin_setup_output(led_red); |
pin_setup_output(led_green); | pin_setup_output(led_green); |
| |
// Seting the timer up in the CTC mode. | // Timer in den CTC Modus setzen. |
timer1_init_ctc( | timer1_init_ctc( |
TIMER1_PRESCALE_1024, | TIMER1_PRESCALE_1024, |
TIMER1_CTC_TOP_ICR); | TIMER1_CTC_TOP_ICR); |
| |
// The maximal value of the timer is 14400, which | // Maximaler Wert des Timers ist 14400, wodurch |
// makes the length of the period 1 s. | // die Periode 1 s lang ist. |
// Formula: 14,7456Mhz / 1024 = 14400 | // Formel: 14,7456Mhz / 1024 = 14400 |
timer1_set_input_capture_value(14400); | timer1_set_input_capture_value(14400); |
| |
// Allowing interruption of achieving the value. | // Dem Interrupt erlauben, den Wert zu erreichen. |
timer1_input_capture_interrupt_enable(true); | timer1_input_capture_interrupt_enable(true); |
| |
// Allowing global interruption. | // Globalen Interrupt zulassen. |
sei(); | sei(); |
| |
// Endless loop. | // Endlosschleife. |
while (true) | while (true) |
{ | { |
// Software delay 1000 ms. | // Softwareverzögerung 1000 ms. |
sw_delay_ms(1000); | sw_delay_ms(1000); |
| |
// Change of the state of the red LED. | // Status der roten LED ändern. |
pin_toggle(led_red); | pin_toggle(led_red); |
} | } |
</code> | </code> |
| |
Zu Beginn des Programms sieht man, dass egal was der Mircocontroller grade im Hauptprogramm macht, Interrupts stattfinden und die grüne LED blinkt. | Zu Beginn des Programms sieht man, dass unabhängig davon was der Mikrocontroller gerade im Hauptprogramm macht, Interrupts stattfinden und die grüne LED blinkt. |
| |
Wenn wir das Programm ein paar Minuten arbeiten lassen, wird ein wichtiger Aspekt sichtbar, dass man nicht so schnell bei dem der Softwareverzögerung gemerkt haben. Auch wenn die Verzögerung der blinkenden LED 1000ms ist, brauch der komplette Zyklus etwas länger. Das Ändern des LED Status, der Callout der Verzögerungsfunktion und das Beenden des Zyklus benötigt ein paar Arbeitstakte des Prozessors und damit auch Zeit. Daher scheint es, als läuft die rote LED der grünen hinterher. Darum sollte man wenn man Uhren oder andere präzise Aktionen nicht mit Verzögerungen sondern mit Countern ausführen. | Läuft das Programm ein paar Minuten wird ein entscheidender Aspekt deutlich, der im Rahmen der Softwareverzögerung nicht so einfach zu erkennen ist. Auch wenn die Verzögerung der blinkenden roten LED 1000 ms beträgt, ist die tatsächlich benötigte Zeit um einen Zyklus zu beenden länger. Das liegt daran, dass die Änderung vom LED-Status', die Angabe der Verzögerungsfunktion und das Beenden vom Zyklus einige Taktzyklen des Prozessors dauern. Daher sieht es so aus, als blinke die rote LED immer nach der grünen. Aus diesem Grund sollten Taktgeber oder andere präzise Vorgänge nicht mit Verzögerungen, sondern mit Timer-Interrupts ausgeführt werden. |