Hi,
wie kann ich am schnellsten binär zu bcd wandeln (als c programm)
möglichst unabhängig. Ich mache das bisher immer so:
uint16_t Hex2Dez (uint16_t hex)
{
uint16_t dez=0;
while(hex>=10000)
{
hex-=10000;
}
while(hex>=1000)
{
dez+=0x1000;
hex-=1000;
}
while(hex>=100)
{
dez+=0x100;
hex-=100;
}
while(hex>=10)
{
dez+=0x10;
hex-=10;
}
while(hex>=1)
{
dez+=0x1;
hex-=1;
}
return dez;
}
aber ich denke es gibt besseres...
Vielen Dank für die Tips schonmal
T.
man sieht es ja auch hier: Beitrag "32 Bit binär in BCD umwandeln" das Modulo und Division nicht die beste Lösung für einen AVR bedeuten, dennoch frage ich mich ob es nicht noch einfacher und schneller geht... T.
ich meine ich hätte noch mal etwas schlaueres gesehen... hier ist auch nur das was man so kennt: http://www.mikrocontroller.net/articles/Festkommaarithmetik T.
Hi Abgesehen, das hier etwas fehlt > while(hex>=10000) > { > hex-=10000; > } ist das eine umständliche Methode für dez = hex. MfG Spess
>>Abgesehen, das hier etwas fehlt<< was denn? ist ein 16Bit Rückgabeewert... >>ist das eine umständliche Methode für dez = hex<< he? Ich meine ich hatte das Thema hier schon mal, ich werde das letzte While nun noch in eine addierung ändern und dann sollte es passen... T.
Hi >Ich meine ich hatte das Thema hier schon mal, ich werde das letzte While >nun noch in eine addierung ändern und dann sollte es passen... Dann reicht auch while(hex>=10000) { hex-=10000; } dez = hex; Der Rest ist überflüssig. MfG Spess
hmm, ne so würde in der Variablen dez nur binär ein Wert kleiner 0x10000 stehen... oder? T.
Aus meiner Snippet-Sammlung
1 | uint8_t itobcd(uint8_t i) |
2 | {
|
3 | uint8_t lo, hi = 0; |
4 | |
5 | //Fehler mit unmoeglicher Zahl "von aussen" erkennbar machen
|
6 | if(i > 99) |
7 | return(0xFF); |
8 | |
9 | //Division, entspricht "hi = i/10;"
|
10 | while (i > 9) |
11 | {
|
12 | hi++; |
13 | i -= 10; |
14 | }
|
15 | |
16 | //Der Rest der Division ist noch in "i", das ist der lo-Anteil
|
17 | //Der Compiler wird die Variable "lo" wegoptimieren
|
18 | lo = i; |
19 | |
20 | return((hi << 4) | lo); |
21 | }
|
Scheint also auch "nix neues im Westen" zu geben. mfg mf
Hey Minifloat,
das ist ja das Prinzip. Bei mir sieht es nun so aus:
uint16_t Hex2Dez (uint16_t hex)
{
uint16_t dez=0;
while(hex>=10000)
{
hex-=10000;
}
while(hex>=1000)
{
dez+=0x1000;
hex-=1000;
}
while(hex>=100)
{
dez+=0x100;
hex-=100;
}
while(hex>=10)
{
dez+=0x10;
hex-=10;
}
dez+=hex;
return dez;
}
Ich schätze schneller geht es wohl nicht. Wenn du dir das Geshifte und
Verknüpfe sparen willst, dann könnte man es auch so machen:
uint8_t itobcd(uint8_t i)
{
uint8_t dez=0
//Fehler mit unmoeglicher Zahl "von aussen" erkennbar machen
if(i > 99)
return(0xFF);
while(i>=10)
{
dez+=0x10;
i-=10;
}
//Der Rest der Division ist noch in "i",
dez+=i;
return(dez);
}
könnte das passen, naja, der Compiler macht warscheinlich eh das selbe
daraus :-)
Gruß,
T.
Hi >hmm, ne so würde in der Variablen dez nur binär ein Wert kleiner 0x10000 >stehen... oder? Ja. Genau wie bei deinem Programm. Dezimal und Hexadezimal sind nur verschiedene Schreibweisen. Keine verschiedenen Zahlen. MfG Spess
spess53 schrieb: >>Ich meine ich hatte das Thema hier schon mal, ich werde das letzte While >>nun noch in eine addierung ändern und dann sollte es passen... > > Dann reicht auch > > while(hex>=10000) > { > hex-=10000; > } > dez = hex; > > Der Rest ist überflüssig. > > MfG Spess ich denke da hast du was übersehen spess, in den anderen whiles paasiert noch mehr ...
Sorry, habe das wohl etwas falsch benannt. Mein Code erzeugt bcds im 16Bit Wert, sieht man nur nicht auf den ersten Blick, muss ich mal umbenennen in bintobcd oder my_itoa oder soetwas... T.
spess53 schrieb: > Dezimal und Hexadezimal sind nur > verschiedene Schreibweisen. Keine verschiedenen Zahlen. es geht nicht um dezimal sondern um BCD, die Hexzahl 0x10 ist in BCD z.B. 0x16
So,
das konnte man falsch verstehen, sorry.
Ich habe meine Routine nun noch mal überarbeitet:
uint16_t bintobcd (uint16_t bin)
{
uint16_t bcds=0;
while(bin>=10000)
{
bin-=10000;
}
while(bin>=1000)
{
bcds+=0x1000;
bin-=1000;
}
while(bin>=100)
{
bcds+=0x100;
bin-=100;
}
while(bin>=10)
{
bcds+=0x10;
bin-=10;
}
bcds+=bin;
return bcds;
}
Gruß,
T.
Hi >es geht nicht um dezimal sondern um BCD, >die Hexzahl 0x10 ist in BCD z.B. 0x16 Stimmt. Mir war das +=0x... entgangen. MfG Spess
wie kann ich mir eigentlich angucken wie die Funktion ins assembler aussieht, beim PIC gab es da immer das "absolut Listing".... Nutze AVR Studio und avrgcc. T.
Thorsten S. schrieb: > wie kann ich mir eigentlich angucken wie die Funktion ins assembler *.lss in "Other Files" mfg.
danke :-)
das ist sie also in asm code:
uint16_t bintobcd (uint16_t bin)
{
9c0: 02 c0 rjmp .+4 ; 0x9c6 <bintobcd+0x6>
uint16_t bcds=0;
while(bin>=10000)
{
bin-=10000;
9c2: 80 51 subi r24, 0x10 ; 16
9c4: 97 42 sbci r25, 0x27 ; 39
9c6: 27 e2 ldi r18, 0x27 ; 39
9c8: 80 31 cpi r24, 0x10 ; 16
9ca: 92 07 cpc r25, r18
9cc: d0 f7 brcc .-12 ; 0x9c2 <bintobcd+0x2>
9ce: 20 e0 ldi r18, 0x00 ; 0
9d0: 30 e0 ldi r19, 0x00 ; 0
9d2: 04 c0 rjmp .+8 ; 0x9dc <bintobcd+0x1c>
}
while(bin>=1000)
{
bcds+=0x1000;
9d4: 20 50 subi r18, 0x00 ; 0
9d6: 30 4f sbci r19, 0xF0 ; 240
bin-=1000;
9d8: 88 5e subi r24, 0xE8 ; 232
9da: 93 40 sbci r25, 0x03 ; 3
9dc: 43 e0 ldi r20, 0x03 ; 3
9de: 88 3e cpi r24, 0xE8 ; 232
9e0: 94 07 cpc r25, r20
9e2: c0 f7 brcc .-16 ; 0x9d4 <bintobcd+0x14>
9e4: 04 c0 rjmp .+8 ; 0x9ee <bintobcd+0x2e>
}
while(bin>=100)
{
bcds+=0x100;
9e6: 20 50 subi r18, 0x00 ; 0
9e8: 3f 4f sbci r19, 0xFF ; 255
bin-=100;
9ea: 84 56 subi r24, 0x64 ; 100
9ec: 90 40 sbci r25, 0x00 ; 0
9ee: 84 36 cpi r24, 0x64 ; 100
9f0: 91 05 cpc r25, r1
9f2: c8 f7 brcc .-14 ; 0x9e6 <bintobcd+0x26>
9f4: 03 c0 rjmp .+6 ; 0x9fc <bintobcd+0x3c>
}
while(bin>=10)
{
bcds+=0x10;
9f6: 20 5f subi r18, 0xF0 ; 240
9f8: 3f 4f sbci r19, 0xFF ; 255
bin-=10;
9fa: 0a 97 sbiw r24, 0x0a ; 10
9fc: 8a 30 cpi r24, 0x0A ; 10
9fe: 91 05 cpc r25, r1
a00: d0 f7 brcc .-12 ; 0x9f6 <bintobcd+0x36>
}
bcds+=bin;
return bcds;
}
a02: 82 0f add r24, r18
a04: 93 1f adc r25, r19
a06: 08 95 ret
00000a08 <_exit>:
a08: ff cf rjmp .-2 ; 0xa08 <_exit>
0xA08-0x90c=0xFC
Also 252 Intruktionen, klingt viel.
T.
Thorsten S. schrieb: > 0xA08-0x90c=0xFC > > Also 252 Intruktionen, klingt viel. und was ist mit den schleifen?
Ja - ha ha - man muss das Thema ja von 2 Seiten betrachten: 1)Wie schnell ist die Routine 2)Wie lang ist sie codeseitig In diesem Fall hat sie codeseitig 252 Instruktionen, die Menge der Ausgeführten Instruktionen hängt bei dieser Routine stark von dem Übergabeparameter ab. Interessant sind sicher Lösungen, die eine konstante Ausführungszeit haben, egal was übergeben wird, wenn also wirklich gerechnet wird, die dennoch weniger Speicherplatz benötigen. T.
...ich probiere jetzt gerade mal nur so zum Spass hiermit rum:
uint16_t bintobcd (uint16_t bin)
{
uint16_t bcds=0;
uint8_t i=0;
while(i<4)
{
bcds |= (bin % 10)<<(4*i);
bin/=10;
i++;
}
return bcds;
}
irgendwie hat das einen komischen Einfluss auf meine Displayausgabe, das
untersuche ich gerade noch.
uint16_t bintobcd (uint16_t bin)
{
9c0: cf 93 push r28
9c2: df 93 push r29
9c4: 9c 01 movw r18, r24
9c6: c0 e0 ldi r28, 0x00 ; 0
9c8: d0 e0 ldi r29, 0x00 ; 0
9ca: e0 e0 ldi r30, 0x00 ; 0
9cc: f0 e0 ldi r31, 0x00 ; 0
uint16_t bcds=0;
uint8_t i=0;
while(i<4)
{
bcds |= (bin % 10)<<(4*i);
9ce: c9 01 movw r24, r18
9d0: 6a e0 ldi r22, 0x0A ; 10
9d2: 70 e0 ldi r23, 0x00 ; 0
9d4: 0e 94 02 05 call 0xa04 ; 0xa04 <__udivmodhi4>
9d8: 0e 2e mov r0, r30
9da: 02 c0 rjmp .+4 ; 0x9e0 <bintobcd+0x20>
9dc: 88 0f add r24, r24
9de: 99 1f adc r25, r25
9e0: 0a 94 dec r0
9e2: e2 f7 brpl .-8 ; 0x9dc <bintobcd+0x1c>
9e4: c8 2b or r28, r24
9e6: d9 2b or r29, r25
bin/=10;
9e8: c9 01 movw r24, r18
9ea: 6a e0 ldi r22, 0x0A ; 10
9ec: 70 e0 ldi r23, 0x00 ; 0
9ee: 0e 94 02 05 call 0xa04 ; 0xa04 <__udivmodhi4>
9f2: 9b 01 movw r18, r22
9f4: 34 96 adiw r30, 0x04 ; 4
9f6: e0 31 cpi r30, 0x10 ; 16
9f8: f1 05 cpc r31, r1
9fa: 49 f7 brne .-46 ; 0x9ce <bintobcd+0xe>
i++;
}
return bcds;
}
9fc: ce 01 movw r24, r28
9fe: df 91 pop r29
a00: cf 91 pop r28
a02: 08 95 ret
00000a04 <__udivmodhi4>:
a04: aa 1b sub r26, r26
a06: bb 1b sub r27, r27
a08: 51 e1 ldi r21, 0x11 ; 17
a0a: 07 c0 rjmp .+14 ; 0xa1a <__udivmodhi4_ep>
00000a0c <__udivmodhi4_loop>:
a0c: aa 1f adc r26, r26
a0e: bb 1f adc r27, r27
a10: a6 17 cp r26, r22
a12: b7 07 cpc r27, r23
a14: 10 f0 brcs .+4 ; 0xa1a <__udivmodhi4_ep>
a16: a6 1b sub r26, r22
a18: b7 0b sbc r27, r23
00000a1a <__udivmodhi4_ep>:
a1a: 88 1f adc r24, r24
a1c: 99 1f adc r25, r25
a1e: 5a 95 dec r21
a20: a9 f7 brne .-22 ; 0xa0c <__udivmodhi4_loop>
a22: 80 95 com r24
a24: 90 95 com r25
a26: bc 01 movw r22, r24
a28: cd 01 movw r24, r26
a2a: 08 95 ret
00000a2c <_exit>:
a2c: ff cf rjmp .-2 ; 0xa2c <_exit>
Thorsten
Hi, mir kam gerade noch das hier in den Kopf, aber da meine Funktion mir erstmal reicht und auch funktioniert bleibe ich erstmal dabei. Gruß, T.
Es geht noch schneller mit Peter Danneggers Routine, die abwechselnd subtrahiert und addiert, siehe Anhang. i muss auf jeden Fall signed sein, kann aber auch statt long nur int sein, dann wird es noch schneller. bcd kann unsigned int sein, falls nur 4 Stellen gewünscht sind. Der Startwert muss dann 65535 sein. Bei i>9999 geht die 10000er-Stelle ins Nirwana. Mit einer binären Suche geht es noch schneller, aber der Code ist länger.
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.
