Zum Inhalt springen

C-Programmierung mit AVR-GCC/ Datentypen

Aus Wikibooks

Ganzzahlige Datentypen

[Bearbeiten]

Bei der Programmierung von Mikrocontrollern ist die Definition einiger ganzzahliger Datentypen sinnvoll, an denen eindeutig die Bit-Länge abgelesen werden kann.

Standardisierte Datentypen werden seit C99 in der Header-Datei stdint.h zur Verfügung gestellt. Zur Nutzung der standardisierten Typen bindest du diesen Header wie folgt ein:

#include <stdint.h>


Integertypen mit Vorzeichen
Typname Bitbreite Wertebereich Alias (unter AVR-GCC)
int8_t 8 Bit -128..127 signed char
int16_t 16 Bit -32768..32767 signed int
int32_t 32 Bit -2147483648..2147483647 signed long int
int64_t 64 Bit -9223372036854775808..9223372036854775807 signed long long
Integertypen ohne Vorzeichen
Typname Bitbreite Wertebereich Alias (unter AVC-GCC)
uint8_t 8 Bit 0..255 unsigned char
uint16_t 16 Bit 0..65535 unsigned int
uint32_t 32 Bit 0..4294967295 unsigned long int
uint64_t 64 Bit 0..18446744073709551615 unsigned long long

Die Typen ohne vorangestelltes u werden als vorzeichenbehaftete Zahlen interpretiert. Typen mit vorgestelltem u dienen dem Speichern positiver Zahlen inclusive 0. Siehe dazu auch: Dokumentation der avr-libc Abschnitt Modules/(Standard) Integer Types.

Da die verschiedenen Datentypen unterschiedlich viel Speicherplatz benötigen, solltest du immer den kleinsten Datentyp wählen, der für den zu erwartenden Variableninhalt ausreicht. Eine 8-Bit Zahl, beispielsweise ein Buchstabe, in einer Integervariablen zu speichern ist Platzverschwendung.

Die Namen unter Alias können prinzipiell auch verwendet werden, jedoch können diesen Namen unter anderen Architekturen andere Bitbreiten zugeordnet sein. Um den Code portabel zu halten, sollten also besser die exakten Typnamen verwendet werden. Auch haben die Aliase den Nachteil, dass aus ihnen nicht hervorgeht, wie viel Speicherplatz sie benötigen.

Fließkommazahlen

[Bearbeiten]

VORSICHT: Zur Ausgabe von floats per sprintf:

1) AVR Studio: PROJECT PROPS ≥ Custom ≥ Options LINKER (!) ≥ add „-Wl,-u,vfprintf“

2) PROPS ≥ Libraries: Add libprintf_flt.a and libm.a

Beispiel:

  1. include <string.h> //für sprintf

char zeichen[15]; //char-array = String als Ziel für sprintf //float myFloat1 = 1.2345; double myFloat2 = 2.2345;

sprintf(zeichen, „Gleitkomma mit 2 Nachkommastellen: %.2f\n\r“, myFloat2); usart_write(zeichen);

Arrays

[Bearbeiten]

Strings

[Bearbeiten]

Bitfelder

[Bearbeiten]

Beim Programmieren von Mikrocontrollern muss auf jedes Byte oder sogar auf jedes Bit geachtet werden. Oft müssen wir in einer Variablen lediglich den Zustand 0 oder 1 speichern. Wenn wir nun zur Speicherung eines einzelnen Wertes den kleinsten bekannten Datentypen, nämlich unsigned char, nehmen, dann verschwenden wir 7 Bits, da ein unsigned char ja 8 Bits breit ist.

Hier bietet uns die Programmiersprache C ein mächtiges Werkzeug an, mit dessen Hilfe wir 8 Bits in eine einzelne Bytevariable zusammenfassen und (fast) wie 8 einzelne Variablen ansprechen können. Die Rede ist von so genannten Bitfeldern. Diese werden als Strukturelemente definiert. Sehen wir uns dazu doch am besten gleich ein Beispiel an:

struct {
   unsigned bStatus_1:1; // 1 Bit für bStatus_1
   unsigned bStatus_2:1; // 1 Bit für bStatus_2
   unsigned bNochNBit:1; // Und hier noch mal ein Bit
   unsigned b2Bits:2;    // Dieses Feld ist 2 Bits breit
   // All das hat in einer einzigen Byte-Variable Platz.
   // die 3 verbleibenden Bits bleiben ungenutzt
} x;

Der Zugriff auf ein solches Feld erfolgt nun wie beim Strukturzugriff bekannt über den Punkt- oder den Dereferenzierungs-Operator:

x.bStatus_1 = 1;
x.bStatus_2 = 0;
x.b2Bits = 3;

Bitfelder sparen Platz im RAM, zu Lasten von Platz im Flash, verschlechtern aber unter Umständen die Les- und Wartbarkeit des Codes. Anfängern wird deshalb geraten, ein "ganzes" Byte (uint8_t) zu nutzen, auch wenn nur ein Bitwert gespeichert werden soll.

Wenn man nur ein paar wenige Variablen vom Typ bool verwenden möchte, kann man auch die Headerdatei <stdbool.h> einbinden und sich dann wie gewohnt einen Booltyp anlegen. Variablen dieses Typs brauchen dennoch 1 Byte Speicher, ermöglichen aber eine genaue Unterscheidung zwischen Zahlenvariable und boolscher Variable.

Strukturen

[Bearbeiten]

TODO