Forum: Mikrocontroller und Digitale Elektronik Konvertieren von Binär nach ASCII


von Philipp Burch (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Philipp Burch (Gast)


Lesenswert?

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 :(

von ...HanneS... (Gast)


Lesenswert?


von Philipp Burch (Gast)


Lesenswert?

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!

von ...HanneS... (Gast)


Lesenswert?

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.

...

von Philipp Burch (Gast)


Lesenswert?

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.

von Philipp Burch (Gast)


Lesenswert?

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!

von ...HanneS... (Gast)


Lesenswert?

Z-Pointer ist bei allen AVRs r30 und r31.

...

von Philipp Burch (Gast)


Lesenswert?

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.

von ...HanneS... (Gast)


Lesenswert?

Dann schau mal ins Datenblatt deines AVRs.
Oder ins Instruction-Set,
oder in die Hilfe zum AVR.Studio,
oder in die Include-Datei deines AVR.

...

von Philipp Burch (Gast)


Lesenswert?

Ich weiss ja jetzt, dass er bei r31:r30 ist. Aber im Tut steht trotzdem
r26:r25. Das sollte vielleicht mal jemand korrigieren...

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.