Forum: Projekte & Code 8 Bit binär zu ASCII


von Daniel K. (lostsoul)


Angehängte Dateien:

Lesenswert?

Anbei ein einfaches Programm um einen 8bit Wert in ASCII umzuwandeln.
Ist vielleicht nicht die eleganteste Lösung aber für meine Zwecke hat es 
bisher gereicht.

Gruß Daniel
Viel Spaß damit

von Christian B. (casandro)


Lesenswert?

Auf den ATMegas ist das so ziemlich die einfachste und schnellste 
Lösung. Gäbe es einen Divitionsbefehl ginge es jedoch einfacher.

Vielleicht gibts noch eine obskure Möglichkeit das per Multiplikation zu 
machen.

von Benedikt K. (benedikt)


Lesenswert?

Christian Berger wrote:

> Vielleicht gibts noch eine obskure Möglichkeit das per Multiplikation zu
> machen.

Ja, die gibt es. Ich habe zwar momentan den Link nicht gefunden, aber 
irgendwo (ich glaube auf http://www.avrfreaks.net/ war das), gab es eine 
ziemlich ausführliche Diskussion dazu. Das Problem dabei ist nur, dass 
man eine Multiplikation mit einer relativ groeßn Zahl braucht, damit die 
Rundungsfehler oder ähnliches einem das Ergebnis nicht verfälschen.

von Peter D. (peda)


Lesenswert?

Daniel Katzenberger wrote:
> Anbei ein einfaches Programm um einen 8bit Wert in ASCII umzuwandeln.

So gehts auch:
1
;input:  R16 = 8 bit value 0 ... 255
2
;output: R18, R17, R16 = ASCII-digits
3
4
bcd:
5
        ldi     r18, -1 + '0'
6
_bcd1:
7
        inc     r18
8
        subi    r16, 100
9
        brcc    _bcd1
10
        ldi     r17, 10 + '0'
11
_bcd2:
12
        dec     r17
13
        subi    r16, -10
14
        brcs    _bcd2
15
        sbci    r16, -'0'
16
        ret

Peter

von 655432 (Gast)


Lesenswert?

Peter, könntest du deinen Code wohl noch etwas erläutern? Der ist schön 
kurz.

von Christian B. (casandro)


Lesenswert?

655432 wrote:
> Peter, könntest du deinen Code wohl noch etwas erläutern? Der ist schön
> kurz.

Im Prinzip macht er das selbe, wie der Vorredner.

Er beginnt bei einer Zahl in "Variable X". Ist X größer als 100, so 
zieht er 100 davon ab (X=X-100), und erhöht die 100-er Stelle.

Dann kuckt er nach, ob der Rest (X) größer als 10 ist. Ist das der Fall, 
so zieht er 10 davon ab (X=X-10) und erhöht die 10-er Stelle.

Im Pseudecode ist das etwa so:

X: Originalzahl
H: Hunderter
Z: Zehner
E: Einer


H=0
Z=0
E=0
Solange X>100
  X=X-100
  H=H+1
Solange X>10
  X=X-10
  Z=Z+1
E=X

Will man binär in BCD umwandeln, so kann man das für 2 Stellen etwas 
abkürzen:
X: Originalzahl
Y: BCD-Version
Y=0
Solange X>10
  X=X-10
  Y=Y+$10
Y=Y+X

von 655432 (Gast)


Lesenswert?

OK danke!

von Peter D. (peda)


Lesenswert?

655432 wrote:
> Peter, könntest du deinen Code wohl noch etwas erläutern? Der ist schön
> kurz.

Zuerst werden jeweils 100 abgezogen bis ein Unterlauf eintritt.

Z.B. von 234 wird 3-mal abgezogen und übrig bleibt:
234 - 3 * 100 = -66.
und -1 + '0' + 3 = '2'

Dann wird 10 addiert, bis ein Überlauf eintritt:
-66 + 7 * 10 = 4
und 10 + '0' - 7 = '3'

Dann noch 4 + '0' = '4'
und fertig.


Peter

von Christian B. (casandro)


Lesenswert?

Ohh, das ist originell. Darauf wäre ich nicht gekommen.

von Daniel K. (lostsoul)


Lesenswert?

Hallo

@ Peter Dannegger: dein code ist ja um einiges kürzer als meiner. Wär da 
nicht drauf gekommen... vorallem auf meinem at-mega habe ich die 
Register oberhalb von r16 schon alle in Verwendung, also ist mir nicht 
anderes übrig geblieben als die unteren Register zu verwenden...
Trotzdem gut zu wissen, dass es noch einfacher geht.

Gruß Daniel

von Peter D. (peda)


Lesenswert?

Daniel Katzenberger wrote:
> nicht drauf gekommen... vorallem auf meinem at-mega habe ich die
> Register oberhalb von r16 schon alle in Verwendung, also ist mir nicht
> anderes übrig geblieben als die unteren Register zu verwenden...


Wenn Du länger programmierst, wirst Du merken, daß es unklug ist, alle 
Variablen ständig in Registern zu halten.

Globale Variablen legt man überlicher Weise im SRAM an.
Werden sie gebraucht, lädt man sie in Register, macht damit die 
anstehenden Aufgabe und schreibt die Ergebnisse wieder ins SRAM.

Nur Variablen, die besonders häufig gebraucht werden, kann man 
ausnahmsweise in Registern definieren (vorzugsweise in den unteren 
R2..R15).

D.h. die meisten Register sind Arbeitsregister und werden kurzzeitig 
verwendet, wie eine Wandtafel (Scratchpad-Register).

Schau Dir mal größere Projekte von anderen an oder das Assemblerlistung 
von einem C-Programm.


Peter

von Daniel K. (lostsoul)


Lesenswert?

@ Peter Dannegger
Ich arbeite schon ein paar Jahre mit µC allerdings mit PIC16FXXX.
Auf Avr bin ich erst vor ein paar Wochen umgestiegen. Daher bin ich mit 
deren Struktur noch nicht so vertraut... Bei PIC kann man ja direkt mit 
werten rechnen die im SRAM stehen. Daher verwende ich den SRAM der AVR 
im moment nur für größere Datenmengen (Laufschrift für LCD usw.)
Aber danke für die tipps.
Ich hoffe ich kann mich "schnell" in die AVR-Welt einarbeiten.

Gruß Daniel

von Matthias Schläfli (Gast)


Lesenswert?

Hallo

Ich habe eine Lösung gefunden! Ist zwar etwas lang, aber es 
funktioniert!
Einfach den gewünschten Wert in die Variable x speichern und du erhälst 
den Zehner und Einer Wert zurück.


if((x>=0) && (x<=9))
 {
 Ascii_Zehner=48;
 }

 if((x>=10) && (x<=19))
 {
 Ascii_Zehner=49;
 }

 if((x>=20) && (x<=29))
 {
 Ascii_Zehner=50;
 }

 if((x>=30) && (x<=39))
 {
 Ascii_Zehner=51;
 }

 if((x>=40) && (x<=49))
 {
 Ascii_Zehner=52;
 }

 if((x>=50) && (x<=59))
 {
 Ascii_Zehner=53;
 }

 if((x>=60) && (x<=69))
 {
 Ascii_Zehner=54;
 }

 if(x==0 || x==10 || x==20 || x==30 || x==40 || x==50 || x==60)
 {
 Ascii_Einer=48;
 }

 if(x==1 || x==11 || x==21 || x==31 || x==41 || x==51 || x==61)
 {
 Ascii_Einer=49;
 }

 if(x==2 || x==12 || x==22 || x==32 || x==42 || x==52 || x==62)
 {
 Ascii_Einer=50;
 }

 if(x==3 || x==13 || x==23 || x==33 || x==43 || x==53 || x==63)
 {
 Ascii_Einer=51;
 }

 if(x==4 || x==14 || x==24 || x==34 || x==44 || x==54)
 {
 Ascii_Einer=52;
 }

 if(x==5 || x==15 || x==25 || x==35 || x==45 || x==55)
 {
 Ascii_Einer=53;
 }

 if(x==6 || x==16 || x==26 || x==36 || x==46 || x==56)
 {
 Ascii_Einer=54;
 }

 if(x==7 || x==17 || x==27 || x==37 || x==47 || x==57)
 {
 Ascii_Einer=55;
 }

 if(x==8 || x==18 || x==28 || x==38 || x==48 || x==58)
 {
 Ascii_Einer=56;
 }

 if(x==9 || x==19 || x==29 || x==39 || x==49 || x==59 || x==69)
 {
 Ascii_Einer=57;
 }

von Peter D. (peda)


Lesenswert?

Matthias Schläfli wrote:

> Ich habe eine Lösung gefunden! Ist zwar etwas lang,

Ja das stimmt, die ist wirklich schon extrem lang, 3800% größer als 
meine.


> aber es
> funktioniert!

Aber nur von 0 ... 63.
Was ist mit den Zahlen 64 ... 255?


Peter

von spess53 (Gast)


Lesenswert?

Hi

@Matthias

Kennt dein Compiler keinen 'mod' (Modulo) Befehl? Damit ist das mit ca. 
10 Zeilen gegessen.

MfG Spess

von Marc S. (euro)


Lesenswert?

Qlternativ hier mal ein codeschnipsel den ich mir mal zusammen gebastelt 
habe, ist allerdings direkt aus ner LCD-Routine:
1
void lcd_int8out(uint8_t i){
2
bool temp = false;
3
if((i/100)||temp){lcd_data((i/100)+48);temp = true;}else{lcd_data(' ');};
4
i %= 100;
5
if((i/10)||temp){lcd_data((i/10)+48);}else{lcd_data(' ');};
6
i%= 10;
7
lcd_data(i+48);
8
};

Ist vermutlich am einfachsten zu verstehen, arbeitet allerdings mit 
Division ;)

von Simon K. (simon) Benutzerseite


Lesenswert?

Marc Seiffert wrote:
> Ist vermutlich am einfachsten zu verstehen, arbeitet allerdings mit
> Division ;)

Alles in möglichst wenig Code Zeilen zu stecken fördert aber nicht die 
Verstehbarkeit ;)

von Peter D. (peda)


Lesenswert?

Simon K. wrote:

> Alles in möglichst wenig Code Zeilen zu stecken fördert aber nicht die
> Verstehbarkeit ;)

Das stimmt.
Man kann ein Programm auch als Einzeiler schreiben, aber dann muß der 
Code noch lange nicht kleiner sein, als mit 1000 Zeilen.
Besonders der AVR-GCC läßt sich mit verschiedenen Schreibweisen 
überhaupt nicht beeinflussen, der compiliert (leider) immer seinen 
eigenen Stil.


Man sollte aber nicht mit der Brechstange versuchen, alles nur mit 
Vergleichen zu machen.
Man kann ja auch jede beliebige Digitalschaltng nur mit 2-fach NAND 
(74HC00) aufbauen, aber das macht keiner.

Und es schadet nichts, zu wissen, daß 10 Subtraktionen effizienter sind 
als eine Division auf MCs ohne Hardware-Division.


Peter

von Schnulli (Gast)


Lesenswert?

>Ja das stimmt, die ist wirklich schon extrem lang, 3800% größer als
>meine.

Welche Codesammlung muß man eigentlich im Kopf haben, um so krankhaft 
angeben zu müssen?

von Rudi D. (rulixa)


Lesenswert?

Peter D. schrieb:
> Daniel Katzenberger wrote:
>> Anbei ein einfaches Programm um einen 8bit Wert in ASCII umzuwandeln.
>
> So gehts auch:
>
1
> 
2
> ;input:  R16 = 8 bit value 0 ... 255
3
> ;output: R18, R17, R16 = ASCII-digits
4
> 
5
> bcd:
6
>         ldi     r18, -1 + '0'
7
> _bcd1:
8
>         inc     r18
9
>         subi    r16, 100
10
>         brcc    _bcd1
11
>         ldi     r17, 10 + '0'
12
> _bcd2:
13
>         dec     r17
14
>         subi    r16, -10
15
>         brcs    _bcd2
16
>         sbci    r16, -'0'
17
>         ret
18
> 
19
>
>
> Peter

Habe heute so eine Routine gebraucht.
Ich bin ja nicht so sattelfest, aber ich finde, dass da drin ein Fehler 
steckt. Nämlich entweder die 1. Zeile muss sein
1
             ldi      r18, -2 + '0'
2
3
;oder man fügt nach der Zeile mit brcc eine Zeile   
4
5
               dec    r18          ;ein

Später im Thread mit dem Beispiel 234 sehe ich nirgends -1 +'0',
die die 3 Hunderter auf 2 Hunderter korrigiert. Man darf ja nicht das 
erste inc    r18 vergessen.

 Wo liegt mein ev. Fehler?

von Karl H. (kbuchegg)


Lesenswert?

Rudi D. schrieb:

 die die 3 Hunderter auf 2 Hunderter korrigiert. Man darf ja nicht das
> erste inc    r18 vergessen.

Dem ersten inc r18 wird doch dadurch Rechnung getragen, dass er nicht 
bei 0 anfängt zu zählen, sondern bei -1.

Sind 3 Subtraktionen notwendig, bis das Ergebnis unterläuft (salopp 
gesprochen: negativ wird), dann waren genau 2 Hunderter in der Zahl. Und 
genau das kriegt er doch auch raus.

Einfach mal im Einzelschrittbetrieb durchsteppen. Dann sollte das 
Prinzip klarer werden.

: Bearbeitet durch User
von Rudi D. (rulixa)


Lesenswert?

Da sieht man was im Kopf falsch laufen kann. Die 3. Subtraktion 
verursacht ja kein inc r18 mehr. Aber am Papier hab ich das getan, als 
ich es durchspielte.
Danke Rudi

von Rudi D. (rulixa)


Lesenswert?

Rudi D. schrieb:
> Da sieht man was im Kopf falsch laufen kann. Die 3. Subtraktion
> verursacht ja kein inc r18 mehr. Aber am Papier hab ich das getan, als
> ich es durchspielte.
> Danke Rudi

Das Codeschnipsel wird im DDS-Generator bei der Einstellung der 
Wobbelfrequenz von 2 Hz bis 73 Hz erfolgreich verwendet Siehe

http://www.radiomuseum.org/forum/neues_vom_dds_heimsenderlein.html

Der Thread dort ist schon sehr lang.

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.