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
@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
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
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
@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?
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;
}
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
Eugen schrieb:> Allerdings, kommen nur 16Bit (max ca 65536) mit Timer0 per UART raus.
Ein unsigned long ist 32Bit.
Aber Du mußt natürlich auch 32Bit anzeigen.
Peter
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.