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
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
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 |
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.
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
Schritt:
Was sind die einzelnen Funktionen? (z.B. Eingabe, Ausgabe, Berechnungen)
Schritt:
Funktionen abstrahieren und in einfachere und kleine aufgliedern.
Einzelne Funktionen separat testen.
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/