Hallo Freunde,
Ich hab ein Impuls Aufnahme Code aus dem Tutorium Anweisungen
geschrieben, bei dem Flanken Zeitintervalle festgehalten werden sollte.
Die Zeitintervalle sind für Standardabweichung meiner Messungen gedacht.
Tools: ATmega32, STK500, LCD 16x1 und FCPU ist 4MHz/64 teiler
Nun das Problem ist, dass bei der Aufnahme von kleinen Impuls Intervalle
(kleiner 1s) nach jeden n zahl Intervall eine Overflow eintritt und
meine Werte um 1s vergrößert.
Ich vermute dass der Overflow Zähler unabhängig von der Impuls Aufnahme
arbeitet und dadurch eine Überschneidung entsteht. Vieles habe ich
versucht um Overflow mit dem „Starttime und Endtime“ in Verbindung zu
setzen, aber keine Erfolg…
Weiß jemand wo der knack Punkt ist.. Wie kann ich das Problem
beseitigen?
Danke
Gruß
Sanchez
1
ISR(TIMER1_CAPT_vect)
2
{
3
Si_wert++;
4
staticunsignedcharErsteFlanke=TRUE;
5
6
if(ErsteFlanke==TRUE)
7
{
8
Starttime=ICR1;// Startzeit= ICR 1
9
Durchlauf=TRUE;
10
ErsteFlanke=FALSE;// Die naechste Flanke ist das Ende der Messung
11
}
12
else
13
{
14
Endtime=ICR1;// Stopzeit für die Messung= ICR1
15
Durchlauf=TRUE;// Eine vollst?ndige Messung. Sie kann ausgewertet werden
16
ErsteFlanke=TRUE;// Bei der naechsten Flanke beginnt der naechste Messzyklus
17
}
18
}
1
ISR(TIMER1_OVF_vect)
2
{
3
Overflow++;
4
}
1
voidImpulse_berechnen(void)
2
{
3
Zeit_ti=(Endtime)-(Starttime);
4
if(Overflow!=0)
5
{
6
Zeit_ti=(Overflow*65536)+Zeit_ti;
7
}
8
9
Zeit1_ti=(Zeit_ti*1000)/65535;// Zeit_ti in sekunden
Wenn ich Dich richtig verstanden habe, willst Du Impulszeiten messen.
Dazu ist der Timer-Überlauf-Interrupt denkbar ungeeignet.
Schau Dir mal den ICP-Interrupt an (Input-Capture), der ist genau für
diesen Zweck vorgesehen. Notfalls kann man noch Software-ICP mittels
externem Interrupt machen, ist nicht ganz so exakt, erlaubt aber mehrere
Messkanäle.
Die Vorgehensweise ist Folgende:
Bei steigender Flanke liest man den Timer aus und sichert den
Zeitstempel als Startwert. Nutzt man den ICP-Interrupt, dann liest man
das Input-Capture-Register aus, denn dies wurde von der Hardware bereits
beim Auftreten der Flanke aktualisiert. Nutzt man den externen
Interrupt, muss man halt den Timerstand auslesen. Zusätzlich ist noch
auf fallende Flanke umzuschalten.
Bei fallender Flanke liest man den Timer aus und erhält den Zeitstempel,
der neuer (größer, wenn man sich die Zeit als "fortlaufende Zahl"
vorstellt) als der Zeitstempel des Startwertes ist. Die Impulsdauer
erhält man durch Subtraktion (Endwert-Startwert). Da der Zählumfang des
Timers nur 16 Bit beträgt, braucht man sich dabei nicht um Überläufe zu
kümmern, die korrigieren sich von alleine. Sieh die 16 Bits des Timers
als die unteren 16 Bit einer riesengroßen Zahl, die die Timertakte seit
dem Urknall zählt... ^^
Ist die Periodendauer zu messen, dann triggert man nur auf steigende
Flanke und sichert den neuen Zeitstempel als alten für die nächste
Messung. Also neuen Wert einlesen, Kopie davon anlegen, von Kopie alten
Zeitstempel subtrahieren und als Periodendauer sichern, neuen
Zeitstempel in alten kopieren, fertig.
Mit ein paar Variablen mehr kann man natürlich auch Impulsdauer,
Impulspause und Periode separat ermitteln.
MfG
Danke fürs Antworten
Ich verwende ja ICP-Interrupt und meine Code Basiert sich auf code von
der Forum seite:
Beitrag "Input Capture Pin (ICP) auslesen ( Frequenz messen)"
In meine code gehe ich ja auch so vor wie du es beschrieben hast (glaube
ich!), aber das man sich um überläufe nicht kummern soll verstehe ich
nicht wie.
16bit timer = 65535 = 1s = 1 Overflow (so ist das doch oder?)
Also beim Intervalle größer 1s müssen auch Overflows beachtet werden.
Das alles passiert auch schon und gut, aber nach bestimmte Anzahl von
flanke triftt eine Overflow zuviel, was nicht passieren dürfte.
Ich vermute das nach jede volle sekunde (1s=65535) eine Überlauf gezählt
wird. Und Falls der erste flanke beim 65300 passiert und der zweite beim
250 er sieht das als eine überlauf. (Overflow== 65535)
Das ist was ich verstanden habe und vermute.. lege ich daneben oder
darauf? ;)
Gruß
diese Berechnung ist falsch.
Du musst die Anzahl der Overflows schon berücksichtigen. Allerdings ist
die Sache die:
Wenn Endtime kleiner als Starttime ist, dann wurde 1 Overflow zuviel
gezählt und du musst nur 1 Overflow weniger als festgestellt
berücksichtigen. Ist Endtime größer/gleich Starttime dann ist die Anzahl
der Overflows korrekt und wird auch so verrechnet.
Am besten macht man sich das klar, wenn man sich einen Zähler vorstellt,
der zb nur bis 8 zählen kann.
Angenommen Starttime wäre 3 gewesen.
Der Zähler zählt jetzt weiter
4 5 6 7
Jetzt kommt der Interrupt für das Ende. Was haben wir?
Starttime := 3
Endtime := 7
Anzahl Overflows := 0
Die Anzahl der gezählten Ticks ist dann 7 - 3 -> 4
was ja auch korrekt ist.
Anderes Beispiel
Starttime sei wieder 3 und der Zähler tickt
4 5 6 7 0 1
Starttime := 3
Endtime := 1
Anzahl Overflows := 1
Da diesmal Endtime kleiner als Starttime ist, muss man die Overflows
prinzipiell berücksichtigen, allerdings um 1 weniger als detektiert,
weil durch die unsigned Rechnerei 1 Overflow automatisch berücksichtigt
wird.
1 - 3 + 0 * 8 -> 6
Neues Beispiel
Starttime 3, der Zähler tickt
4 5 6 7 0 1 2 3 4
Starttime := 3
Endtime := 4
Anzahl Overflows: 1
Hier ist jetzt Endtime größer als Starttime und die Anzahl der Overflows
geht so wie sie ist in die Berechnung ein
4 - 3 + 1 * 8 -> 1 + 8 -> 9
zähl die Ticks nach, stimmt auffallend.
Wenn der Timer dann mehr als einmal überläuft kann man das Ganze weiter
durchprobieren und ich rate dir auch dazu, das am Papier auszuprobieren.
Gut, dann habe ich Dich falsch verstanden, sorry.
Zum Überlauf...
Wenn mir der Zählumfang des 16-Bit-Timers reicht (davon gehe ich aus,
ansonsten wähle ich einen besser passenden Vorteiler), muss ich mich
nicht um den Überlauf kümmern, zumindest nicht in ASM. Ich subtrahiere
den Startwert vom Endwert und erhalte die Differenz. Da ich die Zahlen
als unsigned betrachte, gibt es immer ein positives Ergebnis. Da der
Zähler des Timers als geschlossener Ring arbeitet, bleibt das Ergebnis
auch dann richtig, wenn bei der Subtraktion das Borrow-Flag (in Form des
Carry-Flags) in Folge eines Unterlaufes beeinflusst wird.
Wie man das in C notieren muss, entzieht sich meiner Kenntnis, ich
mach's nunmal in ASM. Das wäre aber nicht der erste Fall, wo man in C
arge Verrenkungen machen muss, um Dinge zu realisieren, die in ASM ganz
einfach sind.
MfG
Danke fürs eure Ausführliche Erklärungen, ich habe es leider Bisschen zu
spät gesehen und während dieser zeit hab meine Code um einiges
verändert.
Mit
if(Endtime < Starttime)
{
Overflow--;
}
Hab ich das Erste Problem beseitigt. Aber danach kamm eine weitere
Overflow Problem der um 65 mal heftiger ist als das davor. Und es
lässt mich nicht schlaffen.
Ich hab einen Simulierte Eingang Frequenz von ca. 70- 100Hz. Für
Bestimmung meine werte, wird Sekunde, Impuls Anzahl, Überlauf Anzahl und
Summe aller Zeiten auf eine 16x1 LCD angezeigt.
Das Sekunden Zähler und Summe aller Zeiten sollen parallel hoch zählen.
Das passiert auch paar Sekunden lang (Unterschiedlich), aber dann
schlagartig springt Summe der Zeiten um 65s Hoch.
Wenn ich denn Overflow komplett auskommentiere, dann Läuft alles
perfekt. Wo hab ich denn mein Fehler. Ich komm nicht drauf.
Na gut ich gibs erst mal auf, schlaffen ist angesagt.. meine eigene
Overflow ist schon am durchbrennen.. ;)
Sanchez schrieb:> Hallo,>> Hat Jemand eine Idee woran das Problem Liegt..
NOch nicht.
Du solltest aber hier
1
ISR(TIMER1_CAPT_vect)
2
{
3
Si_wert++;
4
5
Endtime=ICR1;// Stopzeit für die Messung= ICR1
6
Durchlauf=TRUE;// Eine vollst?ndige Messung. Sie kann ausgewertet werden
7
}
den kompletten Satz aktueller Daten (Timerwert + Overflowert)
wegspeichern. Ansonsten hast du nämlich keine Garantie, dass nicht in
der Zwischenzeit vom Capture Interrupt bis dann endlich die
Auswertefunktion aufgerufen wird, sich die Anzahl Overflows verändert.
Du hast da ein bischen naiv überall implizit die Annahme drinnen, dass
dein Programm alles in 0-Zeit machen kann bzw. deine zu messende
Frequenz so freundlich ist und darauf wartet, dass dein Programm mit der
Auswertung fertig ist ehe es dann wieder weiter geht.
Auch gibt es da noch ein Problemchen,
2 Interrupts können ja nicht gleichzeitig ausgeführt werden, sondern nur
hintereinander. Wenn nun aber der CaptureInterrupt bei einem Zählerstand
vom Maximum Timer erfolgt, wurde dann der Overflow Interrupt schon
ausgeführt oder nicht (ich weiß es nicht auswendig)
Ganz andere Frage: Kann es dir überhaupt passieren, dass deine
Timerdifferenz bei den dich interessierenden Frequenzen größer als 65535
werden kann? Wenn das eh nicht passieren kann, brauchst du auch die
Overflows nicht berücksichtigen und damit umschiffst du alle damit
zusammenhängenden Probleme.
Wauuu... danke Karl,
Aber ich bin überfordert, das hier ist meine aller erste code in C und
überhaupt Programmieren..
>den kompletten Satz aktueller Daten (Timerwert + Overflowert)>wegspeichern. Ansonsten hast du nämlich keine Garantie, dass nicht in>der Zwischenzeit vom Capture Interrupt bis dann endlich die>Auswertefunktion aufgerufen wird, sich die Anzahl Overflows verändert.
Muss das nach jede Flanke gemacht werden, verstehe nicht ganz genau wie
das gehen soll..
>Du hast da ein bischen naiv überall implizit die Annahme drinnen, dass>dein Programm alles in 0-Zeit machen kann bzw. deine zu messende>Frequenz so freundlich ist und darauf wartet, dass dein Programm mit der>Auswertung fertig ist ehe es dann wieder weiter geht.
Heißt das Programm Aufbau umschreiben so dass der Berechnung parallel zu
Flanken Aufnahme abläuft?
>Auch gibt es da noch ein Problemchen,>2 Interrupts können ja nicht gleichzeitig ausgeführt werden, sondern nur>hintereinander. Wenn nun aber der CaptureInterrupt bei einem Zählerstand>vom Maximum Timer erfolgt, wurde dann der Overflow Interrupt schon>ausgeführt oder nicht (ich weiß es nicht auswendig)
2te Interrupt ist der Sekunden Zähler gemeint? Ich brauche aber eine
Sekunden Zähler.. Kann man nicht die beide mit einem Interrupt
realisieren?
>Ganz andere Frage: Kann es dir überhaupt passieren, dass deine>Timerdifferenz bei den dich interessierenden Frequenzen größer als 65535>werden kann? Wenn das eh nicht passieren kann, brauchst du auch die>Overflows nicht berücksichtigen und damit umschiffst du alle damit>zusammenhängenden Probleme.
Ich werde größere Frequenzen haben..
Das Code am Anhang ist nur eine Ausschnitt von ganzem, den Rest wollt
ich nicht zeigen da sonst keiner durch blicken wird. Also das Ganze soll
eine Windgeschwindigkeit Messgerät werden. In dem eigentlichen Code habe
ich noch Datenspeicherung auf der SD-Karte und noch Uhr und Datum.
Es gibt einmal die variable Sekunde das für gesamt zeit zählen dient:
der macht seine Arbeit vernünftig. Und es gibt noch variable ss, der die
Uhr hoch zählen muss. Obwohl ss und Sekunde an dem selben Interrupt
angeschlossen sind, ss kann nur bis 12 hoch zählen dann bleibt er stehen
merwürdig...
Bei Windstärkemessung interessiert nicht unbedingt die Dauer jedes
einzelnen Impulses (oder Impulsabstandes), denn in den Impulsen ist ja
keine serielle Information codiert. Es interessiert vielmehr die Anzahl
der Impulse pro Zeiteinheit (z.B. Sekunde). Daher würde ich es nicht
über den Input-Capture machen, sondern einen Timer/Counter als Zähler
mit externem Takteingang nutzen. Ein anderer Timer dient dann als
Zeitnormal (Sekundentakt) zum Auslesen und Löschen des Zählers.
Ein Sekundentakt lässt sich auch mit einem 8-Bit-Timer erzeugen,
notfalls als Hundertstelsekunde mit nachgeschaltetem Zähler in Software
(Zählvariable). Also wird Timer0 zum Erzeugen des Sekundentaktes
genutzt.
Timer1 wird als Zähler genutzt, sein Zähleingang ist der T1-Pin. Falls
seine 16 Bit nicht ausreichen kann man den OVF-Interrupt des Timer1
nutzen, um eine Zählvariable hochzuzählen, die den Timer auf 24 oder 32
Bit aufstockt.
Im Interrupt des Timer0 (also im Sekundentakt) werden Zählerstand von
Timer1 und Zählvariable gesichert (in andere Variablen kopiert) und auf
0 gesetzt. Zusätzlich wird der Mainloop über einen Merker (Flag,
Semaphore, Zustandsvariable, Boolean-Variable, Jobauftrag) mitgeteilt,
dass ein neues Ergebnis vorliegt.
Die Mainloop fragt zyklisch alle Jobflags ab und verzweigt zu einem Job,
wenn ein Auftrag vorliegt. Hier ist es das Jobflag für die neue Sekunde,
das zum Aufruf der Handler-Routine führt. Diese macht nun Folgendes:
- Jobauftrag (Merker) löschen (Job wird ja erledigt)
- gesicherten Timerstand und Zählvariable zu einer Zahl (24 oder 32
Bit) zusammensetzen
- Ergebnis skalieren, also so umrechnen, dass es ein Mensch versteht
- Ergebnis per UART versenden
- Ergebnis am LCD anzeigen
- Entscheidungen treffen (Markisen einfahren, (A)Lärm auslösen)
- ...
Das Zählen der Impulse erfolgt dabei in Hardware, also ohne Zutun von
Programmcode (außer Initialisierung). Lediglich Überläufe des Zählers
nach jeweils 65536 Impulsen lösen einen Interrupt aus, in dem der
High-Teil hochgezählt wird. Das ist vernachlässigbar wenig Prozessorlast
und tritt, wenn überhaupt, nur bei starkem Sturm auf. Ich würde sogar
auf den Übertrag verzichten und evtl. mit einem variablen
Abfrage-Intervall arbeiten.
Also die Grundfunktion ist sehr einfach realisierbar und es bleibt
verdammt viel Spielraum für Erweiterungen und Gimmicks. Da braucht es
auch keinen ATMega32 für, das macht ein ATTiny2313 mit links und 40
Fieber.
MfG