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

From Free Pascal wiki
Jump to navigationJump to search
Line 124: Line 124:
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
 
begin
 
begin
   DDRB  := DDRB or (1 shl 5); // Pin PD5 auf Ausgabe
+
   DDRB  := 1 shl 5)       // Pin PD5 auf Ausgabe
  
   TCCR0A := %00;               // Normaler Timer
+
   TCCR0A := %00;           // Normaler Timer
   TCCR0B := %111;             // Clock / Externer Pin TO, steigende Flanke.
+
   TCCR0B := %111;         // Clock / Externer Pin TO, steigende Flanke.
   TIMSK0 := (1 shl TOIE0);     // Timer 0 Interrupt aktivieren.
+
   TIMSK0 := (1 shl TOIE0); // Timer 0 Interrupt aktivieren.
  
   asm sei end;                 // Interrupts einschalten.
+
   asm sei end;             // Interrupts einschalten.
  
 
   repeat
 
   repeat
Line 137: Line 137:
 
end.
 
end.
 
</syntaxhighlight>
 
</syntaxhighlight>
 
  
 
==Stolperfalle==
 
==Stolperfalle==

Revision as of 23:04, 30 November 2017

Template:Translate

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 inizialisierent

begin
  // -- Interupt 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