PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Zahl in Ziffern zerlegen



Spion
01.08.2006, 17:14
Hallo

Wie heisst der Befehl, der eine Zahl in einzelne Ziffern zerlegt? Und wie wird dieser angewendet? Die Zahl ist max. 4 Ziffern lang, sie kann aber auch kleiner sein.

mfg Luca

Edit: Dass man nicht den ganzen Thread durchwüllen muss, poste ich hier mal den Code, er ist in Bascom, und man kann damit eine Zahl mit 4 Ziffern in Ziffern zerlegen.




Dim Einer As Word
Dim Zehner As Word
Dim Hunderter As Word
Dim Tausender As Word
Dim A As Word

A = 8956

Einer = A Mod 10
A = A - Einer
A = A / 10
Zehner = A Mod 10
A = A - Zehner
A = A / 10
Hunderter = A Mod 10
A = A - Hunderter
A = A / 10
Tausender = A Mod 10



Print tausender '8
Print hunderter '9
Print zehner '5
Print einer '6

linux_80
01.08.2006, 17:34
Hallo,

was willst Du nachher damit machen, wenn Du sie über die UART senden willst, einfach die Variable mit Print ausgeben, da wird sie automatisch gewandelt.

Ansonsten schaust Dir mal str() an.

Spion
01.08.2006, 17:49
Hallo

Ich muss die Zahl zerlegen, damit ich sie nachher auf 4 Siebensegment (Rndigi)anzeigen, anzeigen lassen kann. Die Zahlen werden per I2C gesendet.

Wie wird str() angewendet?(Beispiel?)

Ich hätte die Ziffern dann gerne in variabeln.

mdg Luca

hacker
01.08.2006, 18:56
In der Bascom Hilfe steht der Befehl eigentlich gut beschrieben. Schau da mal nach. Das Forum liefert dir den Tip und dann muss Eigeninitiative gezeigt werden.

molleonair
01.08.2006, 19:29
ich hab das auch mal mit ner 7 segment gemacht

einfach die zahl (zb 8763) durch 1000 dann haste die 1.ziffer (8)
dann 1.ziffer mal 1000 (=8000) und von deiner zahl abziehen (8763-8000=763)
nun diese zahl durch 100 (=7) wieder mal 100 (=700) und die von der vorihgen abzihen (763-700=63) nun diese durch 10 und so weiter ...

Hanni
01.08.2006, 19:41
ich hab das auch mal mit ner 7 segment gemacht

einfach die zahl (zb 8763) durch 1000 dann haste die 1.ziffer (8)
dann 1.ziffer mal 1000 (=8000) und von deiner zahl abziehen (8763-8000=763)
nun diese zahl durch 100 (=7) wieder mal 100 (=700) und die von der vorihgen abzihen (763-700=63) nun diese durch 10 und so weiter ...

Wobei zu beachten ist, das Divisionen und vor allem Kommaberechnungen bei AVR Mikrocontrollern recht lange dauern.

Einfacher und schneller ist die sogenannte Subtraktionsmethode um aus dieser Zahl die einzelnen Ziffern zu bekommen (Binär -> BCD Wandlung).

Grüße,
da Hanni.

Spion
01.08.2006, 20:01
Hallo


An die Hilfe hatte ich nicht gedacht. Diese Funktion wandelt aber einfach z.B. ein Byte zu einem String um oder? Wie aber kann ich den String nun zerlegen?
Hier ein Beispiel, wie ich die Zahl nachher gerne hätte:



A = 1354 'grundwert
...... 'Befehl
B = 4 'Zahl 1
C = 5 'Zahl2
D = 3 'Zahl3
E = 1 'Zahl4



@molleonair
Als Notlösung währe das möglich, aber dass geht sicher einfacher.

@Hanni
Leider verstehe ich bei der Hilfe für BCD nur Banhof.

mfg Luca

digitali
01.08.2006, 20:31
Also ich haette es so spontan gemacht:

Zunächst die ganze Zahl als String umwandeln:
Zahl_String= Str(Zahl)


Laenge des Strings ermitteln:
LZ = Len(Zahl_String)


Einzelne Zeichen aus Gesamtstring ermitteln:
For A = 1 To LZ
EZ(a) = Mid( Zahl_String, A , 1)
Next A


Einzelne Zeichen in numerische Werte umwandeln:
For A = 1 To LZ
Ew(a) = val(EZ(a))
Next A

Und somit haste die einzelnen Ziffern zur weiteren Verwendung.

Oder gab's einen direkten Befehl? Keine Ahnung, einfach die Bascom-Hilfe studieren. Da steht alles.

linux_80
01.08.2006, 20:39
hui,
besser gehts in etwa so:


DIM MyString AS STRING * 20
DIM MyArray(21) AS BYTE AT MyString OVERLAY

macht nicht soviel arbeit.
Man muss nur noch schauen wie lange der String wirklich geworden ist, damit man keinen Müll weiterverarbeitet.

Und daran denken, das die Zahlen als ASCII-Werte dastehen, d.H. 48 abziehen damit die 0 auch 'ne 0 ist !

DIYLAB
01.08.2006, 20:42
Moin,

A = 1354

tausender = A / 1000
tausender = tausender mod 10
hunderter = A / 100
hunderter = hunderter mod 10
zehner = A / 10
zehner = zehner mod 10
einer = A mod 10

In den Variablen tausender, hunderter, zehner und einer stehen dann Deine einzelnen Ziffern.

Viele Grüße,
Bruno

Spion
01.08.2006, 21:03
Hallo
Danke Digitali für das Beispiel.
Auch wenn dass für euch ein bisschen nervig ist, leider habe ich nicht sehr viel Ahnung von Basic, darum frage ich so viel.

Nur zur Kontrolle ob ich denn Code von Digitali richtig verstanden habe:
Zahl_String = Anfangs Zahl, nachher String Zahl
LZ = Länge der Zahl
EZ(A) = Einzelne Zeichen
Ew(a) = Endgültige Ziffer

Zahl ist meine ZAhl
Zahl_String muss ich als String definieren?
Lz muss ich als Integer definieren?
Ez ebenso?
Ew auch als Integer?

Stimmt das?

Wenn ich jetzt Zahl_String als String definiere, dann muss man da noch “* (eine Zahl)“ eingeben, für was ist dass? Was muss ich beim obigem Beispiel einstellen?

Wenn ich nun alles so wie oben eingestellt habe, dann meldet Bascom 3 Fehler:
EZ(a) = Mid( Zahl_String, A , 1) Fehler: String expected for assignment [EZ(A)]
Ew(a) = val(EZ(a)) Fehler: Variable is not dimensioned as an array [EZ(A)]/[EW(A)]

Was muss ich ändern, dass diese Fehler verschwinden

mfg Luca

Ps: Sorry für die endlose Fragerei.

Spion
01.08.2006, 21:09
@ Lynux 80

Wie kann ich dann die länge bestimmen? In welcher variabel sind dann meine Zahlen?

@Bruno Pisarek

Kann ich dass so einfach ins Bascom übernehmen? Als was muss ich "A" definieren?

Also das Beispiel von Bruno Pisarek gefällt mir am besten, da es einfach ist.

mfg Luca

digitali
01.08.2006, 21:10
Nimm das Beispiel von Bruno. Er hat's wesentlich eleganter geloest. :)

DIYLAB
01.08.2006, 21:17
Kann ich dass so einfach ins Bascom übernehmen? Als was muss ich "A" definieren?

Hi Luca,

ja - ist alles 100% Bascom, ich benutze diese Variante in sehr vielen Projekten. Wenn Du bei 4 Stellen bleibst, dann deklariere alle Variablen als Typ "Word".

Viele Grüße,
Bruno

izaseba
01.08.2006, 21:21
Nimm das Beispiel von Bruno. Er hat's wesentlich eleganter geloest. :)

Wenn Du das so machst, wie der Hanni es beschrieben hat, ist es nicht nur elegant, sondern noch effektiv.

Gruß Sebastian

simonit
01.08.2006, 22:06
Moin,

A = 1354

tausender = A / 1000
tausender = tausender mod 10
hunderter = A / 100
hunderter = hunderter mod 10
zehner = A / 10
zehner = zehner mod 10
einer = A mod 10


Meiner Meinung nach effizienter müsste folgender Code sein:


A = 1354
einer = A mod 1
zehner = A mod 10
zehner = zehner - einer
hunderter = A mod 100
hunderter = hunderter - zehner
tausender = A mod 1000
tausender = tausender - hunderter

Eine Division wird im Controller ja nur als mehrfache Subtraktion durchgeführt (behauptet zumindest unser Lehrer), deshalb sollten hier weniger Schritte benötigt werden.

Spion
01.08.2006, 22:06
Hallo

Dann werde ich wohl die variante von Bruno gebrauchen, da sie wie schon erwähnt einfach, elegant und effektiv ist.
Ich danke hier aber auch allen anderen, die mir helfen wollten =D>

Eine Frage noch an Bruno, was ist wenn ich es erweiter will auf z.B. 6 Ziffern? Wass muss ich alles abändern?

mfg Luca

simonit
01.08.2006, 22:14
bei Brunos Lösung wüsste ich es nicht, allerdings bei meiner kann man leicht erweitern, einfach unten
zehntausender = A mod 10000
zehntausender = zehntausender - tausender
usw. anfügen =)

DIYLAB
01.08.2006, 22:25
Eine Frage noch an Bruno, was ist wenn ich es erweiter will auf z.B. 6 Ziffern? Wass muss ich alles abändern?

Hi Luca,

die Prozedur ist so einfach, dass sich eigentlich mehr als 4 Stellen daraus ableiten lassen sollten - oder 8-[ ?
Ich bin der Meinung, dass Du auch selbst ein bisschen denken solltest und natürlich probieren!

Z.B. hat mich das Posting von Sebastian dazu veranlasst, Morgen auch mal die Hanni/Sebastian Version zu probieren. Wenn es ein paar Byte spart - prima! Ist mir nie in den Sinn gekommen..

Aber in Deinem Fall kommst Du mit meinem leicht zu erweiternden Beispiel auch ressourcenschonend und schnell ans Ziel.

Viele Grüße,
Bruno

Hanni
01.08.2006, 22:29
Moin,

A = 1354

tausender = A / 1000
tausender = tausender mod 10
hunderter = A / 100
hunderter = hunderter mod 10
zehner = A / 10
zehner = zehner mod 10
einer = A mod 10

In den Variablen tausender, hunderter, zehner und einer stehen dann Deine einzelnen Ziffern.

Viele Grüße,
Bruno

Nunja. die Modulo Operatoren wären insofern sehr effektiv, wenn man sie direkt isn duale Zahlensystem übernehem könnte. Kann man aber leider nicht ... daher ist der Code eher sehr ineffizent und langsam.

Effektiv und Elegant ist es nicht deswegen, weil der Code schön aussieht. Effektiv wird es erst dann, wenn eine Aufgabe mit minimalem Aufwand an Ressourcen erledigt wird. Die Eleganz kommt meiner Meinung nach daher, dieses ganze Gebilde in eine kleinen Subroutine zu verbannen, damit ich sie immer, wann ich sie brauche nutzen kann.

Sicherlich kann man auf einem PC mit endlos krassen Resourcen derartige Codemonster realisieren (mach ich selbst gerne aber halt in ner Skriptsprache) aber auf einem Microcontroller ist dieses eher fehl am Platz.

Mir scheint es daher, das das Programmieren in einer Hochsprache zuweilen vergessen lässt, das man nur sehr geringe Ressourcen im µC zur Verfügung hat.



Wenn Du das so machst, wie der Hanni es beschrieben hat, ist es nicht nur elegant, sondern noch effektiv.

Danke für die zustimmenden Worte.

Grüße,

da Hanni.

Spion
01.08.2006, 22:36
Hallo

Leider funktioniern bei mir beide varianten nicht. Ich habe die erhaltene Zahl als Byte gespeichert, könnte es an dem liegen? Ich bin mir nicht ganz sicher, aber ich glaube die Zahl kann nur in einem Byte gespeichert werden, dass das Programm für die Anzeigen funktioniert. Hier mal den ganzen code, vileicht habe ich ja sonst wo einen Fehler.

Declare Sub Led_display_init()
Declare Sub Led_display(byval Ziffer As Byte , Byval Zahl As Byte)


$regfile = "m32def.dat"

Const Rn_digi_slave_write = &H70
Const Rn_digi_slave_read = &H71
Const Dezimalpunktziffer = 0 'Segment wo Dezimalpunkt leuchten soll (0=keinen)

Dim Segmente As Byte
Dim Z As Byte
Dim I As Byte




Dim Einer As Byte
Dim Zehner As Byte
Dim Hunderter As Byte
Dim Tausender As Byte
Dim A As Word


$crystal = 16000000 'Quarzfrequenz
$baud = 9600

Config Scl = Portc.0 'Ports fuer IIC-Bus
Config Sda = Portc.1




I2cinit
Led_display_init




I = 0
Sound Portd.7 , 400 , 450 'BEEP
Sound Portd.7 , 400 , 250 'BEEP
Sound Portd.7 , 400 , 450 'BEEP
Print
Print "**** RN-CONTROL V1.4 *****"
Print "Das neue Experimentier- und Roboterboard"
Print
Do


A = 1245

einer = A mod 1
zehner = A mod 10
zehner = zehner - einer
hunderter = A mod 100
hunderter = hunderter - zehner
tausender = A mod 1000
Tausender = Tausender - Hunderter

Print ; Tausender ; Hunderter ; Zehner ; Einer;
Print
Waitms 500
Led_display 1 , Tausender 'Anzeigen der Zahlen
Led_display 2 , Hunderter
Led_display 3 , Zehner
Led_display 4 , Einer


Loop

End



Sub Led_display_init()
I2cstart
I2cwbyte Rn_digi_slave_write
I2cwbyte 0 'Control Byte

'Dynamic Alternative Mode und Helligkeit
'Die oberen 3 Bits bestimmen die Helligkeit
'Wenn es dunkler sein soll dann z.b. &B0110111
I2cwbyte &B0110111

I2cstop

'Alle Ziffern auf 0
For Z = 1 To 4
Led_display Z , 0
Next Z

End Sub


Sub Led_display(ziffer An Byte , Zahl As Byte)
I2cstart
I2cwbyte Rn_digi_slave_write
I2cwbyte Ziffer


Select Case Zahl
Case 0:
Segmente = &H3F
Case 1:
Segmente = &H06
Case 2:
Segmente = &H5B
Case 3:
Segmente = &H4F
Case 4:
Segmente = &H66
Case 5:
Segmente = &H6D
Case 6:
Segmente = &H7D
Case 7:
Segmente = &H07
Case 8:
Segmente = &H7F
Case 9:
Segmente = &H67
Case Else :
Segmente = &H80 'Ansonsten Dezimalpunkt

End Select

If Dezimalpunktziffer = Ziffer Then Segmente = Segmente Or &H80
I2cwbyte Segmente
I2cstop
End Sub
anstatt der 1245 werden über Print 2012010 ausgegeben.
Das Display zeigt auf den ersten 2 Segmenten einen Dezimal Punkt an, dass heisst dass er keine Zahl bekommt. Auf dem 3ten Segment wird eine 1 angezeigt, auf dem ganz rechts eine 0.
Was mache ich falsch?


mfg Luca

izaseba
01.08.2006, 23:12
Z.B. hat mich das Posting von Sebastian dazu veranlasst, Morgen auch mal die Hanni/Sebastian Version zu probieren. Wenn es ein paar Byte spart - prima! Ist mir nie in den Sinn gekommen

Schön, daß Du es ausprobieren willst :-)
Ich wollte Deinen Lösungsvorschlag auch nicht abwerten (sollte jemand es gedacht haben) Es ist sicher schnell geschrieben und für Anfänger verständlich.
Der Hanni hat ja schon die Gründe genannt, warum es mit subtrahieren schneller geht.

Gruß Sebastian

simonit
01.08.2006, 23:24
Meiner Meinung nach liegt der Fehler in der deklaration von A im typ Word. Soweit ich das jetzt gefunden habe kann man diesen Datentyp nur mit 1 und 0 belegen, was für diesen Fall zuwenig wäre. Bin allerdings auch nicht wirklich fit in Basecom, kenn mir nur mitm Algorithmus aus ;)

Hanni
01.08.2006, 23:49
A = 1245

einer = A mod 1
zehner = A mod 10
zehner = zehner - einer
hunderter = A mod 100
hunderter = hunderter - zehner
tausender = A mod 1000
Tausender = Tausender - Hunderter


Dort liegt übrigens der Hund begraben ...

Vielleicht einige Worte zur Erklärung:
Der Modulo Operator besorgt mir den Rest einer Division durch x.

Damit ergibt sich nach deiner Rechnung:

einer = 0
zehner = 5
hunderter = 40
tausender = 205

Damit hast du defakto einen Denkfehler drinne.

Grüße,
da Hanni.

simonit
02.08.2006, 00:33
Hallo

Sorry, stimt natürlich, hab den Algorithmus nur im Kopf zusammengestellt, ihn dabei allerdings nicht wirklich nachgerechnet. Nach einigen Modifikationen sieht er ähnlich aus wie Brunos, funktionieren müsste er auch.



einer = A mod 10
A = A - einer
A = A / 10
zehner = A mod 10
A = A - zehner
A = A / 10
hunderter = A mod 10
A = A - hunderter
A = A / 10
tausender = A mod 10

Spion
02.08.2006, 10:09
Hallo

Also die 2t variante von simonit funktioniert, wenn ich die Ziffern dann in Integer speichere. Aber ich muss leider die Zahl in ein Byte speichern, da es dem Prog. sonst nicht passt. Wenn ich sie in ein Byte speichere, dann bekomme ich z.B. anstatt 8569, 8481. Auch wenn ich andere Zahlen verwende, dann stimmt der Tausender immer. Ich habe mal nur eine 3stellige Zahl eingegeben und er hatt immer die erste Zahl richtig gemacht, die 2te manchmal richtig und die erste immer falsch. Wie kann ich dass beheben?
Hier noch der neue code:


Declare Sub Led_display_init()
Declare Sub Led_display(byval Ziffer As Byte , Byval Zahl As Byte)


$regfile = "m32def.dat"

Const Rn_digi_slave_write = &H70
Const Rn_digi_slave_read = &H71
Const Dezimalpunktziffer = 0 'Segment wo Dezimalpunkt leuchten soll (0=keinen)

Dim Segmente As Byte
Dim Z As Byte
Dim I As Byte




Dim Einer As Byte
Dim Zehner As Byte
Dim Hunderter As Byte
Dim Tausender As Byte
Dim A As Word


$crystal = 16000000 'Quarzfrequenz
$baud = 9600

Config Scl = Portc.0 'Ports fuer IIC-Bus
Config Sda = Portc.1




I2cinit
Led_display_init




I = 0
Sound Portd.7 , 400 , 450 'BEEP
Sound Portd.7 , 400 , 250 'BEEP
Sound Portd.7 , 400 , 450 'BEEP
Print
Print "**** RN-CONTROL V1.4 *****"
Print "Das neue Experimentier- und Roboterboard"
Print

'-------------------------------------------------------------------------------

Do


A = 923


einer = A mod 10
A = A - einer
A = A / 10
zehner = A mod 10
A = A - zehner
A = A / 10
hunderter = A mod 10
A = A - hunderter
A = A / 10
Tausender = A Mod 10

Print ; Tausender ; Hunderter ; Zehner ; Einer;
Print
Waitms 500
Led_display 1 , Tausender 'Anzeigen der Zahlen
Led_display 2 , Hunderter
Led_display 3 , Zehner
Led_display 4 , Einer


Loop

End

'-------------------------------------------------------------------------------

Sub Led_display_init()
I2cstart
I2cwbyte Rn_digi_slave_write
I2cwbyte 0 'Control Byte

'Dynamic Alternative Mode und Helligkeit
'Die oberen 3 Bits bestimmen die Helligkeit
'Wenn es dunkler sein soll dann z.b. &B0110111
I2cwbyte &B0110111

I2cstop

'Alle Ziffern auf 0
For Z = 1 To 4
Led_display Z , 0
Next Z

End Sub

'-------------------------------------------------------------------------------

Sub Led_display(ziffer An Byte , Zahl As Byte)
I2cstart
I2cwbyte Rn_digi_slave_write
I2cwbyte Ziffer


Select Case Zahl
Case 0:
Segmente = &H3F
Case 1:
Segmente = &H06
Case 2:
Segmente = &H5B
Case 3:
Segmente = &H4F
Case 4:
Segmente = &H66
Case 5:
Segmente = &H6D
Case 6:
Segmente = &H7D
Case 7:
Segmente = &H07
Case 8:
Segmente = &H7F
Case 9:
Segmente = &H67
Case Else :
Segmente = &H80 'Ansonsten Dezimalpunkt

End Select

If Dezimalpunktziffer = Ziffer Then Segmente = Segmente Or &H80
I2cwbyte Segmente
I2cstop
End Sub

mfg Luca

Spion
02.08.2006, 22:05
Trotz langem Probieren, habe ich es nicht geschafft, dass er vernünftige werte ausgiebt.
Wenn ich die Zahl in ein Integer speichere, dann ist es kein Problem, jedoch muss ich es in ein Byte speicheren und dann funktioniert es nicht richtig.
Gibt es einen Befehl um einen Integer in einen Byte zu verwandeln?

mfg Luca

DIYLAB
02.08.2006, 22:17
Hallo Luca,

lass das doch mal mit Integer - negative Werte erwartest Du doch nicht.
Nimm - wie schon beschrieben - für alle Variablen Typ "Word".
Also Dein A und auch die Variablen für die Ziffern.

Jetzt stehen also in den Word-Variablen hunderter, zehner, einer jeweils die einzelnen Ziffern, die ja vom Wert her auch in eine Variable "Byte" passen.

Was hindert Dich also daran, einfach für jede Stellen noch jeweils eine Byte-Variable zu deklarieren und den Wert zu übergeben?

Also angenommen, Deine Byte-Variablen heissen bhunderter, bzehner und beiner.

Dann einfach zuweisen:

bhunderter = hunderter
bzehner = zehner
beiner = einer

Fertig.

Gruß,
Bruno

DIYLAB
02.08.2006, 22:34
Hallo Hanni & Sebastian,

ich finde die Subtraktionsmethode wunderbar!
Im mikrocontroller.net hat ja z.B. der Peter Dannegger in diesem Thread LINK (http://www.mikrocontroller.net/forum/read-1-154196.html) zwei schöne Beispiele in Assembler gegeben.
Einmal für 32Bit und einmal für 16Bit - prima.

Ich habe versucht, diese Beispiele in Bascom mit dem Inline-Assembler in bestehende Programme einzufügen. Leider meckert der Compiler an mehreren Stellen.

Weil es in Bascom keine BIN2BCD Wandlung gibt, hab ich dann ein wenig mit Schleifen-Konstrukten gearbeitet. Geht auch wunderbar, aber bläht leider den Code im Endeffekt noch mehr auf, also die Modulo-Lösung.

Ich hatte es ungefähr so versucht:



'============================================
' Stellen separieren
'============================================
Sub separieren()

hunderter = 0
zehner = 0
einer = 0

While result > 100
result = result - 100
Incr hunderter
Wend

While result > 10
result = result - 10
Incr zehner
Wend

einer = result

End Sub
'--------------------------------------------


In "result" stand die zu zerlegende Zahl. Geht wiegesagt, ist aber alles andere als effizient - liegt aber an mir O:)

Ich wäre dankbar für ein paar Denkanstöße, wie diese Methode auch in Bascom gut umzusetzen wäre..

Viele Grüße,
Bruno

Spion
02.08.2006, 22:35
Danke


Die Idee hatte ich auch schon, nur haber ich leider etwas vertauscht, ich habe anstatt bhunderter = hunderter, hunderter = bhunderter gemacht und mich dann gewundert warum er 0 ausgiebt. ](*,) ](*,) ](*,)

Also jetzt funktionierts. Hier noch einmal denn Code der Funktioniert:



Dim Einer As Word
Dim Zehner As Word
Dim Hunderter As Word
Dim Tausender As Word
Dim A As Word

A = 8956

Einer = A Mod 10
A = A - Einer
A = A / 10
Zehner = A Mod 10
A = A - Zehner
A = A / 10
Hunderter = A Mod 10
A = A - Hunderter
A = A / 10
Tausender = A Mod 10

Print tausender '8
Print hunderter '9
Print zehner '5
Print einer '6

In Tausender, Huderter,zehner,einer stehen dann die einzelnen Zahlen.

Nochmals Danke an alle die geholfen haben. Schönen Tag noch (ist ja nicht mehr lang)

mfg Luca
mfg Luca

Hanni
03.08.2006, 00:33
Hallo Hanni & Sebastian,

ich finde die Subtraktionsmethode wunderbar!
Im mikrocontroller.net hat ja z.B. der Peter Dannegger in diesem Thread LINK (http://www.mikrocontroller.net/forum/read-1-154196.html) zwei schöne Beispiele in Assembler gegeben.
Einmal für 32Bit und einmal für 16Bit - prima.

Ich habe versucht, diese Beispiele in Bascom mit dem Inline-Assembler in bestehende Programme einzufügen. Leider meckert der Compiler an mehreren Stellen.

Weil es in Bascom keine BIN2BCD Wandlung gibt, hab ich dann ein wenig mit Schleifen-Konstrukten gearbeitet. Geht auch wunderbar, aber bläht leider den Code im Endeffekt noch mehr auf, also die Modulo-Lösung.



Hehe, Peter Dannegger steht nunmal für sehr effizienten Code. Such in der Codesammlung von mikrocontroller.net mal nach "Tasten entprellen - bullet proof" (3. oder 4. Seite) dann weisst du was ich meine.

Um den größeren Code zu erklären müsste man das sehen, was Bascom aus deinen Zeilen macht (also den Assembler Output). Ich tippe aber jetzt schon mal drauf, das a) so einige überflüssiger Vergleiche und b) so einige überflüssige Speicheroperationen darin versteckt sein werden.

Ansonsten könnte es meiner Meinung nach übrigens eine gute Idee sein, derartige Funktionen via Libs selbst zu erstellen und ggf hier zu veröffentlichen.

Wie man allerdings Libs in Bascom erstellt, kann ich dir nicht verraten (ich progge nunmal lieber etwas Hardwarenäher).

PS: Respekt, das du dir die Arbeit gemacht hast diesen Gedankenanstoß nachzuvollziehen.

Nachtrag:
vom Prinzip her sollte es aber mit inlineassembler recht einfach zu realisieren sein.

1. die Register die du verwenden willst auf den Stack sichern.
2. Die Ausgangswerte in diese laden
3. Peter Dannegger Methode anwenden (muss nur etwas angepasst werden)
4. die Ergebnisse ins RAM schreiben
5. die Register wiederherstellen
6. fertig.

Vielleicht hilft dir ja das etwas weiter.

Grüße,
da Hanni.

DIYLAB
03.08.2006, 08:02
vom Prinzip her sollte es aber mit inlineassembler recht einfach zu realisieren sein.

Moin Hanni,

ja - dachte ich auch.
Die Hürden beginnen allerdings schon bei reservierten Worten des Compilers. Und High/low bei den Subtraktionsbefehlen gehören auch dazu. Tolle Sache das 8-[

subi a0, low(10000)
sbci a1, high(10000)

Viele Grüße,
Bruno

DIYLAB
03.08.2006, 08:13
Moin Hanni,

peinlich peinlich!
Wollte mich gerade auf die Libs stürzen und selber Hand anlegen..
Da guck ich doch ins Lib-Verzeichnis und was sehen meine verquollenen Augen da? Eine BIN2BCD16 Lib O:)

Daaa muss ich doch glatt mal gucken..

Viele Grüße,
Bruno

Hanni
03.08.2006, 10:57
Tja Dinge gibts :D

Grüße,
Hanni.

izaseba
03.08.2006, 19:25
Hallo,
Ja Peter Danneggers Programme zu verstehen ist wirklich ein Ding, ich bin jedenfalls zu doof dafür :-$
Aber so in etwa wie Dein Code Bruno hab ich mir das schon vorgestellt, warum das dann so groß wird weiß ich auch nicht.
Wenn Du möchtest kann ich in meiner Codesammlung was passendes rauskopieren (das wäre dann zwar Assembler, aber vielleicht hilfreich)

viel Erfolg noch Sebastian

DIYLAB
03.08.2006, 19:40
Wenn Du möchtest kann ich in meiner Codesammlung was passendes rauskopieren (das wäre dann zwar Assembler, aber vielleicht hilfreich)

Moin Sebastian,

das wäre prima!! Bitte mach mal.
Ich habe die Bascom Lib wieder verworfen, die ist nicht wirklich gut.
Dann habe ich Peters Routine benutzt, die Übergabe von Bascom und wieder zurück eingepflegt, aber der Compiler kann mit den High und Low´s nichts anfangen - unglaublich. FastAVR compiliert das Assemblerstück anstandslos - Bascom nicht.
Dann habe ich eine andere Routine ausprobiert - ging.
Aber... dort liegt nur das "einer"-Segment einzeln in einem Register. Die restlichen Segmente als gepacktes BCD in den Registern. Also 2x4 Bit pro Register. Konnte ich dann auch nicht weiterverarbeiten mit meinen Kenntnissen <Haare rauf>.

Viele Grüße,
Bruno

izaseba
03.08.2006, 20:14
Ok, es ist zum Teil von Gerd Schmidt http://www.avr-asm-tutorial.net/index.html abgekupfert, habe nur etwas für mich angepasst, aber egal.

Alles dreht sich um Folgende Funktion:


Bin2ToDigit:
clr rmp ; Zähler auf Null
Bin2ToDigita:
cp rBin1H,rBin2H ; Vergleiche MSBs miteinander
brcs Bin2ToDigitc ; MSB Binärzahl kleiner, fertig
brne Bin2ToDigitb ; MSB Binärzahl größer, subtrahiere
cp rBin1L,rBin2L ; MSB gleich, vergleiche LSBs
brcs Bin2ToDigitc ; LSB Binärzahl kleiner, fertig
Bin2ToDigitb:
sub rBin1L,rBin2L ; Subtrahiere LSB Dezimalzahl
sbc rBin1H,rBin2H ; Subtrahiere Carry und MSB
inc rmp ; Erhöhe den Zähler
rjmp Bin2ToDigita ; Weiter vergleichen/subtrahieren
Bin2ToDigitc:
st z+,rmp ; Speichere das Ergebnis und erhöhe Zeiger
ret ; zurück

Kurz erklärt:
Ich speichere das Ergebnis in SRAM, der Z Zeiger muß auf die erste Speicherzelle eingestellt werden.
In rBin1H und rBin1L liegt meine Zahl die Umgewandelt werden soll.
Jetzt ruft man die Funktion 3 Mal auf, aber bevor man sie aufruft muß man in die Register rBin2H und rBin2L die Zahl laden, die substrahiert werden soll, etwa so:


ldi rBin2H,HIGH(1000)
ldi rBin2L,LOW(1000)
rcall Bin2ToDigit
ldi rBin2H,HIGH(100)
ldi rBin2L,LOW(100)
rcall Bin2ToDigit
ldi rBin2H,HIGH(10)
ldi rBin2L,LOW(10)
rcall Bin2ToDigit

Da die einer nicht mehr abgezogen werden müßen reicht ein
st z,rBin1L aus um die in Sram zu kriegen.

Ich hoffe, es ist verständlich und irgendwie nützlich :-k .
Bin mal gespannt was Ihr dazu sagt .

Gruß Sebastian

DIYLAB
03.08.2006, 20:43
Hi Sebastian,

kenn ich doch irgendwo her? -> LINK (http://www.avr-asm-tutorial.net/avr_de/rechnen/konvert.html)
Sehr nützlich das ASM-Tut. Aber mir raucht Heute der Kopf 8-[
Ich seh mir das Morgen mal genauer an.
Vielen Dank Sebastian!

Gut´s Nächtle,
Bruno

izaseba
03.08.2006, 20:59
kenn ich doch irgendwo her?

Ja ganau, die Quelle hab ich oben schon genannt, Gerds Beispiele sind sehr einfach und verständlich geschrieben :-)

Gruß Sebastian

Alicik
13.08.2006, 19:50
Danke für diesen Tip.
Heute stand ich vor dem selben Problem.
Ich habe die sehr elegante Lösung von Linux_80 verwendet.
Funktioniert wunderbar.

Noch ein Mal: Vielen herzlichen Dank!

Gruss

Ali

dibahh
25.10.2006, 11:48
a=1354

s=0
t=0
u=0
r=0
goto s_step

s_step:
if a<1000 then goto t_step else a=a-1000 and s=s+1 and goto s_step
t_step:
if a<100 then goto t_step else a=a-100 and t=t+1 and goto t_step
u_step:
if a<10 then goto u_step else a=a-10 and u=u+1 and goto u_step
r_step:
if a<1 then goto stepXXX else a=a-1 and r=r+1 and goto stepxxx

for_ro
25.10.2006, 20:08
Hallo,
mal abgesehen davon, dass du dich vertippt hast und den µC in eine Endlosschleife geschickt hast, aber den Code meinst du doch wohl nicht ernst, oder?

dibahh
26.10.2006, 20:02
erstmal habe ich meinen ganzen controller in einer schleife laufen ;o)

und ja ich meine es ernst mit dem Code - ist mal etwas anderes

gpo
27.10.2006, 17:59
Hallo,

hier ist meine Art eine 5 Stellige Zahl zu zerlegen. Dieser Code ist recht schnell.

Dim Az As Word
Dim Ah As Word
Dim Ata As Word
Dim Azt As Word

Dim Einer As Byte
Dim Zehner As Byte
Dim Hunderter As Byte
Dim Tausender As Byte
Dim Zehntausender As Byte At Azt Overlay

Dim Temp As Word
Dim A As Word



A = 54321



Az = A / 10
Ah = A / 100
Ata = A / 1000
Azt = A / 10000

Temp = Azt * 10
Tausender = Ata - Temp

Temp = Ata * 10
Hunderter = Ah - Temp

Temp = Ah * 10
Zehner = Az - Temp

Temp = Az * 10
Einer = A - Temp


End

lg
Günter

PicNick
27.10.2006, 18:34
Variante, nur so, als Alternative : ( beispiel für maximal 6 Stellen )


Dim Zahl As Long
Dim Postext As String * 3

Dim Strg As String * 20
Dim Arr(21) As Byte At Strg Overlay
Dim Ix As Integer
Dim Iy As Byte
Dim Ln As Byte

Zahl = 348365 ' das ist die Zahle

Strg = Str(zahl)
Ln = Len(strg)

Iy = 6 - Ln

For Ix = 1 To Ln
Postext = Lookupstr(iy , Posit)
Print Postext ; Chr(arr(ix))
Incr Iy
Next
End

Posit:
Data "hT:" , "zT:" , "T:" , "H:" , "Z:" , "E:"

Spion
27.10.2006, 19:42
Hallo

Der code denn ich schlussund endlich verwendet habe, funktioniert sehr gut. danke einenweg.

mfg Luca

Ps: Habe denn Code im ersten Post hinzugefügt.