Hallo Forum, zurzeit arbeite ich an einem Schulprojekt, vorgenommen habe ich mir mithilfe eines uC einen digitalen Drehzahlmesser für einen Zweitaktmotor zu bauen. (Hab hier im Forum schon viel darüber gelesen sowie auch auf anderen Seiten und fand es ein interessantes Projekt) Das Programm MUSS leider in ASM geschrieben werden. Hier der Stand: Das Zündsignal kommt auf einen Interrupt, ein Timer zählt eine Sekunde lang die Impulse, die Anzahl wird mit 60 Multipliziert und (sollte) anschliessend aufs Display ausgegeben (werden). Das Problem: Nach dem Multiplizieren von A- und B-Register landet das Ergebnis aufgeteilt in Lower Byte (A) und Higher Byte (B) wieder in den Registern. Nun kann ich aber immer nur 8 Bit an das Display übertragen. Bsp: A = 5 B = 60 A*B = 300 => B=01h (256d), A=2Ch (44d) Ich müsste also irgendwie das 16Bit ergebnis der Multiplikation in seine einzelnen Stellen aufteilen und nacheinander auf dem Display ausgeben, oder so irgendwie. Hat da jemand einen Rat wie ich das am besten lösen könnte? Mfg Tobias
Teilen durch 10000 := Zehntausender Digit rest durch 1000 := Tausender Digit etc. dann noch in ASCI umwandeln. movlw '0' ; ASCI Nummer von 0 ins WRegister addwf xy(var des jeweiligen Digits) ; da ja zahlen aufsteigend im ASCI-Code angeordnet sind :)
@ Tobias B. (betsch) >Registern. Nun kann ich aber immer nur 8 Bit an das Display übertragen. Reicht das nicht? Du kannst auch keinen Satz auf einmal übertragen, immer nur einzelene Buchstaben bzw. Zeichen. >Ich müsste also irgendwie das 16Bit ergebnis der Multiplikation in seine >einzelnen Stellen aufteilen Ist es doch schon nach deiner Aussage. > und nacheinander auf dem Display ausgeben, Und wo ist das Problem? >Hat da jemand einen Rat wie ich das am besten lösen könnte? Du musst sogar noch mehr. Du must die Binärzahl in eine Zeichenkette umwandeln. Siehe Festkommaarithmetik. MFG Falk
Ich würde es mit einer "lookup table" lösen. Also den über 1 sek. gezählten Wert gar nicht mit 60 multiplizieren, sondern als Index auf ein String array benutzen: 0 -> "0000" 1 -> "0060" 2 -> "0120" 3 -> "0180" (...) 166 -> "9960" mehr als 10000 U/min wird der Motor ja nicht machen...
Und noch ein Tip: für Drehzahlmessungen ist es besser, einen Timer zu nehmen (z.B. mit 10 kHz), und die Zeit, die zwischen 2 Umdrehungen vergeht in U/min umzurechnen. Dann hast du ein feingradigeres Ergebnis, statt grober 60 U/min-Stufen.
Vielen dank für die Vorschläge. Ich glaube die Lösungen von Falk und Manfred sind leider nicht umsetzbar, da ich nur das A-Register durch das B-Register dividieren kann, und da maximal 255 reinpasst. Ich bräuchte also für diese Lösung einen Speicherplatz für 16Bit, mit dem ich auch rechnen kann. Also wird eswohl die lösung von kolabier. So hatte ich es auch Anfangs geplant, falls die andere Methode nicht lösbar ist. Aber mit nem kleinen Unterschied: Ich bekomme ne Routine für Textausgabe am Display zur verfügung gestellt, diese funktioniert so:
1 | mov dptr, #1_umdr_pro_sek |
2 | lcall LCDTextZeile1 |
Für die einzelnen Werte hätte ich dann geplant:
1 | #1_umdr_pro_sek: |
2 | db ' 60 rpm', 0 |
3 | #2_umdr_pro_sek: |
4 | db ' 120 rpm', 0 |
5 | etc. |
Ich denke die Lösung ist nicht so gut wie die mit dem String-Array, nur leider hab ich keine Ahnung wie man String-Arrays in Assembler deklariert/benutzt/etc. Ich weiss, dass man irgend eine Anfangsadresse festlegt, bsp 0000h und dann in 16er Schritten die einzelnen Strings ablegt um danach mit nem Zeiger drauf zuzugreifen, aber kein Plan wie man das in ASM macht. :( MFG
Tobias B. schrieb: > Ich glaube die Lösungen von Falk und Manfred sind leider nicht > umsetzbar, da ich nur das A-Register durch das B-Register dividieren > kann, und da maximal 255 reinpasst. Ich bräuchte also für diese Lösung > einen Speicherplatz für 16Bit, mit dem ich auch rechnen kann. Da musst Du halt mit 2 Registern für eine Variable arbeiten :) mit Var_xy:2 reserviert Dir der Compiler zwei aufeinander folgende Register, Var_xy = LoByte Var_xy+1 = HiByte (die Var.Namen sind ja nur Platzhalter im Assemplercode für die reellen Registeradressen) Hier ein Beispiel für eine 16Bit Addition mit 8Bit breiten Registern
1 | Add16 ; 16-bit add: f := f + xw |
2 | movf Math_Temp2,W ; Math_Temp2 nach W |
3 | addwf Math_Temp1,F ; Math_Temp1 := Math_Temp1 + Math_Temp2 |
4 | |
5 | movf Math_Temp2+1,W ; Math_Temp2+1 nach W |
6 | btfsc STATUS,C ; fall ein Überlauf auftrat: |
7 | incfsz Math_Temp2+1,W ; Math_Temp2+1+1 nach W |
8 | addwf Math_Temp1+1,F ; Math_Temp1+1 := Math_Temp1+1 + Math_Temp2+1 |
9 | |
10 | return ; fertig |
mfg Manfred
Hallo Manfred, ich versteh zwar was du meinst, bin mir aber nicht sicher ob sich das so umsetzen lässt. Übrigens, der Controller ist ein AT89C5131, und die Befehle die du verwendest hab ich auch nicht, mir steht nur "mov", "movx" und "movc" zur Verfügung. Was ich bisher auch noch nicht erwähnt habe: So wie ich es ursprünglich vor hatte war geplant die LCD Routine "LCDDezAus" zu benutzen, welche die 8Bit die im Akku stehen als Dezimalzahl auf dem Display ausgibt. Bsp: Die Anzahl der in 1 sek gemessenen Impulse beträgt mit 60 Multipliziert 400d (0190h), nach der Operation steht also 01h in B und 90h in A. Den Pseudocode stell ich mir in etwas so vor:
1 | WENN ((0*16^3) + (1*16^2) + (9*16^1) + (0*16^0) / 1000) > 1 |
2 | AUSGABE AN POS1 (0*16^3) + (1*16^2) + (9*16^1) + (0*16^0) / 1000) |
3 | WENN (0*16^3) + (1*16^2) + (9*16^1) + (0*16^0) % 1000) / 100) > 1 |
4 | AUSGABE AN POS2 (0*16^3) + (1*16^2) + (9*16^1) + (0*16^0) / 100) |
5 | WENN (0*16^3) + (1*16^2) + (9*16^1) + (0*16^0) % 100) / 10 > 1 |
6 | ... |
7 | etc |
Und genau diese Operation, "IST B-Register + A-Register > IRGENDWAS" bekomm ich glaub ich nicht gebacken :( mfg
kolabier schrieb: > Ich würde es mit einer "lookup table" lösen. Für diesen hochqualifizierten und eleganten Lösungsvorschlag sollte dir die Welt ewig dankbar sein. ;-)
Moin moin, Tobias B. schrieb: > ich versteh zwar was du meinst, bin mir aber nicht sicher ob sich das so > umsetzen lässt. Übrigens, der Controller ist ein AT89C5131, und die > Befehle die du verwendest hab ich auch nicht, mir steht nur "mov", > "movx" und "movc" zur Verfügung. das ist ein aus meinem momentanen Projekt kopierter, funktionierender Code für einen PIC16F.... der Dir nur mal den grundsätzlichen Umgang mit Zahlen größer als die Bitbreite des verwendeten µC's zeigen soll. Ok, Pseudocode hätte es anschaulicher gemacht, war aber zu faul, sorry :) Tobias B. schrieb: > Und genau diese Operation, "IST B-Register + A-Register > IRGENDWAS" > bekomm ich glaub ich nicht gebacken :( BReg + AReg = CReg CReg - IRGENDWAS ; erzeugt einen Unterlauf bei CReg ist kleiner... test des zuständigen Flgs (CarryFlag) .... mfg
Tach, > BReg + AReg = CReg > CReg - IRGENDWAS ; erzeugt einen Unterlauf bei CReg ist kleiner... > test des zuständigen Flgs (CarryFlag) genau hier ist mein Problem, quasi. Sowohl B und A haben jeweils 8 Bit, wenn die addiere brauch ich auf jeden Fall mehr als 8 Bit speicher um die Zahl irgendwo zu speichern. Das hab ich ja nicht. Ich hab mal ne Testsimulation gemacht:
1 | mov B, #60d |
2 | mov A, #05d |
3 | mul AB ;danach steht in B 01h und in A 2Ch |
4 | add A,B ;danach steht in B immernoch 01h in A aber 2Dh |
Hierbei ignoriere ich ja, dass B das HiByte is und bei 16^2 anfängt. mfg
installiere Var C und C+1 ; C:=LoBit, C+1:=HiBit a + b = c ; LoBit Test CarryFlag wenn ja dann increment c+1 ; HiBit wie das mit Multiplikation bei Deinem Prozessor genau funst weiß ich nicht, sollte aber ein SpezialRegister geben der das HiByte aufnimmt o. Hi im ersten Argument, Lo im zweiten ö.ä. Muss ja irgend wo hin der ÜBERSCHÜSSIGE Müll :) Tobias B. schrieb: > mov B, #60d > mov A, #05d > mul AB ;danach steht in B 01h und in A 2Ch > add A,B ;danach steht in B immernoch 01h in A aber 2Dh bitte bleib bei einer Zahlendarstellung (d o. h) bin'n Alter Man und hab nich mehr so viele Gehirnzellen übrig für's umrechnen :) mfg EDIT: Gug mal den Thread "rechnen in Assembler mit AVR" Beitrag "rechnen in Assembler mit AVR" Die kennen dich sicher besser aus als ich!
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.