Forum: Mikrocontroller und Digitale Elektronik Geschwindigkeit Mittels ICP messen


von Laeubi (Gast)


Lesenswert?

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.

von Rahul (Gast)


Lesenswert?

>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).

von johnny.m (Gast)


Lesenswert?


von Laeubi (Gast)


Lesenswert?

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?

von johnny.m (Gast)


Lesenswert?

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.

von Rahul (Gast)


Lesenswert?

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.

von Laeubi (Gast)


Lesenswert?

@jonny.m: Hab ich ja Zeitpunkt 0 und Zeitpunkt 0+ICP Wert

@Rahul: öm irgenwie versteh ich grad nicht ganz was genau du sagen
willst... verwirrt

von Rahul (Gast)


Lesenswert?

>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?

von johnny.m (Gast)


Lesenswert?

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

von Laeubi (Gast)


Lesenswert?

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?

von Laeubi (Gast)


Lesenswert?

Also Geschwindikeit zwischen 1 und 180 km/h (maximal eher weniger) in
1km/h Auflösung hatte ich gedacht.

von Rahul (Gast)


Lesenswert?

>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.

von Laeubi (Gast)


Lesenswert?

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.

von Laeubi (Gast)


Lesenswert?

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...

von johnny.m (Gast)


Lesenswert?

> 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...

von Laeubi (Gast)


Lesenswert?

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.

von johnny.m (Gast)


Lesenswert?

> 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!

von johnny.m (Gast)


Lesenswert?

Poste am besten mal den kompletten Code. An der ISR alleine kann man
nicht sehen, ob das Konzept funktionieren kann.

von Laeubi (Gast)


Lesenswert?

> 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)

von johnny.m (Gast)


Lesenswert?

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...

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
Noch kein Account? Hier anmelden.