Hallo zusammen.
Ich möchte eine Kommazahl auf dem Display Darstellen. Beispiel: 8,75
Bitte erklärt mir folgendes:
in der main.c , Funktion readADC();
Diese Funktion gibt mir eine Ganzzahl raus. Die kann ich auch mit itoa
umwandeln und auf dem LCD ausgeben. Funktioniert.
1. Wie schreibe ich das um, dass ich aus der Funktion schon eine
Kommazahl bekomme?
2. Wenn ich ohne readADC(); eine Kommazahl deklariere,
quasi so: float a = 8.75;
diese dann mit itoa umwandeln lasse und aufs LCD ausgebe, funktioniert
das leider nicht. woran liegt das.?
Liegt es an der itoa Funktion, die das nicht umwandeln kann oder an
meiner Ausgabe aufs LCD. (Im Anhang ist die lib vom LCD Controller)
Vielen Dank
MfG
@ relte (Gast)
>1. Wie schreibe ich das um, dass ich aus der Funktion schon eine>Kommazahl bekomme?
Mit Festkommaarithmetik.
>2. Wenn ich ohne readADC(); eine Kommazahl deklariere,>quasi so: float a = 8.75;>diese dann mit itoa umwandeln lasse und aufs LCD ausgebe, funktioniert>das leider nicht. woran liegt das.?
Das itoa() nut INTEGER verarbeiten kann. Sagt ja der Name
I nteger to A SCII
relte schrieb:> quasi so: float a = 8.75;> diese dann mit itoa umwandeln
Was heißt "itoa"?
Richtig: Integer to ASCII.
Und: ist ein Float ein Integer?
Wenn du eh' schon mit floats herumhampelst: sieh dir mal sprintf() und
%f an.
Aber ich würde in hundertstel Volt rechnen und bekäme statt 8,75V dann
den Integerwert 875. Davon dann die Hunterters ausgeben. Dann einen
Punkt, dann den Rest. Und fertig...
Lothar M. schrieb:> Aber ich würde in hundertstel Volt rechnen und bekäme statt 8,75V dann> den Integerwert 875. Davon dann die Hunterters ausgeben. Dann einen> Punkt, dann den Rest. Und fertig...
wie errechnest du dass bei 875 ein Ergebnis von 8 heraus kommt.? da die
875 nicht konstant bleiben.
relte schrieb:> wie errechnest du dass bei 875 ein Ergebnis von 8 heraus kommt.? da die> 875 nicht konstant bleiben.
Einfach zwischen die erste und zweite Stelle einen Punkt einfügen. Das
geht genauso, wenn an erster Stelle eine 7 steht :-)))
relte schrieb:> wie errechnest du dass bei 875 ein Ergebnis von 8 heraus kommt.?
Ich teile die Zahl 875 durch 100 und erhalte 8 Rest 75.
> da die 875 nicht konstant bleiben.
Klar. Ich muss die 875 ja auch erst mal aus dem ADC-Wert berechnen. Aber
auch dafür ist mit ein wenig Nachdenken kein float nötig...
Erwin D. schrieb:> Einfach zwischen die erste und zweite Stelle einen Punkt einfügen.
LCDSoftText(buffer1,0,0,BLACK);
wie.? da müsste ich den string aufsplitten
Lothar M. schrieb:> Aber> auch dafür ist mit ein wenig Nachdenken kein float nötig...
da bin ich der gleichen Meinung. Aber dafür habe ich das Problem:
relte schrieb:> Erwin D. schrieb:>> Einfach zwischen die erste und zweite Stelle einen Punkt einfügen.>> LCDSoftText(buffer1,0,0,BLACK);>> wie.? da müsste ich den string aufsplitten
relte schrieb:> da müsste ich den string aufsplitten
Ja, das ist doch keine Raketentechnik...
Mal angenommen, ich habe aus der Zahl 875 einen String "875" gemacht,
dann kopiere ich einfach die 75 und die abschließende /0 um eins nach
hinten und erhalte "8775". Dann füge ich an zweiter Stelle einen Punkt
ein und bekomme "8.75". Fertig.
relte schrieb:> wie.? da müsste ich den string aufsplitten
Nee, nicht aufsplitten, sondern gleich beim Bilden des Strings den Punkt
einfügen. So wie Lothar schrieb:
Lothar M. schrieb:> Ich teile die Zahl 875 durch 100 und erhalte 8 Rest 75.
Lothar M. schrieb:> Mal angenommen, ich habe aus der Zahl 875 einen String "875" gemacht
den string mach ich ja bei mir so:
itoa(a,buffer1,10);
gibt es hierfür noch eine bessere lösung.?
Lothar M. schrieb:> dann kopiere ich einfach die 75 und die abschließende /0 um eins nach> hinten
wie stelle ich das an.?
relte schrieb:> den string mach ich ja bei mir so: ...
Diese Vorgehensweise wirst du überarbeiten müssen. Aber es hat ja keiner
behauptet, dass es immmer einfach sein muss.
relte schrieb:> wie stelle ich das an.?
relte schrieb:> Lothar M. schrieb:>> Mal angenommen, ich habe aus der Zahl 875 einen String "875" gemacht>> den string mach ich ja bei mir so:> itoa(a,buffer1,10);> gibt es hierfür noch eine bessere lösung.?>> Lothar M. schrieb:>> dann kopiere ich einfach die 75 und die abschließende /0 um eins nach>> hinten>> wie stelle ich das an.?
Zum Beispiel so:
Lothar M. schrieb:> itoa(a,buffer1,10);> buffer1[4]=0; // Stringende> buffer1[3]=buffer1[2]; // Einer> buffer1[2]=buffer1[1]; // Zehner> buffer1[1]='.'; // Hurra, der PUNKT!
itoa(a,buffer1,10);
buffer1[4]=0; // Warum hier eine 0?
buffer1[3]=buffer1[2]; // quasi verschiebe ich hier nach rechts?
buffer1[2]=buffer1[1]; // hier genauso
buffer1[1]='.'; // Hurra, der PUNKT!
buffer1[0]; //hier steht meine 8?
relte schrieb:> Lothar M. schrieb:>> itoa(a,buffer1,10);>> buffer1[4]=0; // Stringende>> buffer1[3]=buffer1[2]; // Einer>> buffer1[2]=buffer1[1]; // Zehner>> buffer1[1]='.'; // Hurra, der PUNKT!>> itoa(a,buffer1,10);> buffer1[4]=0; // Warum hier eine 0?
Das ist das String-Ende
> buffer1[3]=buffer1[2]; // quasi verschiebe ich hier nach rechts?> buffer1[2]=buffer1[1]; // hier genauso> buffer1[1]='.'; // Hurra, der PUNKT!> buffer1[0]; //hier steht meine 8?
Richtig, bzw. was du eben beim Teilen dirch 100 rausbekommst.
relte schrieb:> wie stelle ich das an.?
Ich nehme mal an, Du hast Dich noch nicht intensiv mit Programmieren
beschäftigt, um solch eine Aufgabe zu bewältigen.
Ich schreibs mal bewusst ganz "dumm" auf, ein Fortgeschrittener würde
dafür eher eine Schleife nehmen und das viel kürzer schreiben:
1
charbuffer[10];
2
3
inta=875;
4
inttausender;
5
inthunderter;
6
intzehner;
7
inteiner;
8
intrest;
9
inti;
10
11
rest=a;
12
tausender=rest/1000;
13
rest=a-1000*tausender;
14
hunderter=rest/100;
15
rest=rest-100*hunderter;
16
zehner=rest/10;
17
rest=rest-10*zehner;
18
einer=rest/1;// einer = rest; geht auch :-)
19
20
buffer[0]=tausender+'0';
21
buffer[1]=hunderter+'0';
22
buffer[2]=',';
23
buffer[3]=zehner+'0';
24
buffer[4]=einer+'0';
25
buffer[5]='\0';
Wie gesagt: Das ist absolute Zu-Fuß-Programmierung. Ich habe auch
bewusst die Verwendung von itoa() oder anderer Funktionen weggelassen.
Aber für einen Anfänger für Dich erstmal genau das richtige, um da
reinzukommen.
Bleibt nur noch das Problem der führenden Nullen für tausender und
hunderter. Diese Denksportaufgabe überlasse ich Dir :-)
relte schrieb:> buffer1[4]=0; // Warum hier eine 0?
Stichwort: "Nullterminierter String"
https://de.wikipedia.org/wiki/Zeichenkette#CFrank M. schrieb:> Das ist absolute Zu-Fuß-Programmierung.
Aber genau so einen aufwand (und noch einiges mehr) muss auch eine
beliebige andere fertige Funktion treiben, um die Zahl umzuwandeln. Da
sieht man dann leicht, warum manche uC so "langsam" sind: sie sind
langsam, weil sie so viel rechnen müssen.
> Das ist absolute Zu-Fuß-Programmierung.
Diese Zu-Fuß-programmierte Lösung sähe übrigens für einen float-Wert
noch wesentlich aufwändiger aus...
Lothar M. schrieb:> buffer1[4]=0; // Warum hier eine 0?> Stichwort: "Nullterminierter String"
Er hätte besser
buffer1[4] = '\0';
scheiben sollen, um die Terminierung mit dem NUL-Character zu
verdeutlichen. 0 und '\0' haben zwar denselben Wert, aber '\0' ist da
viel klarer verstehen.
ok vielen dank erstmal.
ich versuch mal mein Glück. Werde glaub erstmal die
Zu-Fuß-Programmierung an mich nehmen und mich danach mit dem rest
beschäftigen.
danke
die zu Fuß Programmierung habe ich getestet. und funktioniert so weit.
Allerdings komm ich mit der Rechnung nicht klar
Frank M. schrieb:> rest = a;> tausender = rest / 1000;> rest = a - 1000 * tausender;> hunderter = rest / 100;> rest = rest - 100 * hunderter;> zehner = rest / 10;> rest = rest - 10 * zehner;> einer = rest / 1;
angenommen: rest = a = 875;
tausender = 875 / 1000; //=0,875
rest=875-1000*0,875; //=-109,375
hunderter=-109,375/100; //=-1,09375
rest=-109,375-100*-1,09375;//=-229,00390625
Meine Rechnung macht überhaupt keinen Sinn. was mache ich falsch.?
und wofür steht
Frank M. schrieb:> buffer[0] = tausender + '0';
hinten die ´0´
?
relte schrieb:> Meine Rechnung macht überhaupt keinen Sinn. was mache ich falsch.?
Du machst keine Ganzzahldivision.
So wie in der Grundschule
875 / 1000 = 0 (Rest 875)
Den Rest kannst du auch mit dem Modulo-Operator % bestimmen.
relte schrieb:> angenommen: rest = a = 875;> tausender = 875 / 1000; //=0,875> rest=875-1000*0,875; //=-109,375> hunderter=-109,375/100; //=-1,09375> rest=-109,375-100*-1,09375;//=-229,00390625>> Meine Rechnung macht überhaupt keinen Sinn. was mache ich falsch.?
Aber sowas von keinen Sinn! Du rechnest mit Gleitkomma und ignorierst
die Operatoren-Rangfolge. Die Variablen sind vom typ 'int' (=Ganzzahl)
und auch in C gilt (u.a.) Punkt- vor Strichrechnung. Probier's nochmal.
relte schrieb:> die zu Fuß Programmierung habe ich getestet. und funktioniert so> weit.>> Allerdings komm ich mit der Rechnung nicht klar>> Frank M. schrieb:>> rest = a;>> tausender = rest / 1000;>> rest = a - 1000 * tausender;>> hunderter = rest / 100;>> rest = rest - 100 * hunderter;>> zehner = rest / 10;>> rest = rest - 10 * zehner;>> einer = rest / 1;>> angenommen: rest = a = 875;> tausender = 875 / 1000; //=0,875> rest=875-1000*0,875; //=-109,375> hunderter=-109,375/100; //=-1,09375> rest=-109,375-100*-1,09375;//=-229,00390625>> Meine Rechnung macht überhaupt keinen Sinn. was mache ich falsch.?
Mach dich mal vom Taschenrechner frei. Hier geht es um
Ganzzahlarithmetik.
In Wirklichkeit ist es so:
tausender = 875 / 1000; //=0 (Rest 875)
rest=875-1000*0; //=875
hunderter=875/100; //=8 (Rest 75)
rest=857-100*8; //=75
und so weiter...
Das / bei Integerarithmetik gibt den ganzzahligen Wert der Division.
Entsprechend gibt es noch den % (Modulo) Operator der den Rest
der Division gibt. Z.B. 875 % 100 = 75. Den hätte man oben verwenden
können und ich erwähne ihn hier nur der Vollständigkeit halber.
Mit dem obigen Programm wird so Stück für Stück jede Zehnerstelle der
Ganzzahl herausgepickt und in der entsprechenden Variablen gesammelt.
Diese Zahlen können aber immer noch nicht direkt ans Display geschickt
werden, da es sogenannte ASCII-Zeichen erwartet. Da ist eine 0 eben
durch die Zahl 48 oder 0x30 oder eben '0' dargestellt. Das sind drei
Schreibweisen für ein und diesselbe Zahl.
Jetzt ist es an der Zeit nach Arithmetikoperatoren in C und ASCII zu
googeln um das Ganze abzurunden. Hinzu kommt noch die Darstellung von
Strings in C ('\0' am Ende).
>> und wofür steht>> Frank M. schrieb:>> buffer[0] = tausender + '0';>> hinten die ´0´> ?
Kurze Frage noch. Danach kümmere ich mich ;)
Wie bekomme ich den String buffer aus der Funktion takeastring() heraus,
dass die Ausgabe aufs LCD in der main() erfolgen kann?
Schließlich möchte ich nicht nur einen string anzeigen.
relte schrieb:> Kurze Frage noch. Danach kümmere ich mich ;)
Ich rate Dir dringend dazu, C systematisch mit einem Buch in der Hand zu
lernen. So, wie Du das anpackst, indem Du Programme zusammenklaubst, die
Du selber nicht verstehst, wird das nix.
> Wie bekomme ich den String buffer aus der Funktion takeastring() heraus,> dass die Ausgabe aufs LCD in der main() erfolgen kann?
Du musst den Buffer übergeben, z.B. so:
Alt:
1
uint16_ttakeastring(uint16_tvalue){
2
charbuffer[10];
1
Neu:
2
voidtakeastring(uint16_tvalue,char*buffer)
3
{
Also:
1. Die Funktion gibt nichts zurück, also ist es eine void-Funktion. Du
hast sie aber so definiert, dass sie angeblich ein uint16_t zurückgibt.
Tut sie aber nicht. Du hast bestimmt eine Warnung vom Compiler bekommen.
Regel: WARNUNGEN VOM COMPILER ERNST NEHMEN!
2. Die ehemalige Definition von buffer wandert in die Argumente-Liste,
hier als Pointer. Verstehst Du wahrscheinlich nicht, aber macht erstmal
nix. Die Definition der lokalen Variable "char buffer[10];" muss weg.
Als nächstes löscht Du den Block
1
SetFont(FONT_8_norm);
2
LCDSoftText(buffer,0,0,BLACK);
3
LCDSoftText("V",30,0,BLACK);
4
LCD_refresh();
[/c]
in takeastring(). Der wird später unten wieder eingefügt, kommt gleich.
Nächste Änderung:
Alt:
1
intmain(void){
Neu:
1
intmain(void){
2
charbuffer[10];
Jetzt wird der buffer in main() definiert.
Nächste Änderung:
Alt:
1
takeastring(spannung1);
Neu:
1
takeastring(spannung1,buffer);
2
3
SetFont(FONT_8_norm);
4
LCDSoftText(buffer,0,0,BLACK);
5
LCDSoftText("V",30,0,BLACK);
6
LCD_refresh();
[/c]
Jetzt wird der Buffer an takeastring() übergeben, damit takeastring()
diesen füllen kann. Und außerdem gibt jetzt die main()-Funktion den
Buffer weiter ans LCD.
Aber nochmal: Lerne C systematisch! Es bringt nichts, eine
Programmiersprache durch Zusammenkopieren von irgendeinem Code zu
lernen. Dabei lernst Du nichts - ganz im Gegenteil: Du wirst Dir
irgendeinen Kram zusammenreimen, der Dir beim nächsten Projekt
nullkommanix hilft.
Frank M. schrieb:> Neu:> void takeastring(uint16_t value, char * buffer)> {
So nicht!
Das ist nämlich der große Fehler in C.
Da gehört unbedingt noch die Größe von buffer mit übergeben!
Dirk B. schrieb:> Da gehört unbedingt noch die Größe von buffer mit übergeben!
Ja, selbstverständlich. Aber bei einem simplen Anfänger-Programm, wo es
um 6 Bytes geht, die zu füllen sind und der Aufruf nur ein paar Zeilen
später darunter steht, kann man das erstmal so machen. Natürlich wäre
das der nächste Schritt, bei Wiederverwendung auch die Funktion so
sicher zu machen, dass kein Buffer-Overflow stattfinden kann.
Das Forum ist nicht dafür da, dem TO eine Programmiersprache bis ins
letzte Detail beizubringen. Hier ist Hilfe zur Selbsthilfe angesagt. Von
daher ist Dein Einwurf natürlich absolut angebracht. Aber dabei sollte
man es auch belassen. Ich habe auch keine Lust, für den TO das Programm
bis ins kleinste Detail anzufertigen. Das muss er schon selber lernen.
Frank M. schrieb:> Aber bei einem simplen Anfänger-Programm,Frank M. schrieb:> Das Forum ist nicht dafür da, dem TO eine Programmiersprache bis ins> letzte Detail beizubringen.
Gerade Anfänger sehen diese Problematik nicht. Darum muss man es so früh
wie möglich erklären.
Man kann auch in dei Funktionsbeschreibung reinschreiben:
"buffer muss mindestens Platz für 10 Zeichen bieten".
Dann ist man fein raus.
Aber wer liest schon die man pages zu den Funktionen durch.
Dirk B. schrieb:> Gerade Anfänger sehen diese Problematik nicht. Darum muss man es so früh> wie möglich erklären.
Dann musst Du aber auch schon hinschreiben, wie es geht. Die bloße
Erwähnung des Problems wird dem TO leider nicht helfen. Auch wird er bei
seinem Wissensstand gar nicht wissen, wie er das umsetzen könnte.
Deshalb schrieb ich ja: Hier hilft ein C-Buch weiter. Das ersetzt keinen
Crash-Kurs über das Forum.
Wenn deine ADC-Funktion lineare Werte zwischen 0 und 32768 liefert, dann
kannst du den Messwert (zwischen 0 und 1, mit zwei Nachkommastellen) so
anzeigen:
1
printf("%.2f",(float)(readADC()/32768.0));
Berechnung und Ausgabe sind allerdings Fließkommazahlen, d.h. das ist
langsam. Wenn es auf Geschwindigkeit nicht ankommt, reicht das aber
auch.