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