Forum: Compiler & IDEs DA wandler 16bit Soll-Wert an LCD ausgeben


von Seb (Gast)


Lesenswert?

Huhu zusammen,

ich bins nochmal, ich habe nochmal eine Frage da ich nun irgendwie 
durcheinander gekommen bin mit meinem Code :/.

Und zwar steuer ich einen 16bit-DA Wandler per SPI an 2 Bytes werden 
übertragen und ich messe auch den richtigen Spannungswert. so nun möchte 
ich die beiden Bytes die ich an den DA wandler setze ins Verhältniss der 
Spannung setzen (einen Soll-Wert)

Der DA Wandler gibt bei 0xFFFF 2,5 Volt aus dementsprechend 0V bei 
0x0000
So nun wollte ich das auf einem LCD ausgeben dafür sieht meine Rechnung 
so aus. Der gesendete Wert ist im uint_t16 "Data" register gespeichert.
Die Rechnung:
((((25 * Data) / 65536) /10))

eigentlich könnte die /10 gestrichen werden und die 25 durch 2,5 ersetzt 
werden, aber ich wollte das ohne Kommazahlen machen da hatte ich 
probleme mit.

So die Rechnung da oben wäre für die Vorkomma stelle, welche auch 
korrekt angezeigt wird.

Nur bei der Nachkomma stelle hapert es.
Hier der Code
1
set_cursor(0,4);
2
char F[200];
3
sprintf( F,"D: %u.%03u",(((25 * Data) / 65536) /10)),
4
                                     (((25 * Data) / 65536) /10)%1000;
5
lcd_string( F );

Bei der Nachkomma zahl wird mir immer nur eine 1 ausgegeben.
Ich denke das da irgendwas mit der Berechnung nicht stimmt oder das 
Format falsch ist. Aber ich komm nicht drauf was falsch ist :/

Könnte mir da jmd auf die Sprünge helfen? Die die %1000 sagt doch aus 
das 3 Nachkommastellen ausgegeben werden sollen oder?


Schönen Gruß
Sebastian

von Karl H. (kbuchegg)


Lesenswert?

Wenn Data ein Wert 0xFFFF, also den größtmöglichen Wert für eine 16Bit 
Variable hat, wird dir

25 * Data

einen Überlauf produzieren.

Um den zu umgehen, musst du die ganze Berechnung auf eine uint32 
Berechnung hochhieven.
1
sprintf( F,"D: %u.%03u",(((25 * Data) / 65536) /10)),
2
                                     (((25 * Data) / 65536) /10)%1000;

Rechne dir den Wert nur einmal aus.
1
  uint16_t Spannung;
2
3
  Spannung = (25 * (uint32_t)Data) / 65536;
4
5
  sprintf( %u.%03u", Spannung / 10, Spannung % 10 );

Nun ist es natürlich nicht besonders sinnvoll, hier

  Spannung = (25 * (uint32_t)Data) / 65536;

auf 32 Bit Arithmetik um zuschwenken, wenn dann sowieso durch 65536 
dividiert wird. 25 / 65536 kannst du auch mit einem Taschenrechner 
ausrechnen:
1
  Spannung = Data / 2621;

liefert für deine Zwecke dasselbe Ergebnis und du brauchst keine 32 Bit 
Arithmetik

von Seb (Gast)


Lesenswert?

Hi Karl Heinz-

So ich habe mal grade das Programm umgeschrieben mit (uint16_t)Data.

Funktionieren tut es noch nicht - aber was mich stutzig macht ist das
1
set_cursor(0,2);
2
        char E[200];
3
        sprintf( E,"U= %u.%03u V",Data_test /10, Data_test %10 );
4
        lcd_string( E );
auf dem LCD ein "1.000 V" ausgibt aber der Code:
1
set_cursor(0,4);
2
        char Out[80];
3
        sprintf( Out, "Test= %03u.",Data_test %10 );
4
        lcd_string( Out );
gibt ein "002" aus

Zwischen dem "Data_test %10" von oben und unten besteht doch kein unter 
schied oder?

Also es Funktioniert noch nicht ganz aber ich mach bestimmt noch nen 
Fehler vieleicht fällt dir/euch ja etwas auf.

Schönen Gruß

Seb

von Karl H. (kbuchegg)


Lesenswert?

Seb schrieb:

> Funktionieren tut es noch nicht - aber was mich stutzig macht ist das
>
>
1
> set_cursor(0,2);
2
>         char E[200];
3
>         sprintf( E,"U= %u.%03u V",Data_test /10, Data_test %10 );
4
>         lcd_string( E );
5
>
> auf dem LCD ein "1.000 V" ausgibt aber der Code:

Mein Fehler.
Ich hab nicht aufgepasst.

Das sollte eigentlich heissen
>         sprintf( E,"U= %u.%01u V",Data_test /10, Data_test %10 );

                             **
Du hast ja nur 1 'Nachkommastelle', wenn du den Rest mittels %10 nimmst.

>
1
> set_cursor(0,4);
2
>         char Out[80];
3
>         sprintf( Out, "Test= %03u.",Data_test %10 );
4
>         lcd_string( Out );
5
>
> gibt ein "002" aus

Das ist aber in der Tat seltsam.
Lass dir Data_test ohne Manipulationen direkt ausgeben. (Welchen 
Datentyp hat Data_test eigentlich?)

von Seb (Gast)


Lesenswert?

Hi,

so

so siehts im moment aus: Data wird am Anfang fest mit einem Dezimalwert 
von "32768" geladen also genau die hälfte von 65536.
Data und Data_test sind beides uint_16t
1
  Data_test = Data / 2621;
2
                      
3
        set_cursor(0,2);
4
        char E[200];
5
        sprintf( E,"U= %u.%03u V",Data_test /10, Data_test %10 );
6
        lcd_string( E );
7
        
8
        set_cursor(0,3);
9
        char G[200];
10
        sprintf( G,"Data= %u.",Data);
11
        lcd_string( G );
12
13
        
14
        set_cursor(0,4);
15
        char Out[80];
16
        sprintf( Out, "Test= %u.",Data_test );
17
        lcd_string( Out );

auf meinem Display sehe ich dann
"
U= 1.002 V
Data= 32768.
Test= 12.
"

aber das im Data_test eine 12 steht sollte ja eigentlich richtig sein 
denn wenn ich die 32768 durch 2621 teile dann ergibt das ja eine 12,502 
und die 502 werden ja dann nicht ins gespeichert sondern nur die 12.

Ich teste mal weiter.

Danke für deine Hilfe.

Gruß

Seb

von Karl H. (kbuchegg)


Lesenswert?

Seb schrieb:
> "
> U= 1.002 V
> Data= 32768.
> Test= 12.
> "

>
> aber das im Data_test eine 12 steht sollte ja eigentlich richtig sein

Und auf dem Display sollte eigentlich "U= 1.2 V" stehen.

Ich sagte schon, ich habe in der sprintf Formatierung nicht darauf 
geachtet, wieviele Kommastellen du haben willst.
1
      sprintf( E,"U= %u.%01u V",Data_test /10, Data_test %10 );

Willst du 2 Nachkommastellen, dann muss in Data_test schon das 10-fache 
rauskommen (also durch 262 dividieren und nicht durch 2621) und dafür 
dann in der Ausgabe
1
      sprintf( E,"U= %u.%02u V",Data_test /100, Data_test %100 );

von Seb (Gast)


Lesenswert?

Moin,

Ich glaube ich hab nen Fehler gefunden und zwar wollte mich mir einfach 
mal eine uint_32t test; Zahl auf dem LCD ausgegeben.


Ich habe Dafür einfach mal ins test register eine 0xFFFFFFFF 
reingeschoben und dann am LCD ausgegeben aber da kommt dann einfach ein 
0xFFFF raus also nur 65535 also sollte das uint_16t die grötmögliche 
Zahl sein die die Sprintf Funktion verarbeiten kann

Deinn wenn ich in dem test register mit der Dezimalzahl 70000 Lade und 
dann in der sprintf zeile "test / 2" schreibe dann wird korrekt 35000 
angezeigt.

ich muss noch mal weiter testen =)

schöne grüße
Seb

von Karl H. (kbuchegg)


Lesenswert?

Seb schrieb:

> Ich habe Dafür einfach mal ins test register eine 0xFFFFFFFF
> reingeschoben und dann am LCD ausgegeben aber da kommt dann einfach ein
> 0xFFFF raus also nur 65535 also sollte das uint_16t die grötmögliche
> Zahl sein die die Sprintf Funktion verarbeiten kann

Das ist Unsinn und ergibt auch logisch gesehen keinen Sinn. Wenn in 
einer Sprache ein Datentyp standardmässig existiert, muss es auch 
Ein/Ausgabefunktionen dafür geben. Alles andere wäre ein 
Schildbürgerstreich.

Viel wahrscheinlicher ist es, dass du ganz einfach den falschen 
Formatspezifizierer für einen uint32_t genommen hast.

Womit wir wieder mal beim Thema wären:
Eine Sprache wie C in den Details mittels 'Versuch und Irrtum' erlernen 
zu wollen, funktioniert einfach nicht.  -> Unterlagen müssen her.

Und auch ein 2-tes Thema, das auch immer wieder auftritt:
Es reicht einfach nicht, bei der Fehlersuche nur ein paar ausführbare 
Anweisungen zu präsentieren. Mindestens genauso wichtig sind die 
Datentypen der beteiligten Variablen, weil sie die genau Funktion der 
Codesequenz modifizieren bzw. erst im Detail festlegen.

von Seb (Gast)


Lesenswert?

mhm das ist aber merkwürdig

bei diesem Code
1
AD_math = (1024 ) ;
2
3
        set_cursor(0,3);
4
        char A[10];
5
        sprintf( A,"Uist= %u, %03u",AD_math /1000, AD_math %1000  );
6
        lcd_string( A );

bekomme ich auf dem LCD "Uist= 1. 000" angezeigt

Aber nur noch mal für mich zum verständniss ich lade das AD_math mit 
1024 und im sprintf befehl teile ich AD_math mit 1000 das ergibt dann 
1,024 und die nachkomma zahl fällt weg und dann kommt der Modulo 
Operator mit AD_math /1000 und gibt nur die Nachkomma stelle 024 aus 
oder ?

denn wenn ich den gleichen Code wie oben nur die sprintf zeile ist 
anders eingebe:
1
sprintf( A,"Uist= %03u",AD_math %1000  );

erhalte ich wie gewünscht meine "Uist= 024" auf dem Display.

Irgendwie scheint das dem sprintf befehl "zuviel" arbeit zu sein.

ich forsche mal weiter :P

von Seb (Gast)


Lesenswert?

Hallo Karl Heinz,

Ich kann den ganzen Code gerne posten, das sollte bei der "normalen" 
Fehlersuche auch üblich sein aber ich fühle mich eigentlich schon so 
sicher das wenn ich am Anfang bei meinen Datentyp Deklarationen:
1
uint8_t foo;
2
uint16_t AD_wert;
3
uint32_t AD_math;
4
uint8_t sw_old;
5
uint8_t sw_new;
6
uint8_t sw_comp;
7
int8_t sw_test;

eigentlich davon ausgegangen bin das AD_math halt den Datentyp uint32_t 
hat. wenn ich den nämlich auf uint8_t setzte dann ist die maximal 
ausgabe auch nur 256.

von Sebastian B. (sebastian86)


Lesenswert?

so mal grade eingeloggt damit ich die antworten auch bearbeiten kann.

Ich lese mir auch grade den befehl sprintf mal hier durch. Das sieht 
eigentlich sehr ausführlich aus.

http://www.cplusplus.com/reference/clibrary/cstdio/sprintf/

Vielen Dank aber schonmal für die bisherigen Bemühungen ;).


Gruß

Seb


//EDIT Fehler gefunden
sprintf
%[flags][width][.precision][length]specifier
1
length  description
2
h  The argument is interpreted as a short int or unsigned short int (only applies to integer specifiers: i, d, o, u, x and X).
3
l  The argument is interpreted as a long int or unsigned long int for integer specifiers (i, d, o, u, x and X), and as a wide character or wide character string for specifiers c and s.
4
L  The argument is interpreted as a long double (only applies to floating point specifiers: e, E, f, g and G).

von Karl H. (kbuchegg)


Lesenswert?

Seb schrieb:

> eigentlich davon ausgegangen bin das AD_math halt den Datentyp uint32_t
> hat.

Das weißt du, weil du vor deinem Montior sitzt bzw. du das geschrieben 
hast. Ich weiß es aber nicht. Ich sehe von deinem Programm nur das, was 
du postest. Trotzdem versuche ich dir zu helfen. Je unvollständiger die 
Informationen die du mir gibst aber sind, desto mehr muss ich Wissen 
durch Raten ersetzen. Bis irgendwann der Punkt erreicht ist, an dem 
meine Hilfe genauso zuverlässig wie das tagliche Horoskop in der Bild 
ist.

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.