Difference between revisions of "AVR Embedded Tutorial - Timer, Counter/de"

From Free Pascal wiki
Jump to navigationJump to search
m (Fixed template loop; modded categories to German; added language category)
 
(13 intermediate revisions by one other user not shown)
Line 1: Line 1:
{{Translate}}
+
{{LanguageBar}}
 +
 
 
=Timer / Counter=
 
=Timer / Counter=
  
 
==Titel==
 
==Titel==
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 Pin0 etwas schneller blinken.
+
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
  
Hier geht es nicht darum, alle Register zu verstehen. Dies sollte nur ein praktisches Beispiel sein, wie man es in FPC umsetzt.
+
==Beispiel, LEDs über Timer steuern==
  
Genauere Details gibt es hier: https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR
+
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==
+
===Beispiel Code===
<syntaxhighlight lang="pascal">program Project1;
 
  
  procedure cli; assembler; inline; // Interrupt aus
+
<syntaxhighlight lang="pascal">
  asm
+
program Project1;
          Cli
+
</syntaxhighlight>
  end;
 
  
  procedure sei; assembler; inline; // Interrupt ein
+
====Timer 0 Interrupt====
  asm
 
          Sei
 
  end;
 
  
  procedure Timer0_Interrupt; public Name 'TIMER0_COMPA_ISR'; interrupt;
+
<syntaxhighlight lang="pascal">
 +
procedure Timer0_Interrupt; public Name 'TIMER0_COMPA_ISR'; interrupt;
 
   const
 
   const
     t = 10;         // LED sollte nur bei jedem 10. Durchlauf umschalten.
+
     t         = 10; // LED sollte nur bei jedem 10. Durchlauf umschalten.
     z: integer = 0; // Zähler für Leerdurchläufe.
+
     z: integer = 0; // Zähler für Leerdurchläufe.
 
   begin
 
   begin
 
     TCNT0 := 128;                      // Speed halbieren  0 = langsam (default)
 
     TCNT0 := 128;                      // Speed halbieren  0 = langsam (default)
Line 34: Line 35:
 
       PORTD := PORTD or (1 shl 0);      // LED Pin0 ein
 
       PORTD := PORTD or (1 shl 0);      // LED Pin0 ein
 
     end;
 
     end;
     if (z = t * 2) then begin
+
     if (z = t shl 1) then begin
 
       PORTD := PORTD and not (1 shl 0); // LED Pin0 aus
 
       PORTD := PORTD and not (1 shl 0); // LED Pin0 aus
 
       z := 0;
 
       z := 0;
 
     end;
 
     end;
 
   end;
 
   end;
 +
</syntaxhighlight>
  
  procedure Timer1_Interrupt; public Name 'TIMER1_COMPA_ISR'; interrupt;
+
====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.
+
     t         = 500; // LED sollte nur bei jedem 500. Durchlauf umschalten.
     z: integer = 0; // Zähler für Leerdurchläufe.
+
     z: integer =   0; // Zähler für Leerdurchläufe.
 
   begin
 
   begin
 
     Inc(z);
 
     Inc(z);
Line 49: Line 54:
 
       PORTD := PORTD or (1 shl 1);      // LED Pin1 ein
 
       PORTD := PORTD or (1 shl 1);      // LED Pin1 ein
 
     end;
 
     end;
     if (z = t * 2) then begin
+
     if (z = t shl 1) then begin
 
       PORTD := PORTD and not (1 shl 1); // LED Pin1 aus
 
       PORTD := PORTD and not (1 shl 1); // LED Pin1 aus
 
       z := 0;
 
       z := 0;
Line 55: Line 60:
 
   end;
 
   end;
  
 +
</syntaxhighlight>
  
 +
====Timer initialisieren====
 +
 +
<syntaxhighlight lang="pascal">
 
begin
 
begin
   // Interupt unterbinden.
+
   // -- Interrupt unterbinden.
   cli();
+
   asm cli end;
  
   // -- Bit 0 und 1 von PortD auf Ausgabe stellen.
+
   // -- PD0 und PD1 auf Ausgabe stellen.
   DDRD := DDRD or (1 shl 0) or (1 shl 1);
+
   DDRD   := %00000011;
  
 
   // -- Timer0 initialisieren.
 
   // -- Timer0 initialisieren.
 
   TCCR0A := 0;
 
   TCCR0A := 0;
   TCCR0B := %101;                   // CPU-Takt / 1024
+
   TCCR0B := %101;                   // CPU-Takt / 1024
   TIMSK := TIMSK or (1 shl OCIE0A); // Timer0 soll Interrupt auslösen.
+
   TIMSK := TIMSK or (1 shl OCIE0A); // Timer0 soll Interrupt auslösen.
  
 
   // -- Timer1 initialisieren.
 
   // -- Timer1 initialisieren.
   TCCR1A := 1;                     // CTC-Modus
+
   TCCR1A := 1;                       // CTC-Modus
   TCCR1B := %010;                   // CPU-Takt / 8
+
   TCCR1B := %010;                   // CPU-Takt / 8
   TIMSK := TIMSK or (1 shl OCIE1A); // Timer1 soll Interrupt auslösen.
+
   TIMSK := TIMSK or (1 shl OCIE1A); // Timer1 soll Interrupt auslösen.
  
 
   // -- Interrupt aktivieren.
 
   // -- Interrupt aktivieren.
   sei();
+
   asm sei end;
 +
 
 +
  // -- Hauptschleife
 
   repeat
 
   repeat
 
     // Mache Irgendwas.
 
     // Mache Irgendwas.
 
   until 1 = 2;
 
   until 1 = 2;
end.</syntaxhighlight>
+
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
 +
    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;
 +
</syntaxhighlight>
 +
 
 +
====Timer inizialisieren====
 +
 
 +
Der springende Punkt ist der Wert bei '''TCCR0B''', dieser sagt, das der Timer extern getaktet wird.
 +
 
 +
<syntaxhighlight lang="pascal">
 +
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.
 +
</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]] {{AutoCategory}}
+
[[Category:AVR/de]]
 +
[[Category:Arduino/de]]
 +
[[Category:Embedded/de]]
 +
[[Category:Tutorials/de]]
 +
{{AutoCategory}}

Latest revision as of 00: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

Autor: Mathias