C-Programmierung mit AVR-GCC/ Datentypen
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>
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 |
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:
- 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