Block 3 - Strings und Kodierung

Funktionen

In dem folgenden Video wird dieses Programm verwendet:

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  int i;
  // lang
  for (i=0;i<3;i++); {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(3000);
    digitalWrite(LED_BUILTIN, LOW);
    delay(1000);
  }
  // kurz
  for (i=0;i<3;i++); {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(1000);
    digitalWrite(LED_BUILTIN, LOW);
    delay(1000);
  }
  // lang
  for (i=0;i<3;i++); {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(3000);
    digitalWrite(LED_BUILTIN, LOW);
    delay(1000);
  }
  // pause
  delay(5000);
}

Programm aus dem Video:

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  int i;
  // lang
  for (i=0;i<3;i++); {
    my_blink(3000);
  }
  // kurz
  for (i=0;i<3;i++); {
    my_blink(1000);
  }
  // lang
  for (i=0;i<3;i++); {
    my_blink(3000);
  }
  // pause
  delay(5000);
}

void my_blink(int period) {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(period);
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}

void blink_long() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(3000);
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}

void blink_short() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}

Übungsaufgaben

1.) Funktion mit Übergabewert

Im Video zu Funktionen mit Übergabewert haben Sie gelernt, wie Sie eine Funktion mit einem nutzerdefinierten Delay programmieren (my_blink). Erweitern Sie diese Funktion so, dass das Delay in Sekunden statt in Millisekunden angegeben wird.

Schreiben Sie eine Funktion, die als Parameter die Anzahl kurzer Blinks angibt – z.B. soll der Aufruf blink_mal(3) die LED dreimal zum Blinken bringen.

Schreiben Sie nun eine Funktion, die zwei Parameter nimmt: period für die Eingabe der Delay-Periode und repeat für die Eingabe wie oft das Blinken wiederholt werden soll.

4.) Serieller Monitor

Gegeben ist folgender Codeschnipsel:

funktion_1(zahl) {
  ergebnis = zahl*2;
  Serial.println(ergebnis);
}
funktion_2(zahl) {
  Serial.println(zahl+5);
}
int a = 3;
funktion_1(a);
funktion_2(a);

Was wird bei Ausführung des Codes auf dem seriellen Monitor ausgegeben?

Lösungen

Lösung zu Aufgabe 1.):

void my_blink_s(int period){
 digitalWrite(LED_BUILTIN, HIGH);
 delay(period*1000);
 digitalWrite(LED_BUILTIN, LOW);
 delay(1000);
}

Lösung zu Aufgabe 2.):

void blink_mal(int mal) {
  for (int i = 0; i < mal; i++) {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(1000);
    digitalWrite(LED_BUILTIN, LOW);
    delay(1000);
  }
}

Lösung zu Aufgabe 3.):

void blink(int repeat, int period) {
  for (int i = 0; i < repeat; i++) {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(period*1000);
    digitalWrite(LED_BUILTIN, LOW);
    delay(1000);
  }
}

Rückgabewerte

Übungsaufgaben

1.) Funktion mit Übergabe- und Rückgabewert

Schreiben Sie eine Funktion, welche die Fakultät berechnet. Der Übergabewert ist eine positive Zahl, der Rückgabewert die Fakultät der Zahl.

Hinweis 1: Verwenden Sie eine For-Schleife Hinweis 2: Mit dem Dateityp int lassen sich nur Fakultäten bis 7! speichern.

2.) Serieller Monitor

Gegeben ist folgender Codeschnipsel

int meine_funktion(zahl) {
  Serial.println(zahl);
  ergebnis = zahl – 2;
  return(ergebnis);
}
int a = 6;
Serial.println(a);
a=meine_funktion(a);
Serial.println(a);

Was wird bei Ausführung des Codes auf dem seriellen Monitor ausgegeben?

Lösungen

Lösung zu Aufgabe 1.):

void setup() {
Serial.begin(9600);

}

void loop() {
  int num = 7;
  Serial.print("Factorial from ");
  Serial.print(num);
  Serial.print(": ");
  Serial.println(factorial(num));
  delay(5000);
  
}

int factorial(int num){
  int result = 1;
  for(int i = 1; i <= num; i++){
    result *=i;
  }
  return result;
}

Globale und lokale Variablen

Programm aus dem Video:

int wait_time;
int unsere_led_out = 12;

void setup() {
  // put your setup code here, to run once:
  pinMode(unsere_led_out, OUTPUT);
  wait_time = 1000;
  Serial.begin(9600);
  Serial.println("Wert von wait_time im setup ist: ");
  Serial.println(wait_time);
  delay(5000);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println("Wert von wait_time im loop ist: ");
  Serial.println(wait_time);
  digitalWrite(unsere_led_out, HIGH);
  delay(wait_time);
  digitalWrite(unsere_led_out, LOW);
  delay(3*wait_time);
}

Programm aus dem Video:

int period = 1000;
  
// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(9600);
}

// the loop function runs over and over again forever
void loop() {
  Serial.println("Der Wert von period vor der Funktion ist: ");
  Serial.println(period);
  blink(period);   
  Serial.println("Der Wert von period nach der Funktion ist: ");
  Serial.println(period);                 
}

void blink(int period) {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(period);                       
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(period);  
  period += 500;
  Serial.println("Der Wert von period in der Funktion ist: ");
  Serial.println(period); 
}

Übungsaufgaben

1.) Lokal vs. Global

Was ist der Unterschied zwischen diesen zwei Programmen:

int i;
void setup() {
  Serial.begin(9600);
  i = 0;
}
void loop() {
  Serial.print(“ Der Wert von i ist : “);
  Serial.println(i);
  i++;
}
void setup() {
  Serial.begin(9600);
  i = 0;
}
void loop() {
  int i = 0;
  Serial.print(“ Der Wert von i ist : “);
  Serial.println(i);
  i++;
}

a) Beide Programme sind gleich b) Das erste Programm zählt von 0 hoch, das zweite zählt von 0 runter c) Das erste Programm zählt von 0 hoch, das zweite gibt immer wieder eine Null raus. d) Das erste Programm zählt von 0 hoch, das zweite würde einen Kompilierungsfehler ausgeben.

2.) Variablen-Chaos

Was ist die Ausgabe des folgendes Programms, nachdem die loop-Funktion genau dreimal gelaufen ist?

int i = 0;
void setup() {
  Serial.begin(9600);
  i = 0;
}
void loop() {
  Serial.print(i);
  Serial.print(", ");
  i++;
  for (int i = 5; i < 10; i ++) {
    Serial.print(i);
    Serial.print(", ");
  }
}

a) Das Programm kompiliert nicht, weil die Variable i re-definiert wurde. b) Das Programm gibt aus: 0, 5, 6, 7, 8, 9, 1, 5, 6, 7, 8, 9, 2, 5, 6, 7, 8, 9, c) Das Programm gibt aus: 0, 5, 6, 7, 8, 9, 0, 5, 6, 7, 8, 9, 0, 5, 6, 7, 8, 9, d) Das Programm gibt aus: 0, 5, 6, 7, 8, 9, 10, 5, 6, 7, 8, 9, 10, 5, 6, 7, 8, 9,

3.) Gültigkeitsbereiche

Was können Sie über folgendes Programm sagen?

void setup() {
  Serial.begin(9600);
}

void loop() {
  for(int i = 0; i<5; i++){
    int i = 6;
    Serial.print(i);
  }
  Serial.println();

  delay(1000);
}

a) Das Programm gibt folgende Zeile aus: 66666 Erklärung: int i = 6; führt eine lokale Variable ein, diese wird durch print ausgegeben. Die Zählvariable der Schleife bleibt von diesem Wert unberührt.

b) Das Programm kann nicht kompiliert werden. Fehlermeldung: redeclaration of 'int i'. Der Schleifenkopf und der Schleifenkörper sind ein und derselbe Gültigkeitsbereich, eine Variable kann nicht in einem Block neu deklariert werden.

c) Das Programm kann nicht kompiliert werden. Fehlermeldung: redeclaration of 'int i'. Eine Variable kann grundsätzlich nicht mehrfach deklariert werden. Man muss immer einen anderen Variablennamen verwenden.

d) Das Programm gibt folgende Zeile aus: 01234 Erklärung: Die For-Schleife läuft von 0 bis 4, Serial.print(i) gibt den aktuellen Wert der Variablen in der Schleife aus. Serial.println() hängt einen Zeilenumbruch an.

e) Das Programm gibt folgende Zeile aus: 012345 Erklärung: Die For-Schleife läuft von 0 bis 5, Serial.print(i) gibt den aktuellen Wert der Variablen in der Schleife aus. Serial.println() hängt einen Zeilenumbruch an.

4.) Codeschnipsel

Gegeben ist folgender Codeschnipsel:

int a = 1;

int meine_funktion(wert) {
  int c = 2;
  return(wert+c);
}

void setup() {
  int b = 3;
  meine_funktion(b);

} 

Wo ist die Variable a sichtbar?

a) Im gesamten Code b) nur innerhalb der Funktion meine_funktion() c) nur innerhalb von setup()

Wo ist die Variable b sichtbar?

a) Im gesamten Code b) nur innerhalb der Funktion meine_funktion() c) nur innerhalb von setup()

Wo ist die Variable c sichtbar?

a) Im gesamten Code b) nur innerhalb der Funktion meine_funktion() c) nur innerhalb von setup()

Arrays

Programm aus dem Video:

int muster[5] = {1000, 2000, 3000, 2500, 1300};
// muster[0] - das erste Feld

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(9600);
}

// the loop function runs over and over again forever
void loop() {
  for (int i = 0; i < 6; i++) {
    blink(muster[i]);
    Serial.println(muster[i]);
  }                  
}

void blink(int period) {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(period);                       
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                      // wait for a second
}

Programm aus dem Video:

int muster[5][3];

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(9600);
  for (int j = 0; j < 5; j++) {
    for (int k = 0; k < 3; k++) {
      muster[j][k] = 1000*j + k;
      Serial.println(muster[j][k]);
    }
  }
}

// the loop function runs over and over again forever
void loop() {
                    
}

void blink(int period) {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(period);                       
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                      // wait for a second
}

Programm aus dem Video:

int muster[5][2] = {1000, 2000, 3000, 2500, 1300, 1000, 2000, 3000, 2500, 1300};
// muster[0] - das erste Feld

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(9600);
}

// the loop function runs over and over again forever
void loop() {
  for (int i = 0; i < 5; i++) { 
    for (int j = 0; j < 2; j++) {
      blink(muster[i][j]);
      Serial.println(muster[i][j]);
    }
  }                  
}

void blink(int period) {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(period);                       
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                      // wait for a second
}

Übungsaufgaben

1.) Länge eines Arrays

Recherchieren Sie Folgendes: Lässt sich zur Laufzeit die Länge eines Arrays in C / Arduino sicher bestimmen? Nehmen Sie ein int-Array an.

2.) Arbeiten mit Arrays

Schreiben Sie ein Programm, welches die Werte in einem int-Array addiert.

3.) Ich bin der Kleinste...

Schreiben Sie ein Programm, das die kleinste Zahl in einem Array findet und ausgibt. Nehmen Sie wieder einen int-Array

4.) Und ich bin der Größte!

Ändern Sie ihr Programm von der Übung davor, so dass sie die größte Zahl findet!

5.) Array verstehen

Ein Integer-Array ist wie folgt deklariert:

int my_array[50];

Ein Element des Arrays wird ausgelesen:

a = my_array[i];

a) Wie viele Elemente hat das Array?

b) Was ist der kleinste zulässige Wert für i?

c) Was ist der größte zulässige Wert für i?

Lösungen

Lösung zu Aufgabe 1.):

Nein, die Länge lässt sich nicht sicher und eindeutig bestimmen. Daher macht es Sinn die Länge eines Arrays z.B. als Konstante zu speichern und ggf. auf diese zu verweisen, wie z.B.:

const int MY_ARR_LENGTH = 5; // muss const sein
int my_array[MY_ARR_LENGTH ] =

for (int i = 0; i < MY_ARR_LENGTH ; i++){
  Serial.print(my_array[i]);

}

Lösung zu Aufgabe 2.):

void setup() {
  Serial.begin(9600);
}

void loop() {
  int my_array[] = {1, 5, 9, 4, 6};
  int MY_ARR_LENGTH = 5;

  int sum = 0;
  for (int i = 0; i< MY_ARR_LENGTH; i++){
    sum += my_array[i];
  }

  Serial.println(sum);
  delay(5000);
}

Lösung zu Aufgabe 3.):

void setup() {
Serial.begin(9600);
}

void loop() {
  int my_array[] = {7, 5, 9, 4, 6};
  int MY_ARR_LENGTH = 5;

  int kleinste = 10000; // wenn man nach der kleinsten Zahl sucht, muss man mit grossen Zahlen vergleichen. 
  int kleinster_index = -1;
  for (int i = 0; i< MY_ARR_LENGTH; i++){
    if (kleinste > my_array[i])
	kleinste = my_array[i];
      kleinster_index = i; // so kann man sich nicht nur merken, welche die kleinste Zahl war, sondern auch wo sie war
  }
  
  if (kleinster_index > -1) // wenn das immer noch -1 ist, dann ist etwas schiefgelaufen (z.B. ist der erste Wert von kleinste zu klein gewesen
      Serial.println(kleinste);
  delay(5000);
}

Lösung zu Aufgabe 4.):

void setup() {
Serial.begin(9600);
}

void loop() {
  int my_array[] = {7, 5, 9, 4, 6};
  int MY_ARR_LENGTH = 5;

  int groesste = -1; // wenn man nach der grössten Zahl sucht, muss man mit kleinen Zahlen vergleichen. Nehmen wir doch positive Zahlen an.
  int gr_index = -1;
  for (int i = 0; i< MY_ARR_LENGTH; i++){
    if (groesste < my_array[i])
	groesste = my_array[i];
      gr_index = i; // so kann man sich nicht nur merken, welche die kleinste Zahl war, sondern auch wo sie war
  }
  
  if (gr_index > -1) // wenn das immer noch -1 ist, dann ist etwas schiefgelaufen (z.B. ist der erste Wert von kleinste zu klein gewesen
      Serial.println(groesste);
  delay(5000);
}

Multidimensionale Arrays

Übungsaufgaben

1.) Mehrdimensionale Arrays

Schreiben Sie folgendes Programm:

  • Definieren Sie ein zweidimensionales Array, welches die Form eines Herzens enthält (siehe unten oder https://de.wikipedia.org/wiki/ASCII-Art)

  • Geben Sie dieses über die Serielle Schnittstelle an den Serial Monitor aus

Das Ergebnis sollte wie folgt aussehen:

...#.#....
..#####...
.#######..
.#######..
..#####...
..#####...
...###....
...###....
....#.....
....#.....

2.) Distanzen

Definieren Sie ein zweidimensionales Array, das Koordinaten von Punkten (in 2D) speichert (z.B. für ein Spiel wie Snake). Definieren Sie nun eine Funktion, die zwei Punkte als Parameter bekommt (deren Indexes) und den Abstand zwischen den beiden berechnet. Probieren Sie es mit ein paar Punkten aus.

3.) Zugriff auf Array

Ein Array und eine Variable sind wie folgt definiert:

int my_array[10][20][30];

int a;

Geben Sie jeweils an, ob die folgenden Zugriffe auf das Array zulässig sind:

a) a = my_array[9][25][28];

b) a = my_array[3][4][5][6];

c) a = my_array[9][10][11];

d) a = my_array[0][0][0];

Lösungen

Lösung zu Aufgabe 1.):

char icon[10][10] = { {'.', '.', '.', '#', '.', '#', '.', '.', '.', '.', },
                      {'.', '.', '#', '#', '#', '#', '#', '.', '.', '.', },
                      {'.', '#', '#', '#', '#', '#', '#', '#', '.', '.', },
                      {'.', '#', '#', '#', '#', '#', '#', '#', '.', '.', },
                      {'.', '.', '#', '#', '#', '#', '#', '.', '.', '.', },
                      {'.', '.', '#', '#', '#', '#', '#', '.', '.', '.', },
                      {'.', '.', '.', '#', '#', '#', '.', '.', '.', '.', },
                      {'.', '.', '.', '#', '#', '#', '.', '.', '.', '.', },
                      {'.', '.', '.', '.', '#', '.', '.', '.', '.', '.', },
                      {'.', '.', '.', '.', '#', '.', '.', '.', '.', '.', },
                    };

void setup() {
  Serial.begin(9600);
}

void loop() {
  
  for (int row=0; row < 10; row++){
    for (int column = 0; column < 10; column++){
      Serial.print(icon[row][column]);
    }
    Serial.println();
  }

  Serial.println("\n");
  delay(5000);
}

Lösung zu Aufgabe 2.):

const int DIMS = 2;
float coord[4][DIMS] = {{2, 2}, {4, 5}, {10, 20}, {-3, 10}}; // 4 Punkte je 2D

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  distance(0,2);
  distance(0,3);
  distance(2,3);
  delay(10000);
}

float distance(int from, int to) {
  float temp = sqrt((coord[from][0] - coord[to][0])*(coord[from][0] - coord[to][0]) + (coord[from][1] - coord[to][1])*(coord[from][1] - coord[to][1]));
  Serial.print("Die Distanz zwischen Punkt ");
  Serial.print(from); 
  Serial.print(" und Punkt "); 
  Serial.print(to);
  Serial.print(" ist: ");
  Serial.println(temp);
  return temp;
}

Char und ASCII

Programm aus dem Video:

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  char var_a = 'a';
  char var_b = 66;
  Serial.println(var_a);
  Serial.println(var_b);
  var_b += 32;
  Serial.println(var_b);
  delay(20000);
}

Programm aus dem Video:

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  char string1[24] = "Heute ist ein schöner ";
  char zeichen = 'a';
  char string2[] = "Tag.";
  char string3[5] = {'a', 'n', 'n', 'a'};
  Serial.print(string1);
  Serial.println(string2);
  Serial.println(string3);
  delay(10000); 
}

Übungsaufgaben

1.) ASCII Tabelle

Sie haben in einem Video den Dateityp „char“ sowie den ASCII-Code kennengelernt (siehe unten oder https://de.wikipedia.org/wiki/American_Standard_Code_for_Information_Interchange).

Die ASCII-Tabelle enthält die Großbuchstaben im Bereich 65 (A) bis 90 (Z). Geben Sie diese Zeichen als

  1. Dezimal

  2. Binär

  3. Hexadezimal

  4. Zeichen selbst

über den Serial Monitor aus.

2.) Groß zu klein

Passen Sie das Programm aus Übung 1 so an, dass es statt der Großbuchstaben die Kleinbuchstaben ausgibt.

3.) Geheime Botschaften

Eins der frühesten Codes der Geschichte ist die einfache Substitution. Es gibt viele Varianten, z.B. die Umdrehung des Alphabets. Dabei wird z.B. ein A mit einem Z ausgetauscht, ein B mit einem Y, usw. Schreiben Sie ein Programm, dass einen kurzen Text (char array) verschüsseln und dann wieder entschlüssen kann. Testen Sie es mit ein paar Beispielen.

4.) Strings

Wie in der Vorlesung gelernt, ist ein String eine Folge von Zeichen, die computerintern entsprechend der ASCII-Tabelle als eine Folge von Bytes dargestellt werden. Gegeben sei nun eine Folge von Bytes, der Wert jedes Bytes ist dezimal angegeben:

67, 111, 109, 78, 101, 116, 115

  • Welcher String wird durch diese Bytes dargestellt?

Das Wort comnets soll nun ausschließlich mit Kleinbuchstaben geschrieben werden.

  • Kann man die Byte-Werte für die Kleinbuchstaben direkt aus den Werten der Großbuchstaben vom ersten Aufgabenteil bestimmen, ohne die ASCII-Tabelle zu benutzen? Geben Sie an, welche der folgenden Aussagen richtig oder falsch sind.

a) Man kann die Werte für die Kleinbuchstaben nicht aus dem ersten Aufgabenteil bestimmen, denn die Codierung der Kleinbuchstaben steht in keinem Zusammenhang mit der Codierung der Großbuchstaben.

b) Man kann die Werte für die Kleinbuchstaben mit Hilfe vom ersten Aufgabenteil bestimmen, indem man bei den Bytes, die Großbuchstaben enthalten, die Zahl 26 abzieht.

c) Man kann die Werte für die Kleinbuchstaben mit Hilfe vom ersten Aufgabenteil bestimmen, indem man bei den Bytes, die Großbuchstaben enthalten, die Zahl 32 addiert.

Lösungen

Lösung zu Aufgabe 1.):

void setup() {
Serial.begin(9600);
}

void loop() {
  for (char c = 65; c<=90; c++){
    Serial.print(c, DEC);
    Serial.print("  ");
    Serial.print(c, BIN);
    Serial.print("  ");
    Serial.print(c, HEX);
    Serial.print("  ");
    Serial.println(c);
  }
  delay(5000);
}

Lösung zu Aufgabe 2.):

a=97, z=122

Lösung zu Aufgabe 3.):

const int MAX_LENGTH = 100;
char text[MAX_LENGTH] = "Dies ist ein kurzer Text, _ den ich geheim halten : moechte {}."; 
char geheim[MAX_LENGTH];

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  // Verschlüsseln
  for (int i = 0; i < MAX_LENGTH; i++) {
    if (text[i] == 0)
      break; // damit unterbricht man die Schleife komplett und sofort
    // haben wir Spezialzeichen? Dann so lassen, wie es ist.
    if (text[i] < 'A' || text[i] > 'z' || (text[i] > 'Z' && text[i] < 'a')) {
      geheim[i] = text[i];
      continue; // damit kann man sofort den nächsten Durchlauf der for-Schleife erzwingen
    }
    // haben wir Gross- oder Kleinbuchstaben?
    char temp;
    if (text[i] <= 'Z') {
      temp = 'Z' - (text[i] - 'A');
    }
    else {
      temp = 'z' - (text[i] - 'a');
    }
    geheim[i] = temp;
  }

  Serial.print("Der Original Text ist: ");
  Serial.println(text);
  Serial.print("Verschlüsselt lautet er: ");
  Serial.println(geheim);

  delay(1000);

  // Umgekehrt ist es genau das Gleiche...
  for (int i = 0; i < MAX_LENGTH; i++) {
    if (geheim[i] == 0)
      break;
    // haben wir Spezialzeichen? Dann so lassen, wie es ist.
    if (geheim[i] < 'A' || geheim[i] > 'z' || (geheim[i] > 'Z' && geheim[i] < 'a')) {
      text[i] = geheim[i];
      continue; // damit kann man sofort den nächsten Durchlauf der for-Schleife erzwingen
    }
    // haben wir Gross- oder Kleinbuchstaben?
    char temp;
    if (geheim[i] <= 'Z') {
      temp = 'Z' - (geheim[i] - 'A');
    }
    else {
      temp = 'z' - (geheim[i] - 'a');
    }
    text[i] = temp;
  }

  Serial.print("Der entschlüsselte Text ist: ");
  Serial.println(text);

  delay(10000);
  
}c

Andere Kodierungen

Übungsaufgaben

1.) Zeichenanzahl

Wieviele Zeichen (Codepunkte) können mit dem erweiterten ASCII-Code dargestellt werden?

2.) Maximum

Wieviele Zeichen (Codepunkte) könnten theoretisch mit Unicode dargestellt werden, wenn man den gesamten durch 4 Byte darstellbaren Wertebereich ausnutzen würde? Beachten Sie, dass es sich um eine vorzeichenlose Darstellung handelt.

3.) UTF-8

Für die Kompatibilität mit UTF-8 wird in Unicode tatsächlich nur der Bereich von 0 bis 10FFFF16 genutzt. Wie viele Bits braucht man, um diesen Wertebereich abzudecken?

4.) Codierung

Ein UTF-8-Codepunkt belegt max. 4 Byte, wovon nur die in Aufgabe 3 bestimmte Anzahl von Bits zur eigentlichen Darstellung des Zeichens dient. Wieviele Bits Overhead kommen demnach durch die UTF-8-Codierung hinzu?

5.) Overheads

Füllen Sie die Lücken aus:

Trotz des Overheads hat UTF-8 bei normalen Texten ______ Speicherverbrauch als Unicode, weil Unicode Codepunkte mit ______ Länge benutzt und die am häufigsten benutzten Zeichen nur _____ Byte belegen.

6.) Kürzer

Füllen Sie die Lücken aus:

Codierungen, die kürzere Codepunkte für häufig vorkommende Daten verwenden, finden auch bei der ______ von Daten Anwendung, z.B. bei der Huffmancodierung.

7.) Lückentext

Füllen Sie die Lücken aus: Der originale ASCII-Code verwendet nur ______ Bit pro Zeichen. Für die Darstellung anderer Sprachen als Englisch ist er nicht geeignet, daher wurde zunächst der ______ ASCII-Code eingeführt, der aber in verschiedenen Versionen für unterschiedliche Sprachen existierte, was leicht zu Fehlern führen kann. Inzwischen steht der ______-Code zur Verfügung, der alle Sprachen umfasst, auch solche mit einer großen Anzahl an Zeichen.

Switch Case

Video einfügen: "Switch Case"

Übungsaufgaben

1.) Serieller Monitor

a) Gegeben ist folgender Code. Welche Ausgabe erfolgt auf dem seriellen Monitor?

void setup() {
  Serial.begin(9600);
  int a = 2;

  switch (a) {

    case 1: 
      Serial.println("eins");
      break;

    case 2:
      Serial.println("zwei");
      break;

    case 3:
      Serial.println("drei");
      break;

    default:
      Serial.println("unbekannt");
  }
}

loop() {
  // leer
}c

b) Gegeben ist folgender Code. Welche Ausgabe erfolgt auf dem seriellen Monitor?

void setup() {
  Serial.begin(9600);
  char c = 'b';

  switch (c) {
    case 'a':
      Serial.print('A');

    case 'b':
      Serial.print('B');

    case 'c':
      Serial.print('C');
      Serial.println('');
      break;

    default:
      Serial.println("unbekannt");
  }
}

loop() {
  // leer
}

2.) Zahlen einordnen

Schreiben Sie ein Ardunio-Programm, das ausgibt, ob eine vorgegebene Zahl zwischen 1 und 10 - eine gerade oder ungerade Zahl ist; - eine Primzahl ist. Verwenden Sie switch ... case-Anweisugen, um die Zahl zu identifizieren.

3.) Code verstehen

Gegeben ist folgender Codeschnipsel:

void setup()  {
  int a = 2;
  switch (a) {

     case 1: Serial.print("ABC");

     case 2: Serial.print("DEF");

     case 3: Serial.print("GHI");

             break;

     default:

             Serial.print("JKL");
}

a) Was gibt das Programm auf dem seriellen Monitor aus?

b) Eigentlich soll nur die erste Hälfte der Lösung aus a) ausgegeben werden. Wie kann der Fehler berichtigt werden?

Serial read

Übungsaufgaben

1.) Serial Read

Wir betrachten noch einmal das Blink-Programm, mit dem die Vorlesung eingeführt wurde.

void setup(){
  // put your setup code here, to run once:
  pinMode(LED_BUILTIN, OUTPUT);
}
void loop(){
  // put your main code here, to run repeatedly:
  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  delay(2000);
}

Erweitern Sie das Programm so, dass beim Start ein Wert für die Länge der Ein-Phase der LED über den seriellen Monitor vom Benutzer abgefragt wird und die LED entsprechend angesteuert wird. Überlegen Sie, welche Fehleingaben auftreten könnten und weisen Sie den Benutzer darauf hin. Sehen Sie im Falle einer Fehleingabe eine Voreinstellung für die LED-Einschaltdauer vor. Hinweise:

  • Die atoi()-Funktion, die Sie für die Umwandlung von String nach Integer benötigen, liefert eine Null zurück, wenn ihr etwas anderes als eine Zahl übergeben wird.

  • Achten Sie darauf, dass der serielle Monitor auf „Newline“ geschaltet ist wie in der Einführung beschrieben.

2.) Paint für Anfänger

In dieser Aufgabe sollen Sie ihr Wissen über die serielle Eingabe sowie Arrays miteinander verknüpfen. Die Idee ist, dass ein Array bestehend aus 10x10 Feldern zwei mögliche Zeichenwerte enthalten kann: . oder #. Der Nutzer wird nach einer Zeilennummer sowie einer Spaltennummer gefragt. Anschließend wird das entsprechende Feld im Array gesetzt: wenn es vorher ein . war, wird es auf # gesetzt und umgekehrt. Anschließend wird das Array über die Konsole ausgegeben und der Nutzer kann einen weiteren Wert eingeben. Die Ausgabe sollte wie folgt aussehen:

Dieses Programm kann als eine Art (sehr primitives) Malprogramm angesehen werden.

In diesem Programm werden Nutzereingaben verwendet. Prüfen Sie diese, bevor Sie diese im Programm verwenden. Liegt die eingegebene Zeilen- bzw. Spaltennummer im gültigen Rahmen?

3.) Serieller Monitor

Was muss man vor dem Starten eines Programmes beachten, das Daten vom seriellen Monitor liest?

Wenn Daten in den seriellen Monitor eingetippt werden, so werden diese vom Arduino gelesen:

Lösungen

Lösung zu Aufgabe 1.):

char incomingString[31];
int len;
int on_time = 1000;
int off_time = 1000;
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(9600);
  Serial.setTimeout(100000000);
  Serial.println("Geben Sie die Ein-Zeit für die LED ein und druecken Sie <Enter>.");
  // Eingabe des Benutzers einlesen
  len = Serial.readBytesUntil('\n', incomingString, 30);
  incomingString[len] = 0;
  // String in Zahl umwandeln
  on_time = atoi(incomingString);
  // Eingabe auf Gültigkeit prüfen
  if (on_time > 0) {
    Serial.print("Eingegebene Zeit: ");
    Serial.println(on_time);
  } else {
    on_time = 1000;
    Serial.println("Ungültige Zeit eingegeben - Default von 1000ms wird eingestellt.");
  }
}
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(on_time);
  digitalWrite(LED_BUILTIN, LOW);
  delay(off_time);
}
c

Lösung zu Aufgabe 2.):

const int rows = 10;
const int columns = 10;

char field[rows][columns];

int stringLen = 0;

void setup() {
  Serial.begin(9600);
  Serial.setTimeout(100000000);
  // init array
  for (int i = 0; i<rows; i++){
    for (int j = 0; j<columns; j++){
      field[i][j] = '.';
    }
  }
}

void loop() {
  print_field();
  
  Serial.println("Bitte die Zeilennummer eingeben, Eingabe mit <Enter> bestätigen:");
  Serial.flush();
  char rowString[4];
  stringLen = Serial.readBytesUntil('\n', rowString, 3);
  rowString[stringLen] = 0;
  int row = atoi(rowString);
  Serial.println(row);

  Serial.println("Bitte die Spaltennummer eingeben, Eingabe mit <Enter> bestätigen:");
  Serial.flush();
  char columnString[4];
  stringLen = Serial.readBytesUntil('\n', columnString, 3);
  columnString[stringLen] = 0;
  int column = atoi(columnString);
  Serial.println(column);

  if (row >= 0 && row < rows && column >= 0 && column < columns){
    if (field[row][column] == '.'){
      field[row][column] = '#';
    } else {
      field[row][column] = '.';
    }
  } else {
    Serial.println("Fehlerhafte Eingabe");
  }

}

void print_field(){
  for (int row=0; row<rows; row++){
    for (int column=0; column<columns; column++){
      Serial.print(field[row][column]);
    }
    Serial.println();
  }
}

Fortgeschrittene Aufgaben

1.) Laufschrift

Schreiben Sie ein Programm, das eine Laufschrift erzeugt. Ein über die Tastatur einzugebender String wird wiederholt ausgegeben, wobei der String in jedem Durchgang um ein Zeichen nach rechts verschoben wird. Die Länge der Ausgabezeile richtet sich nach der Länge des Strings. Zeichen, die rechts herausgeschoben wurden, werden links wieder eingefügt. Beispiel:

Lorem ipsum dolor sit amet.
.Lorem ipsum dolor sit amet
t.Lorem ipsum dolor sit ame
et.Lorem ipsum dolor sit am
met.Lorem ipsum dolor sit a
amet.Lorem ipsum dolor sit

usw.

2.) Schiffe versenken

Schreiben Sie ein Programm, gegen das Sie „Schiffe versenken“ spielen können. Verwenden Sie ein Spielfeld mit 5x5 Kästchen, dessen Reihen von a bis e und dessen Spalten von 1 bis 5 nummeriert sind. Der Arduino platziert zufällig 5 Schiffe auf dem Spielfeld, die jeweils eine Größe von genau einem Kästchen haben. Wenn zwei Schiffe dasselbe Kästchen belegen, würfelt das Programm für das neu hinzugekommene Schiff ein anderes Kästchen aus. Nach Beginn des Spieles geben Sie die Koordinaten eines Kästchens in der Form z.B. „a2“ , „c3“ ein und bekommen die Rückmeldung, ob ein Schiff versenkt wurde oder der Schuss daneben ging. Diese Abfrage wird wiederholt, bis alle Schiffe versenkt sind. Am Schluss gibt der Arduino eine Rückmeldung, wie viele Schüsse ingesamt benötigt wurden.

Die obige Beschreibung ist eine vereinfachte Version des Spiels für Übungszwecke. Wenn Sie mögen, können Sie das Programm auf das originale Spiel erweitern, wie in https://de.wikipedia.org/wiki/Schiffe_versenken beschrieben.

Last updated