Hallo zusammen, ich komme mit meiner Software zur Zeitmessung einfach nicht weiter... Der Plan: Eine Lichtschranke wird periodisch unterbrochen, die Zeit zwischen N Unterbrechungen soll genauer als 1ms bestimmt werden. Die Umsetzung: Hardware: Arduino Uno. Jede Unterbrechung der Lichtschranke löst einen Timer1-Capture-Interrupt aus. Der 1. Interrupt enabled den T1-Overflow-Interrupt, da die Zeiten zwischen den Impulsen einige Sekunden lang sein können. Der letzte T1-Capture-Interrupt disabled den T1-Overflow und den T1-Capture-Interrupt. Aus den beiden Captures und den Overflows wird die Zeit berechnet. Hilfskonstruktion: Mit Timer2 wird ein periodisches Signal erzeugt, welches auf den Capture-Eingang gegeben wird.. --> Funktioniert, habe ich mit dem Oszi nachgeprüft. Das Problem: a) Ich bekomme keine T1-Overflow-Interrupts, auch die Captures sind meist Null. b) Nach einem Durchlauf bleibt das Programm hängen! Bin für jeden zielführenden Tipp dankbar! Gruß Hermann
Hallo nochmal, hab ich in meiner Frage etwas vergessen zu erwähnen, oder hat wirklich niemand einen Hinweis für mich??? Viele Grüße Hermann
Hermann G. schrieb: > Hallo nochmal, > hab ich in meiner Frage etwas vergessen zu erwähnen, oder hat wirklich > niemand einen Hinweis für mich??? > > Viele Grüße > Hermann Variablen, welche in einer Interrupt-Routine verändert und an anderer Stelle gelesen werden, sollten besser volatile deklariert werden. Wäre mal so der erste Versuch.
Ich glaube man kann es komplizierter nicht machen! Male Dir mal ein Zeitdiagramm auf. Dann ist eine fallende Flanke am INTx für den Start eines Timers, z.B. Timer1 zuständig, den man per Software beliebig auf 32 Bit oder 64 Bit erweitern kann. Die nächste steigende Flanke am INTx stopp den Timer und man setzt ein Flag "Messung beendet" auf true. Im der Mainloop wird dann das Ergebnis ausgewertet und verrechnet. In der Interrupt Serviceroutine wird natürlich auch der INTx um konfiguriert - Flanke high-low und umgekehrt - man achtet auf das Zeitverhalten der Routine.
Hallo! Ich habe mir den Code nicht angesehen, hoffe aber trotzdem, dass dir dieser Hinweis hilft: Konzentriere deinen Blick auf's Wesentliche, reduziere den Code, und lass dich nicht ablenken vom Drumherum. Aktuell ist dein Problem, dass ein Timer-Overflow keinen Interrupt auslöst. Lösche (oder kommentiere) allen Code, der damit nichts zu tun hat. Das alles lenkt jetzt nur ab. Wenn das dann hinhaut, kannst du den Programm Schritt um Schritt ergänzen. Prüfe nach jedem Schritt, dass wirklich noch alles tut. Ich frage mich, warum dieses Problem jetzt erst auftaucht, wo dein Programm schon quasi fertig zu sein scheint. Müsste dieses Problem nicht schon von Beginn an existieren? Das kommt mir ein bisschen vor, als würde man, während man am Dachgeschoss arbeitet draufkommen, dass die Wasserleitung im Keller schon seit Beginn an leckt.
Karl M. schrieb: > Die nächste steigende Flanke am INTx stopp den Timer und man setzt ein > Flag "Messung beendet" auf true. Warum den Timer stoppen? Es reicht doch, per Capture auf der Flanke den Zählerstand in ein Register zu übernehmen. In der Capture ISR kann man dann in Ruhe das Register lesen und in eine Variable übernehmen. Der Wert ist gleichzeitig das Ende der abgelaufenen Taktperiode und der Anfang der nächsten. Die Differenz zweier solcher Capture Werte, erweitert um volle Timer-Durchläufe, die einer Overflow ISR mitgezählt werden können, liefert die Zeitdifferenz zwischen den Flanken. Die Zeitauflösung entspricht der Taktfrequenz des Timers, kann also locker im µs-Bereich liegen.
Wolfgang schrieb: > Die > Zeitauflösung entspricht der Taktfrequenz des Timers, kann also locker > im µs-Bereich liegen. Der Plan: Eine Lichtschranke wird periodisch unterbrochen, die Zeit zwischen N Unterbrechungen soll genauer als 1ms bestimmt werden.
Karl M. schrieb: > Wolfgang schrieb: >> Die >> Zeitauflösung entspricht der Taktfrequenz des Timers, kann also locker >> im µs-Bereich liegen. > > Der Plan: > Eine Lichtschranke wird periodisch unterbrochen, die Zeit zwischen N > Unterbrechungen soll genauer als 1ms bestimmt werden. Ist eine µs-Auflösung denn nicht genauer als eine ms?
Karl M. schrieb: > Eine Lichtschranke wird periodisch unterbrochen, die Zeit zwischen N > Unterbrechungen soll genauer als 1ms bestimmt werden. Was willst du damit sagen? "genauer als 1ms" kriegt man doch fast noch mit der Handstopuhr zu fassen. Zusammen mit einem µC ist das eher keine ernste Anforderung, wenn die Lichtschranke nicht zu sehr unter Schwierigkeiten mit Umweltstörungen zu kämpfen hat.
Hermann G. schrieb: > Bin für jeden zielführenden Tipp dankbar!
1 | volatile unsigned long nOverflow = 0; |
2 | volatile unsigned long nTime = 0; |
3 | volatile unsigned char bReady = 0; |
4 | |
5 | ISR(TIMER1_CAPT_vect) |
6 | {
|
7 | static unsigned long last = 0; |
8 | unsigned long icr = ICR1 + nOverFlow; |
9 | nTime = icr -last; |
10 | last = icr; |
11 | bReady = 1; |
12 | }
|
13 | |
14 | ISR(TIMER1_OVF_vect) |
15 | {
|
16 | nOverFlow += 65536; |
17 | }
|
18 | |
19 | int main(void) |
20 | {
|
21 | .
|
22 | .
|
23 | .
|
24 | |
25 | if(bReady) |
26 | {
|
27 | bReady = 0; |
28 | /* Tu, was zu tun ist*/
|
29 | }
|
30 | }
|
Kein INTx-Blödsinn, kein Timer-Interrupt-Geschalte-Unsinn.
:
Bearbeitet durch User
Das hat zwar noch nichts mit der groben Funktion zu tun, aber noch ein Hinweiss, wenn es zuverlässig werden soll: Bei der Nutzung von Überläufen zur erweiterung der Auflösung auf mehr als 16 Bit muss man etwas aufpassen, wenn ICP event und Timer Überlauf zusammenfallen. Da passt dann die Zählung der Überläufe ggf. nicht zum ICP1 Stand. Meistens geht es gut aber etwa eine von 10000 Messungen wird deutlich (1 Überlauf) daneben liegen, wenn man nicht aufpasst. Das Problem lässt sich aber lösen (siehe z.B. hier: http://rn-wissen.de/wiki/index.php?title=Timer/Counter_%28Avr%29#Input_Capture). Für einfach nur besser als 1 ms Auflösung könnte man ggf. einfach den Timer langsam genug laufen lassen, dass man mit der 16 Bit Auflösung des Timers auskommt. Der geziegte Code ist einfach recht lang / unübersichltich. Das hat findet sich nicht unbedingt einer zur Fehlersuche. Je weiter der Code auf das wesentliche reduziert ist, desto eher wird man Hilfe finden.
Danke, Lurchi,
> ... wenn ICP event und Timer Überlauf zusammenfallen.
Das Risiko hatte ich bisher noch nicht im Blickfeld.
Gut, dass Du mich jetzt schon drauf gebracht hast, bevor wegen eines
extrem seltenen Fehlers lange rätseln muss.
Ciao
Wolfgang Horn
Hier mal die lesbare Version des Bugfixes. Doch Vorsicht! Die Abfrage auf <128 ist nicht ganz korrekt! Den im Extremfall kann ein anderer, hochpriorer Interrupt die Ausführung sowohl von ICP1 als auch TOV1 für mehr als 128 Timertakte verhindern (auch vor dem Timerüberlauf!), vor allem bei hohen Timerfrequenzen (kleiner Vorteiler)! Dann stimmt der Vergleich NICHT! Mit der Abfrage auf ICP1<32000 hat man nahezu die halbe Timerperiode Zeit, so einen Fehler auszugleichen. Länger darf der TOV1 Interrupt nicht blockiert werden. Wenn doch, knallt es und man mißt Fahrkarten. Hier ist auch eine schöne Anwendung von Short Circuit Evaluation in C. Wenn der 1. Vergleich (TIFR1 & (1<<TOV1)) false ist, was er zu 99,99% immer sein wird, wird der 2. "aufwändige" Vergleich nicht ausgeführt.
1 | ISR(TIMER1_CAPT_vect) { |
2 | static unsigned long last = 0; |
3 | unsigned long icr; |
4 | |
5 | // check race condition of timer overflow
|
6 | if ((TIFR1 & (1<<TOV1)) && (ICR1 < 32000)) { |
7 | nOverFlow++; |
8 | TIFR1 = (1<<TOV1); // clear flag, increment already done |
9 | }
|
10 | |
11 | icr = ICR1 + nOverFlow; |
12 | nTime = icr - last; |
13 | last = icr; |
14 | bReady = 1; |
15 | }
|
:
Bearbeitet durch User
Im oben verlinkten Code bezieht sich der Vergleich mit 128 auf das ober Byte von ICR1, macht also ein ICR1 Wert von 32768. Das ist kein wesentlicher Unterschien zum Vergleich mit 32000.
Danke für die vielen Tipps. Ich werde das morgen versuchen umzusetzen und werde dann berichten. Danke nochmals, bis morgen Hermann
Ich dachte immer, dass es im Arduino-System, bereits einen Timer gibt. Den braucht man doch nur bei jeder Unterbrechung auslesen, und anschließend feststellen, wann das letzte Mal was los war. Das geht natürlich erst ab dem n+1-ten Mal. Natürlich sollte der Hintergrund nicht total zugemüllt, mit irgendwelchen Unterbrechungen, sein.
Mein grosses V. schrieb: > Kein INTx-Blödsinn, kein Timer-Interrupt-Geschalte-Unsinn. intx ist kein Blödsinn sondern schon eine sehr sinnvolle Sache, einfach mal damit beschäftigen ;)
So, es geht. Vielen Dank an alle, die konstruktive Vorschläge gepostet haben. Ich habe die Interrupt-Struktur überarbeitet und so weit wie möglich vereinfacht und etliche der Hinweise berücksichtigt. @Falk: Danke für den Tipp, den Overflow-Interrupt ggf. im Capture-Interupt abzufangen. ("Race"). Das hat dem Prohramm den letzten Schliff gegeben. Grüße an alle Mitleser Hermann
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.