double Ausgabe

Gast #5993765
Lesenswert?

Hallo,


bei der Ausgabe der Temperatur eines DS18b20 stehe ich vor der 
Problematik die Nachkommastellen auszugeben, laut diesem Beitrag:
https://stackoverflow.com/questions/37815771/snprintf-not-working-as-expected-with-avr-gcc

Fehlten mir: -Wl,-u,vfprintf -lprintf_flt -lm

diese habe ich hier hinzugefügt:
CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm

(Die Makefile kommt hier aus dem Forum, minimal verändert)


Hier der Code zur Ausgabe, es wird ein "?" gesendet. USART_end() sendet 
'\r\n'.

        char zeichen[15];
        double myFloat2 = 2.2345;

        sprintf(zeichen, "%.4f", myFloat2);
        for (char *p = zeichen; *p; p++) {
            USART_transmit(*p);
        }
        USART_end();


Der rest vom Code funktioniert, ein USART_transmit('a'); sendet dieses 
ohne Probleme.
Sind die "Linker" Optionen richtig in den CFLAGS?
#5993879
Lesenswert?

Dieses Gehampel mit der Float/Double-Ausgabe hab ich umgangen indem ich 
die Funktion:
1
...
2
#include <stdlib.h>
3
...
4
dtostrf(float_variable,
5
        zahl_aller_stellen_incl_komma,
6
        zahl_der_nachkommastellen,
7
        stringvariable);
8
...
benutze. Vielleicht hilft das dir auch.
Gast #5993905
Lesenswert?

neuer_benutzer55 schrieb:
> bei der Ausgabe der Temperatur eines DS18b20 stehe ich vor der
> Problematik die Nachkommastellen auszugeben

Mit Float (single Precision) Datenformat hast du 24 Bit für den 
Zahlenwert. Ein DS18B20 liefert dir maximal 12 Bit Auflösung bei einer 
Genauigkeit von 0.5K, i.e. 8 1/2 Bit.

Was versprichst du dir dabei von der Verwendung von Double?
Gast #5994208
Lesenswert?

@Dirkb
CFLAGS += -Wl,-u,vfprintf
und:
LDFLAGS += -lprintf_flt -lm

so funktioniert es leider auch nicht :(
makefile: https://bpaste.net/show/WQn0

@Wolfgang
Bisher habe ich diesen Code für die Ausgabe verwendet:
1
        int temp;
2
        int temp2;
3
        temp2 = temp / 16;
4
        char buf[10];
5
        itoa(temp2, buf, 10);
6
       
7
        for (char *p = buf; *p; p++) {
8
            USART_transmit(*p);
9
        }
10
        USART_end();

Warum durch 16 teilen? Weil dieses Library:
https://github.com/Jacajack/avr-ds18b20/wiki

den Wert mit 16 multipliziert, für eine einfachere Ausgabe weil die 
Werte im Register des Sensors anders liegen sonst.

Durch die Integer Divsion kann natürlich auch nur ein Integer Wert 
angezeigt werden. Darum bin ich auf double / float gekommen.



Zweiter Versuch mit double:
1
        volatile double db1;
2
        db1 = temp / 16;
3
        char buf[20];
4
        dtostrf(db1, 4, 3, buf);
5
        for (char *p = buf; *p; p++) {
6
            USART_transmit(*p);
7
        }
8
        USART_end();

Das liefert jetzt 20.000, 21.000 aber nie Werte dazwischen.

Wenn ihr da ein besserers Library habt immer her damit.
#5994215
Lesenswert?

neuer_benutzer55 schrieb:
> CFLAGS += -Wl,-u,vfprintf
> und:
> LDFLAGS += -lprintf_flt -lm

neuer_benutzer55 schrieb:
> CFLAGS += -Wl,-u,vfprintf
> und:
> LDFLAGS += -lprintf_flt -lm
>
> so funktioniert es leider auch nicht :(
> makefile: https://bpaste.net/show/WQn0

Zeile 121 auskommentieren hätte gereicht.

Gefällt dir der Zahlenwert von sprintf nicht, oder kommt nur wirres Zeug 
raus?
Gast #5994225
Lesenswert?

@Dirkb: Ahja, stimmt. 121 ist der passende Ort.

Die Zahlen können von meinem Bluetooth Terminal interpretiert werden und 
passen auch, aber es wundert mich das ich bisher nur 20.000 oder 21.000 
gesehen habe, in den Beispielen im Datenblatt gibt es auch; +25.0625.
Also 4 Nachkommastellen Präzision, da müsste ja irgendwann mal ein 
anderer Wert gekommen sein.
#5994396
Lesenswert?

Wolfgang schrieb:
> Trotzdem ist es Käse, wenn double ≠ IEEE double precision ist, weil
> man dann keine portierbare Möglichkeit hat, gesichert mit /IEEE double
> precision/ zu rechnen.

IEEE Unterstützung wird auch erst seit C11 gefordert.

Viele Systeme unterstützten das auch vorher.
Nur sollte man bei C nicht von dem Verhalten des eigenen System auf die 
Allgemeinheit schließen.
#5994467
Lesenswert?

Auf einem 8-Bit uC hatte ich es mal sinngemäß so gemacht (hier als 
PC-Version zum ausprobieren)
1
#include <stdint.h>
2
#include <stdio.h>
3
#include <stdlib.h>
4

5
int
6
main (int argc, char *argv[])
7
{
8
   char    *bp, buf[42];
9
   int      bc, len;
10
   int32_t  temp;
11

12
   if (argc != 2) {
13
      printf ("usage: %s DS18B20-Datenwort\n", argv[0]);
14
      exit (EXIT_FAILURE);
15
   }
16
   temp = strtol (argv[1], NULL, 0);
17

18

19
   if (temp & 2048) {
20
      temp |= 0xfffff000UL;
21
   }
22
   len = snprintf (buf, sizeof buf, "%+06d", temp * 625);
23
   bp = buf;
24
   for (bc = 0; bc < 9 - len; bc++) {
25
      putchar (' ');
26
   }
27
   for (bc = 0; bc < len - 4; bc++) {
28
      putchar (*bp++);
29
   }
30
   putchar ('.');
31
   for (bc = 0; bc < 4; bc++) {
32
      putchar (*bp++);
33
   }
34
   putchar ('\r');
35
   putchar ('\n');
36
   return 0;
37
}
Gast #5994528
Lesenswert?

Wenn es dir nur um die Nachkommastellen, die durch die Division mit 16 
entstehen, geht, kannst du das auch ohne float/double erreichen:
1
    char buf[12];
2
    unsigned t = abs(temp);
3
    sprintf(buf, "%u.%03u", t/16, t%16 * 1000 / 16);
4
    if (temp < 0)
5
        USART_transmit('-');
6
    USART_transmit_string(buf);

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