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
@Thomas J.: Das geht. Hab ich auch schon so gemacht. Gibt halt einen leichten Jitter, weil man manchmal zum Einlesen etwas mehr Zeit braucht.
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; }
Nö, da darf nichts abgezogen werden. t2_soft darf von get_ticks nur gelesen werden, sonst gibts Ärger. Peter
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.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.