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