Forum: Mikrocontroller und Digitale Elektronik Problem mit Übertragung an LCD-Display


von Tobias B. (betsch)


Lesenswert?

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

von M. J. (manfred-64)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

@  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

von kolabier (Gast)


Lesenswert?

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...

von kolabier (Gast)


Lesenswert?

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.

von Tobias B. (betsch)


Lesenswert?

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

von M. J. (manfred-64)


Lesenswert?

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

von Tobias B. (Gast)


Lesenswert?

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

von Programmierer (Gast)


Lesenswert?

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. ;-)

von M. J. (manfred-64)


Lesenswert?

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

von Tobias B. (betsch)


Lesenswert?

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

von M. J. (manfred-64)


Lesenswert?

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
Noch kein Account? Hier anmelden.