Kommazahl auf Display anzeigen

Gast #4703985
Lesenswert?

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
Angehängte Dateien:
#4703989
Lesenswert?

@ 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
Moderator (Firma: Titel) Persönliche Seite #4703991
Lesenswert?

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...
Gast #4703999
Lesenswert?

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.
Moderator (Firma: Titel) Persönliche Seite #4704018
Lesenswert?

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.
Moderator (Firma: Titel) Persönliche Seite #4704039
Lesenswert?

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.?
1
itoa(a,buffer1,10);
2
buffer1[4]=0;          // Stringende
3
buffer1[3]=buffer1[2]; // Einer
4
buffer1[2]=buffer1[1]; // Zehner
5
buffer1[1]='.';        // Hurra, der PUNKT!
Gast #4704045
Lesenswert?

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:
1
memcpy(ArrayZiel, ArrayQuelle, sizeof(ArrayQuelle));
2
oder
3
memmove (str+3,str+2,4);
Gast #4704048
Lesenswert?

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?
Gast #4704053
Lesenswert?

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.
Moderator Persönliche Seite #4704058
Lesenswert?

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
char buffer[10];
2

3
int a = 875;
4
int tausender;
5
int hunderter;
6
int zehner;
7
int einer;
8
int rest;
9
int i;
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 :-)
Moderator (Firma: Titel) Persönliche Seite #4704060
Lesenswert?

relte schrieb:
> buffer1[4]=0;          // Warum hier eine 0?
Stichwort: "Nullterminierter String"
https://de.wikipedia.org/wiki/Zeichenkette#C

Frank 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...
Gast #4704125
Lesenswert?

1
void AdcValOut (uint16_t AdcValue)
2
{
3
    uint8_t AdcValArray [5];                              // Integer Array
4
    uint8_t m = 4;                                        // Schleifenzähler für Ausgabe
5

6
    do  {
7
        AdcValArray [m] = '0' + AdcValue %10;             // Berechnung der einzelnen Stellen sowie
8
        AdcValue /= 10;                                   // Wandlung nach ASCII und abspeichern im
9
    } while (m--);                                        // Array
10
    while (m != 3)  {                                     // Anzahl der auszugebenden Stellen = 4
11
        DeineDisplayZeichenAusgabe (AdcValArray [++m]);   // Integer Wert ausgeben
12
        if (m==0) DeineDisplayZeichenAusgabe ('.');       // Dezimalpunkt setzen
13
    }
14
}

Kleines Schleifchen drumherum und dann wird aus Frank M code dieser 
Schnipsel.
Gast #4704366
Lesenswert?

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´
?
#4704424
Lesenswert?

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.
Gast #4704431
Lesenswert?

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´
> ?
Gast #4704677
Lesenswert?

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.
Angehängte Dateien:
Moderator Persönliche Seite #4704704
Lesenswert?

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_t takeastring(uint16_t value){
2
  char buffer[10];
1
Neu:
2
void takeastring(uint16_t value, 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
int main(void) {

Neu:
1
int main(void) {
2
  char buffer[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.
Moderator Persönliche Seite #4704896
Lesenswert?

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.
#4705060
Lesenswert?

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.
Moderator Persönliche Seite #4705088
Lesenswert?

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.
#4705346
Lesenswert?

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.

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