Hallo,
Ich habe ein Programm geschrieben, womit man pulsweite des Squarewaves
am Input(ICP/PB0) in Millisekunden messen kann. Ich bin nicht so
zufrieden damit, irgendwas scheint immer noch nicht so optimal zu sein.
In diesem Beispiel, habe ich mit hilfe eines Switches (siehe Bild im
Anhang), den Steigende und Fallende Flanke emuliert und die Pulsweite
wird über dem USART ausgegeben. Meine Frage ist was mache ich hier immer
noch falsch oder wo kann ich noch optimieren?
Angehängt Source code.
Kenne mich mit dem AT328 im Detail nicht aus, aber der hat doch auch den
Capture für den 16-Bit Timer. Einfach im Interrupt den Capture-Wert
auslesen und ggf. die Flanke wechseln (oder kann der gar beide
Flanken?).
Wenn ich das richtig sehe, läuft in deinem Fall der Timer beim Auslesen
weiter? Dabei kann es ja grobe Fehler geben, wenn der Zähler gerade
einen Überlauf low/high Byte hat. Also der Zähler hat gerade 0x2FF,
folgendes passiert:
- Du liest low=0xFF
- genau danach läuft der Zähler weiter von 0x2FF aus 0x300
- du liest das Highbyte high=0x03
Der sich ergebende Wert ist 0x3FF, also falsch.
Harald schrieb:> Kenne mich mit dem AT328 im Detail nicht aus, aber der hat doch> auch den> Capture für den 16-Bit Timer. Einfach im Interrupt den Capture-Wert> auslesen und ggf. die Flanke wechseln (oder kann der gar beide> Flanken?).
Mache ich doch. :)
Beim nächsten mal wird der Interrupt durch steigende Flanke
1
TCCR1B|=(1<<ICES1);
verursacht
und beim fallende
1
TCCR1B&=~(1<<ICES1);
> Wenn ich das richtig sehe, läuft in deinem Fall der Timer beim Auslesen> weiter? Dabei kann es ja grobe Fehler geben, wenn der Zähler gerade> einen Überlauf low/high Byte hat. Also der Zähler hat gerade 0x2FF,> folgendes passiert:> - Du liest low=0xFF> - genau danach läuft der Zähler weiter von 0x2FF aus 0x300> - du liest das Highbyte high=0x03>> Der sich ergebende Wert ist 0x3FF, also falsch.
Okay, dass muss ich noch untersuchen.
Durch den Capture-Mechanismus gehst du genau diesen Problemen aus dem
Weg. Das arme Silizium der Capture-Einheit soll doch auch ein schönes
Leben haben und kein sinnloses Dasein fristen...
Harald schrieb:> Durch den Capture-Mechanismus gehst du genau diesen Problemen aus> dem> Weg. Das arme Silizium der Capture-Einheit soll doch auch ein schönes> Leben haben und kein sinnloses Dasein fristen...
Ich verstehe diese Aussage nicht wirklich. Da soll später ein andere
Baustein kommen, ich wollte das überhaupt in betrieb nehmen und schauen
ob "Time capture" wirklich passiert. Ich habe das am Anfang beschrieben
oder?
Aa B. schrieb:> Ich bin nicht so> zufrieden damit, irgendwas scheint immer noch nicht so optimal zu sein.
Kannst Du mal beschreiben, woran sich Deine Unzufriedenhet genau
"festmacht"?
Was genau ist Dein Problem?
So etwas mit einem Taster zu testen ist nicht gerade ideal - Stichwort
"Tastenprellung".
Dieter F. schrieb:> Kannst Du mal beschreiben, woran sich Deine Unzufriedenhet genau> "festmacht"?> Was genau ist Dein Problem?
Wenn ich die taste ungefähr 1 Sekunde gedruckt halte und los lasse,
hätte ich in der variable
1
elapsed_time
ca 1000 ms erwartet. Das klappt aber nicht immer. Es kommt manchmal
100, 50 usw.
> So etwas mit einem Taster zu testen ist nicht gerade ideal - Stichwort> "Tastenprellung".
Um debounce zu erkennen habe ich ein led togglen lassen, in diesem Fall
ist der LED an wenn er steigende Flanke gesehen hat und noch keine
fallende. Und dass passiert auch wie erwartet, also kein komische
Rauschen oder so am pin.
Ich hoffe es ist verständlich. :)
Das Register ICR1 macht genau das, was Du in deinem Source
beabsichtigst. Er kopiert beim Ereignis den aktuellen Timerwert in ICR1
- und zwar ohne die von mir benannten Probleme. Mittels ICES1 wählst du
die Flanke, dieses Bit müsste dann im Capture(!) Interrupt umgeschaltet
werden.
Also im Interrupt der pos Flanke Wert von ICR1 merken und im Interrupt
der fallenden Flanke den aktuellen ICR1 vom gemerkten Wert abziehen.
Probleme gibt es weiterhin, wenn der Tastendruck länger ist als was der
16-Bit zählen kann. Dann kann man per Software Überläufe zählen, aber
die dann auftretenden Fallstricke sind noch einmal eine Liga höher.
Aa B. schrieb:> Wenn ich die taste ungefähr 1 Sekunde gedruckt halte und los lasse,> hätte ich in der variableelapsed_time ca 1000 ms erwartet. Das klappt> aber nicht immer. Es kommt manchmal> 100, 50 usw.
Dann rechne mal nach.
Der Zählbereich ist nur 1,04s, d.h. bei "ungefähr" bist Du eben zu
langsam.
Nimm den Prescaler 1024.
Man kann die Timer aber auch per SW leicht auf 32 Bit aufbohren.
Beitrag "AVR Timer mit 32 Bit"
Aa B. schrieb:> Meine Frage ist was mache ich hier immer> noch falsch oder wo kann ich noch optimieren?
Deinen Code habe ich mir nicht angesehen,aber hab'ne pdf
zusammengestellt die das Thema Pulse Width behandelt.Ist zwar fuer
Pics,laesst sich aber leicht auf andere uCs uebertragen - ist ja
C-code.....
Das letztere Kapitel ist ein bischen Skizzenhaft(fuer
Schueler/Studenten) dargestellt und sieht lausig aus,ist aber eine
genauere Betrachtung wert.
Peter D. schrieb:> Dann rechne mal nach.> Der Zählbereich ist nur 1,04s, d.h. bei "ungefähr" bist Du eben zu> langsam.> Nimm den Prescaler 1024.
OMG! Ich kann nicht glauben das der "ATMega Chuck Norris" auf mein
Beitrag geantwortet hat. Wie cool. Danke:)))
Du hast völlig recht, 1024 als prescaler, habe ich ausprobiert,
unktioniert deutlich besser, einfach weil der timer tick kommt alle
64us, damit kann ich bis ca. 4sec messen, aber da soll später ein US
sensor kommen der ein Square wave erzeugt und dafür ist der Prescaler
von 256 perfect.
> Man kann die Timer aber auch per SW leicht auf 32 Bit aufbohren.> Beitrag "AVR Timer mit 32 Bit"
Vielen Dank, werde ich nachlesen. :)
Aa B. schrieb:> damit kann ich bis ca. 4sec messen, aber da soll später ein US> sensor kommen der ein Square wave erzeugt und dafür ist der Prescaler> von 256 perfect.
Na ja, wenn Du US messen willst - dann kann es ja nicht sooo weit sein.
HC-SR04 misst bis ca. 3 m "genau"(~ 18 ms), beim SRF08 braucht ein
Messzyklus ungefähr 64 ms. Vielleicht gibt es ja US-Module, die weiter
(zuverlässig) messen - das wage ich aber leicht zu bezweifeln (vom
Ballon Richtung Erde aus ggf. deutlich mehr).
Wenn Du größere Entfernungen messen möchtest ist US nicht unbedingt das
Mittel erster Wahl. Bei den angepeilten 4 Sec. wären das ungefähr 660 m
- das kannst Du vergessen ...
Dieter F. schrieb:> Na ja, wenn Du US messen willst - dann kann es ja nicht sooo weit sein.> HC-SR04 misst bis ca. 3 m "genau"(~ 18 ms), beim SRF08 braucht ein> Messzyklus ungefähr 64 ms. Vielleicht gibt es ja US-Module, die weiter> (zuverlässig) messen - das wage ich aber leicht zu bezweifeln (vom> Ballon Richtung Erde aus ggf. deutlich mehr).
Mir ist heute eingefallen dass man den TIMER2 laufen lassen kann, und
diese Output on Compare (von Timer2) als input für mein ICP nutzen kann.
erst heute morgen, manchmal bin ich zu doof. :)) Aber jetzt kann ich bis
1 microsekunde messen.
Meinst Du US ist zu ungenau? Ic h habe diese PDF hier entdeckt, und habe
mich darauf orientiert.
https://www.mikrocontroller.net/attachment/218122/HC-SR04_ultraschallmodul_beschreibung_3.pdf> Wenn Du größere Entfernungen messen möchtest ist US nicht unbedingt das> Mittel erster Wahl. Bei den angepeilten 4 Sec. wären das ungefähr 660 m> - das kannst Du vergessen ...
Braucht man dafür nicht ein laser oder so? es sei denn, der Ultraschall
Trigger Signal hat ein große Amplitude, oder verstehe ich falsch?
Aa B. schrieb:> Meinst Du US ist zu ungenau?
Kommt drauf an, was Du wie weit entfernt messen willst und welche
Gegenstände ggf. im Schallkegel (15 Grad lt. Deinem PDF) sonst noch so
sind. Ich habe damit nicht die besten Erfahrungen gemacht, was
Genauigkeit angeht - aber das kann ein persönliches Problem sin :-\
Aa B. schrieb:> Braucht man dafür nicht ein laser oder so?
Für größere Entfernungen - ja. Deswegen wunderte es mich auch, dass Du
Dich so über die Messbereichserweiterung auf 4 Sek. gefreut hast :-)
m.n. schrieb:> Für Zeit/Impulsmessungen im Bereich 10 µs - 200 s kann man auch INT0 und> INT1 verwenden:
Aber nur eingeschränkt. Sogar wenn keine anderen Interrupts erlaubt
sind, ein Befehl kann 1..4 Zyklen dauern, d.h. man hat einen Jitter von
3 Zyklen, ist also Faktor 3 ungenauer als der ICP.
Peter D. schrieb:> m.n. schrieb:>> Für Zeit/Impulsmessungen im Bereich 10 µs - 200 s kann man auch INT0 und>> INT1 verwenden:>> Aber nur eingeschränkt.
Keine Frage, aber bei längeren Zeiten fallen die Mikrosekunden kaum noch
ins Gewicht.
Man erspart sich allerdings zusätzliche Logik, wenn man separate Signale
für Start und Stopp hat (z.B. Lichstschranke), und man kann keine Flanke
verlieren möchte (unabhängig vom gemessenen Ergebnis), wie es beim
Umschalten von ICP passieren kann. Für die Flanken- und ggf.
Kanalumschaltung muß die INT-Quelle ja kurz abgeschaltet und das Flag
gelöscht werden.
Aber das sind dann Feinheiten.
Für ganz kurze Reflexionsmessungen könnte man einen TDC7200
(Time-Digital-Converter) einsetzen. Aber bleiben wir beim AVR ;-)
m.n. schrieb:> Man erspart sich allerdings zusätzliche Logik, wenn man separate Signale> für Start und Stopp hat (z.B. Lichstschranke)
"Zusätzliche Logik" = 2 Dioden und ein Widerstand...
> und man kann keine Flanke> verlieren möchte (unabhängig vom gemessenen Ergebnis), wie es beim> Umschalten von ICP passieren kann.
Erstmal: wenn man wirklich zwei Signale hat, braucht man überhaupt nicht
umschalten, weil von jedem der beiden Signale nur jeweils eine Flanke
relevant ist. Man wird natürlich dieselbe verwenden...
Davon abgesehen ist bei ICP die Chance, eine Flanke zu verlieren
deutlich geringer als bei PCINT aus zwei Quellen.
c-hater schrieb:> "Zusätzliche Logik" = 2 Dioden und ein Widerstand...
Zu dieser "Schaltung" fehlt noch die Gurke => Gurkenschaltung.
> Erstmal: wenn man wirklich zwei Signale hat, braucht man überhaupt nicht> umschalten, weil von jedem der beiden Signale nur jeweils eine Flanke> relevant ist. Man wird natürlich dieselbe verwenden...
1. umzuschalten
2. die gleiche Flanke
3. am gleichen Eingang?
> Davon abgesehen ist bei ICP die Chance, eine Flanke zu verlieren> deutlich geringer als bei PCINT aus zwei Quellen.
INT0/INT1 != PCINT
m.n. schrieb:> INT0/INT1 != PCINT
Da musst du dann aber auch wieder die Flanke umschalten. Und du hast
zwei Interrupts, also hat jeder der beiden zusätzlich in seiner variable
Latenz die Laufzeit des jeweils anderen...
Vergiss es! Nix ist besser zur Zeitmessung geeignet als ICP. Wenn die
ICP-ISR die einzige im System ist, kann man mit entsprechend kompetenter
Programmierung der ISR dafür sorgen, dass man GARANTIERT keine Flanke
verpasst, die mehr als 10 Takte von der vorigen entfernt ist und man
erfaßt jede dieser Flanken mit einer Genauigkeit von EINEM Takt. Das
geht nur mit ICP, mit keiner anderen Methode ist das möglich, nicht mit
PCINTx und auch nicht mit INTx, und schon garnicht, wenn auch noch zwei
ISRs beschäftigt werden müssen...
Ok, natürlich hat auch ICP Grenzen. Die genannten 10 Takte kann man
natürlich nicht dauerhaft erreichen, sondern nur so lange der Puffer im
SRAM reicht, der die Events aufzeichnet. Zwischendurch müssen immer mal
wieder "Pausen" im Eingangssignal sein, damit der Puffer auch
ausgewertet und geleert werden kann., sonst läuft er irgendwann über und
dann verliert man natürlich Flanken.
c-hater schrieb:> Vergiss es!
Ja, denk bitte mal an den gedachten Zweck. US-Module abfragen - meinst
Du wirklich, da kommt es auf jede µs an? Oh, ich habe vergessen - bei 16
MHz bewegen wir uns ja im Nanosekundenbereich - 1 ns = ~ 30 cm (Licht)
:-)
Dieter F. schrieb:> Ja, denk bitte mal an den gedachten Zweck. US-Module abfragen - meinst> Du wirklich, da kommt es auf jede µs an?
Was, zum Teufel, sind US-Module?
Abgesehen davon: Wenn man ein Feature in der Hardware hat, was
nachweislich für einen bestimmten Zweck am besten geeignet ist, dann
nutzt nur ein Vollidiot dieses Feature nicht. Das gilt selbst dann, wenn
man die die erreichbare Leistung dieses Features für die Ziel-Anwendung
garnicht benötigt.
Weil: Nicht benötigte Leistung kostet kein extra Geld, denn die Sache
ist ja sowieso vorhanden und damit bereits bezahlt...
c-hater schrieb:> US-Module?
Nix Teufel - US = Ultraschall - darum geht es hier (falls es Dir
entgangen ist). Außerdem habe ich nichts gegen ICP nur bei dem
schnarchigen US-Modul mit der sowieso begrenzten Auflösung und
Genauigkeit ist es wohl egal.
c-hater schrieb:>> INT0/INT1 != PCINT>> Da musst du dann aber auch wieder die Flanke umschalten.
Nein. Zu jedem INTx wird die aktive Flanke einmalig eingestellt und
bleibt auch so.
> Nix ist besser zur Zeitmessung geeignet als ICP.
Auf jeden Fall, aber die AVR8 haben in der Regel nur ein
Capture-Register, was die Umschalterei so oder so notwendig macht. Viel
eleganter ginge es z.B. mit einem STM32Fxxx. Ein Griff in die Schaublade
zeigt auch wie es geht:
http://mino-elektronik.de/FM_407/fmeter_407.htm#a5
;-)
Aber der TO hat seinen ATmega328 und sollte sein Problem damit gelöst
bekommen.
c-hater schrieb:> Das gilt selbst dann, wenn> man die die erreichbare Leistung dieses Features für die Ziel-Anwendung> garnicht benötigt.
Wenn ich mit viertel-Gas im 4. Gang mein Ziel genau so schnell wie mit
Vollgas im 1. Gang erreiche, dann fahre ich viertel-Gas - oder ich bin
der angesprochene Vollidiot :-)
m.n. schrieb:> Auf jeden Fall, aber die AVR8 haben in der Regel nur ein> Capture-Register, was die Umschalterei so oder so notwendig macht. Viel> eleganter ginge es z.B. mit einem STM32Fxxx. Ein Griff in die Schaublade> zeigt auch wie es geht:> http://mino-elektronik.de/FM_407/fmeter_407.htm#a5> ;-)
Schön - hindert Dich irgend jemand daran? Falls ja biete ich Dir meine
Hilfe an.
Soooo, ein ganz kleine Update, ich habe die US Sensor mit ATMega328p in
betrieb genommen, und er misst einfach, den Abstand zwischen US Sensor
und dem Objekt in cm. Bisschen ungenau ist er schon und es gibt einiges
zu optimieren, die ganze Operationen mit float im Program zum Beipiel.
Display auf dem LCD. Kann man auch Temperature compensation einbauen,
weil Geschwindigkeit von Sound wellen ändern sich mit Temperatur. aber
da bräuchte ich ein vernünftige scheduler weil ich einige ISRs haben
wurde.
Nächste schritt wäre auf dem STM32 zu portieren. :) Da hat man mehr
Luxus, 32-bit Timer zum Capture, Output compare und FPU, und vieeeel
mehr. :)
Verwendete sprache: nur C
Hardware: Arduino UNO
Toolchain: avr-gcc, avrdude(zum Programmieren)
OS: Linux
Danke euch für euer Tipps. :)