Hallo zusammen,
Ich möchte den Inhalt eines Registers (Binär) als ASCII-Code auf ein
LC-Display ausgeben. Allerdings hab' ich da ein Problem mit dem
Konvertieren des Binärtwerts nach ASCII. Im INET hab' ich dazu
folgendes gefunden:
http://www.avr-asm-tutorial.net/avr_de/quellen/konvert.asm
Das ist alles schön und gut, aber irgendwie funktioniert das bei mir
nicht so richtig...
Mein Aufruf:
1. Zahl in rBin1H:rBin1L laden
2. Z-Pointer auf die Adresse eines Labels am Ende des Codes setzen
3. Routine 'Bin2ToAsc5' aufrufen
Soweit so gut, nur:
Auf meinem Display werden damit einfach vier Zeichen angezeigt, die
aber sicher keine Zahlen sind. Und es sind immer die gleichen. Was ich
an dem Code eben vor allem nicht verstehe, ist, wie hier Daten
gespeichert werden sollen. Vom laufenden Programm aus kann man doch
nicht ins Flash-ROM schreiben, oder? Gibt's den Z-Pointer denn noch
für's RAM oder EEPROM?
Ich hoffe, mir kann jemand den richtigen Aufruf zeigen/erklären.
Vielen Dank schonmal!
mfG Philipp Burch
PS: Im Anhang befindet sich mein Code. Wundert euch nicht über das
Durcheinander dort, ich hab' heute den ganzen Tag versucht, was
gescheites auszugeben, da ist der halt so geworden...
Das Label, wo die Zahl hingeschrieben werden soll(te) befindet sich
ganz unten.
Hab' gerade gesehen, dass da steht "Der Z-Pointer zeigt entweder ins
SRAM [...]". Wie krieg' ich das hin? Im Tutorial hier wird die Arbeit
mit dem RAM ja leider nicht beschrieben :(
Danke vielmals für den Code. Leider schiesst der bei mir etwas über's
Ziel hinaus. Mir wär's lieber, ich könnte den Code den ich jetzt habe
ein bisschen ändern. Eigentlich scheitert es momentan einfach am SRAM.
Da weiss ich eben nicht, wie man das verwendet...
Kann mir da vielleicht mal schnell jemand erklären, wie das geht? Denn
irgendwie muss man dem doch beibringen, dass der Z-Pointer nun auf eine
Adresse im SRAM statt im Flash zeigt.
Vielen Dank schonmal!
Dann schau dir doch mal die LD... und ST... -Befehle in der Hilfe zum
AVR-Studio an. Als Referenz (welche Befehle es gibt) hilft vielleicht
die Befehlsliste des Datenblatts.
Übrigens war der Hinweis auf den Code nicht als Angebot zur unbesehenen
Benutzung gedacht, sondern als Möglichkeit, durch Code-Analyse zu
verstehen, wie es gemacht werden kann. Da der Code recht üppig
kommentiert ist, gibt es eine Chance, ihn zu verstehen.
...
Also, ich hab' jetzt mal versucht, das Zeug ordnungsgemäss über's RAM
laufen zu lassen. Leider kommt auf meinem LCD immernoch nur Mist...
Hier mal der Code:
--- Meine Hauptschleife (Ausschnitt) ---
;Zeit in rBin1H:rBin1L speichern
mov rBin1H, TimeH
mov rBin1L, TimeL
;Z-Pointer initialisieren
ldi ZL, LOW(adrNumbers)
ldi ZH, HIGH(adrNumbers)
;Konvertieren
rcall Bin2ToAsc5
;LCD leeren
ldi Temp, 0b00000001
ldi Temp2, 0b000
rcall LCDSend
ldi Temp3, 5 ;5 Zeichen
rcall LCDPrint
--- ---
adrNumbers hat den Wert 0x0061. Der sollte also auf einem Bereich nach
den Registern zeigen, oder?
Dann kommt hier die Routine zum Schreiben:
--- Schreibroutine ---
;Einen String auf's LCD ausgeben ('Temp3' Zeichen) von der Adresse
;im Z-Pointer aus
LCDPrint:
ld Temp, Z+ ;Byte lesen und Z inkrementieren
ldi Temp2, 0b100
rcall LCDSend
dec Temp3
brne LCDPrint ;Warten bis alles ausgegeben ist
_LCDPrint_End:
ret
--- ---
Und zum Schluss noch die Routine zum Senden eines Bytes an's LCD:
--- LCDSend ---
;Dem LCD ein Byte senden
;Das Byte muss sich in Temp befinden, der Wert für die Status-
;leitungen (R/W b1, RS b2) in Temp2
LCDSend:
rcall Delay
;Byte in PC schreiben
out PORTC, Temp
rcall Delay
;Enable High und die anderen Statusleitungen ausgeben
andi Temp2, 0b110
out PORTE, Temp2
sbi PORTE, E
rcall Delay
;Enable wieder Low
cbi PORTE, E
ret
--- ---
An dieser Routine wird's aber eher nicht liegen, da es funktioniert
hatte, als ich einfach einen statischen String verwendet hatte.
Der ganze Code von hier
http://www.avr-asm-tutorial.net/avr_de/quellen/konvert.asm
hab' ich einfach unten angehängt.
Die verwendeten Funktionen sind wohl diese:
; Paket II: Von Binär nach ASCII bzw. BCD
;
; Bin2ToAsc5
; ==========
; wandelt eine 16-Bit-Binärzahl in eine fünfstellige ASCII-
; kodierte Dezimalzahl um
; Aufruf: 16-Bit-Binärzahl in rBin1H:L, Z zeigt auf Anfang
; der Zahl
; Rückkehr: Z zeigt auf Anfang der Zahl, führende Nullen sind
; mit Leerzeichen überschrieben
; Benutzte Register: rBin1H:L (bleibt erhalten), rBin2H:L
; (wird überschrieben), rmp
; Aufgerufene Unterroutinen: Bin2ToBcd5
;
Bin2ToAsc5:
rcall Bin2ToBcd5 ; wandle Binärzahl in BCD um
ldi rmp,4 ; Zähler auf 4
mov rBin2L,rmp
Bin2ToAsc5a:
ld rmp,z ; Lese eine BCD-Ziffer
tst rmp ; prüfe ob Null
brne Bin2ToAsc5b ; Nein, erste Ziffer <> 0 gefunden
ldi rmp,' ' ; mit Leerzeichen überschreiben
st z+,rmp ; und ablegen
dec rBin2L ; Zähler um eins senken
brne Bin2ToAsc5a ; weitere führende Leerzeichen
ld rmp,z ; Lese das letzte Zeichen
Bin2ToAsc5b:
inc rBin2L ; Ein Zeichen mehr
Bin2ToAsc5c:
subi rmp,-'0' ; Addiere ASCII-0
st z+,rmp ; und speichere ab, erhöhe Zeiger
ld rmp,z ; nächstes Zeichen lesen
dec rBin2L ; noch Zeichen behandeln?
brne Bin2ToAsc5c ; ja, weitermachen
sbiw ZL,6 ; Zeiger an Anfang
ret ; fertig
; Bin2ToBcd5
; ==========
; wandelt 16-Bit-Binärzahl in 5-stellige BCD-Zahl um
; Aufruf: 16-Bit-Binärzahl in rBin1H:L, Z zeigt auf die
; erste Stelle der BCD-kodierten Resultats
; Stellen: Die BCD-Zahl hat exakt 5 gültige Stellen.
; Rückkehr: Z zeigt auf die höchste BCD-Stelle
; Benötigte Register: rBin1H:L (wird erhalten), rBin2H:L
; (wird nicht wieder hergestellt), rmp
; Aufgerufene Unterroutinen: Bin2ToDigit
;
Bin2ToBcd5:
push rBin1H ; Rette Inhalt der Register rBin1H:L
push rBin1L
ldi rmp,HIGH(10000) ; Lade 10.000 in rBin2H:L
mov rBin2H,rmp
ldi rmp,LOW(10000)
mov rBin2L,rmp
rcall Bin2ToDigit ; Ermittle 5.Stelle durch Abziehen
ldi rmp,HIGH(1000) ; Lade 1.000 in rBin2H:L
mov rBin2H,rmp
ldi rmp,LOW(1000)
mov rBin2L,rmp
rcall Bin2ToDigit ; Ermittle 4.Stelle durch Abziehen
ldi rmp,HIGH(100) ; Lade 100 in rBin2H:L
mov rBin2H,rmp
ldi rmp,LOW(100)
mov rBin2L,rmp
rcall Bin2ToDigit ; Ermittle 3.Stelle durch Abziehen
ldi rmp,HIGH(10) ; Lade 10 in rBin2H:L
mov rBin2H,rmp
ldi rmp,LOW(10)
mov rBin2L,rmp
rcall Bin2ToDigit ; Ermittle 2.Stelle durch Abziehen
st z,rBin1L ; Rest sind Einer
sbiw ZL,4 ; Setze Zeiger Z auf 5.Stelle (erste Ziffer)
pop rBin1L ; Stelle den Originalwert wieder her
pop rBin1H
ret ; und kehre zurück
Bin leider noch ein ASM-N00b, daher bitte nicht über meine Postings
wundern.
Och Menno! War ich 'n Idiot! Im Tut steht ja, dass der Z-Pointer die
Register 25 und 26 belegt. Gut, die hab' ich nicht verwendet.
Dummerweise hab' ich aber keine ATmega8, sondern einen ATmega8515. Und
da liegen die doch bei 30 und 31.
Trotzdem Danke für die Hilfe!
Na toll!
Zitat aus dem hiesigen Tut:
Um die Daten wieder auszulesen, muss man die Adresse auf die
zugegriffen werden soll in den Z-Pointer laden. Der Z-Pointer besteht
aus den Registern R25 (Low-Byte) und R26 (High-Byte), daher kann man
das Laden einer Konstante wie gewohnt mit dem Befehl "ldi"
durchführen. Statt R25 und R26 kann man übrigens einfach "ZL" und
"ZH" schreiben, da diese Synonyme bereits in der include-Datei
4433def.inc definiert sind.