Forum: Mikrocontroller und Digitale Elektronik Double auf Display ausgeben!


von u_SD (Gast)


Lesenswert?

Guten Morgen,

ich habe folgende Fkt. die einen Double Wert auf dem Display ausgibt:
1
unsigned char zaehler;
2
double wert;
3
4
void integertodisplay_double(double zahl, unsigned char pos)
5
{
6
    unsigned char zweitenachkommastelle = fmod(zahl*100,10);
7
    unsigned char erstenachkommastelle = fmod(zahl*10,10);
8
    unsigned char einser = fmod(zahl,10);
9
    unsigned char zehner = fmod(zahl/10,10);
10
    unsigned char hunderter = fmod(zahl/100,10);
11
    
12
    integertodisplay_1stellig(zweitenachkommastelle,pos);
13
    pos--;
14
    integertodisplay_1stellig(erstenachkommastelle, pos);
15
    pos--;
16
    integertodisplay_1stellig(einser, pos);
17
    pos--;
18
    if(zehner > 0 || hunderter > 0)
19
    {
20
    integertodisplay_1stellig(zehner,pos);
21
    pos--;
22
    }
23
    if(hunderter > 0)
24
    {
25
    integertodisplay_1stellig(hunderter, pos);
26
    }
27
28
}
29
30
int main()
31
{
32
33
integertodisplay_double(32,10); // klappt wudnerbar
34
zaehler = 16;
35
wert = zaehler*2;
36
integertodisplay_double(wert,10); // dies klappt nicht, meist wird der "Einser" falsch, nämlich gleich Null angezeit
37
38
}

Fällt jemanden auf Anhieb auf, wo hier der Wurm drinsteckt?
Gruß

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

u_SD schrieb:
> Fällt jemanden auf Anhieb auf, wo hier der Wurm drinsteckt?
Der Fehler liegt sehr wahrscheinlich in einem anderen Teil des 
Programms. Ich vermute einen amoklaufenden Pointer...

Was macht fmod()?

Sonst das übliche: welcher Controller? Welche Toolchain?

von Klaus W. (mfgkw)


Lesenswert?

Evtl. fehlen dir die kompletten float-Libs, und der Compiler kann es im 
ersten Fall schon zur Übersetzungszeit retten, weil es eine Konstante 
ist.
Evtl. math-Lib dazu linken (-lm) und/oder richtige Libs angeben.

von u_SD (Gast)


Lesenswert?

es ist ein PIC23 Controller,

fmod macht hoffentlich die "normale" Modulu Operation, habe dazu nur das 
folgende gefunden:
1
math.h:
2
#define __MPROTOL(x)  x ## f
3
#define  fmod(p1,p2) __MPROTOL(fmod)(p1,p2)

nath.h sowie FenericTypeDefs.h sind natürlich inkludiert.
Der Fehler erscheint auch eher unregelmäßig, d.h. die Ausgabe auf dem 
Display wechselt ständig, d.h. mal ist die Ausgabe von 16*2 30 und mal 
32.

Kurios

von u_SD (Gast)


Lesenswert?

auffällig ist ebenso, dass das Ergebnis immer um 2 zu klein ist, d.h. 
16*2 = 30; 15*2 = 28 ...

von m.n. (Gast)


Lesenswert?

Ein Beispiel für double->Display ist in dem Programm 'f_mess.c' zu 
finden.
Beitrag "reziproker Frequenzzähler mit STM32F4Discovery"
Die Funktion 'zeige_x()' ist zwar etwas ausführlicher, als das, was Du 
brauchst, kann aber auf das Notwendige gekürzt werden. Auch wird das 
Ergebnis in einen string gepackt, aber ein Beispiel für eine LCD-Ausgabe 
findet sich weiter unten.
Ich nehme an, daß 'fmod()' Modulo von float liefert; gibt es vielleicht 
eine Funktion 'dmod()'?

von u_SD (Gast)


Lesenswert?

danke für den ganzen Input.

Kann es nicht sein, dass ich noch ein Typcast etc. einfügen muss. Ich 
kenne mich leider nicht genau mit Compilern aus und was dieser intern 
macht:

ein
1
wert = (double)zaehler*2;

hat leider auch keine Beseerung gebracht.
Ich habe ja double = unsigned char * 2;
Wie genau verarbeitet der Compiler das?

Ich habe das Gefühl´, dass irgendwo hier der Hund begraben sein muss.

von u_SD (Gast)


Lesenswert?

Zaehler kann ich mir btw immer richtig auf dem Display ausgeben lassen, 
der Fehler ergibt sich erst bei der Multiplikation!

von Dirk B. (dirkb2)


Lesenswert?

u_SD schrieb:
> Wie genau verarbeitet der Compiler das?

bei
1
unsigned char zaehler;
2
double wert;
3
wert = zaehler*2;
 wird zaehler in ein int gewandelt (2 ist schon ein int) und dann als 
Integermultiplikation durchgeführt.
Das Ergebnis (ist auch ein int) wird dann in ein double gewandelt und 
wert zugewiesen.

bei
1
unsigned char zaehler;
2
double wert;
3
wert = (double)zaehler*2;
 werden zaehler und 2 in double gewandelt und dann als 
double-Multiplikation berechnet. Das Ergebnis wird wert zugewiesen.

von Thomas Beck (Gast)


Lesenswert?

probier mal
wert = (double)zaehler * 2.0;

von u_SD (Gast)


Lesenswert?

> wert = (double)zaehler * 2.0;

Leider ohne Erfolg, trotzdem Danke.

Ich habe mir folgendes mal etwas genauer angeguckt:
1
void integertodisplay_mehrstellig_double(double zahl, unsigned char pos)
2
{
3
    unsigned char zweitenachkommastelle = fmod(zahl*100,10);
4
    unsigned char erstenachkommastelle = fmod(zahl*10,10);
5
    unsigned char einser = fmod(zahl,10);
6
    unsigned char zehner = fmod(zahl/10,10);
7
    unsigned char hunderter = fmod(zahl/100,10);
8
    
9
    integertodisplay_1stellig(zweitenachkommastelle,pos);
10
    integertodisplay_1stellig(erstenachkommastelle, pos);
11
    integertodisplay_1stellig(einser, pos);
12
    if(zehner > 0 || hunderter > 0)
13
    {
14
    integertodisplay_1stellig(zehner,pos);
15
    }
16
    if(hunderter > 0)
17
    {
18
    integertodisplay_1stellig(hunderter, pos);
19
    }
20
21
}

Hierzun hat Herr Brunegg in einem vorherigen Thread mal das folgende 
geschrieben:

> Die Zahl mit 10 multiplizeren, die Zerlegung auf die Einerstelle
> durchführen :-)
>
> Aber Achtung: gegebenenfalls muss bzw. sollte man vorher noch runden.
> Denn 0.1 kann beispielsweise im Rechner nicht gespeichert werden,
> sondern liegt zb als 0.0999999 vor. printf berücksichtigt das und rundet
> entsprechend, so dass die Ausgabe wieder 0.1 lautet, obwohl die im
> Rechner so gar nicht vor liegen.

Was genau hat es damit auf sich?
Wo genau muss ich runden und mit welchen Befehl wäre dies möglich?

Vielen Dank auch an Dirk. Die Ausführungen haben mir sehr geholfen!

von u_SD (Gast)


Lesenswert?

In etwa so etwas?
1
unsigned char erstenachkommastelle = ceil(fmod(zahl*10,10));

von Eric B. (beric)


Lesenswert?

Wohl eher so:
1
void integertodisplay_mehrstellig_double(double zahl, unsigned char pos)
2
{
3
    /* Zuerst das ganze in ein integer umwandeln */
4
    unsigned long longzahl = (long) (zahl * 1000.0);
5
6
    char ziffern[8];
7
    char idx;
8
9
    /* Zerlege longzahl in ziffern - umgekehrte Reihenfolge! */
10
    for(idx = 0; idx < 8; idx ++)
11
    {
12
        ziffern[idx] = longzahl % 10;
13
        longzahl /= 10;
14
    }
15
    
16
    /* Ziffern ausgeben */
17
    for(idx = 0; idx < 8; idx ++)
18
    {
19
        integertodisplay_1stellig(ziffern[7 - idx], idx);
20
    }
21
}
Ohne Gewähr ;-)

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
Noch kein Account? Hier anmelden.