Was läuft denn hier falsch?! Ich habe einen 1Byte Wert dieser soll mir jeweils aus dem Oberen und unteren Byte eine Dez. Zahl von 1 bis 9 Zählen und dann auf einen Display ausgeben. Nur leider Zählt es jetzt mit den Einer 1->3->7->? FERTIG und die Zehner 1.2.3.4.5.6.7.8.9 noch 6 Sonderzeichen und dann wieder bei 0 und die Einerstelle ändert sich nicht. Ist hier ein Denkfehler drin? R21 : Ist sind meine zwei Dez. Zahlen … also 00 bis 99 zaelen: push r16 ldi r16,0 mov r16,r21 cbr r16,0b11110000 ;Lösche Oberes Halbbyte cpi r16,9 ;Ist die Zahl jetzt 9? breq zaelenZehn ;Dann verzweige inc r16 ;Addiere um 1 add r21,r16 pop r16 ret ;Zurück zaelenZehn: mov r16,r21 swap r16 ;Oberes und unteres Halbbyte tau schen cbr r16,0b11110000 ;Löschen Oberes Halbbyte cpi r16,9 ;Ist der Wert jetzt 9? breq zaelenReset ;Dann verzweige inc r16 ;Addiere um 1 swap r16 ;Oberes und unteres Halbbyte tau schen mov r21,r16 pop r16 ret zaelenReset: clr r20 pop r16 ret AusgabeWertA: ldi r16,0x44 rcall lcdGoto ldi r17,0x30 mov r16,r21 swap r16 cbr r16,0xF0 add r16,r17 rcall lcdData ldi r17,0x30 mov r16,r21 cbr r16,0xF0 add r16,r17 rcall lcdData ret
breq schreibt keien Rücksprungadresse auf den Stack so wie z.B. rcall. Das heißt beim ret am Ende von zaehlenZehn landest du irgendwo aber nicht dort wo du hinwillst.
Ne das ist es nicht. Das sollte ja so sein dann will ich ja wieder in mein mainloop da wo ich her komme. Ich habe aber den fehler. inc r16 ;Addiere um 1 (bevor ich die Werte wieder zusammenbringe muss ich doch den unteren bzw. oberen Halbbyte löschen sonst addiere ich den wert mit dem wert 1 - 3 - 7 also ->cbr r21,0x0F ;Unteren Halbbyte löschen <- add r21,r16 pop r16 ret ;Zurück Aber danke für die Antworten... man muss manchmal eben nur eine rauchen und nochmal überlegen. in diesem fall war das erfolgreich =)
Tim Simon schrieb: > und nochmal überlegen. Was soll denn bei Erreichen von 99+1 passieren? Wenn schon Assembler: mit dem BRHC-Befehl könntest Du die Zählerei auf ca 10 Befehle kürzen. Gruß Anja
Hi >Wenn schon Assembler: mit dem BRHC-Befehl könntest Du die Zählerei auf >ca 10 Befehle kürzen. Nein. Das wird erst bei $xF+1 gesetzt. Aber das mit den 10+x Befehlen kommt trotzdem hin. MfG Spess
spess53 schrieb: > Nein. Das wird erst bei $xF+1 gesetzt. Aber das mit den 10+x Befehlen > kommt trotzdem hin. Ich wollte jetzt nicht die komplette Lösung zu den Hausaufgaben hinschreiben aber wenn man will kann man den Überlauf des digit carry bei $xA + testweise Addition von 6 in ein Hilfsregister erzwingen. Gruß Anja
Eine CPU rechnet immer binär. Es kostet daher viel Code, wenn man versucht, sie auf dezimal zu vergewaltigen. Einfacher ist es, binär zu zählen und nur zur Ausgabe nach Dezimal zu wandeln:
1 | .def counter = r16 |
2 | .def wr0 = r18 |
3 | .def wr1 = r19 |
4 | ;---------------------------------------- |
5 | |
6 | ;count up 0 .. 99 |
7 | count: |
8 | inc counter |
9 | cpi counter, 100 |
10 | brcs _count1 |
11 | clr counter |
12 | _count1: |
13 | ret |
14 | ;---------------------------------------- |
15 | |
16 | ;input: wr0 = number 0 .. 99 |
17 | ;output: wr0 = ones, wr1 = tens (ASCII) |
18 | numout: |
19 | ldi wr1, '0' - 1 |
20 | _numout1: |
21 | inc wr1 |
22 | subi wr0, 10 |
23 | brcc _numout1 |
24 | subi wr0, -(10 + '0') |
25 | ret |
26 | ;---------------------------------------- |
Es ist sinnvoll, die Register zu benamen. Ansonsten kommt man sehr schnell durcheinander, was nun welches Register für eine Funktion hat. Auch sollte man einige Register als zerstörbar (Arbeitsregister) reservieren, das erspart haufenweises Push/Pop. Sinnvoll dienen sie auch gleich der Parameterübergabe (Argumente und Returnwerte). Peter
Hi >Es kostet daher viel Code, wenn man >versucht, sie auf dezimal zu vergewaltigen. Nicht wirklich. Mit der Anregung von Anja:
1 | bcd_cnt: push r16 |
2 | ldi r16,$67 |
3 | add r21,r16 |
4 | brcs bcd_cnt20 |
5 | brhs bcd_cnt10 |
6 | subi r21,$06 |
7 | bcd_cnt10: subi r21,$60 |
8 | bcd_cnt20: pop r16 |
9 | ret |
Wenn man die $67 noch in einem der unteren Register ablegt, würden es nur noch 6 Befehle sein. Gerade einer mehr wie bei dir. MfG Spess
spess53 schrieb: > Gerade einer mehr wie bei dir. Ziemlich tricky der Code, schwer zu durchschauen. Wenn man nicht nur INC, sondern auch andere Operationen machen will, artet das aber schnell aus. Und die Ausgabe muß die Nibble ja wieder auseinanderpfrimeln. Die Ausgabe des Binärwertes würde so aussehen:
1 | AusgabeWertA: |
2 | ldi wr0, 0x44 |
3 | rcall lcdGoto |
4 | |
5 | mov wr0, counter ; get value |
6 | rcall numout ; bin -> dec |
7 | push wr0 |
8 | mov wr0, wr1 ; tens first |
9 | rcall lcdData |
10 | pop wr0 ; then ones |
11 | rjmp lcdData |
Peter P.S. Der Originalcode sichert R16 beim Zählen, aber die Ausgabe zerstört R16, R17. Entweder immer sichern oder garnicht. Gerade bei Assembler ist es wichtig, konsequent zu sein, sonst sucht man sich dumm und dämlich nach den Fehlern. Deshalb auch der Tip mit der Benamung, damit die zerstörbaren Register sofort ins Auge fallen. Und auch, damit man Argumente nicht im falschen Register übergibt. Namen lassen sich leichter merken, als nur die Zahlen 0 .. 31.
Hi >Wenn man nicht nur INC, sondern auch andere Operationen machen will, >artet das aber schnell aus. Ist richtig. Mit BCD/Packet BCD kann man kaum etwas herausreissen. >Der Originalcode sichert R16 beim Zählen,... Da passt einiges nicht. MfG Spess
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.