8 Bit binär zu ASCII

#821361
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.
#821398
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
#821481
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
#821601
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
#822628
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
#823261
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
#823281
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
Gast #1012985
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;
 }
#1013269
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 ;)
#1013820
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
#4248872
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?
#4248955
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.
#4249663
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren