mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Zeitmessung mit Timer2 asynchron


Autor: Thomas (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Guten Tag,
hab schon die Suchfunktion bemüht und schon einige Stunden mit 
Experimenten verbracht, aber ich komme nicht zum gewünschten Ergebnis. 
Auch im Datenblatt habe ich für mein Problem nichts gefunden. Leider 
komme ich nicht drauf was genau passiert.
Mein Projekt:
Tacho der mittels Reedkontakt die Umdrehungen meines Rades mißt und 
daraus unter anderem die Geschwindigkeit errechnet.
Prozessor: ATMEGA169 der dauernd schläft und beim Ticken des asynchronen 
Timer2 (64 mal pro Sekunde, macht immer 64 Schritte bei 4096Hz) 
aufwacht. Der Reed ist am Pin Change Interrupt welcher auch den Schläfer 
weckt.

Code ist mal im Anhang was die problematischen Teile angeht. Um den PCI 
kurz zu halten, lese ich beim Schließen des Kontaktes den Timer2 Zustand 
aus und die Variable revolution. Mein Rad dreht so langsam, dass der 
Timer2 mehrfach tickt, bis eine Umdrehung fertig ist.
Um die Anzahl der Timerschritte zu berechnen, multipliziere ich die 
Anzahl der revolutions mit 64, addiere der Timerstand hinzu und 
subtrahiere den alten Timerstand vom letzten Mal.
Oh Wunder: Funktioniert wunderbar.
Aber hin und wieder ist das Resultat der Timerschritte falsch, es 
scheint um 64 zu hoch oder zu wenig zu sein. Hab beide Effekte.

Liegt es daran, dass beide Interrupts gleichzeitig feuern und dabei die 
Berechnung einen Fehler bekommt? Ich inkrementiere die revolutions im 
Timer2 Interrupt, denke wenn beide gleichzeitig feuern kommt das einmal 
zu spät.
Habe daraufhin in diesem Falle eine revolution zur gezogenen Kopie 
hinzugefügt, es kommt aber immer mal sporadisch solch ein Ausreisser 
vor.

Timer1 mit 16 Bit wäre natürlich besser geeignet, da entfällt das 
Aufzählen der Timer Interrupts. Wegen Stromsparen nutze ich aber nur den 
asynchronen Timer2 der leider nur 8 Bit hat.

Ich teste zur Zeit mit einem externen Frequenzgenerator ohne Reed, also 
da ist nix mit Prellen und so.

Also: Es funktioniert im Prinzip, aber es kommen selten sporadisch 
Ausreisser. Woher kann das kommen? Wie fange ich diese Dinger ab?

Interrupt Spezies: Wer kanns erklären?

Besten Dank

Thomas

Autor: Knut Ballhause (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde mal auf einen prellenden Reed-Kontakt tippen. Wie wär´s wenn 
Du das erstmal abfängst?

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab doch geschrieben dass ich mit einem elektronisch generierten Takt 
arbeite...
Der Reed kommt später und prellt nicht.

Autor: Ulrich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es könnte ein problem mit fast gleichzeitig auftretenden Interrupts 
sein. Es kann dann passieren das die Reihenfolge mit der der Overflow 
Interrupt und der PCI aufgerufen werden nicht stimmt. Den Fall muß man 
dann in Software abfragen, anhand des Zählerstandes.  Ein ähnliches 
Problem gibt es auch bei der Messung über timer1 mit ICP und Überlauf.

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das prüfe ich schon ab:
if (TIFR2&0x02)  //in case Timer2 and PCI fire at the same time, PCI has 
priority
   {
    tmp_rev++;
    revolution=0;
   }
  else
    revolution=0;

Wenn beide gleichzeitig feuern hat der externe PRIO und sieht bei TIFR2 
nach ob der andere auch will. Dann wird bei tmp_rev einer zugezählt und 
das Ergebnis stimmt. Hab den Fall analysiert und die Geschwindigkeit 
stimmt hier. Die Ausreisser kommen woanders her. Soweit hab ich es 
nachvollzogen...

Autor: Holger (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Kannst du uns ein Modell-Flow-Chart machen.
(Skizze ) und dann hier reinposten.
Möglicherweise geht das noch trickreicher zu
lösen.
Siehe hier im Forum das Project mit
dem 32 Bit-Zähler von Peda. glaube ich.
Das war echt ausgefuchs gemacht.
Mit der mathematischen Korrektur u.
Konditioneller Nachberechnung.
Suche ich auch noch raus.


Ich poste noch das Komplette PDF
Teil. Embedded Design Pattern.
Der Professor schreibt, sonst ist das nicht
störungfrei möglich, OK
aber wieso. ???? Geht das nur so
100% richtig???,
und hier bei dir nur 99,99 %

Der Professor aus der FH Klaustal
hat einen Leitfaden dazu geschrieben,
aber nur nicht das „Zauberwort“ volatile hat
er vor die dedizierten IRQ-Variablen geschrieben.
OK ist halt so...  aber warum meldet der
Prof. da  bedenken an. ????
Und schaltet dediziert den IRQ_ab und geht die
volatile Varaiablen holen. bzw. lesen und
zwischenspeichern.
Und schaltet danach dediziert den General-Master-IRQ
wieder an.


Aber auch speziell bei den AVRs mit dem GNU C Compiler
ist das volatile var „atomar“ wichtig.!!!!

Siehe Anhang: Störungfreie Ubergabe der
volatile Variablen vom IRQ zum MAIN
1) Dedizierte Befehle mit cli, bzw. sei ...
   Befehl im Main.

Autor: Holger (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hast du Z.B erst mal zum testen
Z.B 10K-Pull-Ups an dem dedizeiten Extern-IRQ PINs??
PitFall:
Die intern MCU-Pulls sind soo weak sometimes.

Grundsätzlich wird
der z.B IRQ_#1 als flg im Latch gespeichert,
falls der andere bearbeitet wird.
Es geht also kein IRQ veschütt.
Der im Rahmen der z.B Latenzzeit
z.B bei 16MHZ respektive liegt.

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Holger,
danke erstmal für die Posts, auch wenn ich nicht ganz folgen kann.
Ich versuche es mal zu erklären was ich tu:

Es gibt zwei Interrupts, den PCI und den Timer2.
Timer2 feuert 64 Mal pro Sekunde und macht zwischendurch 64 Schritte.
Ich möchte die Anzahl der Schritte des Timer2 zwischen zwei PCI messen.
Dazu setze ich im PCI den Wert revolution (volatile) auf 0 und 
inkrementiere den in jedem Timer2 Interrupt. Damit weiß ich, wie oft der 
Timer gefeuert hat. Wenn der nächste PCI kommt nehme ich mir eine KOPIE 
dieses Wertes. Da das in einem Interrupt erfolgt brauche ich kein cli() 
und sei(), ich mach keine nested Interrupts. Einverstanden? Die 
Atomarität sollte also gewährleistet sein.
Mit new_round=1 signalisiere ich der main() dass eine neue 
Geschwindigkeit berechnet werden soll.
Ich habe vorher mir den Wert des TCNT2 kopiert (auch im Interrupt) als 
curr_TC.
Dieser fließt bei der Berechnung mit ein und wird für die nächste 
Berechnung als old_TC behalten nachdem die Berechnung fertig ist. Alle 
Variablen sind volatile.

Die vergangenen Timerticks sind also:

tmp_rev *64 + curr_TC - old_TC im Moment wenn der PCI feuert.

Die Falschwerte die ich ab und an bekomme sind haben immer 64 zu wenig 
bei den Timerticks, dadurch bekomme ich eine falsche Geschwindigkeit.
Die Werte für TCNT2 sind oft aber nicht immer 0 in diesem Fall. Den Fall 
dass beide IRQ gleichzeitig vorliegen, der PCI also Vorrang hat und der 
Timer noch nicht die revolution hochzählen konnte, habe ich abgefangen. 
Dieser liefert das korrekte Ergebnis. Die Ausreisser haben einen anderen 
Grund.

Ist da in dem Konzept ein Fehler den ichnicht sehe?

Gruß
Thomas

Autor: oldmax (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi
Sieht mir nach Zählerüberlauf aus. Wenn ich dich richtig verstanden 
habe, möchtest du eine Geschwindigkeit messen. Die ergibt sich aus 
Zeiteinheiten pro Umdrehung. Also: Zeitinterrupte zählen.
Ereignisimpuls von Umdrehung löst folgendes aus: Gezählte Zeiteinheiten 
der Berechnungsroutine auf sep. Variable zur Verfügung stellen und 
Zeitzähler auf 0 setzen.Entweder direkt von hier die Berechnung und 
Aktualisierung der Anzeige aufrufen, oder Flag setzen und vom 
Hauptprogramm Flag bearbeiten lassen. Entschuldige, wenn ich's nicht mit 
Code verdeutliche, ich hab von "C" nur einen ganz blassen Schimmer. Aber 
immerhin, ich weiß, wie man es schreibt ....
Also, vielleicht noch mal in Blöcke gefasst:
Timer_ISR: Zählen der Interrupts
IO_ISR: Zeitzähler umkopieren,
        Zeitzähler löschen
        Berechnung auslösen
So sollte es gehen und der Zähler kann so gewählt werden, das er nicht 
"überläuft".
Gruß oldmax

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Oldmax,
genau so mache ich es und es funktioniert ja richtig!
Nur ab und an bekomme ich "Ausreisser":
Hab das mal analysiert:
Mein externer Taktgenerator läuft mit einer Frequenz, so dass ich etwa 
107 "Sachen" fahre. Passt! Jedoch dann und wann fahre ich entweder 135 
oder auch mal 88 Sachen.
Bei 4096Hz Takt für Timer2 und einem Radumfang von 2.16m vergehen also 
etwa 300 Ticks bei 107km/h.
Bei 88 sind es etwa 364, bei 135 etwa 236. Diese Werte bekomme ich 
sporadisch. Es ist also ab und zu ein Fehler von genau 64 Ticks da, 
WARUM??

Es kommt nicht vom Doppelinterrupt, wenn also beide zugleich feuern. Den 
Fall hab ich analysiert und abgefangen, passt.

Gruß
Thomas

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thomas schrieb:

> Bei 88 sind es etwa 364, bei 135 etwa 236. Diese Werte bekomme ich
> sporadisch. Es ist also ab und zu ein Fehler von genau 64 Ticks da,
> WARUM??
>
> Es kommt nicht vom Doppelinterrupt, wenn also beide zugleich feuern. Den
> Fall hab ich analysiert und abgefangen, passt.

Ganz sicher?

Da sich deine Geschwindigkeit ja normalerweise nicht sprunghaft 
verändert, könntest du ja auch mal die Ausreisser mitprotokollieren 
(also die Ausgangswerte), wenn es doch passiert. Dann hast du besseres 
Zahlenmaterial zur Analyse und bist nicht auf Ratespielchen angewiesen.

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich bin ziemlich sicher.
Habe einen Parameter definiert, der mir ein Segment meiner Anzeige 
einschaltet. Dieser wird mit der Bedingung

if (TIFR2&0x02)

im PCI gesetzt. Das ist wohl der Fall hier. Im PCI ist TIFR2 auf 2, also 
wartet der Timer2 Interrupt bis der PCI fertig ist da dieser höhere Prio 
hat.
Einsprüche hier?

Mein Segment geht dann und wann an, die Geschwindigket ist aber richtig 
in dem Moment. Und im Gegensatz dazu geht mein Segment nicht an, es hat 
aber eine falsche Geschwindigkeit gegeben.
Deshalb bin ich einigermassen sicher dass der Fall Doppelinterrupt nicht 
mein Problem ist. Ich hab die Ausreisser mal mitprotokolliert, es ist 
meist ein Wert von 364 oder 236 Timerticks wenn 300 erwartet wird.
Das sind immer 64 zu viel oder zu wenig, meine simulierte Frequenz von 
aussen ist konstant.

Autor: Ulrich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Abfangen des geleichzeitigen Interupts sieht mir noch nicht ganz 
richtig aus. Wenn man den verpaßten Timer Overflow erkannt hat, und dann 
durch
tmp_rev++;
revolution=0;
nachholt, muß man den anstehenden Timerinterupt auch noch löschen. Sonst 
wird 2 mal erhöht.
Je nachdem ob der Effekt beim Start oder Stop bekommt, gibt das dann den 
einen overflow zu viel oder zu wenig.

Sonst ggf. nochmal den kompletten Code zu den ISRs posten.

Autor: Thomas (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe schon diverse Versionen die alle das selbe Problem haben.
Den Timer Interrupt will ich nicht löschen, der macht noch andere 
Sachen:
Uhr weiterzählen
LCD steuern. Deshalb bin ich auch auf 64Hz festgelegt.

Ich hänge mal meinen Code dran, das ist eine Version die noch am 
wenigsten das Problem zeigt.
Der problematischste Fall ist zu hohe Geschwindigkeit, die wird als 
Maximalgeschwindigkeit abgespeichert.
Die Ausreisser nach unten sind nicht ganz so kritisch. Aber ich will 
wissen woran es liegt.
Also: ZIP im Anhang.
Besten Dank!!

Autor: Holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Super das du den Code gepostet hast.
An duo tüftel IRQ#s rumspielen macht immer viel Spass,
und ich lernt was dabei.

Ich versuche mir immer ein Bild von der Anwendung. zu machen.
Du hast viel Zeit in dein Projekt investiert.
Ist deine Anwendung etwar so wie in diesem Video???
Die ist mit einem PIC gemacht.
Ich habe mal eine Drehzahl in (RPM) mit CAPTURE MODE gemacht.
PIN-EXT-IRQ EDGE GATE geht Puls in das Capture Reg.=Zähler
von 80535 MCU.
Hast du einen Anderen Weg vor falls das nicht
mit deinem  Algorithmus  klappen sollte.???

1)Ist das so ein Schaltbild ????

Youtube-Video "PIC18 Pulse Width Modulation (PWM) DC Motor Speed Controller with the RPM Counter Project"
Analoges Integral nachbilden. Digitaler Analog-Tacho RPM Rounds Per 
MINUTE.
Stichwort: CAPTURE MODE:
VIA TIME-CLOCKS triggers Gated Counter.
++CountedClocks per MCU-CLOCK SPEED
Wie bei der ADC Messung mache ich einen Messbuffer auf,wo die Werte 
gemittelt
werden, damit ich da arithmetisch via Mittelwert FILTER:geglättet 
rauskomme.
Du hast keinen Mittelbuffer in deinem Code.
Viel Erfolg.
Gruss Holger.

Autor: Ulrich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei der Erkennung eines noch ausstehenden Overflow Interrupts könnte ein 
Fehler passieren.  Genau hab ich es nicht kontrolliert, aber besonders 
wenn der Takt relativ hoch ist, könnte es passieren, das die ISR für den 
Overflow zu schnell fertig wird, trotz der länge. Dann wäre der Counter 
2 noch beim Wert 0, obwohl die Overflow ISR schon ganz fertig ist.

Meiner meinig nach sicherer geht das Erkennen eines aussteheden 
Interrupts über das Interrupt flag Register, zusammen mit der Forderung 
das der Timerwert klein ist. So funktioniert es jedenfalls bei Timer1 
und ICP.

An 2.tes Mögliches Problem könnte ein mechnisches Prellen sein. Das 
sollte dann aber zu ausreißen mit deutlich zu hoher Geschwindigkeit 
führen, nicht gerade der eine falsche Überlauf.

Autor: Holger (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
http://www.ermicro.com/blog/?p=1461
Flow-Charts sind auch dabei.
Ich habe den Code mal analysiert.
Da ist eine STATE-ENGINE für PCI drin
(PIN-CHANGE-IRQ)= PCI
Einfach und sicher, denke ich..
Mit Kombinations-Hilfe als TIMER OVERFLOW IRQ
= (TOVR-IRQ)
Sauber gemacht mit case switch().....
IRQ ACK, u. volatile....Koppel-Variablen.

Gruss Holger.
// PIC18 High-priority Interrupt Service
void interrupt high_isr(void){
  static unsigned char pulse_state=0;
  unsigned int rpm_timer;
  if (TMR0IF) {                     // Check for TIMER0 Overflow 
Interrupt
    rpm_value = 0;                  // Reset the global volatile  RPM 
Value
    TMR0IF=0;                       // Clear TIMER0 interrupt 
flag,T-OVR_(ACK-IRQ#1AVR)
  }
  if (INT0IF){                      // Check for External INT0 Interrupt
    switch(pulse_state) {
      case 0:                       // First Low to High Pulse
        TMR0H = 0;                  // Zero the high byte in TMR0H 
Buffer
        TMR0L = 0;                  // Clear 16-bit TIMER0 Counter
        pulse_state=1; // P´reset for-Next_STATE ‘#S1

        break;
      case 1:                       // Second Low to High Pulse at STATE 
‘#
        rpm_timer=TMR0L;            // Get the first 8-bit TIMER0 
Counter
        rpm_timer+=(TMR0H << 8);    // Get the last 8-bit TIMER0 Counter
        // Calculate RPM = 60 x (1/Period)
        // RPM Value = 60000 (1 / (0.032 ms x rpm_timer))
        rpm_value = (int) (60000.0 / (0.032 * rpm_timer));
        pulse_state=0;// XOR P´reset forNext_STATE ‘#S0
    }
    INT0IF = 0;                     // Clear INT0 interrupt flag, 
_(ACK-IRQ#1AVR)
  }

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke erstmal an euch, aber ich bin nich sicher dass ich das Problem 
verstehe. Ulrich schreibt:

"Bei der Erkennung eines noch ausstehenden Overflow Interrupts könnte 
ein
Fehler passieren.  Genau hab ich es nicht kontrolliert, aber besonders
wenn der Takt relativ hoch ist, könnte es passieren, das die ISR für den
Overflow zu schnell fertig wird, trotz der länge. Dann wäre der Counter
2 noch beim Wert 0, obwohl die Overflow ISR schon ganz fertig ist."

Was ist damit gemeint? Die Erkennung des ausstehenden Timer IRQ wenn der 
PCI feuert?
Was ist gemeint mit "zu schnell fertig"? Wenn TCNT2 nach dem Timer 
Interrupt immer noch auf 0 ist so ist das aus meiner Sicht normal und 
OK. Ich hab das Problem mit 500KHz Takt und auch 8MHz.
Welchen Fall muss ich denn nun genau analysieren? Ich sehe drei 
Möglichkeiten:

1.PCI feuert alleine, so ist es üblich. Sollte unproblematisch sein.
2.Timer und PCI feuern gleichzeitig: PCI hat Prio, Timer wird nacher 
bedient.
3.Timer IRQ wird bedient, PCI funkt dazwischen.

Für Punkt drei habe ich es mal mit und ohne nested Interrupt versucht, 
das Problem bleibt.
Was meinst du Ulrich? Geht es um Punkt 2?
Ich fürchte ich stehe hier auf dem Schlauch.

Autor: Ulrich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Problem mit der zu schnellen Ausführung des Interrupts könnte 
passieren, wenn erst der Timer Interrupt Auftriff, und dann gleich 
danach der PCI. Mit dem 500 kHz Takt sollte das aber eher selten 
passieren. Auch sonst ist da Zeitfenstser vermutlich ziehmlich keine und 
der Fehler würde nur sehr selten auftreten.


Mir ist da noch eine Mögliche Fehlerquelle eingefallen: Bei einigen der 
AVRs gibt es einen Fehler beim Timer, und es kann passieren das ein 
Timer Interrupt verloren geht, wenn man zur falschen Zeit in das OCR 
register schreibt. Habs nicht genau nachgelesen, nur so aus dem 
Gedächnis.

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Ulrich,
stimmt, hab ich irgendwie nicht so richtig verstanden. Aber diese 
Änbderung bringt es auch nicht:

TCCR2A |= (1<<CS21) | (1<<WGM21);
while (ASSR&0x01) ;//wait until OCR2UB reads 0, TCNT2 reads correctly
curr_TC = TCNT2;//take snapshot of timer 2 status NOW!

Hatte da vorher den OCR2A beschrieben, das ist ungünstig. Habe in 
anderen Versionen auch schon mal das Timer IF Register gelsesen anstatt 
TCNT2 auf 0 zu prüfen. Egal was ich versuche, das Problem bleibt.
Danke für den Tip erstmal.

Autor: oldmax (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi
Ich habe mal deine Geschwindigkeitsmessung nachgerechnet.... Also, wenn 
du mit 64 Hz über eine Bewegung die Zeitimpulse mißt, also alle 15,2ms 
dann ist deine Rotationsgeschwindigkeit 1/(imp*(1/64)) also 
1/(imp*0,0152s)
Annahme, dein Rad hat 1 m Umfang und du hast bei einer Umdrehung 17 
Impulse gezählt, dann ergibt das 3,77 m/s.
Hochgerechnet 13,574 Km/h.
nächste Annahme : du hast 18 Impulse gezählt ergibt eine 
Umfangsgeschwindigkeit von 12,8Km/h.
Nun lassen wir das Rad mal langsam drehen.. also wesentlich mehr 
Zeitinterrupts zählen. Angenommen 1000
Also (1/(1000*1/64))*60*60 ergibt 230,4 m/h
2. Rechnung mit 1001 Impulsen (1/(1001*1/64))*60*60 =230,1 m/h
Nun lassen wir es mal extrem schnell laufen, d. h. es gibt nur wenige 
gezählte Zeitinterrupts z. 2
Also (1/(2*1/64))*60*60 ergibt 115,2 km/h
2.Rechnung mit 3 Impulsen (1/(3*1/64))*60*60 ergibt 76,8 km/h
Wenn du nun knapp um den nächsten Zeitimpuls drehst, kann die 
Ungenauigkeit der Reed-Kontakte dazu führen, mal einen Zeitimpuls mehr 
oder weniger zu sehen, je nachdem. Irgendwo multiplizierst du diese 
Zeitimpulse auch noch mit 64, wofür auch immer. Kein Wunder, das dein 
Fehler auch diese 64 irgendwie aufzeigt.....
Zu deinem Programm: Ich hab keine Ahnung von C, aber soviel ich sehe, 
ist deine Rechnung auch falsch. Wenn du genauer werden möchtest, dann 
löse mit ms auf und leite die anderen Ereignisse aus dieser ms ab. Dazu 
wird der Timer mit entsprechendem Vorteiler und Überlauf 
parametriert.Dazu kann ich hier das Timer-Tutorial empfehlen.
Hier mal beispielsweise den Unterschied aus ms-Interrupts
Also   (1/(1000*0,001s))*60*60 ergibt 3,6 km/h
  (1/(1001*0,001s))*60*60 ergibt 3,596 km/h
  (1/(10*0,001s))*60*60 ergibt 360 km/h
  (1/(11*0,001s))*60*60 ergibt 327,272km/h
Du siehst, 1 Interrupt mehr oder weniger fällt nicht so stark ins 
Gewicht.
Diese Rechnung hab ich überhaupt nicht durchschaut....
new_round=0;
    {
       time = tmp_rev*64+curr_TC-oldTC;
       loc_tmp= 2160;
       loc_tmp= 72*loc_tmp;
       loc_tmp/=time;
       veloc=(loc_tmp+2)/5;  //km per hour, rounding included
    }
    oldTC=curr_TC;  //remember last Timer value
Vielleicht seh ich das aber auch nur falsch, weil ich deinen Code nicht 
versteh.
Gruß oldmax

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Oldmax,
ich weiß, der Code von anderen (und meine eigener nach ein paar Wochen) 
ist immer schwer zu verstehen. Ich erkläre es gerne mal:
Ich betreibe ein LCD das mit 32Hz umschaltet, deshalb nehme ich den 
Timer2 mit 64Hz. Der ist fest, kann ich nicht ändern. Ausserdem zählt er 
meine Uhr weiter.
Die 64Hz sind aber nur die Überläufe, die Schrittweite ist 1/4096Hz also 
etwas mehr als 240µs.
Ich zähle nicht allein die Überläufe (revolution) sondern lese auch den 
TCNT2 aus. Damit bekomme ich eine schön hohe Auflösung.
Beispiel:
Reed schaltet, ich lese TCNT2=20 aus und revolution=10.
Nächste Umdrehung:
TCNT2 = 55, revolution = 10.
Zwischen den Reed Schaltpunkten habe ich also 10*64 +55-20 Timerticks 
gehabt, das sind 675 Ticks zu 244µs. Auflösung ist 244µs, reicht mir 
vollkommen aus.
64 weil jede revolution schon 64 Ticks hatte, 55 weil ich in diesem 
Timerzyklus bis 55 gekommen bin und -20 weil ich letztes Mal bei erst 
bei 20 angefangen habe.
Ich hoffe es ist klar geworden. Klar kann ich für diese Spielereien den 
16 Bit Timer1 nehmen, aber den kann ich nicht asynchron betreiben wie 
Timer2. Stichwort: Stromsparen.
Ich hab das in anderen Projekten auch schon mal so gemacht, geht auch 
braucht aber mehr Strom. Es fällt ein Timertick nicht so ins Gewicht, 
ein Überlauf zuviel oder zu wenig schon. Ich stimme zu, das löst aber 
nicht mein Problem.
Zur Info: Es funktioniert ja richtig, die Geschwindigkeit wird genau 
angezeigt, alles super.
Mein Problem sind die Ausreisser dann und wann, oder um genau zu sein: 
Was verursacht die denn?? Wenn ich es verstanden habe kann ich es 
bestimmt lösen.
Gruß
Thomas

Autor: MWS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Würde es so machen, revolution muss natürlich ein signed Typ werden:
if (TIFR2&0x02)
  {
    tmp_rev++;
    revolution = -1;
    curr_TC = 0;
  }
else
  revolution=0;

Autor: oldmax (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi
Jetzt hab ich's verstanden... Na ja, bin ja auch schon etwas älter, da 
rieselt's schon leicht. Aber ich bin noch lernfähig.
Ok, dann werd ich mal weiter denken...  Ich bin immer noch davon 
überzeugt, es liegt an der Multiplikation mit 64...
Gruß oldmax

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So Freunde,
ich hab mal meine serielle Schnittstelle angeworfen und mit meiner 
Testfrequenz (elektornisch generiert) die Interrupts gefeuert.
Es werden dabei etwa 300 Ticks erwartet, ich habe mal die Ticks, die 
Timerüberläufe (Revs), den TCNT2 Wert TC und den TC vom letzten Male 
(oldTC) ausgedruckt.
Sowas kommt heraus, bitte mal um Kommentare was da schiefgeth, es ist 
nicht immet TCNT2=0 oder so...

300   Revs:5 oldTC:38 TC:18
301   Revs:4 oldTC:18 TC:63
300   Revs:5 oldTC:63 TC:43
300   Revs:5 oldTC:43 TC:23
300   Revs:5 oldTC:23 TC:3
301   Revs:4 oldTC:3 TC:48
300   Revs:5 oldTC:48 TC:28
300   Revs:5 oldTC:28 TC:8
301   Revs:4 oldTC:8 TC:53
300   Revs:5 oldTC:53 TC:33
301   Revs:5 oldTC:33 TC:14
300   Revs:4 oldTC:14 TC:58
300   Revs:5 oldTC:58 TC:38
272   Revs:4 oldTC:38 TC:54
299   Revs:5 oldTC:54 TC:33
301   Revs:5 oldTC:33 TC:14
259   Revs:4 oldTC:14 TC:17
300   Revs:4 oldTC:17 TC:61
250   Revs:4 oldTC:61 TC:55
263   Revs:4 oldTC:55 TC:62
299   Revs:5 oldTC:62 TC:41
300   Revs:5 oldTC:41 TC:21
301   Revs:5 oldTC:21 TC:2
273   Revs:4 oldTC:2 TC:19
300   Revs:4 oldTC:19 TC:63
300   Revs:5 oldTC:63 TC:43
300   Revs:5 oldTC:43 TC:23
300   Revs:5 oldTC:23 TC:3
300   Revs:4 oldTC:3 TC:47
300   Revs:5 oldTC:47 TC:27
301   Revs:5 oldTC:27 TC:8
300   Revs:4 oldTC:8 TC:52
300   Revs:5 oldTC:52 TC:32
301   Revs:5 oldTC:32 TC:13
300   Revs:4 oldTC:13 TC:57
300   Revs:5 oldTC:57 TC:37
300   Revs:5 oldTC:37 TC:17
300   Revs:4 oldTC:17 TC:61
301   Revs:5 oldTC:61 TC:42
300   Revs:5 oldTC:42 TC:22
300   Revs:5 oldTC:22 TC:2
300   Revs:4 oldTC:2 TC:46
300   Revs:5 oldTC:46 TC:26
300   Revs:5 oldTC:26 TC:6
300   Revs:4 oldTC:6 TC:50
300   Revs:5 oldTC:50 TC:30
300   Revs:5 oldTC:30 TC:10
300   Revs:4 oldTC:10 TC:54
301   Revs:5 oldTC:54 TC:35

Autor: Thomas (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Guten Morgen,
noch eine kurze Rückmeldung an MWS:
Das hatte ich schon alles versucht, offensichtlich kommt das Problem 
nicht nur vor wenn die Interrupts zusammenfallen. Hat leider nicht 
geholfen.
Ich hab den Testcode mal angehängt, so habe ich das Problem mal ohne das 
ganze LCD Gerümpel nachgebildet.
Hat jemand eine Idee was da passiert? Ich feuere den externen Interrupt 
mit etwa 13.6Hz. Auch bei anderen Frequenzen tritt das sporadisch auf.

Bin bis Freitag beruflich unterwegs und kann mich erst dann wieder 
melden.
Gruß
Thomas

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und nochwas:
Ich hab mal die Ticks anders berechnet, nicht revolutions aufgezählt und 
dann mit 64 multipliziert, sondern jeden Interrupt die Variable um 64 
erhöht, das spart die Multiplikation.
Und plötzlich kommt das Problem nur noch SEHR vereinzelt vor, und dann 
scheint mir der TC Null zu sein.
Sehe ich mir an wenn ich wieder Zeit habe, am Wochenende geht es weiter.

Bid die Tage,
Gruß
Thomas

Autor: MWS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Hat jemand eine Idee was da passiert?
So wie ich das sehe hast Du da keine groben Schwankungen, sondern nur 
einen Fehler von 1, gleichbedeutend der kleinsten Auflösung des Timers. 
Das ist normal, wenn Timerfrequenz und Sampelfrequenz in keinem fest 
verzahnten Zusammenhang steht. Die Genauigkeit würde besser, wenn der 
Prescaler 1 würde und der Timer einfach durchläuft, also ohne Compare. 
Den Rest wie gehabt, im Ovf Int die Runden zählen und ggf. anstehende 
Ovf Ints in der PC Int behandeln.

Autor: Manuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Thread ist ja schon etwas älter, gibt es da inzwischen eine Lösung?
Ich vermute, dass es daran liegt, dass in der main mit Variablen 
gerechnet wird, die größer als 8bit sind. Problemlösung müsste dann 
sein, während der Rechnung die Interrupts abzuschalten.

Autor: Oliver S. (oliverso)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Manuel schrieb:
> Der Thread ist ja schon etwas älter, gibt es da inzwischen eine Lösung?

Es gab ja nicht mal ein eindeutiges Problem.

Oliver

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.