Benötigte Werkzeuge

Um die Übungen in diesem Tutorial nachvollziehen zu können benötigen wir folgende Hard- und Software:

Definition einiger Datentypen

Für die Programmierung von Microcontrollern ist es sinnvoll, dass wir uns vorerst einige Datentypen definieren, welche den Zugriff auf die verschiedenen Komponenten des Controllers vereinfachen oder wenigstens das Programm lesbarer machen können.

typedef unsigned char  BYTE;
typedef unsigned short WORD;

BYTE

Der Datentyp BYTE definiert eine Variable mit 8 Bit Breite zur Darstellung von ganzen Zahlen im Bereich zwischen 0 ... 255.

WORD

Der Datentyp WORD definiert eine Variable mit 16 Bit Breite zur Darstellung von ganzen Zahlen im Bereich zwischen 0 ... 65535.

Wir können aber auch die von der AVR-Umgebung des Compiler in der Headerdatei <inttypes.h> definierten Datentypen verwenden. Ich persönlich finde dieselben allerdings nicht sehr leserlich.

typedef signed char int8_t;
typedef unsigned char uint8_t;

typedef int int16_t;
typedef unsigned int uint16_t;

typedef long int32_t;
typedef unsigned long uint32_t;

typedef long long int64_t;
typedef unsigned long long uint64_t;

typedef int16_t intptr_t;
typedef uint16_t uintptr_t;

Bitfelder

Beim Programmieren von Microcontrollern 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 Bit breit ist.
Hier bietet uns die Programmiersprache C ein mächtiges Werkzeug an, mit dessen Hilfe wir 8 Bits in einer einzelnen Bytevariable zusammen fassen und (fast) wie 8 einzelne Variablen ansprechen können.
Die Rede ist von sogenannten Bitfeldern. Diese werden als Strukturelemente definiert. Sehen wir uns dazu doch am besten gleich ein Beispiel an:

struct {
    unsigned char bStatus_1:1;    // 1 Bit für bStatus_1
    unsigned char bStatus_2:1;    // 1 Bit für bStatus_2
    unsigned char bNochNBit:1;    // Und hier noch mal ein Bit
    unsigned char 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;

Grundsätzlicher Programmaufbau eines µC-Programms

Wir unterscheiden zwischen 2 verschiedenen Methoden, um ein Microcontroller-Programm zu schreiben, und zwar völlig unabhängig davon, in welcher Programmiersprache das Programm geschrieben wird.

Sequentieller Programmablauf

Bei dieser Programmiertechnik wird eine Endlosschleife programmiert, welche im Wesentlichen immer den gleichen Aufbau hat:

Interruptgesteuerter Programmablauf

Bei dieser Methode werden beim Programmstart zuerst die gewünschten Interruptquellen aktiviert und dann in eine Endlosschleife gegangen, in welcher Dinge erledigt werden können, welche nicht zeitkritisch sind..
Wenn ein Interrupt ausgelöst wird so wird automatisch die zugeordnete Interruptfunktion ausgeführt.