Lieber Besucher, herzlich willkommen bei: RCLine Forum. Falls dies Ihr erster Besuch auf dieser Seite ist, lesen Sie sich bitte die Hilfe durch. Dort wird Ihnen die Bedienung dieser Seite näher erläutert. Darüber hinaus sollten Sie sich registrieren, um alle Funktionen dieser Seite nutzen zu können. Benutzen Sie das Registrierungsformular, um sich zu registrieren oder informieren Sie sich ausführlich über den Registrierungsvorgang. Falls Sie sich bereits zu einem früheren Zeitpunkt registriert haben, können Sie sich hier anmelden.

swessels

RCLine User

  • »swessels« ist der Autor dieses Themas

Wohnort: 31535 Neustadt, in der Woche HH

Beruf: Arbeitsplanung in der Luftfahzeugkomponenten - Instandsetzung

  • Nachricht senden

1

Dienstag, 23. Juni 2009, 09:35

snprintf und Fliesskommazahlen

Hallo zusammen,

ich habe ein Problem bei der Darstellung von Fliesskommazahlen mit snprintf .

Es geht um die Ausgabe der Impulsdauer eines Servoimpulses in ms auf einem LCD-Display.

Quellcode

1
2
3
4
5
6
7
....
uint16_t pulse = 1499;
char buf[6];

snprintf(buf,5,"%04d",pulse+1);
lcd_puts(buf);
....

ergibt 1500 auf dem Display.

Quellcode

1
2
3
4
5
6
7
....
uint16_t pulse = 1499;
char buf[6];

snprintf(buf,5,"%f",(double)((pulse+1)/1000));
lcd_puts(buf);
....

ergibt ? auf dem Display. Erwünscht wäre aber 1.500.

In der Doku zur AVR libc steht, dass zur Nutzung der Fliesskommafunktionalität einige Linkeroptionen zu setzen sind. Das habe ich getan, aber keine Änderung.

Ich benutze AVR Studio und winavr. Die Optionen habe ich in den Projekteinstellungen der betroffenen Datei im AVR Studio gesetzt.

Wer weiss Rat?

Danke und Gruß,
Stefan

Thallius

RCLine User

Wohnort: 58313

Beruf: Uhrmachermeister / Software Entwickler

  • Nachricht senden

2

Dienstag, 23. Juni 2009, 09:51

Hi Stefan,

kenne mich mit WIN-AVR nicht wirklich aus, bin nur eingefleischter C/C++/C# Programmierer, aber mir fallen auf Anhieb zwei Fehlermöglichkeiten auf

1) Das Casting stimmt nicht

(((double)pulse)+1)/1000)

müßte es heißen, denn sonst wird ja erst gerechnet und dann konvertiert und das Ergebnis wäre 1. Das sollte aber kein Grund sein ein "?" auszugeben

2) Eventuel solltest Du eine Stellenzahl angeben bei der Ausgabe also

"%3.2f"

damit das Ergebnis auch in deinen nur 5 Stellen langen Puffer passt.

Wenn das auch nicht geht, versuch es mal mit "%3.2g" oder mach den Puffer einfach testhalber mal größer

Gruß

Claus
T-Rex 450SE / 40-8-16 / LTG21000+LTS3100
T-Rex 250 / LTG21000+LTS3100
MPX Twinstar II
MPX Gemini / Himax Outrunner
FF10

Forum der Dortmunder Indoor Flieger

swessels

RCLine User

  • »swessels« ist der Autor dieses Themas

Wohnort: 31535 Neustadt, in der Woche HH

Beruf: Arbeitsplanung in der Luftfahzeugkomponenten - Instandsetzung

  • Nachricht senden

3

Dienstag, 23. Juni 2009, 11:16

Hallo Claus,

danke für Deine Antwort. Mit dem Casting hast Du recht, ich habe es heute Morgen nur schnell hingetippt. Im Originalquelltext stimmt es aber.

Die Ausgabe des Fragezeichens ist, wenn ich die Library Doku (avr-libc) richtig interpretiere, so gewollt. Die Funktionalität für Fliesskomma muss extra aktiviert werden, und genau das will mir nicht gelingen.

Gruß,
Stefan

Thallius

RCLine User

Wohnort: 58313

Beruf: Uhrmachermeister / Software Entwickler

  • Nachricht senden

4

Dienstag, 23. Juni 2009, 11:21

Hi Stefan,

ja da kann ich leider auch nicht helfen.
Je nach Prozessor wo das ganze nachher drauf laufen soll wäre es aber eventuell doch einfacher wenn Du bei Fixkomma bleibst und einfach die Zahlen mit 100 oder 1000 multiplizierst (2 oder 3 Stellen nach dem Komma) und dann bei der Ausgabe halt

printf("%3d."%02d",zahl/100,zahl%100)

machst ?

Gruß

Claus
T-Rex 450SE / 40-8-16 / LTG21000+LTS3100
T-Rex 250 / LTG21000+LTS3100
MPX Twinstar II
MPX Gemini / Himax Outrunner
FF10

Forum der Dortmunder Indoor Flieger

Thallius

RCLine User

Wohnort: 58313

Beruf: Uhrmachermeister / Software Entwickler

  • Nachricht senden

5

Dienstag, 23. Juni 2009, 11:27

Gerade mal ein wenig gegoogled (sowas läßt mir ja keine Ruhe)

http://www.siwawi.arubi.uni-kl.de/avr_pr…troller_net.pdf

Sollen Fließkommazahlen ausgegeben werden, muss im Makefile eine andere (größere) Version der printflib
eingebunden werden.

Vlt hilft das weiter.

Gruß

Claus
T-Rex 450SE / 40-8-16 / LTG21000+LTS3100
T-Rex 250 / LTG21000+LTS3100
MPX Twinstar II
MPX Gemini / Himax Outrunner
FF10

Forum der Dortmunder Indoor Flieger

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Thallius« (23. Juni 2009, 11:28)


swessels

RCLine User

  • »swessels« ist der Autor dieses Themas

Wohnort: 31535 Neustadt, in der Woche HH

Beruf: Arbeitsplanung in der Luftfahzeugkomponenten - Instandsetzung

  • Nachricht senden

6

Dienstag, 23. Juni 2009, 15:18

Zitat

Sollen Fließkommazahlen ausgegeben werden, muss im Makefile eine andere (größere) Version der printflib


Nochmals Danke für Deine Mühe. Das ist genau mein Problem. Die Optionen die das laut library doku machen zeigen bei mir keine Wirkung.

Für meinen aktuellen Anwendungsfall ist das nicht weiter tragisch. Ich will halt nur den intern als µs vorhandenen Wert als ms anzeigen. Das werde ich weniger speicherintensiv lösen, indem ich mittels itoa einen String erzeuge und den Dezimalpunkt hineinmogele.

Die Fliesskommavariante wird aber vielleicht wirklich mal gebraucht, und dann möchte ich schon wissen wie...

Gruß,
Stefan

swessels

RCLine User

  • »swessels« ist der Autor dieses Themas

Wohnort: 31535 Neustadt, in der Woche HH

Beruf: Arbeitsplanung in der Luftfahzeugkomponenten - Instandsetzung

  • Nachricht senden

7

Dienstag, 23. Juni 2009, 21:07

RE: snprintf und Fliesskommazahlen - Lösung

Hallo nochmal,

wer lesen kann ist klar im Vorteil.....

Um die Floating-Point-Funktionalität in winavr einzuschalten, muss dem Linker folgendes Optionspaket übergeben werden:

Quellcode

1
-Wl,-u,vfprintf -lprintf_flt -lm

Das gilt dann für alle Funktionen der printf -Familie.

ich hatte es zuerst in die Compiler-Optionen geschrieben. :wall:

Einzustellen im AVR-Studio:
Edit Configuration Options -> Custom Options -> Linker Options

ist eventuell auch für Andere interessant. Benötigt allerdings massiv Speicher.

Mein Programm macht jedenfalls jetzt was es soll: Eine Ausgabe auf dem LCD in der Form Servo: x.xxx ms

Der komplette Code:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#define F_CPU 8000000UL

#include <avr/io.h>
#include <util/delay.h>
#include "lcd.h"
#include <stdio.h>

int main(void) {

char buf[7];

DDRD |= (1<<PD4) | (1<<PD5) | (1<<PD7);


//lcd
lcd_init(LCD_DISP_ON);
lcd_clrscr();
_delay_ms(500);

//timer 1, Fast-PWM (Mode 15), Prescaler 8
OCR1A=19999;	//Periode 20ms
OCR1B=2199;		//Puls 2,1ms
TCCR1A |= (1<<COM1B1) | (1<<WGM11) | (1<<WGM10);
TCCR1B |= (1<<WGM13) | (1<<WGM12) | (1<<CS11);

//Servotester:
lcd_puts("Servo: ");
lcd_gotoxy(13,0);
lcd_puts("ms");

while(1) {
    lcd_gotoxy(7,0);
    sprintf(buf,"%5.3f",((double)(OCR1B+1))/1000);
    lcd_puts(buf);
    _delay_ms(500);
    if(OCR1B >899)
        OCR1B -=10;
    else
        break;
    }
lcd_gotoxy(0,1);
lcd_puts("Ready!");

return(1);
}


Bisher dient das nur der Überprüfung der Darstellung auf dem LCD. Soll mal ein Servotester / Drehzahlmesser usw werden. Ich weiss gibts schon....

Gruß,
Stefan

Thallius

RCLine User

Wohnort: 58313

Beruf: Uhrmachermeister / Software Entwickler

  • Nachricht senden

8

Dienstag, 23. Juni 2009, 21:52

und warum benutzt du dann nicht den Code den ich bereits weiter oben beschrieben habe ?

statt

sprintf(buf,"%5.3f",((double)(OCR1B+1))/1000);

einfach

sprintf(buf,"%5d.%03d",OCR1B/1000,OCR1b%1000);

? dann brauchst keine floats

btw: buf[7] ist für 5+3 stellen bissel wenig findest nicht auch ? Da brauchst schon nen buf[9]

Gruß

Claus
T-Rex 450SE / 40-8-16 / LTG21000+LTS3100
T-Rex 250 / LTG21000+LTS3100
MPX Twinstar II
MPX Gemini / Himax Outrunner
FF10

Forum der Dortmunder Indoor Flieger

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Thallius« (23. Juni 2009, 21:53)


9

Dienstag, 23. Juni 2009, 22:03

Und denk dran das mit der Fliesskomma Lib dein Code auch deutlich groesser wird. Irgendwann ist so ein Prozessor voll. :D
Gruss
Thomas
🖖

Vielleicht ist Wissen doch nicht die Antwort auf alles

swessels

RCLine User

  • »swessels« ist der Autor dieses Themas

Wohnort: 31535 Neustadt, in der Woche HH

Beruf: Arbeitsplanung in der Luftfahzeugkomponenten - Instandsetzung

  • Nachricht senden

10

Mittwoch, 24. Juni 2009, 07:18

Hallo Claus, Hallo Thomas,

der enorme Speicherbedarf ist klar. Es sind ca. 2kb. Ich wollte es halt so zum laufen bringen, und im Mega16 habe ich im Moment genug Platz.

Bufferlänge:
Vielleicht interpretiere ich die Doku falsch:

Zitat

fF The double argument is rounded and converted to decimal notation in the format "[-]ddd.ddd", where the number of digits after the decimal-point character is equal to the precision specification. If the precision is missing, it is taken as 6; if the precision is explicitly zero, no decimal-point character appears. If a decimal point appears, at least one digit appears before it.


Die benötigte Bufferlänge ist Vorzeichen+Dezimalpunkt+Ziffern vor dem Punkt+Ziffern nach dem Punkt +1. In meinem Fall bei einem Wertebereich von 2.100 - 0.900 7.

Zitat

An optional decimal digit string specifying a minimum field width

Bei "%f5.3" werte ich die 5 als Feldbreite, oder ist das Falsch?

Den Code mit den Integers muss ich mir erst mal verinnerlichen.

Gruß,
Stefan

Thallius

RCLine User

Wohnort: 58313

Beruf: Uhrmachermeister / Software Entwickler

  • Nachricht senden

11

Mittwoch, 24. Juni 2009, 08:53

Hi Stefan,

also, der Formatstring macht bei Fließkomma und Fixkomma andere unterschiedliche Dinge:

Bei Fließkomma ist die Zahl vor dem Punkt ist bei Fließkomma eigentlich sinnlos. Es wird immer die ganze Vorkommestelle der Zahl ausgegeben und das linksbündig im Puffer. Die Zahl hinter dem Komma gibt an auf wie viele Stellen der Nachkommateil gerundet werden soll. Das der Buffer lang genug ist das die maximale Zahl reingeht, dafür mußt Du selber sorgen. also nehmen wie mal an

double zahl=12345
char buf[4]

sprintf(buf,"%1.2f",zahl/1000)

würde trotzdem einen Stackfehler ereugen da das Ergebnis 12.34 ist und damit 5 Zeichen lang. Es muss also buf[5] deklariert werden.

Bei Fixkomma kannst du zwei verschiedene Dinge angeben:

%5d

bedeutet er schreibt die Zahl rechtsbündig an die 5te stelle. Auch hier wird aber immer die volle länge ausgegeben.

zahl=1 ergäbe die Ausgabe

____1

zahl=12 ergäbe die Ausgabe

___12
zahl=123 ergäbe die Ausgabe

__123
zahl=1234 ergäbe die Ausgabe

_1234

zahl=12345 ergäbe die Ausgabe

12345

zahl=123456 ergäbe die Ausgabe

123456

Wenn Du der Zahl im Formatstring eine oder mehrere Nullen voranstellst, dann füllt er die leesren Stellen mit einer 0 auf, Also

zahl=123

%5d

123

zahl=123

%05d

00123

Somit kannst du wenn Du die Zahl 12345 hast diese als Quasi Fließkomma ausgeben mit

zahl=12345

"%d.%03d",zahl/1000,zahl%1000

12.345

Gruß

Claus
T-Rex 450SE / 40-8-16 / LTG21000+LTS3100
T-Rex 250 / LTG21000+LTS3100
MPX Twinstar II
MPX Gemini / Himax Outrunner
FF10

Forum der Dortmunder Indoor Flieger

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Thallius« (24. Juni 2009, 08:54)


swessels

RCLine User

  • »swessels« ist der Autor dieses Themas

Wohnort: 31535 Neustadt, in der Woche HH

Beruf: Arbeitsplanung in der Luftfahzeugkomponenten - Instandsetzung

  • Nachricht senden

12

Mittwoch, 24. Juni 2009, 09:10

Hallo Claus,

vielen Dank für die ausführliche Erläuterung. Ich werde es so machen.

Aber:

Zitat

da das Ergebnis 12.34 ist und damit 5 Zeichen lang. Es muss also buf[5] deklariert werden.


Muss ich in diesem Fall nicht buf[6] nehmen, da ein String mit "\0" abgeschlossen wird?

Gruß,
Stefan

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »swessels« (24. Juni 2009, 09:10)


Thallius

RCLine User

Wohnort: 58313

Beruf: Uhrmachermeister / Software Entwickler

  • Nachricht senden

13

Mittwoch, 24. Juni 2009, 09:26

Hi Stefan,

jein,

Du must unterscheiden

also char[5] ist ja erstmal nur ein char Buffer mit fixer größe und kein string. Dem sprintf ist es egal wie groß Dein Buffer ist. Er schreibt einfach gemütlich da rein. Wenn Du also in einen buf[5] mit sprintf(buf,"%d",zahl) eine "12345" reinschreibst, dann steht die auch drin und du überschreibst das Ende nicht, allerdings steht im letzten Feld auch keine "0". Würdest du mit dem gleichen Befehlt eine "123456" reinschreiben, würde der sprintf() einfach über den Buffer hinaus schreiben und damit Deinen Stack ruinieren. Das Ergebnis wären unbrechenbare Abstürze. Schreibst Du dort "1234" rein, dann kannst Du aber auch nicht sicher sein, daß im letzten Feld eine "0" steht, da das Feld bei der Deklarierung ja nicht initialisiert wird (Wobei die meisten modernen Kompiler das Feld automatisch löschen und es deswegen meist auch funktioniert. Darauf verlassen sollte man sich allerdings nicht). Hier müßtest Du dann ein "sprint(buf,"%d\0",zahl) machen. Dann würde hinter der letzten Zahl noch eine 0 eingefügt und Du kannst das Feld wie einen String verwenden.

Die meisten Systeme bieten auch ein

snprintf()

an. Hier kannst Du die maximale Bufferlänge angeben. Das ist auf jeden Fall die sauberer Methode. Perfekt wäre es also folgendermaßen:

#define ARRAYSIZE 5

char buf[ARRAYSIZE];
memset(buf,0,ARRAYSIZE);
snprintf(buf,ARRAYSIZE-1,"Formatstring",zahl);

Gruß

Claus
T-Rex 450SE / 40-8-16 / LTG21000+LTS3100
T-Rex 250 / LTG21000+LTS3100
MPX Twinstar II
MPX Gemini / Himax Outrunner
FF10

Forum der Dortmunder Indoor Flieger

swessels

RCLine User

  • »swessels« ist der Autor dieses Themas

Wohnort: 31535 Neustadt, in der Woche HH

Beruf: Arbeitsplanung in der Luftfahzeugkomponenten - Instandsetzung

  • Nachricht senden

14

Donnerstag, 25. Juni 2009, 06:20

Hallo Claus,

nochmals vielen Dank für Deine Ausführungen. Ich glaube jetzt habe ich es verstanden. Es funktioniert jetzt alles wie es soll.

Gruß,
Stefan

15

Donnerstag, 25. Juni 2009, 08:13

Zitat

Wenn Du also in einen buf[5] mit sprintf(buf,"%d",zahl) eine "12345" reinschreibst, dann steht die auch drin und du überschreibst das Ende nicht, allerdings steht im letzten Feld auch keine "0".

Das geht sicher schief. Denn das Ergebnis ist ein String. Und der ist in C immer mit \0 abgeschlossen. Dieses \0 wird automatisch angehaengt.
Das Ergebnis waere also 12345\0. Und das ist um ein Zeichen groesser als der definierte Puffer.

"%d\0" ist ein hier sinnloser String. Die explizite Angabe von \0 verlaengert den String nur um ein Zeichen. Intern wird %d\0\0 dargestellt. Der Sting ist schon beim ersten \0 zu Ende.
Gruss
Thomas
🖖

Vielleicht ist Wissen doch nicht die Antwort auf alles

16

Mittwoch, 8. Juli 2009, 17:49

Zitat

Original von Thallius
Hi Stefan,

also, der Formatstring macht bei Fließkomma und Fixkomma andere unterschiedliche Dinge:


Nein, tut er nicht. Er gibt bei beiden die Gesamtzahl der Zeichen an, die ausgegeben werden, solange "es passt".

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

int main()
{

        int   i = 1, j = 123456;
        float f = 1.23456, g = 123456.789;

        printf( "%5d\n", i );
        printf( "%5.3f\n", f );
        printf( "%5d\n", j );
        printf( "%5.3f\n", g );

        return 0;

}

ergibt
[FONT="courier"]

Quellcode

1
2
3
4
      1
1.235
123456
123456.789
[/font]

d.h. solange die Werte klein genug bleiben werden für beide 5 Bytes plus ein Nullbyte verwendet.

@Thomas:

Richtig! Das sprintf fügt ein \0 am Ende an, der Buffer würde also am Ende überschrieben werden!

Dieser Beitrag wurde bereits 8 mal editiert, zuletzt von »DrM« (8. Juli 2009, 17:56)


17

Mittwoch, 8. Juli 2009, 21:50

Fast 25 Jahre C bleiben doch irgendwie haengen. :D
Gruss
Thomas
🖖

Vielleicht ist Wissen doch nicht die Antwort auf alles

18

Mittwoch, 8. Juli 2009, 23:07

Ja, C bleibt gut haften, aber nur ein paar Jahre Pause beim C++-proggen und ich musste nachsehen, wo das public bei der Klassendefinition hinkommt. :dumm:

19

Mittwoch, 8. Juli 2009, 23:45

:D :w
Gruss
Thomas
🖖

Vielleicht ist Wissen doch nicht die Antwort auf alles