PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Kommazahlen - addieren, multiplizieren - in ASSEMLBER



funkuhr
26.05.2006, 21:10
Hallo,
folgender Sachverhalt:

Ich habe den Pic 16f628 und muss hiermit Kommazahlen addieren und multiplizeiren, bisher habe ich leider keinen blassen schimmer wie das realiseren kann. ICH PROGRAMMIERE IN ASSEMBLER.

Kurze Beschreibung des gesamten Systems:
Hab einen Sensor der mir binär (8 bit) Werte ausgibt z.B. Temperatur, Spannung usw.

Ich bekomme den Wert 80 binär am Sensor ausgegeben, diesen Wert lege ich im Pic an einem Speicherbereich ab. Nun um hieraus die Bestriebsspannung zu ermitteln muss ich diese Zahl mit 0.0184 multiplizieren und dann mit 1.74 addieren d.h.

80 * 0.0184 + 1.74 = 3.212

dass heisst ich habe die Betriebsspannung von 3.212 V an meinen Sensor anliegen habe.

Wie kann ich nun den Wert 80 (binär) mit den Kommazahlen (auch binär da ich im assembler proggramiere) multiplizieren und addieren .

Eine Stelle hinterm Komma ist nach der Rechnung völlig ausreichend.

Vielen Dank für EURE hilfe.

BigWumpus
26.05.2006, 22:13
Hallo,
die Frage ist dann immer, was mit dem Ergebnis passieren soll ?
Meist rechnet man nicht in "Kommazahlen", sondern kann eine geschickte Integer-Arithmetik nehmen...

Also,
was passiert mit dem Ergebnis ?

SprinterSB
26.05.2006, 22:18
AM einfachstn geht das wohl, indem du auf 32- oder 16-Bit Zahlen zurückgreifst.

Je nachdem, wie die Genauigkeit/Wertebereich sein soll und wie diese zwischen Vor- und Nachkommastellen verteilt sein soll. ETwa: 8 Bit vor dem komma und 8 Bit danach.

Oder du multipliziert den genzen Salat mit 1000:

80 * 18.4 + 1740 = 3212

Die .4 musst du dann runden

80 * 18 + 1724 = 3180

Oder du nimmst 2000 und rundest auf 37:

80 * 37 + 3480 = 6440 = 2 * 3220

Hier reichen schon 16 Bit aus zum Berechnen. Du kannst natürlich auch jeden anderen Faktor nehmen, es bieten sich aber 2er Potenzen und evtl Zehnerpotenzen besonders an. Erstere, weil damit leicht zu rechen ich auf einem µC; Zweitere, weil man für die Darstellung oft Dezimal verwendet.
Die 2000 ist eine Kombination aus beiden, danach noch durch 2 zu teilen ist ja ein Klacks...

funkuhr
29.05.2006, 10:59
Vorab Vielen dank einmal!!!

An bigwumpus:
Das ergebnis soll an einem LCD-Display ausgegeben werden. Es wäre für mich ausreichend erst mal die mathematischen operation anzuwenden. ich wüßte nicht einmal die ich multplizieren könnte, also wie der befehl in assembler aussehen würde. Ich will das ergebnis erst mal irgendwo im speicher ablgegen. ich habe mir auf der microchip seite umgeguckt und flouting point routines (an575) gefunden aber von denen habe ich nichts verstanden. erst weil ich noch anfänger bin und zweitens mein englisch ist auch nicht das ware.


An sprintersb:

wie sieht den zum beispiel der code in assembler für 80 * 18 aus oder 45 / 2 oder 45/7 um es bischen schwere zu machen?

funkuhr
29.05.2006, 11:04
Noch etwas, in der pdf datei der an575 stehen die pic bezeichnungen immer mit 16cXXX oder 17cXXX wäre diese dann auch für 16FXXX , also für die F variente geeignet?

BigWumpus
29.05.2006, 11:32
die Prozessoren verarbeiten die gleichen Befehle !

kalledom
29.05.2006, 11:53
Hallo funkuhr,
einen MUL- oder DIV-Befehl gibt es beim PIC in Assembler leider nicht.
Deshalb mußt Du bei Microchip (oder anderswo) nach geeigneten Routinen suchen.
Bei Microchip gibt es die AN 526 Math Utillity Routines mit z.B. der Routine FXD1608U (FX=fixed Point, D=Division, 1608=16Bit DIV 08Bit, U=unsigned=ohne Vorzeichen) oder das Maco UDIV1608L (U=unsigned=ohne Vorzeichen, DIV=Division, 1608 = 16Bit DIV 08Bit, L=???)
Für Multiplikation gibt es z.B. die Routine D_mpy = 16Bit MUL 16Bit.
Mulu0810 (08Bit MUL 10 ohne Vorzeichen) oder Divu0810 (08Bit DIV 10 ohne Vorzeichen) findest Du unter http://www.domnick-elektronik.de/picasm.htm

funkuhr
30.05.2006, 11:20
hallo,

hab meine rechung so umgestellt das ich nun ganze zahlen habe und die zahl

((x * 1772) +102400) / 1024

verarbeiten muss. Nun habe ich einen 8 bit pic und die

zahl x ist 8 bit lang.
die zahl 1772 ist 11 bit lang und
102400 ist 17 bit lang.

nun habe ich auf der microchip seite die routine gefunden, die eine 16 bit und 8 bit zahl zusammen multipliziert. Routine FXM68.A16 (AN617)

Nun weiß ich nicht, wie die diese routine in meinen Assembler code einbinde?

und wie ich die 11 bit lange zahl der routine übergebe.? ich kann mir vorstellen das die 11 bit zahl in zwei teile aufgeteilt wird (hi teil und lo teil) aber ich verstehe nicht in welchen speicher welcher teil rein kommt.

und des weiteren steht im quelltext der routine c quelltext änlicher text.ist das möglich? oder verstehe ich den quelltext falsch. ich schreibe in assembler wird mplab diesen text dann verstehen können.

vielen dank

p.s. um die addition kümmere ich mich später und die division habe ichmir sagen lassen bedeutet für 1024, das letzte byte verwerfen und die bits 2 stellen verschieben.(nach rechts).

*Mario*
30.05.2006, 18:53
hallo funkuhr,

ich bin leider etwas "kurz angebunden", daher vorerst eine kurze Antwort. Also die Gleichung die Du auswerten musst ist ziemlich einfach. Zunächst solltest Du noch die Division durchführen:

x*1772/1024 + 100

Damit reduziert sich das ganze Problem auf die Auswertung des ersten Terms. Dieser kann mit einer Fixed-Point Multiplikation wie in der AN erledigt werden. Die .../1024 Division wird dann quasi "nebenbei" erledigt.
Also FXM1608, bzw. bei signed x die FXM1608S. Wenn Du damit noch nicht zurecht kommst, kann ich Dir morgen (mehr zeit) den Code reinstellen.

Grüße
Mario

funkuhr
30.05.2006, 22:09
Hallo mario,

hast recht - die 102400/1024 kann ich ja schon vorher teilen und somit das ganze vereinfachen.

Wie gesagt, hab mir die Routine FXM68.A16 (AN617) angeguckt. hier
ist auch das unterprogramm FXM1608 vorhanden. (FXM1608U =unsigned oder FXM1608S =signed) . x ist ist bei mir immer positiv also die "u"-version.
wie halt beschrieben komme ich nicht so ganz klar damit. Mit der Einbindung in meinen code, und das stückchen quelltext was wie c-code aussieht macht mich auch stutzig.

Wäre dir für jede hilfe dankbar.
Vielen dank.

cu und
mfg

SprinterSB
30.05.2006, 22:40
wie sieht den zum beispiel der code in assembler für 80 * 18 aus oder 45 / 2 oder 45/7 um es bischen schwere zu machen?

Öhm... an Assembler kann ich nur bieten AVR, 6510, TriCore und XC16x ;-)

Division und Multiplikation kann man immer so machen, wie man es in der Grundschule lernt, nur eben im Dualsystem anstatt zur Basis 10. Das Handwerkszeug, das man dazu braucht, hat jeder µC:

-- eine Zahl auf 0 setzen
-- eine Zahl negieren
-- 2 Zahlen vergleichen und abhängig davon springen
-- testen, ob eine Zahl durch 2 teilbar ist und abhängig davon springen
-- 2 Zahlen addieren/subtrahieren, evtl mit Übertrag
-- eine Zahl rechts/links schieben (also durch 2 teilen bzw. mit 2 multiplizieren), evtl mit Übertrag

...und das war's auch schon!

Ist ne ganz gute Fingerübung das. Und man kann testen, ob man damals wirklich aufgepasst hat *g*.

*Mario*
31.05.2006, 14:37
Hallo,

OK ich seh schon, Du bist richtig erst am Anfang. Ich würde Dir ein Buch zur Einführung in die Assemblerprogrammierung empfehlen. Der Umgang mit Dualzahlen ist unabdingbar und tägliches Brot. D.h. auch wenn ich Dir hier gleich die Lösung hinschreibe, hast Du damit eigentlich nichts gelernt und nichts gewonnen.

Schau Dir am besten mal: http://de.wikipedia.org/wiki/Dualsystem
an. Dort ist alles bestens anhand von Beispielen erklärt.

So und jetzt geb ich Dir einen Tipp wie Du dein Problem "optimal" im Sinne von Laufzeit löst:

y = x
y <<= 1
y += x
y <<= 2
y += x
y = y + (y<<4)
y = (y<<1) + x
y <<= 2
y += 0x19000

Ergebnis: Die zahl die Du suchst, multipliziert mit 1024, d.h. Genauigkeit ca. 0,001. yi muss 24 Bit sein, also 3 Bytes. Im Anschluss musst Du das Ergebnis noch ins Dezimalsystem umrechnen und auf dem Display ausgeben.

Überleg Dir mal warum das so passt (hoffe habe keinen Tippfehler).

Grüße
Mario

funkuhr
31.05.2006, 21:12
Hallo Mario,

irgendwie hast du mich misverstanden glaube ich.

Noch mal eine Kurze Beschreibung.

Ich habe die Formel (Luftdruck in k Pascal)

p/(kPa) = x *1772/1024 +100

die Zahl x ist eine 8-Bit Zahl, welches ich von meinem Drucksensor auslese und in den Pic hinterlege. Je nach Luftdruck ändert sich die Zahl x. Also x ist keine unbekannte. Wenn ich dann den Luftdruck in kilo pascal ermitteln will, muss ich die obige Formel ausrechnen. Nun habe ich halt probleme die Multiplikation auszuführen und das auch noch mit einem 8-bit Pic. Das ist nun eine 8-bit Zahl multipliziert mit einer 11-bit zahl. Auf papier ( auch in duazahl format)kein Problem aber nun halt das ganze zu programmieren .... ohh man.....hab die routinen gefunden, aber ich komm damit noch nicht so ganz klar. Weil ich noch ein newby im programmieren bin und bisher auch noch nie so etwas gemacht habe. Alle anfang ist halt schwer.

Ich brauche halt ein stückchen quellcode an dem ich die 8-bit zahl und die 11-bit Zahl übergebe und der mir dann 3 byte groß (also dual) das ergebnis "ausspuckt".

P.S. Ich kenne mich mit dualzahlen, dezimalzahlen, oktalzahlen und etc. ziemlich gut aus. Ich weiß wie ich von der einen Form in die andere Form umrechnen kann. (Auf papier) Das Ganze zu Programieren ist doch der tot. Daher wollte ich mir abhilfe mit den routinen schaffen, aber komm damit noch nicht ganz klar. (Wieso das Rad neu erfinden???)


Vielen Dank

Andi

*Mario*
01.06.2006, 09:24
Hallo Andi,

irgendwie bin ich jetzt etwas verwirrt. Die Lösung ist in der AN, also einfach rauskopieren und fertig. Was Du so schreibst klingts wohl mehr nach Verständnisproblem, und nein, ich weiß schon dass x die Eingabegröße ist. Achja, je nachdem welche Genauigkeit Du brauchst werden 8-Bit unter umständen nicht ausreichen.
Programmieren auf dem PIC ist ja ein Kinderspiel, nur 35 Befehle. Da musst Du halt jeden einzelnen Befehl in der Referenz nachschlagen und in einen für Dich verständlichen Pseudocode aufschreiben. Das bleibt Dir in keinem Fall erspart!

So als kleine Gedankenanregung (alles andere als optimal, nur quick und dirty, nicht gestestet):


clrf Y0
movlw 0x08
movwf LOOPCOUNT
goto $+5
mul_loop
bcf STATUS,C
rlf Y2,f
rlf Y1,f
rlf Y0,f
rlf x,f
btfss STATUS,C
goto no_add
movlw low(1772)
addwf Y2,f
movlw high(1772)
btfsc STATUS,C
movlw high(1772+1)
addwf Y1,f
btfsc STATUS,C
incf Y0,f
no_add
decfsz LOOPCOUNT,f
goto mul_loop


Den Rest must jetzt selber machen, das Programm schreibt Dir hier keiner. Es geht doch schließlich darum auch was zu lernen dabei.

Grüße
Mario

*Mario*
01.06.2006, 09:27
Nachtrag: es sollte natürlich low(D'1772') bzw. high(D'1772') heissen und (Y1, Y2) müssen vorher mit geladen werden. Y1 = low(D'1772'), Y2=high(D'1772').