Difference between revisions of "AVR Embedded Tutorial - Timer, Counter/de"
m (Fixed template loop; modded categories to German; added language category) |
|||
(29 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
+ | {{LanguageBar}} | ||
+ | |||
+ | =Timer / Counter= | ||
+ | |||
==Titel== | ==Titel== | ||
+ | |||
+ | Hier geht es nicht darum, alle Register zu verstehen. Dies sollte nur ein praktisches Beispiel sein, wie man es in FPC/Lazarus umsetzt. | ||
+ | |||
+ | Genauere Details gibt es hier: | ||
+ | |||
+ | * https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR | ||
+ | |||
+ | ==Beispiel, LEDs über Timer steuern== | ||
+ | |||
Dieses Beispiel zeigt, wie man die beiden Timer eines ATtiny2313 verwenden kann. | Dieses Beispiel zeigt, wie man die beiden Timer eines ATtiny2313 verwenden kann. | ||
− | Jeder Timer steuert eine LED an, welche an Bit 0 und 1 des PortD sind. | + | Jeder Timer steuert eine LED an, welche an Bit 0 und 1 des PortD sind. Dabei sollte die LED an PD0 etwas schneller blinken. |
− | + | ||
− | + | ===Beispiel Code=== | |
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
+ | program Project1; | ||
+ | </syntaxhighlight> | ||
− | == | + | ====Timer 0 Interrupt==== |
− | |||
− | |||
− | |||
− | + | <syntaxhighlight lang="pascal"> | |
− | + | procedure Timer0_Interrupt; public Name 'TIMER0_COMPA_ISR'; interrupt; | |
− | + | const | |
+ | t = 10; // LED sollte nur bei jedem 10. Durchlauf umschalten. | ||
+ | z: integer = 0; // Zähler für Leerdurchläufe. | ||
+ | begin | ||
+ | TCNT0 := 128; // Speed halbieren 0 = langsam (default) | ||
+ | Inc(z); | ||
+ | if (z = t) then begin | ||
+ | PORTD := PORTD or (1 shl 0); // LED Pin0 ein | ||
+ | end; | ||
+ | if (z = t shl 1) then begin | ||
+ | PORTD := PORTD and not (1 shl 0); // LED Pin0 aus | ||
+ | z := 0; | ||
+ | end; | ||
end; | end; | ||
+ | </syntaxhighlight> | ||
− | + | ====Timer 1 Interrupt==== | |
− | |||
− | |||
− | |||
− | + | <syntaxhighlight lang="pascal"> | |
− | + | procedure Timer1_Interrupt; public Name 'TIMER1_COMPA_ISR'; interrupt; | |
− | |||
const | const | ||
− | + | t = 500; // LED sollte nur bei jedem 500. Durchlauf umschalten. | |
+ | z: integer = 0; // Zähler für Leerdurchläufe. | ||
begin | begin | ||
− | + | Inc(z); | |
− | Inc( | + | if (z = t) then begin |
− | if ( | + | PORTD := PORTD or (1 shl 1); // LED Pin1 ein |
− | PORTD := PORTD or (1 shl | ||
end; | end; | ||
− | if ( | + | if (z = t shl 1) then begin |
− | PORTD := PORTD and not (1 shl | + | PORTD := PORTD and not (1 shl 1); // LED Pin1 aus |
− | + | z := 0; | |
end; | end; | ||
end; | end; | ||
− | procedure | + | </syntaxhighlight> |
+ | |||
+ | ====Timer initialisieren==== | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
+ | begin | ||
+ | // -- Interrupt unterbinden. | ||
+ | asm cli end; | ||
+ | |||
+ | // -- PD0 und PD1 auf Ausgabe stellen. | ||
+ | DDRD := %00000011; | ||
+ | |||
+ | // -- Timer0 initialisieren. | ||
+ | TCCR0A := 0; | ||
+ | TCCR0B := %101; // CPU-Takt / 1024 | ||
+ | TIMSK := TIMSK or (1 shl OCIE0A); // Timer0 soll Interrupt auslösen. | ||
+ | |||
+ | // -- Timer1 initialisieren. | ||
+ | TCCR1A := 1; // CTC-Modus | ||
+ | TCCR1B := %010; // CPU-Takt / 8 | ||
+ | TIMSK := TIMSK or (1 shl OCIE1A); // Timer1 soll Interrupt auslösen. | ||
+ | |||
+ | // -- Interrupt aktivieren. | ||
+ | asm sei end; | ||
+ | |||
+ | // -- Hauptschleife | ||
+ | repeat | ||
+ | // Mache Irgendwas. | ||
+ | until 1 = 2; | ||
+ | end. | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==Timer extern getaktet== | ||
+ | |||
+ | Einen Timer kann man auch extern getaktet werden. Folgendes Beispiel demonstriert dies mit einem Atmega328. | ||
+ | Zum extern takten gibt es folgende Pins am AVR: | ||
+ | |||
+ | * '''T0''' taktet Timer 0 | ||
+ | * '''T1''' taktet Timer 1 | ||
+ | |||
+ | Der Timer 2 kann '''nicht''' extern getaktet werden. | ||
+ | |||
+ | ===Beispiel einer Uhr=== | ||
+ | |||
+ | Für eine exakte Uhr ist ein Quarz/Oszilator mit 4.194304MHz geeignet. Dieser lässt sich gut in einer 2er Potenz teilen, so das man auf einen Sekunden-Takt kommt. | ||
+ | Hier wird der Timer 0 extern getaktet, dazu muss man den Oszilator an '''T0''' (PD4) anschliessen. | ||
+ | |||
+ | ====Timer Interrupt==== | ||
+ | |||
+ | Jeder 16384 Aufruf des Interupts ist eine Sekunde. | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
+ | procedure Timer0_Interrupt; public Name 'TIMER0_OVF_ISR'; interrupt; | ||
const | const | ||
− | + | cl = 16384 shr 1; // 4194304 / 256 / 2; | |
− | + | zaehler: UInt16 = 0; // Zählt bis cl erreicht ist. | |
− | + | ||
begin | begin | ||
− | Inc( | + | Inc(zaehler); |
− | if | + | |
− | + | // Nach einer halben Sekunde LED ausschalten. | |
+ | if zaehler = cl then begin | ||
+ | PORTB := PORTB and not (1 shl 5); | ||
end; | end; | ||
− | if | + | |
− | + | // Sekunde ist erreicht. | |
− | + | if zaehler >= cl shl 1 then begin | |
+ | PORTB := PORTB or (1 shl 5); | ||
+ | zaehler := 0; // Zähler zurücksetzen. | ||
end; | end; | ||
end; | end; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ====Timer inizialisieren==== | ||
+ | Der springende Punkt ist der Wert bei '''TCCR0B''', dieser sagt, das der Timer extern getaktet wird. | ||
+ | <syntaxhighlight lang="pascal"> | ||
begin | begin | ||
− | + | DDRB := 1 shl 5; // Pin PD5 auf Ausgabe | |
− | DDRB | ||
− | |||
− | + | TCCR0A := %00; // Normaler Timer | |
− | TCCR0A := | + | TCCR0B := %111; // Clock / Externer Pin TO, steigende Flanke. |
− | TCCR0B := % | + | TIMSK0 := (1 shl TOIE0); // Timer 0 Interrupt aktivieren. |
− | |||
− | // | + | asm sei end; // Interrupts einschalten. |
− | |||
− | |||
− | |||
− | |||
repeat | repeat | ||
+ | // Hier kann die Zeit auf ein Display ausgegeben werden. | ||
until 1 = 2; | until 1 = 2; | ||
− | end.</syntaxhighlight> | + | end. |
+ | </syntaxhighlight> | ||
+ | |||
+ | ==Stolperfalle== | ||
+ | |||
+ | Die Namen der Proceduren können abweichen, ein Beispiel: | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
+ | // ATtiny2313 | ||
+ | procedure Timer0_Interrupt; public Name 'TIMER0_COMPA_ISR'; interrupt; | ||
+ | // ATtiny44 | ||
+ | procedure Timer0_Interrupt; public Name 'TIM0_COMPA_ISR'; interrupt; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | = Siehe auch = | ||
+ | |||
+ | * Übersichtseite [[AVR Embedded Tutorial/de|AVR Embedded Tutorial]] | ||
+ | |||
+ | Autor: [[User:Mathias|Mathias]] | ||
+ | |||
+ | [[Category:AVR/de]] | ||
+ | [[Category:Arduino/de]] | ||
+ | [[Category:Embedded/de]] | ||
+ | [[Category:Tutorials/de]] | ||
+ | {{AutoCategory}} |
Latest revision as of 01:35, 24 January 2020
│ Deutsch (de) │ English (en) │
Timer / Counter
Titel
Hier geht es nicht darum, alle Register zu verstehen. Dies sollte nur ein praktisches Beispiel sein, wie man es in FPC/Lazarus umsetzt.
Genauere Details gibt es hier:
Beispiel, LEDs über Timer steuern
Dieses Beispiel zeigt, wie man die beiden Timer eines ATtiny2313 verwenden kann. Jeder Timer steuert eine LED an, welche an Bit 0 und 1 des PortD sind. Dabei sollte die LED an PD0 etwas schneller blinken.
Beispiel Code
program Project1;
Timer 0 Interrupt
procedure Timer0_Interrupt; public Name 'TIMER0_COMPA_ISR'; interrupt;
const
t = 10; // LED sollte nur bei jedem 10. Durchlauf umschalten.
z: integer = 0; // Zähler für Leerdurchläufe.
begin
TCNT0 := 128; // Speed halbieren 0 = langsam (default)
Inc(z);
if (z = t) then begin
PORTD := PORTD or (1 shl 0); // LED Pin0 ein
end;
if (z = t shl 1) then begin
PORTD := PORTD and not (1 shl 0); // LED Pin0 aus
z := 0;
end;
end;
Timer 1 Interrupt
procedure Timer1_Interrupt; public Name 'TIMER1_COMPA_ISR'; interrupt;
const
t = 500; // LED sollte nur bei jedem 500. Durchlauf umschalten.
z: integer = 0; // Zähler für Leerdurchläufe.
begin
Inc(z);
if (z = t) then begin
PORTD := PORTD or (1 shl 1); // LED Pin1 ein
end;
if (z = t shl 1) then begin
PORTD := PORTD and not (1 shl 1); // LED Pin1 aus
z := 0;
end;
end;
Timer initialisieren
begin
// -- Interrupt unterbinden.
asm cli end;
// -- PD0 und PD1 auf Ausgabe stellen.
DDRD := %00000011;
// -- Timer0 initialisieren.
TCCR0A := 0;
TCCR0B := %101; // CPU-Takt / 1024
TIMSK := TIMSK or (1 shl OCIE0A); // Timer0 soll Interrupt auslösen.
// -- Timer1 initialisieren.
TCCR1A := 1; // CTC-Modus
TCCR1B := %010; // CPU-Takt / 8
TIMSK := TIMSK or (1 shl OCIE1A); // Timer1 soll Interrupt auslösen.
// -- Interrupt aktivieren.
asm sei end;
// -- Hauptschleife
repeat
// Mache Irgendwas.
until 1 = 2;
end.
Timer extern getaktet
Einen Timer kann man auch extern getaktet werden. Folgendes Beispiel demonstriert dies mit einem Atmega328. Zum extern takten gibt es folgende Pins am AVR:
- T0 taktet Timer 0
- T1 taktet Timer 1
Der Timer 2 kann nicht extern getaktet werden.
Beispiel einer Uhr
Für eine exakte Uhr ist ein Quarz/Oszilator mit 4.194304MHz geeignet. Dieser lässt sich gut in einer 2er Potenz teilen, so das man auf einen Sekunden-Takt kommt. Hier wird der Timer 0 extern getaktet, dazu muss man den Oszilator an T0 (PD4) anschliessen.
Timer Interrupt
Jeder 16384 Aufruf des Interupts ist eine Sekunde.
procedure Timer0_Interrupt; public Name 'TIMER0_OVF_ISR'; interrupt;
const
cl = 16384 shr 1; // 4194304 / 256 / 2;
zaehler: UInt16 = 0; // Zählt bis cl erreicht ist.
begin
Inc(zaehler);
// Nach einer halben Sekunde LED ausschalten.
if zaehler = cl then begin
PORTB := PORTB and not (1 shl 5);
end;
// Sekunde ist erreicht.
if zaehler >= cl shl 1 then begin
PORTB := PORTB or (1 shl 5);
zaehler := 0; // Zähler zurücksetzen.
end;
end;
Timer inizialisieren
Der springende Punkt ist der Wert bei TCCR0B, dieser sagt, das der Timer extern getaktet wird.
begin
DDRB := 1 shl 5; // Pin PD5 auf Ausgabe
TCCR0A := %00; // Normaler Timer
TCCR0B := %111; // Clock / Externer Pin TO, steigende Flanke.
TIMSK0 := (1 shl TOIE0); // Timer 0 Interrupt aktivieren.
asm sei end; // Interrupts einschalten.
repeat
// Hier kann die Zeit auf ein Display ausgegeben werden.
until 1 = 2;
end.
Stolperfalle
Die Namen der Proceduren können abweichen, ein Beispiel:
// ATtiny2313
procedure Timer0_Interrupt; public Name 'TIMER0_COMPA_ISR'; interrupt;
// ATtiny44
procedure Timer0_Interrupt; public Name 'TIM0_COMPA_ISR'; interrupt;
Siehe auch
- Übersichtseite AVR Embedded Tutorial
Autor: Mathias