Grundlagen

Schnelle Hilfe

Um kurze Hinweise über Funktionen und deren Übergabeparameter zu erhalten nutze die Funktion die dir VS Code zur Verfügung stellt. Diese ist im Video darunter zu sehen.



main.c Aufbau

In diesem Projekt beinhaltet die Hauptdatei zwei große Funktionen. In der setup() Funktion werden alle Aufrufe und Anweisungen einmal zu Beginn des Starts ausgeführt. Hingegen werden Inhalte der loop() Funktion kontinuierlich wiederholt.

Programmiersprache

Im gesamten Projekt wird die Programmiersprache C++ genutzt. Diese ermöglicht das objektorientierte Programmieren und stellt die Möglichkeit von Klassen zur Verfügung, aber dazu später mehr. Im Grunde nutzt C++ die Syntax von der Programmiersprache C. Hierzu nützliche Erklärungen zu den [arduino] Funktionen und Klassen. Zusätzlich kann die Website [cppreference] genutzt werden um diverse C und C++ Funktionen nachzuschlagen. C ist eine der effizienteren Programmiersprachen im Bezug auf Echzeitfähigkeit und Speichermanagement die deshalb insbesondere auf Microcontrollern eingesetzt wird. Zusätzlich kann sie auf nahezu allen Platftformen ausgeführt werden.



Kommentare

In C können Kommentare an jeder Stelle mit „// Dies ist ein Kommentar“ oder mit „/* Dies ist ebenfalls ein Kommentar */“ verfasst werden. Kommentare werden vom Compiler ignoriert, das bedeutet sie sind rein für euch Entwickler als Anmerkung und werden nicht Teil des Programmes werden. Sie helfen dir deinen Code übersichtlicher bzw. verständlicher zu machen und ermöglichen dir nach einer kurzen Pause leichter wieder in dein Programm einzusteigen.



Syntax

Die Syntax beschreibt den Aufbau eines typischen C / C++ Programmcodes. Im Gegensatz zu diesem Projekt gibt es in nur eine main() Funktion, in der alle anderen Funktionen aufgerufen werden.

// Einbinden der Standardbibliothek
#include <stdio.h>

int main()
{
    printf("Willkommen bei IT-4-Education\n");
    return 0;
}

In C wird jede Anweisung mit einem Semikolon „;“ abgeschlossen.



Variablen

Der Variablenname sollte den Verwendungszweck widerspiegeln. Bei komplizierteren Namen werden einzelne Worte mit Unterstrichen abgetrennt. Zur Lesbarkeit hier ein kurzes Beispiel: erstevariable, zweiteVariable und dritte_Variable. Wie hier zu sehen ist, sind Variablennamen, die mit Unterstrichen oder mit variabler Groß- und Kleinschreibung einfacher zu lesen. Konstanten werden nur in Großbuchstaben bezeichnet.



Eigenschaften von Variablen

  • Datentyp

  • Name

  • Inhalt

  • Speicheradresse

Datentypen geben an, wie der Wert interpretiert werden soll. Ob es eine natürlich Zahl ist, oder eine Gleitkommazahl oder etwa ein Char, also sprich ein ASCII Zeichen, aber dazu später mehr. Der Name jeder Variable muss eindeutig und einmalig sein. Zusätzlich sollten diese mit Buchstaben beginnen und keine Sonderzeichen enthalten. Der Inhalt wird mittels Datentypen interpretiert. Die Speicheradresse gibt an, an welcher Adresse im Speicher die Variable abgelegt wird. Diesen Vorgang erläutern wir später detaillierter.

Der Programmierer legt normalerweise nur Datentyp, Name und Inhalt fest.

Unterschiedliche Datentypen sind:



Funktionen

Funktionen besitzen einen Funktionskopf mit Rückgabetyp und Übergabeparameter und einen Funktionsrumpf. Funktionen werden in der Regel in sogenannten „Header“ Dateien deklariert. Dort werden die Funktionsköpfe verfasst und die Dateiendung eines Headers ist „.h“. Hingegen werden die eigentlichen Funktionen in den Quelldateien geschrieben, welche die Dateiendung „.c“ haben. Um später in der main.c die geschriebenen Quelldateien bzw. Header Dateien nutzen zu können, müssen diese mit #include „header.h“ inkludiert werden.

Beispielinhalt einer Header Datei:



Datentypen

Datentypen werden grob in vier Untergruppen unterteilt.

  • Primitive/Basis Datentypen > arithmetische Datentypen (ganzzahlig und gleitkomma)

  • Aufzählungen/Enumeration > verbindet Variablen mit diskreten Werten

  • Void > gibt an, dass Variable / Funktion keinen Wert hat

  • Abgeleitete Typen > Zeiger(Pointer), Felder(Arrays), Strukturen(structs), Unions und Funktionen



Datentypen
Liste einiger Datentypen

Typ

Speicherbedarf

Wertebereich

char

1 byte

-127 bis 127 bzw. 0 bis 255

unsigned char

1 byte

0 bis 255

signed char

1 byte

-127 bis 127

int

4 bytes

-2147483648 bis 2147483647

unsigned int

4 bytes

0 bis 4294967295

signed int

4 bytes

-2147483648 bis 2147483647

short int

2 bytes

-32768 bis 32767

unsigned short

2 bytes

0 bis 65535

signed short

2 bytes

-32768 bis 32767

unsigned long int

4 bytes

0 bis 4294967295

float

4 bytes

1.2E-38 bis 3.4E+38

double

8 bytes

2.3E-308 bis 1.7E+308

long double

16 bytes

3.4E-4932 bis 1.1E+4932

void

keinen Speicherbedarf

kein Wert



Eigene Datentypen

Eigene Datentypen können mit der Direktive „typedef“ erstellt werden. Somit können neue Namen bzw. Synonyme für vorhandene Datentypen erzeugt werden. Dies ist im folgenden Beispiel zu sehen:

// Hierbei sind beide Variablen vom Datentyp Integer (int)

typedef int steine;
steine ziegel = 10;
steine dachplatte = 5;


Aufzählungen „enumeration“

Bei Aufzählungen werden Synonyme für Zahlen in aufsteigender Reihenfolge festgelegt.

enum farben {rot, gruen, blau};
// rot hat die Ganzzahl 0
// gruen entspricht einer 1
// blau entspricht einer 2


Operatoren

Operatoren :widths: 25 25 50 :header-rows: 1

Kategorie

Operator

Assoziativität

Scope Operator

„::“

links nach rechts

Klammerung, Funktionsaufruf, Feldzugriff, Zugriff auf Strukturfelder

() [] > .

links nach rechts

unäre Operatoren

++ + * & (type) sizeof

rechts nach links

binär, Multiplikation

* / &

links nach rechts

binär, Addition

+ -

links nach rechts

bitweise shiften

<< >>

links nach rechts

relationale Operatoren

< <= > >=

links nach rechts

Test auf Gleichheit

== !=

links nach rechts

bitweise und

&

links nach rechts

bitweise exclusiv oder

^

links nach rechts

bitweise oder

|

links nach rechts

logisches und

&&

links nach rechts

logisches oder

||

links nach rechts

konditionaler Operator

? :

rechts nach links

Zuweisung

= ,+= ,* ,*= ,/= ,%= ,&= ,^= ,!= ,<<= ,>>=

rechts nach links

Komma Operator

,

links nach rechts



Konstanten

Konstanten werden

void main() {
// Die const Anweisung kann vor dem Datentypen oder vor dem Namen stehen.
  const int laenge = 130;
  int const breite = 100;
}


Steuerzeichen

Steuerzeichen

Steuerzeichen

Bedeutung

\a

BEL (bell) - akustisches Warnsignal

\b

BS (backspace) - setzt den Cursor um eine Position nach links.

\n

NL (newline) - der Cursor geht zum Anfang der neuen Zeile.

\r

CR (carriage return) - Der Cursor springt zum Anfang der aktuellen Zeile.

\t

HT (horizontal tab) - Zeilenvorschub nur nächsten Tabulatorposition (meistens acht oder vier Leerzeichen breit).

\“

Ausgabe der Hochkommata

\‘

Ausgabe von '

\?

Ausgabe von ?

\

Ausgabe von \

\0

Endmarkierung eines Strings



Printf

Die printf Ausgabe gibt eine gewünschte Zeichenkette + Variablen aus. Dies ermöglicht Programmierern eine leichte Möglichkeit den Ablauf des Codes zu verstehen. Zwischen den Hochkommata werden Befehle für die Formatierung von Variablen mit %i, %d %f und vielen mehr eingestellt. Zusätzlich können beliebiger Strings d.h. Zeichenketten also Worte und Sätze ausgegeben werden.

#include <stdio.h>

void main() {

printf("Willkommen bei IT-4-Education\n"); // Ergibt auf der Konsole folgende Ausgabe: Willkommen bei IT-4-Education.
int i = 100;
printf("Integer: %i\n"); // Ausgabe: Integer: 100

// Formatierte Ausgabe mit einer Fließkommazahl
float f = 12.123;
printf("Float: %f \n", f); // Ausgabe: Float: 12.123
printf("Float: %.2f\n", f); // Ausgabe mit zwei Nachkomma Stellen: Float: 12.12

}


Gültigkeitsbereich von Variablen

Variablen die innerhalb eines Blocks definiert sind, sind auch nur dort Gültig.

#include <stdio.h>

void main() {

// Deklaration eines Blocks zwischen den { }
{
int n = 1;
printf("%d\n", n); // Gibt den Wert von n aus.
}
printf("%d\n", n); // Ausgabe ergibt einen Fehler, da Variable n außerhalb des Blocks nicht bekannt ist.

}

Zusätzlich können Variablen auch als global instanziiert werden. D.h. aus jedem Funktionsblock kann auf diese globalen Variablen zugegriffen werden.



Anweisungen


Bedingte Verzweigungen - if-Anweisung


In C können logische Verzweigungen mit Bedingungen erstellt werden.

if(Bedingung)
{
// Ausführung dieses Codeabschnitts.
}

Wie im unteren Codeblock zu sehen ist, können Bedingungen beliebig erweitert werden. Falls alle vorherigen Bedingungen nicht erfüllt sind, deckt die Anweisung „else“ diesen Fall ab.

#include <stdio.h>

void main() {

  int i = 3;

  if(i == 1)
  {
    printf("Integer i entspricht eins. i: %i\n", i);
  }
  else if (i == 2)
  {
    printf("Integer i entspricht zwei. i: %i\n", i);
  }
  else
  {
    printf("Integer i weder eins noch zwei. i: %i\n", i);
  }
}


Datenreihe - Array

In C gibt es die Möglichkeit Arrays zu nutzen. Diese sind eine Aneinanderreihung von Blöcken im Speicher, die es uns ermöglicht.

Switch - case


Beim switch-case ist es besonders wichtig, dass jeder einzelne case bzw. Anweisung mit einem „break“ Statement endet.

#include <stdio.h>

switch(i) {
case 1:
//Anweisung wenn i == 1 entspricht.
  break;
case 2:
//Anweisung wenn i == 2 entspricht.
  break;
case 3:
//Anweisung wenn i == 3 entspricht.
  break;
default:
//Anweisung wenn keiner der obigen Fälle eintritt.
  break;
}


Schleifen

In C gibt es die Möglichkeit diverse Schleifen zu nutzen. Zu ihnen gehören die while, do while und for Schleife. Im unteren Codeblock sind zu Beispiele zu den genannten Schleifen zu sehen.

Die while ermöglicht Schleifendurchläufe solange auszuführen, bis die ihr übergebene Bedingung von „TRUE“ auf „FALSE“ wechselt. Falls die Bedingung der while von Beginn an nicht „WAHR“ ist, wird diese Schleife nicht ausgeführt und wird vom Programm übergangen. Zusätzlich können while Schleifen ebenfalls wie Case oder IF Vergleiche genutzt werden.

#include <stdio.h>

int durchlaeufe = 1;

while(durchlaeufe < 10) // Schleifenbedingung
{
  durchlaeufe++; // Integervariable schleife erhöht sich bei jedem Durchlauf um 1
}

Der Wert der Variable ist nach den Schleifendurchläufen gleich „10“.

Hingegen durchläuft die do while Schleife auf jedenfall einmal den inneren Codeabschnitt, denn sie ist eine Variation der while Schleife.

#include <stdio.h>

int durchlaeufe = 10;

do while(durchlaeufe < 10) // Schleifenbedingung
{
  durchlaeufe++;
}

Nachdem die Schleifenbedingung nicht erfüllt ist es sich jedoch um eine do while Schleife handelt wird die Variable durchlaeufe „11“ sein.

Die for Schleife wird häufig für zählende Aufrufe genutzt. Hierfür ein kleines Beispiel. Die Übergabeparameter belaufen sich auf eine zu erhöhende Variable, eine Bedingung wie lange die Schleife ausgeführt werden soll und der zu erhöhende Wert.

#include <stdio.h>

int i;

for(i = 0; i <= 100; i++) // Übergabeparameter
{
  printf("%i \n", i);
}

Das Ergebnis dieses Aufrufs sind Konsolenausgaben von 0 bis 100. | |

Pointer - Zeiger

C bzw. C++ ermöglicht das Arbeiten mit Zeigern. Ein Zeiger zeigt auf einen Bereich im Speicher, welcher aufgrund des Datentypen dann entsprechend interpretiert wird. Ein Zeiger wird mit „Datentyp * Variablenname“ deklariert. Da der Zeiger auf den Integer „zahl“ zeigen soll, wird dem Zeiger die „Zahl“ mit dem & Operator zugewiesen. Das heißt der Zeiger zeigt auf das erste Byte im Speicher von der „Zahl“. Dies ist in der Abbildung darunter zu sehen.

Abb.Nr.1: Zeiger und Speicher

Wie oben in der [Datentypen] Tabelle zu sehen ist, benötigt eine Zahl mit dem Datentyp Integer vier Byte im Speicher.

#include <stdio.h>

int zahl = 5; // Deklaration eines Integers
int* zeiger; // Deklaration eines Zeigers

zeiger = &zahl; // Zuweisung des Zeigers auf den Integer "Zahl"


Programmentwicklung

  1. Schritt:

    • Was sind die einzelnen Funktionen? (z.B. Eingabe, Ausgabe, Berechnungen)

  2. Schritt:

    • Funktionen abstrahieren und in einfachere und kleine aufgliedern.

    • Einzelne Funktionen separat testen.

  3. Schritt:

    • Abläufe und Funktionen grafisch darstellen z.B. als Flussdiagramm.



Objektorientierte Programmierung

Klassen dienen im allgemeinen als eine Art Template um programmierte Inhalte mehrfach verwenden zu können. Ein Beispiel hierfür wäre das Bauen eines Hauses. Hierfür würde es Klassen für Ziegelsteine, Dachplatten und Fenster geben. Ein Haus besteht aus mehreren Ziegelsteinen, Dachplatten und Fenstern und somit können mehrere Instanzen der einzelnen Klassen erzeugt werden, um das gesamte Haus zu erstellen.



Arduino Funktionen

Literaturangaben

cppreference

Wiki zu C++ (besucht am 07.12.2022) https://en.cppreference.com/w/

arduino

Wiki zu Arduino Funktionen und Klassen (besucht am 07.12.2022) https://www.arduino.cc/reference/en/