Forum: Mikrocontroller und Digitale Elektronik Hilfe bei Umwandlung Binär --> Ascii


von Graupler (Gast)


Lesenswert?

Ihc probiere gerade eine Routine zu schreiben, die mir eine Binärzahl so 
umrechnet, dass ich sie asugeben kann. Wobei selber schreiben etwas zu 
viel gesagt wäre. Ich pfusche in einer Routine von Peter Dannegger rum:
http://www.mikrocontroller.net/attachment/6553/BCD32.ASM
Aber bei mir will es nicht so recht.
1
loop1:
2
  mov r27,r1
3
  mov r28,r2
4
  mov r29,r3
5
  mov r30,r4
6
  mov r31,r5
7
  clc
8
9
  ldi r16,-1
10
  loop1:
11
  inc r16
12
  subi r28,0b11101000
13
  sbci r29,0b01110110
14
  sbci r30,0b01001000
15
  sbci r31,0b00010111
16
  brcc loop1
17
  rcall AUSGABEENT
18
19
  ldi r16,10
20
  loop2:
21
  dec r16  
22
  subi r28, -0b11100100
23
  sbci r29, -0b00001011
24
  sbci r30, -0b01010100
25
  sbci r31, -0b00000010
26
  brcs loop2
27
  rcall AUSGABEENT

Die erste Ziffer stimmt noch(wird in AUSGABEENT direkt in eine 
Schieberegister geschoben) die zweite schon nicht mehr. Aber ich finde 
den Fehler nicht. Vielen Dank für eure Hilfe.

ps: AUSGABEENT ist noch nicht geschrieben, da steht nur ein ret drin. 
Also wird nichts weiter verändert.

von Ralf G. (ralg)


Lesenswert?

Graupler schrieb:
> Ich pfusche in einer Routine von Peter Dannegger rum
Da ist aber nichts mehr davon übrig!

Soll da ein String aus '0'en und '1'en angezeigt werden?

von Graupler (Gast)


Lesenswert?

Ne, in r16 steht ja nach jedem Block wie oft die jeweilige Dezimalstelle 
vorkommt (das ist zumindest der Plan). In der Unterroutine wird dann 
anhand des Wertes in r16 ein entsprechendes Muster an eine LED Matrix 
geschickt.

Die Routine ist eigentlich ja viel länger, das ist klar. Ich hab den 
Rest weggelassen, da ich ja schon nach dem zweiten Block einen Fehler 
habe.

von Uwe (Gast)


Lesenswert?

>subi r28, -0b11100100
was soll denn das "-" vor der Zahl ? Dann müßte doch aus der 8bit 
Konstante eine neun Bit Konstante im zweier Komplement werden ! Und der 
sub Befehl arbeitetet doch nur mit 8bit.

von Karl H. (kbuchegg)


Lesenswert?

>  subi r28,0b11101000
>  sbci r29,0b01110110
>  sbci r30,0b01001000
>  sbci r31,0b00010111

Wo hast du denn diese Binärkonstanten her und warum hast du die Art und 
Weise, wie Peter das gemacht hat, ausgetauscht?

Peters Version (am Beispiel 1000000 dezimal)

  subi r28, byte1( 1000000 )
  sbci r29, byte2( 1000000 )
  sbci r30, byte3( 1000000 )
  sbci r31, byte4( 1000000 )

ist leicht zu lesen, leicht zu verstehen und nicht schwierig 
nachzuvollziehen was da passiert. Von der 4 Byte Zahl in R28:R31 wird 
die Konstante 1000000 (dezimal) abgezogen und mitgezählt, wie oft das 
möglich war, ehe das Ergebnis negativ wurde. Wie auch immer 
1000000(dezimal) dann in Binärschreibweise aussieht - darum soll sich 
der Assembler kümmern. Der kann diese Umrechnung besser als ich und 
macht da keinen Fehler. Von der Binärschreibweise von 1000000 soll er 
sich dann das jeweils gebrauchte Byte (stellenrichtig) rausholen und die 
jeweilige Teil-Subtraktion machen.

Deine Version ist kryptisch, nicht nachvollziehbar und wenn ich mir 
deine Binärzahl in eine Dezimalzahl umrechne, komme ich nicht auf eine 
10-er Potenz. Wenn ich mich da jetzt mit dem Taschenrechner nicht vertan 
habe, dann ziehst du jeweils 390625000 (dezimal) ab.

Und hier

  subi r28, -0b11100100
  sbci r29, -0b00001011
  sbci r30, -0b01010100
  sbci r31, -0b00000010

stimmt das ganze schon mal sowieso nicht. Du kannst nicht einfach die - 
auf die 4 Einzelbytes verteilen. Die 10-er Potenz, die du abziehen 
(eigentlich addieren) willst, muss als ganzes Negativ gemacht werden, 
ehe man sich dann die Einzelbytes rausholt. Machst du das umgekehrt, 
kommt da was anderes raus, weil dann jedes Byte für sich einem 2-er 
Komplement unterzogen wird.

Mir ist absolut nicht klar, warum du da am generellen Mechanismus 
rumpfuschen musst. In Peters Routine ist ziemlich eindeutig klar, wo die 
Stellen sind, an denen dann die jeweiligen Ziffern zur Ausgabe gehen. 
Ersetz die ganz einfach durch deinen Ausgabe-Mechanismus und lass doch 
den Rest so wie er ist.

von Graupler (Gast)


Lesenswert?

Hallo, ich hab das anders als Peter gemacht, weil der Assembler dieses 
Zerlegung nur für Zahlen bis 32 bit macht. Meine hat 40 bit. Soll 
heißen: byte5(große Zahl) gibt eine Fehlermeldung. Deshalb musste ich 
die von Hand eintragen. Das unterste Byte fehlt in der Rechung im ersten 
und zweiten Block weil es sowieso Null ist.

Zum zweiten Punkt:
Danke für deinen Hinweis. Also erst die 40bit Zahl negativ machen 
(Zweierkomplement) und dann die bytes rauspulen. Muss ich dann im 
Quelltext trotzdem -0bxxxxxxxx schreiben oder reicht 0b00000000?

von Karl H. (kbuchegg)


Lesenswert?

Graupler schrieb:
> Hallo, ich hab das anders als Peter gemacht, weil der Assembler dieses
> Zerlegung nur für Zahlen bis 32 bit macht. Meine hat 40 bit. Soll
> heißen: byte5(große Zahl) gibt eine Fehlermeldung. Deshalb musste ich
> die von Hand eintragen. Das unterste Byte fehlt in der Rechung im ersten
> und zweiten Block weil es sowieso Null ist.

Dann wär aber zumindest ein fetter Kommentar dazu fällig!
Samt Nennung der dezimalen Zahl UND der Binärzahl, die da jeweils 
abgezogen wird.

von Ralf G. (ralg)


Lesenswert?

Graupler schrieb:
> weil der Assembler dieses
> Zerlegung nur für Zahlen bis 32 bit macht. Meine hat 40 bit.

Was macht denn byte1..byte4? Das gleiche schreibst du einfach noch für 
die oberen 8Bit dazu. Fertig.

-----------------
Graupler schrieb:
> Ne, in r16 steht ja nach jedem Block wie oft die jeweilige Dezimalstelle
> vorkommt (das ist zumindest der Plan). In der Unterroutine wird dann
> anhand des Wertes in r16 ein entsprechendes Muster an eine LED Matrix
> geschickt.

Graupler schrieb:
> Ihc probiere gerade eine Routine zu schreiben, die mir eine Binärzahl so
> umrechnet, dass ich sie asugeben kann.
-----------------

Das musst du, glaube ich, etwas präzisieren.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Graupler schrieb:
> Danke für deinen Hinweis. Also erst die 40bit Zahl negativ machen
> (Zweierkomplement) und dann die bytes rauspulen.

Ja. Der zweite Block muss dann so aussehen:
1
  ldi r16,10
2
  loop2:
3
  dec r16  
4
  subi r28, 0b00011100
5
  sbci r29, 0b11110100
6
  sbci r30, 0b10101011
7
  sbci r31, 0b11111101
8
  brcs loop2
9
  rcall AUSGABEENT

Hast du berücksichtigt, dass die größte 40-Bit-Zahl größer als 10¹² ist?
Dein Code beginnt aber bei 10¹¹. Oder sind das vorzeichenbehaftete
Zahlen, von denen du vor der Konvertierung den Absolutwert berechnest?
In diesem Fall passt der Wertebereich.

von Dauertroll (Gast)


Lesenswert?

Ralf G. schrieb:
> Was macht denn byte1..byte4? Das gleiche schreibst du einfach noch für
> die oberen 8Bit dazu. Fertig.

#define byte5(a) (a>>4*8)&0xFF

von Yalu X. (yalu) (Moderator)


Lesenswert?

Graupler schrieb:
> Hallo, ich hab das anders als Peter gemacht, weil der Assembler dieses
> Zerlegung nur für Zahlen bis 32 bit macht. Meine hat 40 bit. Soll
> heißen: byte5(große Zahl) gibt eine Fehlermeldung.

Um den 32-Bit-Überlauf zu vermeiden, kannst du das auch so schreiben:
1
zehnhoch11durch256 = 100000000/256*1000
2
zehnhoch10durch256 = 100000000/256*100
3
4
  ldi r16,-1
5
loop1:
6
  inc r16
7
  subi r28, lo8 (zehnhoch11durch256)
8
  sbci r29, hi8 (zehnhoch11durch256)
9
  sbci r30, hlo8(zehnhoch11durch256)
10
  sbci r31, hhi8(zehnhoch11durch256)
11
  brcc loop1
12
  rcall AUSGABEENT
13
14
  ldi r16,10
15
loop2:
16
  dec r16  
17
  subi r28, lo8 (-zehnhoch10durch256)
18
  sbci r29, hi8 (-zehnhoch10durch256)
19
  sbci r30, hlo8(-zehnhoch10durch256)
20
  sbci r31, hhi8(-zehnhoch10durch256)
21
  brcs loop2
22
  rcall AUSGABEENT

Das sieht auch nicht schön aus, man sieht aber besser, woher die
komischen Konstanten kommen. Außerdem vermeidet man Fehler bei der
Umrechnung, weil man die meiste Arbeit den Assembler machen lässt.

Die Funktionen lo8 ... hhi8 sind für den GNU Assembler. Falls du den
gleichen Assembler wie Peter verwendest, musst du sie wahrscheinlich
durch byte1 ... byte4 ersetzen.

von Yalu X. (yalu) (Moderator)


Angehängte Dateien:

Lesenswert?

Ich habe die Funktion mal zu Ende geschrieben. Funktionsgarantie gebe
ich keine, für ein paar Tausend zufällig generierte Werte hat sie aber
die richtigen Ergebnisse geliefert.

Edit: Die "output"-Aufrufe habe ich erst nach dem Test hinzugefügt und
dabei aus Versehen eine andere Zeile gelöscht.

In der viertletzten Zeile vor

  rjmp output

muss

  mov r16, r27

eingefügt werden (in r27 steht die letzte Ziffer), damit "output" auch
diese Ziffer in r16 geliefert bekommt.

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.