AVR Timer mit 32 Bit

Gast #371564
Lesenswert?

Manchmal reicht die Auflösung der Timer nicht aus.

Kein Problem, wozu gibt es denn die Overflowinterrupts. Damit kann man
bequem in Software weiterzählen. Es ist auch nicht weiter kompliziert,
nur beim Auslesen muß man einiges beachten, damit man ein gültiges
Ergebnis erziehlt.

Die einfachste Möglichkeit zum korrekten Auslesen ist es, den Timer
solange zu stoppen. Blöd nur, wenn dann gerade ein Zählimpuls
reinkommt, den verliert man dann.

Also ist es besser, den Timer weiterlaufen zu lassen.
Für 32 Bit müssen insgesamt 4 Bytes ausgelesen werden, was beim AVR
nicht atomar möglich ist. Deshalb disabled man während des Auslesens
erstmal die Interrupts.

Die nächste Hürde ist dann, wenn gerade dabei ein Overflow auftritt,
ist zwar selten, aber es passiert. Mancher, der mal einen
Frequenzzähler so aufgebaut hat, wird gemerkt haben, daß bei bestimmten
Werten die Anzeige verrückt spielt und große Sprünge macht. Genau das
ist dann so ein nicht berücksichtigter Overflow.

Man hat also 3 Bytes aus dem Softwarezähler und das Timerbyte. Ist nun
ein Overflow aufgetreten konnte ja der Interrupt den Softwarezähler
nicht weiterschalten, da ja die Interrupts zum auslesen gesperrt
wurden. Bevor nun die Interrupts wieder freigegeben werden, merkt man
sich also das Overflowbit.

Ist das Overflowbit gelöscht, dann sind alle 4 Bytes gültig und gut.

Ist es aber gesetzt, muß man noch feststellen, ob es vor den Lesen des
Timerbytes gesetzt wurde und das ist dann der Fall, wenn das Timerbyte
0x00, 0x01 usw. ist. Hätte man es vor dem Overflow gelesen, müßte es ja
0xFF, 0xFE usw. sein.

Man testet also noch das höchstwertige Bit 7 und ist es gelöscht, dann
hat man nach dem Overflow gelesen und muß noch 256 zum Returnwert
addieren.


Peter
Angehängte Dateien:
Gast #371565
Lesenswert?

@Peter
Das ist eine geniale Methode. Leider kann ich den Algorithmus nicht
nachempfinden, da ich kein C beherrsche. Könntest Du das auch in Bascom
schreiben oder in Worten beschreiben? So eine Funktion könnte ich im
Moment gut gebrauchen.

MfG Paul
Gast #371566
Lesenswert?

Hallo,

Könnte man das Auslesen nicht auch so machen ?

1. Overflow-Zähler einlesen
2. Zählerstand einlesen
3. Overflow-Zähler erneut einlesen
4. wenn Overflow-Zähler verändert zurück zu 1.

Bei dieser Variante bräuchte mann weder Timer noch INT's zu sperren.


Gruss Thomas
Gast #371568
Lesenswert?

Neben dem Jitter gibt das auch mehr Code.

Ist doch nicht schlimm, die 2 Bits zu testen und 256 zu addieren.



@Paul,

ich habs doch beschrieben, was ist denn daran unklar ?

Anbei mal das Assemblerlisting.


Peter
Angehängte Dateien:
Gast #371569
Lesenswert?

@Peter
Danke für das Assemblerlisting. Das ist mir eine bessere Hilfe als
der C _ Quelltext. Mal sehen, ob ich das in Bascom hinkriege.

Wenn ich es bis jetzt richtig verstanden habe, zählst Du die Überläufe
des Interupts vom Timer2 in einem separaten Zähler hoch, der beliebig
vorgeladen werden kann, um auch "krumme" Teilerverhältnisse erzeugen
zu können, auf die man die Timer selber nicht einstellen kann.

Ist das soweit richtig?
Gast #1565736
Lesenswert?

Hi !

Vielen Dank, bei mir funktioniert es nun einwandfrei !!!

Aber ich habe einen kleinen Bug in Timer32.c gefunden.
Wenn man die 256 "einfach" addiert, muss man sie an
anderer Stelle auch wieder abziehen, sonst hat man bei
der nächsten Abrage ca. 256 zu viel.

Hier meine Änderung:

u32 get_ticks( void )        // read T2 as 32 bit timer
{
  u32 val;
  u8 tifr;

  cli();
  val = t2_soft + TCNT2;
  tifr = TIFR;          // read interrupt flags
  if( (tifr & 1<<TOV2) && !(val & 0x80) ) // overflow prior reading 
TCNT2 ?
  {
    val += 256;          // then add overflow
  t2_soft -= 256;    // the next "ISR(TIMER2_OVF_vect)" would add to 
much
  }
  sei();

  return val;
}
Gast #2151373
Lesenswert?

Hallo Community,

Ich muss den Peter's TIMER32.C-Beispiel an den Atmega8515 anpassen, da 
der keinen Timer2(8Bit), sondern nur Timer0(8bit) und Timer1(16Bit) 
besitzt.
Allerdings, kommen nur 16Bit (max ca 65536) mit Timer0 per UART raus.

Peter's TIMER32.C-Beispiel  ----> Anpassung

TCCR2 = 1<<CS21; ---> TCCR0 = 1<<CS00;
TIMSK |= 1<<TOIE2; ---> TIMSK |= 1<<TOIE0;
val = t2_soft + TCNT2; ---> val = t2_soft + TCNT0;
if( (tifr & 1<<TOV2) && !(val & 0x80) ) --->  if( (tifr & 1<<TOV0) && 
!(val & 0x80) )

Insbesondere mach ich mir Sorgen um die letzte if-Schleife, weil ich sie 
noch nicht verstehe.

Könnte mir jemand bei der Anpassung weiter helfen?


MfG

Eugen
Gast #2153400
Lesenswert?

Vielen Dank, Peter, für Deine schnelle Antwort.
Das stimmt, mit ultoa() klappt es.

Von allein würde ich nicht so schnell drauf gekommen.

Schöne Grüße

Eugen


P.S.
Ich lade jetzt dieses Beispiel für Neulinge wie mich hoch.

AvrStudio4.18SP3 + WinAVR-20100110
STK-500, Atmega8515L, Timer0, UART

Um Compiler-Warnungen zu vermeiden, kann man u8 in uputs() und 
uputchar() mit char ersetzen.
Angehängte Dateien:

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren