Hallo alle zusammen. Sitze gerade vor folgendem Problem: Bin dabei eine 4Stellige sieben Segment Anzeige aufzubauen und möchte dort die Zahlen anzeigen lassen, die von einem Atmega8 kommen sollen. Mein Problem ist jetzt, wie splitte ich eine Zahl z.B. 9876 ( in C ) so auf, dass die 9 in einer Variablen steckt, die 8 in einer anderen usw? PS: Ja, geggoogelt hab ich auch, hab nur nichts Sinnvolles gefunden.
Durch sukzessive Modulo / Division. z.B.: unsigned char stelle[4]; unsigned int wert; for(i = 0; i < 4; i++) { stelle[i] = wert % 10; wert /= 10; } Dann stehen in stelle[0...3] die einzelnen Dezimalstellen, und zwar die Einser in stelle[0], die Zehner in stelle[1] usw...
1 | uint8_t digits[5]; |
2 | |
3 | void splitit(int num) |
4 | {
|
5 | div_t x; |
6 | int8_t i; |
7 | |
8 | memset(digits, 0, sizeof digits); |
9 | for (i = 4; i >= 0; i--) { |
10 | x = div(num, 10); |
11 | digits[i] = x.rem; |
12 | num = x.quot; |
13 | }
|
14 | }
|
ja ich glaube damit lässt sich was anfangen. danke euch. werde es mal sofort ausprobieren.
Eine andere Möglich keit ist die Zahl in einen buffer zu sprinten, und die jeweilge Zahl aus dem String zu nutzen zahl = 123; buffer[46]; sprintf(buffer,"%i",zahl); stelle = buffer[x]-0x30
Naja, ein sprintf ist aber in dem Zusammenhang echt mit Kanonen auf Spatzen geschossen. Da kann man noch eher itoa nehmen. Das bläht das Programm nicht so auf und das Ergebnis ist das selbe...
@Walter: Nur als kleines Beispiel: Aus dem hier unsigned char string[6]; unsigned int wert = 12345; sprintf(string, "%i", wert); macht der AVR-GCC-C-Compiler satte 1922 Bytes Code (Optimierung -Os). Das hier unsigned char string[6]; unsigned int wert = 12345; itoa(wert, string, 10); gibt kompakte 312 Bytes. Ich glaub, da fiele die Wahl nicht schwer, gell? Aber die ganz oben genannten Methoden sind sicher noch kleiner...
290 Bytes Code. Zahl ist in 4 ASCII Zeichen umgewandelt. Wenn du kein ASCII haben willst, ziehe 30hex von jeder ab. unsigned char lookup [17] = "0123456789ABCDEF"; unsigned char buffer[5]; int main(void) { unsigned int zahl; buffer[0] = lookup[(zahl) & 0x000F]; buffer[1] = lookup[(zahl >>4 ) & 0x000F]; buffer[2] = lookup[(zahl >>8 ) & 0x000F]; buffer[3] = lookup[(zahl >>12) & 0x000F]; return 0; }
Oops, der Zahl fehlt noch dein Beispielwert. unsigned char lookup [17] = "0123456789ABCDEF"; unsigned char buffer[5]; int main(void) { unsigned int zahl = 9847; buffer[3] = lookup[(zahl) & 0x000F]; buffer[2] = lookup[(zahl >>4 ) & 0x000F]; buffer[1] = lookup[(zahl >>8 ) & 0x000F]; buffer[0] = lookup[(zahl >>12) & 0x000F]; return 0; }
Das macht aber leider etwas anderes. Du kreierst das Equivalent zu itoa(wert, string, 16); Gesucht war aber itoa(wert, string, 10);
Genau, in dem Beispiel würde nicht 9847 ausgegeben, sondern das Hexadezimal-Äquivalent 2677. Und das ist ein klitzekleiner Unterschied. Genau das ist ja das Problem, wenn man von einem Prozessor Dezimalstellen bekommen will: Die Division durch 10 ist eben nicht so schön einfach durch Bitschubsereien machbar und macht deshalb mehr Code erforderlich.
Na klar, die Codesammlung ist dazu da, damit da garantiert keiner reinguckt :-( Man oh man. O.k. das Beispiel ist fürn 8051, aber C ist ja portabel. Anbei die Version umgeschrieben für Konstanten im Flash fürn WINAVR. Ist dann ganze 58 Byte groß. Also Leute wirklich. Peter
Hmm. > void outint( u16 val, u8 * result ) > { > u8 d, i; > u16 tval; > > for( i = 4; i; i-- ){ > tval = pgm_read_word(TEST+i-1); // get test value > for( d = 0; val >= tval; val -= tval ) > d++; // count subtractions > *result = d; // store digit *result = d + '0'; > result++; > } > *result = val; // store ones > } macht noch ein paar Bytes zusätzlich :-)
Oder aber: for( d = '0'; val >= tval; val -= tval ) d++; // count subtractions *result = d; // store digit d fängt nicht mehr bei 0, sondern bei '0' an zu zählen. Damit sollte das wieder auf 58 Bytes rauslaufen.
@Karl Heinz, ASCII nützt bei 7-Segment aber nichts. Außerdem hast Du die Einer vergessen. Ansonsten siehe Codesammlung. Peter
> @Karl Heinz, > > ASCII nützt bei 7-Segment aber nichts. <nach oben scroll> Schäm. Ja, das hatte ich übersehen.
Meine Variante braucht übrigens (einschließlich der Bibliotheksroutine, die ja u. U. sowieso gebraucht wird) 132 bytes. Wäre die Frage, was von beiden schneller ist, und was einem dann dabei wichtiger ist.
Die Benutzung der Funktion div() hat halt den Vorteil, daß die Divisionen nicht alle doppelt gemacht werden müssen. Das spart eine Menge Zeit.
> daß die Divisionen nicht alle doppelt gemacht werden müssen.
Was glaubst Du denn, was die Funktion div() macht? Du musst die
Division und das Modulo vielleicht nicht explizit hinschreiben, aber
div() macht intern mit Sicherheit auch nix anderes... Vom
Programmieraufwand ist das glaub ich kein wirklicher Unterschied.
> Vom Programmieraufwand ist das glaub ich kein > wirklicher Unterschied. Dann solltest du dir mal den Divisionsalgorithmus angucken. Der Rest fällt bei der ganzzahligen Division immer zugleich mit dem Quotienten mit an. Erinnere dich einfach an deine Division natürlicher Zahlen in der Grundschule: dort war das auch schon so. Daher hat es Sinn, div() zu benutzen, wenn man sowohl den Quotienten als auch den Rest ohnehin benötigt. (Sonst gäbe es diese Funktion sicher gar nicht erst.) Da die Division die teuerste Grundrechenoperation ist, spart man knapp die Hälfte an Zeit (und vermutlich einiges mehr gegenüber Peter's "poor man division" mittels fortlaufender Subtraktion).
@Jörg: Hast natürlich recht. Mit Programmieraufwand meinte ich aber eigentlich den Schreibaufwand im Programm. Dass der Code dann größer und evtl. langsamer wird ist die andere Sache...
@Jörg, "Da die Division die teuerste Grundrechenoperation ist, spart man knapp die Hälfte an Zeit (und vermutlich einiges mehr gegenüber Peter's "poor man division" mittels fortlaufender Subtraktion)." Nö. Die 16Bit-Divisonsschleife wird 16* durchlaufen je Digit, die Subtraktion aber nur max 9* (worst case). Die optimierte Assemblersubtraktion über Null hinweg ist nochmal wesentlich schneller (siehe Anhang). Spielt aber für menschliche Ausgaben keinerlei Rolle. Peter
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.