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
Microchip hat App-notes, wo solche sachen drin sind, einfach App-note nach Math durchsuchen.
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
Wenn ich das machen müsste, würde ich die Division in eine Multiplikation umwandeln, zumal der Pic warscheinlich HW-Multiplikationen beherrscht.
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!
Laut mir ist das die falsche Vorgehensweise. Poste mal ein Beispiel, wie du die Gänge identifizierst.
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 :)
Mach bitte ein komplettes Beispiel mit Zahlen. Zudem, der uC rechnet Binär, nicht Dezimal.
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.
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.