Ich will die Geschwindigkeit eines Rades messen, wofür ich pro Umdrehung
ein impuls bekomme.
Ich benutze den 16bit Timer zusammen mit dem Input Capture Pin.
Nur ich werd nicht so ganz schlau aus dem Datenblatt, ob man Overflow
und ICP zusammen verwenden kann (würde ich gerne verwenden um zu
detektieren ob das Rad "stillsteht") und ob der Counterwert bei einem
IPC Event automatisch reseted wird.
Als umrechnung für die Geschwindigkeit habe ich mir folgendes
überlegt:
X=36 * Counter_Stand_nach_1_sek*Radumfang_in_m (könnte man als
Konstante Ablegen)
kmh = ( X / ICP_Zählerstand) / 100
Sieht jemand in der Rechnung noch nen Denkfehler bzw
Optimierungsmöglichkeit?
hatte alternativ noch an:
X=3600 * Counter_Stand_nach_1_sek*Radumfang_in_m
kmh = X / ICP_Zählerstand
gedacht dan muß ich aber wohl aufgrund der Größe der Zahl nen 32bit
Wert für X vorsehen.
>ob man Overflow und ICP zusammen verwenden kann
ja, geht.
>ob der Counterwert bei einem IPC Event automatisch reseted
Nein, wird er nicht.
Du musst dir nur die beiden Timer-Werte merken und dann von einandern
abziehen.
OC kann man dabei auch noch machen (lassen)...
Overflow ist dann natürlich etwas problematisch, da der auch so
auftreten kann, ohne dass das Rad steht (2-3 Overflow müssten dann
vielleicht auftreten, damit man das detektieren kann).
Naja, der Controller läuft mit 16mhz, vorteiler 1024, ergibt 4sek lang
keine Impuls, das wären dann bei einem Umfang von 165cm, ne
Geschwindikeit < 0.5kmh und ich wollte Minimal Geschwindikeit im
Bereich ab 1kmh erfassen :)
Könnte ich also bei einem ICP Event einfach Counter auf 0 setzen, ICP
Register auslesen, und mit obiger Formel berechnen?
Um die Geschwindigkeit zu berechnen brauchst Du zwei Ereignisse bzw. die
Zeitspanne dazwischen. Du brauchst also schon mal einen
Capture-Interrupt um eine Messung zu starten und dann einen, der die
Messung beendet und das Ergebnis ausspuckt.
Würde ich nicht machen.
Nimm einfach den aktuellen ICP-Wert und addiere ihn zum OCA-Wert hinzu.
Der erzeugt dann bei einem "virutellen" Überlauf einen Interrupt wenn
kein neues ICP-Ereignis eingetreten ist.
>Hab ich ja Zeitpunkt 0 und Zeitpunkt 0+ICP Wert
Du lässt den Timer konstant laufen.
Bei einem ICP-Interrupt sicherst du den ICP-Wert in einer Variablen
Beim folgenden ICP-Intrerupt sicherst du auch diesen Wert und ziehst du
den ersten von diesem ab. Damit hat du die Zeit zwischen zwei Impulsen.
Zu meinem "Watchdog":
Solange ein ICP-Interrupt auftritt, wird in das OC-Register ein
entsprechend höherer Wert geschrieben. Dieser Wert setzt sich aus dem
aktuellen ICP-Wert und einer Zeitkonstante zusammen, die du als
Überlauf definierst.
Sobald kein ICP-Interrupt mehr auftritt, weil das Rad steht, wird
irgendwann der OC-Wert erreicht und dessen Interrupt ausgelöst.
Damit hättest du dann dein "OVerflow-Interrupt"...
Jetzt klarer?
1. Capture-Ereignis: Timer starten (oder rücksetzen), 2. Capture: Wert
einlesen und Ergebnis berechnen. Bei nem Überlauf -> Geschwindigkeit
'0'. Wenn Du es so machst, sehe ich da keine Probleme, zumal in
Deiner Anordnung die Frequenz der zu messenden Ereignisse sehr niedrig
zu sein scheint. Da brauchste dann nicht die maximale Genauigkeit und
der Aufruf der Capture-ISR fällt nicht störend ins Gewicht. Für Deine
Anwendung sollte das tatsächlich ausreichen. Wenns allerdings in den
Bereich höherer Geschwindigkeiten bzw. Genauigkeit geht, dann sollte
die andere Methode benutzt werden. Ich würde den µC dann aber in Deinem
Fall auch nicht mit vollen 16MHz betreiben, es sei denn, da hängen noch
andere, zeitkritische Dinger dran...
Gruß
Johnny
Das mit der Zeit ist klar, dann muß ich aber ja noch prüfen welcher von
beiden Werten größer ist sonst krieg ich ja negative Zahlen (bzw
falsche) oder ist da jezt nen Denkfehler drinn?
Das zweite ist klar, also soll ich den Output Compare Interupt noch
verwenden, dachte ich soll ins Zählregister schreiben das wäre dan
natürlich unsinnig.
Da ich das ganze in Assembler programiere wäre mir natürlich am
liebsten das ganze möglichst ohne zuviel 16bit Artimetik auskommt ;)
Wenn ich es auf diese Weise mache, müßte allerdings das ganze Wohl am
genausten sein und am besten anzupassen, würde den dann obige Formel
funktionieren wenn ich erstmal die anzahl Takte zwischen zwei Interupts
habe?
>Das mit der Zeit ist klar, dann muß ich aber ja noch prüfen welcher>von beiden Werten größer ist sonst krieg ich ja negative Zahlen (bzw>falsche) oder ist da jezt nen Denkfehler drinn?
Nö, ist nicht wichtig. Probier es einfach mal auf dem Papier aus.
Das dachte ich nämlich auch zuanfang. Solange du nicht auf die Idee
kommst, den Zahlenbereich zu verringern (z.B. per CTC) und immer schön
deine 8 oder 16 Bit durchtickern lässt, ist alles schön.
Peter Dannegger hatte dazu mal was in irgendnem Beitrag geschrieben...
Die Variante mit Timer-Start und -Stop ist nur empfehlenswert, wenn
dieser explizit nur für diese Anwendung benutzt werden soll.
Wenn das so ist (ich glaub dir das mal) vereinfacht das die Sache
natürlich erheblich.
Ich wollte den Timer einfach stur laufen lassen auf seinen 16bit.
Und der Vorteil ist natürlich der Timer kann noch für andere
Anwendungen benuzt werden :)
Danke schonmal für die Hilfe, kann den meine Umrechnung auf KMH so
klappen? Habs zwar jezt shcon so zweimal überdacht aber im Prinzip ist
mir kein Fehler aufgefallen.
So hier mal meine ISR:
ICP_int:
push temp
in temp, SREG
;Timerwert einlesen
in ICPL1, ICR1L
in ICPH1, ICR1H
;Alten Wert abziehen
sub ICPL2, ICPL1
sbc ICPH2, ICPH1
;In Register speichern
mov ICPL, ICPL2
mov ICPH, ICPH2
;Alter Wert = neuer Wert
mov ICPL2, ICPL1
mov ICPH2, ICPH2
;Flag setzen für WertUpdate
sbr Flags, (1<<F_CPM)
out SREG, temp
pop temp
reti
Im Hauptprogramm wird dann auf den geänderten Wert in ICPL/ICPH
reagiert, der "alte" Wert wird vorerst mit 0 inistialisiert, da ich
mit einer "falschen" Messung am Anfang leben kann.
Wenn noch wer was sieht, das ich anders oder besser machen sollte...
> mov ICPH2, ICPH2
Da ist aber noch was faul...
> push temp> in temp, SREG
...
> out SREG, temp> pop temp
...und das macht so keinen Sinn. Wenn, dann andersrum. Du willst ja
SREG sichern. Musst es also erst in temp laden und dann pushen bzw. am
Ende erst poppen und dann in SREG schreiben...
Arg... hast recht da muß ne 1 hin
in liest doch aber in das erste Register den Wert von Parameter 2 und
umgekehrt, für out also sollte das so stimmen, temp braucht ja nicht
nochmal gepusht werden da ich das innerhalb nicht verwende, aber die
SUB Operation die Flags verändert.
> out SREG, temp
schreibt irgendwas undefiniertes (halt das, was zu dem Zeitpunkt in
temp steht) in SREG. Da kann alles Mögliche passieren. Wenn Du das
gesicherte SREG zurückschreiben willst, musst Du erst den Wert vom
Stack in temp laden (mit pop) und dann das was vorher drin war in
SREG schreiben. Und am Anfang natürlich genauso, nur andersrum. Du
sicherst ja nur temp. Da steht aber zu dem Zeitpunkt mit Sicherheit
nicht das drin, was DU eigentlich sichern willst!
> push temp
temp wird gesichert (weil ggf. von einer Routine verwendet die durch
die ISR unterbrochen wird)
> in temp, SREG
wert in temp wird durch den Wert in SREG überschrieben
>...
die ISR macht was (ändert aber am Wert von temp nix)
> out SREG, temp
der vorher in temp gespeicherte Wert wird ins SREG geschrieben
> pop temp
der Orginalzustand von temp wird wieder hergestellt
>reti
die ISR wird verlassen (SREG udn TEMP wie vor dem ientritt in die ISR)
Ah so! Sehr unübliche Methode. Normalerweise sichert man das SREG auf
dem Stack und nicht im Registersatz (deshalb auch mein ungläubiges
Kopfschütteln). Naja, Du musst es ja wissen... Aber wenn Du den Code
nicht einstellst, kann Dir auch keiner weiter helfen:-( Ich mache jetzt
Feierabend...