Hallo,
Ich bin dabei eine universelle Ganganzeige für Motorräder zu entwickeln.
Dazu werden Drehzahl und Geschwindigkeit mit Hilfe der CCP-Module
gemessen und anschließend dividiert. Dieses Ergebnis wird mit einem
zuvor abgespeicherten Wert verglichen, wodurch Rückschlüsse auf den
eingelegten Gang gemacht werden können.
Da das Ganze möglichst universell werden soll, muss ich die Timer um 1
Byte erweitern und die Überläufe mitzählen.
Somit brauch ich insg. eine 24 / 24 bit Division, wobei auch teilweise
die 2. Nachkommestelle des Ergebnisses wichtig ist.
Da mich der eigentliche Wert ja nicht interessiert und nur mit einem
anderen verglichen wird, dachte ich an eine einfache Ganzzahldivision,
anschließend einen Multiplikation des Rests mit z.B. 100 und erneuter
Division.
Was meint Ihr? Geht das vll noch einfacher?
Hat jemand eine Divisionsroutine für die 18f PICs? Ich konnte nur für
die 16er was finden.
Grüße Fabian
Hi
warum quälst du dich mit Assembler rum. Hol dir den C18-Compiler von
Microchip und arbeite mit Float. Der C18 kostet als Studentenversion
nix.
Gerhard
Da dachte ich auch schon dran. Ich habe zwar noch nie direkt mit C
gearbeitet, aber das sollte kein Problem darstellen. Ist wahrscheinlich
wirklich einfacher.
Das einzige Problem könnte vll sein, dass alles ohne merkbare
Berechnungszeit geschehen soll.
Ich versuche mich erstmal mit dem C-18 Compiler vertaut zu machen
Hi
es gibt da noch
http://www.piclist.com/techref/piclist/index.htm
Da stehen auch so manche Assembler Routinen für Pics. Die Seite ist aber
schon älter und beinhaltet wohl mehr Routinen für den PIC16. Aber
vielleicht nützt das ja was.
Gerhard
Stimmt, das macht die Sache einfacher. Anstatt den Quotienten zu bilden
und diesen zu vergleichen, vergleiche ich das Produkt aus Quotient und
z.B. Geschwindigkeit mit der Drehzahl...
Dann brauch ich aber immernoch die einmal die Division, um zu beginn
einen Referenzwert (somit den einen Multiplikator) zu bekommen.
Das Problem ist halt, dass dieser Quotient rein theoretisch zwischen ca.
1000 und kleiner 1 liegen kann. Wobei mich die konkreten Zahlen nicht
interessieren, ich muss sie nur vergleichen.
Somit müsste ich doch z.B. 2 Byte für die Stellen vor dem Komma und 2
Byte für die Nachkommastellen nehmen können und das Ganze als eine ganze
("nicht Komma") Zahl nutzen können, oder?
Halt. Ich habe 6 Gänge und will beim Erkennen einen Toleranzbereich
haben, also einen obere und eine untere Grenze die ich jeweils mit einem
Wert multiplizieren und dann mit dem anderen Wert vergleichen muss.
Macht also 12 Multiplikationen... Ob das dann noch ein Vorteil ist?...
Grüße und ein herzliches Dankeschön!
Ich nutze die zwei CCP Module im Capture-Modus um die Zeit zwischen zwei
Impulsen vom Drehzahl- und Geschwindigkeitssignal zu messen. Da ich
möglichst flexibel sein möchte und auch noch nicht weiß wieviel Impulse
pro Umdrehung ankommen (ich will alle Türen offen haben, was die
Signalquelle angeht) brauche ich eine hohe Taktrate für den Timer (um
den Fehler bei "schneller Impulsfolge klein zu halten) und andererseits
muss ich den 16 bit Timer mit einem Register, das die Timer-Überläufe
zählt, erweitern, um lange Folgen messen zu können.
Ich dachte mir jetzt:
Durch den Quotienten aus Drehzahl und Geschwindigkeit (Einheit und Größe
sind hier ja egal) wird der Gang identifiziert. In einem
Programmiermodus werden jeweils die "Referenzquotienten" mit
Tolerantzen abgespeichert.
Im Anzeigemodus wird dann wieder der Quotient gebildet und getestet ob
dieser in die abgespeicherten Bereiche passt.
Vll. wäre es auch geschickt, eine Art automatische Kalibrierung
durchzuführen, die dann den Takt und Prescaler für die Timer so
einstellt, dass ich mit dem normalen 16 bit Timer auskomme und so die
Zahlen kleiner halte. Allerdings soll auch alles recht schnell gehen,
wodurch lange messzeiten eher schlecht sind.
Ändert jetzt aber an meinem Problem nicht so viel :)
Timer läuft mit 1Mhz --> alle 10^-6 sek wird der Timer erhöht
2. Gang --> 9000 U/min --> 96km/h=26,7m/sek (Reifenumfang 1,953m)
Nehmen wir als Beispiel an, das Drehzahlsignal besteht aus 4 H-L-Flanken
pro Umdrehung und 8 H-L-Flanken pro Radumdrehung(hier können auch andere
Werte wie 64 bei Drehzahl und 4 bei Geschwindigkeit stehen).
9000 U/min --> 0,0066 sek/Umdrehung --> 0,0016 sek Abstand zwischen zwei
Impulsen --> Timer zählt 1600 = b'11001000000'
26,7 m/sek --> 13,7 U/sek --> 0,009 sek Abstand zwischen zwei Impulsen
--> Timer zählt 9000 = b'10001100101000'
Also haben wir den Quotienten aus 10001100101000 und 11001000000
= 5,625 = B'101' und Rest
Jetzt den Rest mit 1000 = b'1111101000' multiplizieren und erneut
dividieren und in sep. zwei Bytes schreiben.
Smomit habe ich eine Zahl die aus zwei Byte vor und zwei Byte nach dem
Komma besteht. Diese Zahl wird als Referenz gesichert
Das ganze wird nun immer wiederholt, wobei der neue Wert mit der
Referenz verglichen wird.
Den Vergleich will ich mit einer Subtraktion lösen (funktioniert genau
so auch schon bei einer anderen Sache)
Bitte steinigt mich nicht für meine evtl. unfachliche Art :)
Hilft das weiter?
Ich denke die Sache mit der Anpassung ist schon mal gut, wird's schonmal
schneller, weil ich nur 16bit Zahlen habe.
A=9000 B=1600
A/B=5
A%B=1000
nicht 5.625
>Jetzt den Rest mit 1000 = b'1111101000' multiplizieren und erneut>dividieren und in sep. zwei Bytes schreiben.
das ist aber Umständlich und entspringt (Volks)Schulmathematik, da
uC nicht auf 10er basis rechnen.
>Smomit habe ich eine Zahl die aus zwei Byte vor und zwei Byte nach dem>Komma besteht. Diese Zahl wird als Referenz gesichert
Das hast du ja schon vorher, achso verstehe.
24bit / 24bit = 24bit result. Das reduziert man auf 16bit, indem man
es nach rechts schiebt, also gebrochen 2/4/8/16/...
Wenn du aber krumme Werte brauchst, dann multipliziere den wert
mit einem 16bit wert, als Beispiel, und nimm dann nur die oberen 32bit.
Damit kannst du krumme Werte bekommen. z.B. wenn du umbedingt 100
brauchst, dann multipliziere mit (256*256)/100 = 656,36, also mit 656
Das ergibt einen Fehler von 0.1%, also Ausgangszahl einmal nach rechts
schieben, und addieren, dann hast du einen Fehler von 0%.
Anstatt der Division könntest du auch eine Multiplikation machen,
also 9000 mal 1600 = 219 (mit shift >32) und 2416 als Rest.
Das ganze wird nun immer wiederholt, wobei der neue Wert mit der
Referenz verglichen wird.
Da hast du ja genug Zeit für die Division, würde ich nicht so
optimieren.
Den Vergleich will ich mit einer Subtraktion lösen (funktioniert genau
so auch schon bei einer anderen Sache)
Bitte steinigt mich nicht für meine evtl. unfachliche Art :)
Hilft das weiter?
Ich denke die Sache mit der Anpassung ist schon mal gut, wird's schonmal
schneller, weil ich nur 16bit Zahlen habe.
Hier fixed point multiplikation/division laut microchip app/note.
24 div 24 sind 420 Instruktionszyklen.
24 mul 16 sind 43 Instruktionszyklen.
40 div 24 sind 130 Instruktionszyklen.
Angenommen, du machst eine Division, sowie eine kombinierte
Multiplikation/
division, wie sie in vielen Mathematisch orientierten Sprachen vorkommt,
dann sind das 593 Instruktionszüklen, also nicht mal 0.6 uS bei 4Mhz
internem Takt oder 0.3ms bei 8Mhz internem Takt.
Welche Zeitprobleme hast du ?
Einige C-Compiler unterstützen auch fixed point arithmetic.
Achso, vergiss nicht den internen OSC eine Temperaturkompensation zu
verpassen, außer du kannst mit 5% Toleranz leben, das kann aber auch
schon zu viel sein. Externen Osc würde ich vermeiden, wegen der
Vibrationen wegen.
Achso, vergiss nicht den internen OSC eine Temperaturkompensation zu
verpassen, außer du kannst mit 5% Toleranz leben, das kann aber auch
schon zu viel sein. Externen Osc würde ich vermeiden, wegen der
Vibrationen wegen. Die internet Temperaturkompensation macht man mit dem
WDT
Danke für Deine ausführliche Antwort!
>Angenommen, du machst eine Division, sowie eine kombinierte>Multiplikation/division, wie sie in vielen Mathematisch orientierten >Sprachen
vorkommt
Damit meinst Du eine Ganzzahldivision und anschließend die
Multiplikation des Restes mit irgendeiner Zahl (kann ich ja einfach
durch Verschiebung nach links lösen) und erneute Division?
In welcher Form habe ich denn dann das edgültige Ergebnis der Division?
Kann doch dann eine 32bit Zahl sein, bei der die oberen 16bit der ersten
Ganzzahldivision entsprechen und die unteren 16bit der zweiten Division
(des Rests) mit vorheriger Multiplikation entsprechen, oder?
An die Temperaturkompensation hätte ich nie gedacht. Aber brauch ich
die, wenn mein PIC über einen externen Quarz getaktet wird?
Grüße Fabian
Du wolltest ja eine Ganzzahldivision, und danach eventuell
mit Fixed Point Float weiterarbeiten, soweit ich dich verstanden haben,
und dann eine Multiplikation, sowie eine erneute Division.
Aber eigentlich brauchst du es einfacher.
im obigen Beispiel
>24 div 24 sind 420 Instruktionszyklen.
Resultat ist 48 Bit, habe aber angenommen, 24bit reichen als Resultat
aus
Du kannst es als 16.8 fixed point Zahl sehen, oder auch als 8.16 oder
12.12
wie du es besser brauchst. Meiner Meinung nach solltest du hier auch die
Möglichkeit einbauen, eines eventuellen Shifts, um die bits auszuwählen,
aufgrund der Bauart, ein Prescaler kann auch dasselbe bewirken, oder /
und
einen Offset dazuzählen. Nur so als Anregung.
Ich persönlich würde zwischen Periode zählen und Impulse zählen
automatisch
umschalten, aber das ist eine andere Baustelle.
>24 mul 16 sind 43 Instruktionszyklen.
resultat 40 bit
>40 div 24 sind 130 Instruktionszyklen.
resultat 16bit
Wenn du 24 Bit resultat brauchst, dann mache 40 div 16.
die 2te sowie dritte Operation ist dieser besagte Operator, da du
sonst 40bit Zahlen haben müsstest.
Wenn du nur ein 24bit als Result der Multiplikation hast, und danach
eine Division machst, dann kann das Resultat falsch sein, da du nicht
mit der erforderlichen Genauigkeit rechnest.
Ich habe als Grundlage die APPL NOTE AN617 hergenommen, die 17c ist
ein Pic mit integriertem Multiplizierer, wie auch der 18f. Der Code
läuft auch im 18f, muß eventuell nur ein bisschen angepasst werden.
Externer Osc. Erstens wirst du dich schwer tun, einen OSC zu finden,
der für automotive temperature range freigegeben ist. Zweitens gibt
es da Probleme wegen der Vibrationen und dem Quarz, welche nicht ohne
sind. Wenn du es nicht umbedingt brauchst, was ich derzeit nicht sehe,
würde ich dir den internen OSC nahelegen. Musst im Datenblatt nachsehen,
welche Toleranz er hat, warscheinlich 4%, aber bei den extendet
temperaturangaben nachsehen, sonst sind die 2% angegeben, welche aber
nur
unter consumer temperature gelten. Ausrechnen, ob diese Tolleranz das
Ergebnis verfälscht, oder innerhalb der vorgesehenen hysterie ist.
>ein Prescaler kann auch dasselbe bewirken, oder / und einen Offset >dazuzählen.
Nur so als Anregung.
Stimmt, ich kann das vorher Anpassen, sodass (im interessanten Bereich)
eine Ganzzahldivision mit der Genauigkeit ausreicht.
Da muss ich mich halt jetzt endgültig mal entscheiden, welcher Weg es
werden soll.
>Ich persönlich würde zwischen Periode zählen und Impulse zählen automatisch>umschalten, aber das ist eine andere Baustelle.
Dann kommen allerdings auch wieder Rechungen dazu, um die Werte aus
Impuls und Periodenmessung zu vergleichen. Das wollte ich mir sparen.
>Resultat ist 48 Bit, habe aber angenommen, 24bit reichen als Resultat>aus. Du kannst es als 16.8 fixed point Zahl sehen, oder auch als 8.16 oder>12.12 wie du es besser brauchst.
Hier hab ich mein Verständnisproblem: Wie kann das Resultat denn fixed
Point sein, wenn es eine Ganzzahldivision ist. Halt, es steht ja Fixed
Point Routine... Aber was ist dann der Rest?
>Dann kommen allerdings auch wieder Rechungen dazu, um die Werte aus>Impuls und Periodenmessung zu vergleichen. Das wollte ich mir sparen.
Wenn die Impulsmessung Fehlschlägt, dann auf Periodenmessung umschalten.
Impulsmessung ist gültig, wenn mehr als ??? Impulse je Zeiteinheit
ankommen. Keine Vergleiche, sondern das wird Kalibriert, und ist
eigentlich
vom Sensor dann abhängig, was verwendet wird. Könnte auch im EEprom
gespeichert werden, was zu nehmen ist und beim Setup ausgemessen werden,
sprich zuerst Impulsmessung alle Gänge durchmachen, dann mit
Periodenmessung, und besseres Ergebnis gewinnt.
Ein Vorschlag. Mach mal alles mit Float oder Double, und dann optimiere
ich dir den Code. Aber bitte PM.