Hallo zusammen! Kann mir jemand 'mal ein paar Tipps zu den Zahlentypen geben, die im AVR-GCC verwendet werden? Ich habe beispielsweise gelesen, dass float und double beide 32 Fließkommazahlen sind. Gibt es irgendwo eine Tabelle oder etwas vergleichbares, in der alle für den GCC möglichen (sinnvollen) Zahlentypen, ihre Bitlänge und ihre Eigenschaften drin stehen? Ich habe ein kleines Programm zur ADC-Wandlung geschrieben und weiß nie genau, mit welchen Zahlentypen ich rechnen soll. Dieses Beispiel hier funktioniert glücklicherweise. Aber eher durch Zufall. Hätte hier auch itoa funtioniert?: char U[9]; char I[9]; uint16_t j; for (j=0; j<800; j++) { dtostrf( (ErgebnisMatrix[j][0]/400.0)*1.9960, 8, 4, U ); } wobei ich vorher uint16_t volatile(ErgebnisMatrix[800][2]); deklariert habe. Das Programm gibt später noch die Zahlen auf die serielle Schnittstelle aus. Deshalb die Wandlung. Wäre sehr dankbar, um ein paar hilfreiche Tipps. Beste Grüße
David P. wrote: > Ich habe ein kleines Programm zur ADC-Wandlung geschrieben und weiß nie > genau, mit welchen Zahlentypen ich rechnen soll. Du benutzt den Datentyp, der für deinen Bedarf gerade noch ausreicht. Wobei auf einem AVR gilt: Wenn möglich vermeide float oder double und versuche nur mit ganzen Zahlen auszukommen. Wenn es denn unbedingt Kommazahlen sein müssen, dann geht auch ein Trick den wir alle gerne benutzen: Anstatt 3.45 Euro plus 2.87 Euro zu rechnen (das sind Kommazahlen), kann man auch rechnen: 345 Cent plus 287 Cent (das sind jetzt ganze Zahlen) Hintergrund: Mit Fliesskommazahlen zu rechnen, ist für einen µC sehr aufwändig wenn er keine FPU besitzt. > Dieses Beispiel hier > funktioniert glücklicherweise. Aber eher durch Zufall. > Hätte hier auch itoa funtioniert?: Kommt drauf an was du unter 'funktioniert' verstehst. itoa - i to a - integer to ascii Wie der Name schon sagt, wandelt itoa einen int in seine ASCII Reräsentierung um. Nun kann man natürlich auch aus den meisten float einen Integer machen. Man verliert halt alle Nachkommastellen und wenn der float vom Zahlenwert her zu gross ist, dann gibt es ganz einfach keinen entsprechenden int dafür. Auf einem AVR gilt char 8 Bit int 16 Bit long 32 Bit float 32 Bit double 32 Bit die ersten 3 sind die Ganzzahltypen oder Integertypen. Die lezteren beiden sind die Fliesskommatypen, wobei es beim gcc auf einem AVR keinen Unterschied zwischen float und double gibt (und man sie vermeiden möchte, wo nur geht) Ich weis nicht was ich jetzt noch schreiben soll, es gibt noch eine Unmenge über diese Basisdatentypen zu erzählen, aber vieles davon ist sehr speziell und sprengt den Umfang eines Forums bei weitem.
Was bedeutet denn, wenn hier jemand in einem AVR-PRogramm uint8_t oder uint16_t benutzt? ISt das genau das selbe wie das benutzen von char bzw. int ? Wofür steht eigentlich dabei das _t ? Da ich in meinem Array Zahlen vom Typ uint16_t benutzt habe, ist doch die Funktion dtostrf zur Umwandlung von double to string überdimensioniert, oder? Ich hätte also atoi verwenden können. Aber dann darf ich sicher keine Kommas mehr schreiben und müsste in millivolt rechnen, wenn ich das richtig verstanden habe. In meiner bisher funktionierenden Version war das Ergebnis, was auch der Seriellen Schnittstelle kam nämlich in Volt und schon als Kommazahl.
>Auf einem AVR gilt > char 8 Bit > int 16 Bit > long 32 Bit > float 32 Bit > double 32 Bit Das ist so nicht richtig, sondern beim GCC. Der IAR-Compiler lässt auch 64 Bit zu. MW
Hi, bleibt nur noch den long long myvariable = 64 Bit lange Variable (auch unsigned möglich) zu erwähnen. Robert
Michael Wilhelm wrote: >>Auf einem AVR gilt > >> char 8 Bit >> int 16 Bit >> long 32 Bit >> float 32 Bit >> double 32 Bit > > Das ist so nicht richtig, sondern beim GCC. Der IAR-Compiler lässt auch > 64 Bit zu. Schon richtig. Aber wir sind hier im GCC Forum :-)
ok danke Michael. Aber ich benutze den GCC vom AVR-Studio. Wo steckt in so einer Zahl denn das Vorzeichen?
Hi, u am Anfang = unsigned = kein Vorzeichen Zahl (z.B. 16) = Länge in Bits Ansonsten: schau mal hier vorbei, da sind die Datentypen mit Ihren Wertebereichen aufgeführt: http://www.nongnu.org/avr-libc/user-manual/group__avr__stdint.html Robert
David P. wrote: > Was bedeutet denn, wenn hier jemand in einem AVR-PRogramm uint8_t oder > uint16_t benutzt? ISt das genau das selbe wie das benutzen von char bzw. > int ? uint8_t u int 8 _t unsigned int mit 8 Bit Datentyp uint16_t u int 16 _t unsigned int mit 16 Bit Datentyp > Wofür steht eigentlich dabei das _t ? Als Kennung, dass es sich bei diesem Wort um einen Datentyp handelt und nicht etwa um den Namen einer Variablen. > > Da ich in meinem Array Zahlen vom Typ uint16_t benutzt habe, ist doch > die Funktion dtostrf zur Umwandlung von double to string > überdimensioniert, oder? In deinem Array stehen zwar uint16_t Werte. Das ist schon richtig. Aber die gibst du ja nicht aus. Was du ausgibst ist vielmehr das Ergebnis der Berechnung: (ErgebnisMatrix[j][0]/400.0)*1.9960 und da da durch 400.0 (beachte den Fliesskommapunkt) dividierst und mit 1.9960 multiplizierst, ist das Ergebnis dieser Berechnung kein uint16_t mehr sondern ein double. Und um double in eine ASCII Form zu überführen, ist dtostrf() ein mögliches Werkzeug. > Ich hätte also atoi verwenden können. Hättest du können. Nur wenn bei der Berechnung 2.34 herauskommt und du auf der Ausgabe nur 2 siehst, wirst du nicht so glücklich damit sein. > Aber dann darf ich sicher keine Kommas mehr schreiben und müsste in > millivolt rechnen, wenn ich das richtig verstanden habe. In meiner > bisher funktionierenden Version war das Ergebnis, was auch der Seriellen > Schnittstelle kam nämlich in Volt und schon als Kommazahl. Genau. Allerdings musst du dich ja nicht mit einer Ausgabe von Millivolt zufrieden geben. Mann kann ja immer noch die Zahl durch 1000 dividieren, dann einen '.' ausgeben und anschliessend den Rest bei einer Division durch 1000 ausgeben (allerdings die führenden Nullen dabei nicht vergessen). So wird dann aus 2387 Millivolt eine Ausgabe von * zuerst die 2 (weil ja 2387 / 1000 genau 2 ergibt) * dann ein '.' * und zum Schluss den Rest bei der Division ( 2387 % 1000 ergibt 387) und schon sieht dein Benutzer: 2.387 und denkt sich: Oha, 3 Nachkommastellen, wie praktisch!
Danke Robert! Aber leider finde ich diese Erklärungen von den .h dateien immer so furchtbar kompliziert. Da steht dann beispielsweise #define INT8_MAX 0x7f #define INT8_MIN (-INT8_MAX - 1) #define UINT8_MAX (__CONCAT(INT8_MAX, U) * 2U + 1U) Was sagt mir das alles? Ich kenne ja .h Dateien. Aber die sehen immer viel übersichtlicher aus. Da sind dann einfach die ersten Zeilen meiner Funktionsdefinitionen drin. Aber hier in dieser Beschreibung stehen Dinge,mit langen Unterstrichen usw. Das versteh ich noch nicht so richtig.
David P. wrote: > Danke Robert! > > Aber leider finde ich diese Erklärungen von den .h dateien immer so > furchtbar kompliziert. > Da steht dann beispielsweise > > #define INT8_MAX 0x7f > #define INT8_MIN (-INT8_MAX - 1) > #define UINT8_MAX (__CONCAT(INT8_MAX, U) * 2U + 1U) > > Was sagt mir das alles? > > Ich kenne ja .h Dateien. Aber die sehen immer viel übersichtlicher aus. > Da sind dann einfach die ersten Zeilen meiner Funktionsdefinitionen > drin. Aber hier in dieser Beschreibung stehen Dinge,mit langen > Unterstrichen usw. Das versteh ich noch nicht so richtig. Die rechten Teile der #define musst du fürs erste nicht verstehen Was wird wohl ein INT8_MAX sein? Welche Teile stecken da drinnen? Da ist die Rede von INT 8 und MAX Also wird das wohl die maximale Zahl sein, die mit einem Integer Datentyp mit 8 Bit gerade noch darstellbar ist. Was wird dann UINT8_MAX sein? U wie unsigned INT wie integer 8 wie 8 Bit MAX wie Maximalwert
Achso. Da stehen die Zahlenwerte in HEX angegeben. Ok. Also int8 geht von -128 bis 127 Aber das #define UINT8_MAX (__CONCAT(INT8_MAX, U) * 2U + 1U) ist wirklich etwas merkwürdig.
David P. wrote: > Achso. Da stehen die Zahlenwerte in HEX angegeben. Ok. Also int8 geht > von -128 bis 127 > > Aber das #define UINT8_MAX (__CONCAT(INT8_MAX, U) * 2U + 1U) ist > wirklich etwas merkwürdig. Sagte ichs schon: Das muss man fürs erste nicht verstehen :-) Aber wenns interessiert: Zerpflücken wir das Teil doch mal: (__CONCAT(INT8_MAX, U) * 2U + 1U) Das soll offensichtlich der Quelltext für eine Berechnung sein. (Der Präprozessor rechnet nicht, der Präprozessor macht Textersetzungen. Aber das Ergebnis von Textersetzungen kann natürlich ein Text sein, der eine Formel darstellt, die vom eigentlichen COmpiler ausgewertet wird). Was haben wir denn da: Da wird der Ausdruck __CONCAT(INT8_MAX, U) mit 2 multipliziert und anschliessend noch 1 dazuaddiert. Die U hinter jeder Zahl weisen die Zahl als unsigned Zahl (also ohne Vorzeichen) aus, weil in C ja standardmaessig eine ganze Zahl wie 2, 3 oder 1 ein int (also mit Vorzeichen) ist. Was macht __CONCAT Da alle Buchstaben Grossbuchstaben sind, ist das nach üblicher C Konvention selbst wieder ein Makro. Es gibt also irgendwo einen #define dafür. Der Name CONCAT deutet darauf hin, dass hier Teile (Texte) miteinander verbunden werden. Welche Texte? Nun, der Text für INT8_MAX und U. INT8_MAX ist auch wieder ein Makro. Dessen Ersetzung ergibt 0x7F. Da dann ein U drann gehängt ergibt 0x7FU Damit ergibt die erste Runde der Textersetzungen Das hier: (__CONCAT(INT8_MAX, U) * 2U + 1U) wird zu ( 0x7FU * 2U + 1U ) und wenn ich das mal ausrechne, dann ergibt sich ( 127 * 2 + 1 ) oder auch (255) und das ist rein 'zufällig* die größte Zahl die mit 8 Bit als unsigned noch darstellbar ist.
@ Karl-Heinz, wohl wahr, dass wir im GCC-Forum sind. Deine Formulierung klang, als ob der AVR nicht 64-Bit Rechnungen kann. Und das wollte ich korrigieren. MW
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.