Arduino Projekt: Türsicherheitssystem: Unterschied zwischen den Versionen

Aus HSHL Mechatronik
Zur Navigation springen Zur Suche springen
Keine Bearbeitungszusammenfassung
Zeile 1: Zeile 1:
test
[[Kategorie:Arduino: Projekt]]
[[Datei:PongGame neu.gif|thumb|right|600px|Abb. 1: Pong Spiel]]
'''Autor:''' Justin Frommberger<br>
 
== '''Aufgabenstellung''' ==
Ziel von dem Projekt ist eine Tür Sicherheitssystem zu simulieren.<br>
Die Aufgabe ist mit einem vier stelligen Zahlen Code die Tür zu öffnen.
 
== '''Benötigte Software''' ==
*Aktuellste '''Arduino IDE''' mit der Version für ihren PC. [https://www.arduino.cc/en/software/ (Download link)]
*Bibliotheken für das OLED Display: [https://github.com/adafruit/Adafruit_SSD1306 Adafruit_SSD1306] und  [https://github.com/adafruit/Adafruit-GFX-Library Adafruit-GFX-Library] downloaden.
** Klicke oben rechts in GitHub auf Code und dann downloade die Zip-Datei.
** Um die Zip-Datei in ihre Arduino Bibliothek einzubinden, folgen diese Schritte: [https://ardutronix.de/anleitung-library-in-arduino-ide-installieren-und-einbinden/ (Link)]
 
== '''Benötigte Materiallien''' ==
'''Tabelle 1: Materialliste'''
{| class="wikitable"
|+ style = "text-align: left"|
|-
 
! Nr. !! Anz.    !! Beschreibung !! Bild !! Pos. !! Anz.    !! Beschreibung !!Bild
|-
|<big><big>&#9312;</big></big>  || 1 || [[Arduino|Funduino Arduino UNO R3]] ||[[Datei:Arduino Uno R3.jpg|ohne|100px|]]
|<big><big>&#9313;</big></big>  || viele || Jumper Kabel, männlich/männlich||[[Datei:R19-F-2-2.jpg|ohne|100px|]]
|-
|-
|<big><big>&#9314;</big></big>  || 1 || [[Steckbrett]] ||[[Datei:R12-A-9-1.jpg|ohne|100px|]]
|<big><big>&#9315;</big></big>  || 4 || Taster||[[Datei:R12-KT-6.jpg|ohne|100px|]]
|-
|-
|<big><big>&#9316;</big></big>  || 1 || 0.96 I2C OLED Display||[[Datei:OLED 0.96.png|ohne|100px|]]
|}
 
== '''Vorab wichtig zu wissen!''' ==
[[Datei:OLED 0.96.png|thumb|rigth|250px|Abb. 2: OLED Display]]
'''Arduino Uno R3:'''
* Der Arduino besitzt unterschiedliche [[Arduino_UNO:_Board_Anatomie | Schnittstellen]], weil der Arduino ein digitaler Mikrocontroller ist, kann er nur <nowiki>&thinsp;</nowiki>5&thinsp;Volt ausgeben oder annehmen.
* Bei einer konstanten <nowiki>&thinsp;</nowiki>5&thinsp;V Spannung, ist die LED immer gleich hell, so ist das Ziel die Spannung zur LED zu reduzieren.
* Dafür wird eine Pulsweitenmodulation (PWM) Schnittstelle benötigt, denn bei den anderen Schnittstellen ist dies nicht möglich.
* Bei einem geringen PWM-Wert ist das <nowiki>&thinsp;</nowiki>5&thinsp;V Signal kaum noch vorhanden und bei einem hohen PWM-Wert liegt das <nowiki>&thinsp;</nowiki>5&thinsp;V Signal nahezu durchgehend am Pin an.
* Durch die PWM Schnittstelle kann nun die LED unterschiedlich hell leuchten, da die Spannung anpassbar ist.
* Die [[https://de.wikipedia.org/wiki/Pulsdauermodulation PWM]] Schnittstellen sind ganz einfach zu erkennen an diesem Zeichen (~)
 
'''Steckbrett:'''<br>
Erklärung zum Arbeiten mit einem Steckbrett [[Steckbrett | (klicken!)]]
 
'''OLED Display:'''<br>
Das Display verfügt über vier Pins:
* '''VCC''': Pin für die Spannungsversorgung, anzuschließen an den 5V Pin des Mikrocontrollers
* '''GND''': Ground-Pin, anzuschließen an den GND Pin des Mikrocontrollers
* '''SDA und SCL''': mit den dafür vorgesehenen Kontakten am Mikrocontroller
** Beim UNO R3 gibt es dafür oberhalb des Pin 13 einen SDA und SCL Pin, alternativ können auch die analogen Pins A4 (SDA) und A5 (SCL) verwendet werden.
 
== '''Aufbau Schaltung''' ==
[[Datei:Schaltung_Pong.png|500px|thumb|right|Abb.3 Schaltung Pong Spiel]]
In Abb. 3 wird die Schaltung für das Projekt '''" Arduino Pong Spiel"''' dargestellt.
 
=='''Arduino Datei erstellen'''==
Erstellen der ersten '''Arduino Datei''' ([https://wiki.hshl.de/wiki/index.php/Erste_Schritte_mit_der_Arduino_IDE Link zum Tutorial]).
 
=='''Programmierung Vorkenntnisse'''==
*Kenntnisse in den '''Programmierrichtlinien''' für die Erstellung von Software. ([[Programmierrichtlinien Einsteiger|Link]])<br>
*Grundkenntnisse von Projekt '''1-5''' verstanden haben. [https://wiki.hshl.de/wiki/index.php/Kategorie:Arduino:_Projekt (Link)]
*Grundkenntnisse für das Projekt '''"Arduino Pong Spiel"''' verstehen. ([[Grundkenntnisse Programmierung (Arduino Pong Spiel) |Link]])
 
=='''Programmierung Anleitung'''==
Nachdem alle Schritte abgeschlossen sind, kann mit der Programmierung des Projektes gestartet werden.
 
===1) Bibliotheken einfügen===
Zuerst muss, für das Projekt Pong Spiel die heruntergeladenen Bibliotheken eingefügt werden.<br>
 
'''Benötigt wird: '''
# Kommunikation zum I2C/TWI Gerät.
# Kommunikation mit dem SPI Gerät.
# Adafruit GFX Grafik.
# 128x64 and 128x32 OLEDs Displays.
 
'''Quelltext 1:''' <code>Pong.ino</code>
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
// Benötigte Bibliotheken
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
</syntaxhighlight>
|}
 
===2) Initialisierung Arduino===
Nachdem nun die Bibliotheken hinzugefügt wurden, folgt nun die Initialisierung der benötigten Pins und Variablen.<br>
Wichtig ist, sich vorab Gedanken zu machen, wie man diese anordnet. (siehe Abbildung 3)
 
====2.1) Taster: ====
Zuerst müssen allen vier Tastern einen Pin am Arduino zugewiesen werden, diese kann man beliebig an den digitalen Schnittstellen anschließen.<br>
Danach werden die Pins mit <code>pinMode();</code> und <code>digitalWrite();</code> initialisiert.
 
'''Quelltext 2:''' <code>Pong.ino</code>
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|     
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
/* Taster PINS */
const char UP_BUTTON = 2;
const char DOWN_BUTTON = 3;
const char UP_BUTTON_TWO = 4;
const char DOWN_BUTTON_TWO = 5;
 
void setup() {
/* Taster Initialisieren */
pinMode(UP_BUTTON, INPUT);
pinMode(DOWN_BUTTON, INPUT);               
digitalWrite(UP_BUTTON, HIGH);
digitalWrite(DOWN_BUTTON, HIGH);
   
/* Taster zwei */
pinMode(UP_BUTTON_TWO, INPUT);
pinMode(DOWN_BUTTON_TWO, INPUT);               
digitalWrite(UP_BUTTON_TWO, HIGH);
digitalWrite(DOWN_BUTTON_TWO, HIGH);
 
void loop() {
//Später
}
</syntaxhighlight>
|}
 
====2.2) OLED Display====
Um das OLED Display zu initialisieren, wird die Bibliothek Adafruit_SSD1306 benötigt.<br>
Hierfür nutzt man die <code>Adafruit_SSD1306 display()</code> Funktion.
 
'''Quelltext 3:''' <code>Pong.ino</code>
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|     
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
/* Deklaration Display, Verbindung zum I2C (SDA, SCL pins) */
const char OLED_RESET; // Reset pin
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
</syntaxhighlight>
|}
 
====2.3) Variablen====
Auch können vorab Variablen bestimmt werden, die für die Programmierung benötigt werden.<br>
Wie die Größe des Displays und die Eigenschaften vom Schläger und Ball.<br>
Zusätzlich ist geplant, eine Punkteanzeige zu entwerfen, wofür zwei Variablen benötigt werden.
 
'''Quelltext 4:''' <code>Pong.ino</code>
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|     
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
const unsigned char PADDLE_RATE = 33;        // const: Konstant, wert bleibt unverändert
const unsigned char BALL_RATE = 16;          // unsigned long: kann keine negativen Zahlen speichern
const unsigned char PADDLE_HEIGHT = 25;
 
const char SCREEN_WIDTH = 128;      // OLED Display Breite
const char SCREEN_HEIGHT = 64;    // OLED Display Höhe
 
unsigned int Player_one = 0, Player_two = 0;
</syntaxhighlight>
|}
 
====2.4) Position vom Ball, Paddle und Spieler auf dem Display ====
Im nächsten Schritt sollen die Postionen auf dem Display festgelegt werden.<br>
Benötigte Postionen sind: '''Ball, Spieler 1 (Player) und Spieler 2 (CPU)'''.<br>
Auch werden '''zwei update Variablen''' benötigt, um später den Ball und Schläger bewegen zu können.<br>
Dieser Werte können nach Geschmack angepasst werden.
 
'''Quelltext 5:''' <code>Pong.ino</code>
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|     
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
unsigned char Ball_x = 64, Ball_y = 32;                 
unsigned char Ball_dir_x = 1, Ball_dir_y = 1;
 
const unsigned char CPU_X = 12;                   
unsigned char Cpu_y = 16;
 
const unsigned char PLAYER_X = 115;
unsigned char Player_y = 16;
 
unsigned long Ball_update;
unsigned long Paddle_update;
 
</syntaxhighlight>
|}
 
===3) Display hochfahren===
Um später zu sehen, wo man welche Objekte platziert hat, muss das Display hochgefahren werden.<br>
Zusätzlich wird beim Start vom Display ein Timer gesetzt, dieser wird für die Bewegung vom Ball benötigt.<br>
'''Benötigt wird: ''' <code>display.display();</code> und <code>mills();</code> zum Zeitauslesen.   
 
'''Quelltext 6: ''' <code>Pong.ino</code>
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung Code &thinsp;</strong>
|-
|     
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
void setup() {
  Serial.begin(9600);
 
/* Hochfahren vom Display */
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // Starte das Display       
  display.display();                    // Zeigt das Startbild vom Arduino an
  unsigned long start = millis();      // Anzahl von Ms zurück, seit Arduino-Board das aktuelle Programm gestartet hat
  delay(1000);
  display.clearDisplay();            // Löscht das Bild
 
/* Ball Timer zuweisen*/
  Ball_update = millis();
  delay(1000);
}
</syntaxhighlight>
|}
 
====3.1) Display Spielname anzeigen====
Als Zusatzaufgabe habe ich überlegt, bevor das Spiel startet den Namen '''Pong Spiel''' auf dem Display anzeigen zu lassen.<br>
Tipp: Hierfür werden die <code>display.set();</code> und <code>display.println();</code> Funktionen benötigt.
 
'''Quelltext 7: ''' <code>Pong.ino</code>
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|     
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
/* Pong Spiel Namen anzeigen */
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(5, 25);
  display.println("Pong Spiel");
  display.display();
  delay(1000);
  display.clearDisplay();
</syntaxhighlight>
|}
 
===4) Display Punkteanzeige===
Um die Punktanzeige ins Spiel mit einzubringen, werden zwei Methoden benötigt.<br>
Die erste Methode soll die Zahlen auf dem Display anzeigen.<br>
Die zweite Methode soll die erstellen Zahlen wieder löschen, um das nächste Ergebnis korrekt anzuzeigen.<br>
'''Tipp:''' Hierfür werden die <code>display.set();</code> und <code>display.println();</code> Funktionen benötigt.
 
'''Quelltext 8:''' <code>Pong.ino</code>
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|     
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
 
/* Punkteanzeigen */
void drawScore() {               
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(43, 0);
  display.println(Player_one);
 
  display.setCursor(73, 0);
  display.println(Player_two);
}
/* Punkte zurücksetzten */
void eraseScore() {                             
  display.setTextSize(2);
  display.setTextColor(BLACK);
  display.setCursor(43, 0);
  display.println(Player_one);
 
  display.setCursor(73, 0);
  display.println(Player_two);
}
</syntaxhighlight>
|}
 
===5) Bewegter Ball===
Damit der Ball sich auf dem Display bewegt, benötigt man eine Rechenfunktion.<br>
'''Tipp:''' Rechne den X und Y Wert + 1 und erstelle eine neue Variable.
 
'''Quelltext 9:''' <code>Pong.ino</code>
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
void loop() {
  unsigned long time = millis();              // Zeit-Variable
 
/* Neue Ballposition */
if (time > Ball_update) {
  unsigned char New_x = Ball_x + Ball_dir_x;              // (x+1)
  unsigned char New_y = Ball_y + Ball_dir_y;              // (y+1)
}
</syntaxhighlight>
|}
 
====5.1) Wände erkennen====
Damit der Ball wie gewünscht von den Wänden abprallt, müssen die Wände mit einer If Abfrage erkannt werden.<br>
Wenn der Ball auf eine Wand trifft, muss die Richtung vom Ball geändert werden.<br>
Zusätzlich soll der Spieler ein Punkt bekommen, wenn die Linke oder Rechte Wand berührt wurde.<br>
'''Tipp: ''' Wenn die X oder Y Position von der Wand erreicht wurde, negiere den Addierer.
 
'''Quelltext 10:''' <code>Pong.ino</code>
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
if (time > Ball_update) {
    /* Neue Ballposition */
    unsigned char New_x = Ball_x + Ball_dir_x;              // (x+1)
    unsigned char New_y = Ball_y + Ball_dir_y;              // (y+1)
 
    /* Checkt ob die verticalen Wände berüht werden */
    if (New_x == 0) {                        // Wand links
      Ball_dir_x = -Ball_dir_x;            // Wechselt die Richtung
      New_x += Ball_dir_x + Ball_dir_x;
      eraseScore();                        // Punkt für Spieler
      Player_one += 1;
      drawScore();
 
    }
    if (New_x == 127) {                    // Wand rechts
      Ball_dir_x = -Ball_dir_x;            // Wechselt die Richtung
      New_x += Ball_dir_x + Ball_dir_x;
      eraseScore();                        // Punkt für den Computer
      Player_two += 1;
      drawScore();
    }
 
    // Checkt ob die horizontalen Wände berüht werden
    if (New_y == 0 || New_y == 63)  {
      Ball_dir_y = -Ball_dir_y;          // Wechselt die Richtung
      New_y += Ball_dir_y + Ball_dir_y;
 
    }
}
 
</syntaxhighlight>
|}
 
====5.2) Paddel erkennen====
Auch muss der Ball, wenn er den Schläger berührt, seine Richtung ändern.<br>
'''Tipp: ''' Postion von den Paddeln muss kleiner sein als die Postion vom Ball.
 
'''Quelltext 11:''' <code>Pong.ino</code>
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
/* Checkt, ob der Spieler 1 Paddel getroffen wurde */
if (New_x == PLAYER_X && New_y >= Player_y && New_y <= Player_y + PADDLE_HEIGHT) {
  Ball_dir_x = -Ball_dir_x;
  New_x += Ball_dir_x + Ball_dir_x;
}
 
/* Checkt, ob der Spieler 2 Paddel getroffen wurde */
if (New_x == CPU_X && New_y >= Cpu_y && New_y <= Cpu_y + PADDLE_HEIGHT) {
  Ball_dir_x = -Ball_dir_x;
  New_x += Ball_dir_x + Ball_dir_x;
}
</syntaxhighlight>
|}
 
====5.3) Neue Ballposition anzeigen====
Nun kann sich der Ball bewegen, muss aber noch auf dem Display als Pixel angezeigt werden und die alten Pixel wieder gelöscht werden.<br>
Auch müssen die neuen Variablen übertragen werden auf die alten, um weitere Abläufe zu ermöglichen.<br>
'''Tipp: '''Nutze <code>display.drawPixel(Name, Name,BLACK/WHITE);</code>.
 
'''Quelltext 12:''' <code>Pong.ino</code>
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
  display.drawPixel(Ball_x, Ball_y, BLACK);
  display.drawPixel(New_x, New_y, WHITE);
  Ball_x = New_x;
  Ball_y = New_y;
 
  Ball_update += BALL_RATE;
  display.display();        // Später: update = true;  (true = display.display();
</syntaxhighlight>
|}
 
===6) Boolean Taster===
Ich habe mich dafür entschieden, mit einem <code>bool</code> zu programmieren, um die Taster abzufragen und falsche Eingaben zu überprüfen.<br><br>
'''Tipp: '''<br>
Neue Variablen für die Taster mit <code>bool</code> initialisieren.<br>
Die alten und neuen Variablen auf <code>LOW</code> setzen, um die Taster schalten zu können.<br>
Wenn die <code>bool</code> Variable = true ist, soll das Display aktualisiert werden. (<code> display.display();</code>)
 
'''Quelltext 13:''' <code>Pong.ino</code>
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
void loop() {
bool update = false;                          // Ein bool enthält einen von zwei Werten, true oder false
 
  static bool Up_state = false;
  static bool Down_state = false;
  static bool Up_state_two = false;
  static bool Down_state_two = false;
 
  Up_state |= (digitalRead(UP_BUTTON) == LOW);                  // Taster auslesen
  Down_state |= (digitalRead(DOWN_BUTTON) == LOW);
  Up_state_two |= (digitalRead(UP_BUTTON_TWO) == LOW);
  Down_state_two |= (digitalRead(DOWN_BUTTON_TWO) == LOW);
 
 
if (update)                      // Wenn Variable = true wird display.display(); ausgeführt
    display.display();
}
</syntaxhighlight>
|}
===7) Paddel Spieler===
Der letzte Schritt ist, die Schläger mit den Tastern steuerbar zu machen.<br>
Diese dürfen aber nicht aus dem Display gelangen.<br><br>
'''Tipp: '''<br>
Der Ablauf ist ähnlich wie beim Ball, nur werden die If-Anweisungen von den Tastern betätigt.<br>
Zusätzlich müssen noch die Schläger auf dem Display angezeigt werden, mit der Funktion <code>display.drawFastVLine(PLAYER_X, Player_y, PADDLE_HEIGHT, BLACK);</code>.
 
'''Quelltext 14:''' <code>Pong.ino</code>
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung &thinsp;</strong>
|-
|
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
void loop() {
/* Spieler 1 Paddel */
  display.drawFastVLine(PLAYER_X, Player_y, PADDLE_HEIGHT, BLACK);
  if (Up_state) {
    Player_y -= 1;
  }
  if (Down_state) {
    Player_y += 1;
  }
  Up_state = Down_state = false;
 
  if (Player_y < 1) Player_y = 1;                                    // Um nicht aus dem Bildschirm zu gelangen
  if (Player_y + PADDLE_HEIGHT > 63) Player_y = 63 - PADDLE_HEIGHT;
  display.drawFastVLine(PLAYER_X, Player_y, PADDLE_HEIGHT, WHITE);
 
  update = true;
 
/* Spieler 2 Paddel */
  display.drawFastVLine(CPU_X, Cpu_y, PADDLE_HEIGHT, BLACK);
  if (Up_state_two) {
    Cpu_y -= 1;                      // Paddle 1 nach unten
  }
  if (Down_state_two) {
    Cpu_y += 1;                      // Paddle 1 nach oben
  }
  Up_state_two = Down_state_two = false;
 
  if (Cpu_y < 1) Cpu_y = 1;                                        // Um nicht aus dem Bildschirm zu gelangen
  if (Cpu_y + PADDLE_HEIGHT > 63) Cpu_y = 63 - PADDLE_HEIGHT;
  display.drawFastVLine(CPU_X, Cpu_y, PADDLE_HEIGHT, WHITE);
}
</syntaxhighlight>
|}
 
== '''Musterlösung''' ==
 
Quelle: [https://github.com/shveytank/Arduino_Pong_Game Link]
{| role="presentation" class="wikitable mw-collapsible mw-collapsed"
| <strong>Lösung Code &thinsp;</strong>
|-
|     
<syntaxhighlight lang="C" style="border: none; background-color: #EFF1C1; font-size:14px">
/* Benötigte Bibliotheken */
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
 
/* Taster PINS */
const char UP_BUTTON = 2;
const char DOWN_BUTTON = 3;
const char UP_BUTTON_TWO = 4;
const char DOWN_BUTTON_TWO = 5;
 
/* Variablen */
const unsigned char PADDLE_RATE = 33;        // const: Konstant, wert bleibt unverändert
const unsigned char BALL_RATE = 16;          // unsigned long: kann keine negativen Zahlen speichern
const unsigned char PADDLE_HEIGHT = 25;
 
const char SCREEN_WIDTH = 128;      // OLED Display Breite
const char SCREEN_HEIGHT = 64;    // OLED Display Höhe
 
unsigned int Player_one = 0, Player_two = 0;
 
/* Deklaration Display, verbindung zum I2C (SDA, SCL pins) */
const char OLED_RESET = 0; // Reset pin
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
 
 
/* Position vom Ball, Paddle und Spieler auf dem Display */
 
unsigned char Ball_x = 64, Ball_y = 32;
unsigned char Ball_dir_x = 1, Ball_dir_y = 1;
 
const unsigned char CPU_X = 12;
unsigned char Cpu_y = 16;
 
const unsigned char PLAYER_X = 115;
unsigned char Player_y = 16;
 
unsigned long Ball_update;
unsigned long Paddle_update;
 
void setup() {
  Serial.begin(9600);
 
  /* Hochfahren vom Display */
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // Starte das Display
  display.display();                    // Zeigt das Startbild vom Arduino an
  unsigned long start = millis();      // Anzahl von Ms zurück, seit Arduino-Board das aktuelle Programm gestartet hat
  delay(1000);
  display.clearDisplay();            // Löscht das Bild
 
  /* Pong Spiel Namen anzeigen */
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(5, 25);
  display.println("Pong Spiel");
  display.display();
  delay(1000);
  display.clearDisplay();
 
  /* Ball Timer zuweisen*/
  Ball_update = millis();
  delay(1000);
 
  /* Taster Initialisieren */
  pinMode(UP_BUTTON, INPUT);      // Taster als INPUT festlegen
  pinMode(DOWN_BUTTON, INPUT);
  digitalWrite(UP_BUTTON, HIGH);      // Taster anschalten
  digitalWrite(DOWN_BUTTON, HIGH);
 
  /* Taster zwei */
  pinMode(UP_BUTTON_TWO, INPUT);
  pinMode(DOWN_BUTTON_TWO, INPUT);
  digitalWrite(UP_BUTTON_TWO, HIGH);
  digitalWrite(DOWN_BUTTON_TWO, HIGH);
}
 
/* Punkteanzeige */
void drawScore() {
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(43, 0);
  display.println(Player_one);
 
  display.setCursor(73, 0);
  display.println(Player_two);
}
/* Punkte zurücksetzten */
void eraseScore() {
  display.setTextSize(2);
  display.setTextColor(BLACK);
  display.setCursor(43, 0);
  display.println(Player_one);
 
  display.setCursor(73, 0);
  display.println(Player_two);
}
 
 
void loop() {
  drawScore();
 
  bool update = false;                          // Ein bool enthält einen von zwei Werten, true oder false
 
  unsigned long time = millis();              // Zeit-Variable
 
  static bool Up_state = false;
  static bool Down_state = false;
  static bool Up_state_two = false;
  static bool Down_state_two = false;
 
  Up_state |= (digitalRead(UP_BUTTON) == LOW);                  // Taster auslesen
  Down_state |= (digitalRead(DOWN_BUTTON) == LOW);
  Up_state_two |= (digitalRead(UP_BUTTON_TWO) == LOW);
  Down_state_two |= (digitalRead(DOWN_BUTTON_TWO) == LOW);
 
/* Neue Ballposition */
  if (time > Ball_update) {
    /* Neue Ballposition */
    unsigned char New_x = Ball_x + Ball_dir_x;              // (x+1)
    unsigned char New_y = Ball_y + Ball_dir_y;              // (y+1)
 
    /* Checkt ob die verticalen Wände berüht werden */
    if (New_x == 0) {                        // Wand links
      Ball_dir_x = -Ball_dir_x;            // Wechselt die Richtung
      New_x += Ball_dir_x + Ball_dir_x;
      eraseScore();                        // Punkt für Spieler
      Player_one += 1;
      drawScore();
 
    }
    if (New_x == 127) {                    // Wand rechts
      Ball_dir_x = -Ball_dir_x;            // Wechselt die Richtung
      New_x += Ball_dir_x + Ball_dir_x;
      eraseScore();                        // Punkt für den Computer
      Player_two += 1;
      drawScore();
    }
 
    // Checkt ob die horizontalen Wände berüht werden
    if (New_y == 0 || New_y == 63)  {
      Ball_dir_y = -Ball_dir_y;          // Wechselt die Richtung
      New_y += Ball_dir_y + Ball_dir_y;
 
    }
    // Checkt, ob der Spieler 1 Paddel getroffen wurde
    if (New_x == PLAYER_X && New_y >= Player_y && New_y <= Player_y + PADDLE_HEIGHT) {
      Ball_dir_x = -Ball_dir_x;
      New_x += Ball_dir_x + Ball_dir_x;
 
    }
    // Checkt, ob der Spieler 2 Paddel getroffen wurde
    if (New_x == CPU_X && New_y >= Cpu_y && New_y <= Cpu_y + PADDLE_HEIGHT) {
      Ball_dir_x = -Ball_dir_x;
      New_x += Ball_dir_x + Ball_dir_x;
    }
 
    display.drawPixel(Ball_x, Ball_y, BLACK);
    display.drawPixel(New_x, New_y, WHITE);
    Ball_x = New_x;
    Ball_y = New_y;
 
    Ball_update += BALL_RATE;
 
    update = true;              // true ~ display.display();
  }
 
/* Spieler 1 Paddel */
  display.drawFastVLine(PLAYER_X, Player_y, PADDLE_HEIGHT, BLACK);
  if (Up_state) {
    Player_y -= 1;
  }
  if (Down_state) {
    Player_y += 1;
  }
  Up_state = Down_state = false;
 
  if (Player_y < 1) Player_y = 1;                                    // Um nicht aus dem Bildschirm zu gelangen
  if (Player_y + PADDLE_HEIGHT > 63) Player_y = 63 - PADDLE_HEIGHT;
  display.drawFastVLine(PLAYER_X, Player_y, PADDLE_HEIGHT, WHITE);
 
  update = true;
 
/* Spieler 2 Paddel */
  display.drawFastVLine(CPU_X, Cpu_y, PADDLE_HEIGHT, BLACK);
  if (Up_state_two) {
    Cpu_y -= 1;                      // Paddle 1 nach unten
  }
  if (Down_state_two) {
    Cpu_y += 1;                      // Paddle 1 nach oben
  }
  Up_state_two = Down_state_two = false;
 
  if (Cpu_y < 1) Cpu_y = 1;                                        // Um nicht aus dem Bildschirm zugelangen
  if (Cpu_y + PADDLE_HEIGHT > 63) Cpu_y = 63 - PADDLE_HEIGHT;
  display.drawFastVLine(CPU_X, Cpu_y, PADDLE_HEIGHT, WHITE);
 
 
  if (update)
    display.display();
}
 
</syntaxhighlight>
|}
 
<br>
----
→ zurück zum Hauptartikel: [[Konzipierung_und_Evaluierung_von_Arduino-Projekten_verschiedener_Schwierigkeitsgrade_für_die_Lehre | BA: Arduino-Projekte für die Lehre]]

Version vom 23. Juli 2023, 14:52 Uhr

Abb. 1: Pong Spiel

Autor: Justin Frommberger

Aufgabenstellung

Ziel von dem Projekt ist eine Tür Sicherheitssystem zu simulieren.
Die Aufgabe ist mit einem vier stelligen Zahlen Code die Tür zu öffnen.

Benötigte Software

  • Aktuellste Arduino IDE mit der Version für ihren PC. (Download link)
  • Bibliotheken für das OLED Display: Adafruit_SSD1306 und Adafruit-GFX-Library downloaden.
    • Klicke oben rechts in GitHub auf Code und dann downloade die Zip-Datei.
    • Um die Zip-Datei in ihre Arduino Bibliothek einzubinden, folgen diese Schritte: (Link)

Benötigte Materiallien

Tabelle 1: Materialliste

Nr. Anz. Beschreibung Bild Pos. Anz. Beschreibung Bild
1 Funduino Arduino UNO R3
viele Jumper Kabel, männlich/männlich
1 Steckbrett
4 Taster
1 0.96 I2C OLED Display

Vorab wichtig zu wissen!

Abb. 2: OLED Display

Arduino Uno R3:

  • Der Arduino besitzt unterschiedliche Schnittstellen, weil der Arduino ein digitaler Mikrocontroller ist, kann er nur  5 Volt ausgeben oder annehmen.
  • Bei einer konstanten  5 V Spannung, ist die LED immer gleich hell, so ist das Ziel die Spannung zur LED zu reduzieren.
  • Dafür wird eine Pulsweitenmodulation (PWM) Schnittstelle benötigt, denn bei den anderen Schnittstellen ist dies nicht möglich.
  • Bei einem geringen PWM-Wert ist das  5 V Signal kaum noch vorhanden und bei einem hohen PWM-Wert liegt das  5 V Signal nahezu durchgehend am Pin an.
  • Durch die PWM Schnittstelle kann nun die LED unterschiedlich hell leuchten, da die Spannung anpassbar ist.
  • Die [PWM] Schnittstellen sind ganz einfach zu erkennen an diesem Zeichen (~)

Steckbrett:
Erklärung zum Arbeiten mit einem Steckbrett (klicken!)

OLED Display:
Das Display verfügt über vier Pins:

  • VCC: Pin für die Spannungsversorgung, anzuschließen an den 5V Pin des Mikrocontrollers
  • GND: Ground-Pin, anzuschließen an den GND Pin des Mikrocontrollers
  • SDA und SCL: mit den dafür vorgesehenen Kontakten am Mikrocontroller
    • Beim UNO R3 gibt es dafür oberhalb des Pin 13 einen SDA und SCL Pin, alternativ können auch die analogen Pins A4 (SDA) und A5 (SCL) verwendet werden.

Aufbau Schaltung

Abb.3 Schaltung Pong Spiel

In Abb. 3 wird die Schaltung für das Projekt " Arduino Pong Spiel" dargestellt.

Arduino Datei erstellen

Erstellen der ersten Arduino Datei (Link zum Tutorial).

Programmierung Vorkenntnisse

  • Kenntnisse in den Programmierrichtlinien für die Erstellung von Software. (Link)
  • Grundkenntnisse von Projekt 1-5 verstanden haben. (Link)
  • Grundkenntnisse für das Projekt "Arduino Pong Spiel" verstehen. (Link)

Programmierung Anleitung

Nachdem alle Schritte abgeschlossen sind, kann mit der Programmierung des Projektes gestartet werden.

1) Bibliotheken einfügen

Zuerst muss, für das Projekt Pong Spiel die heruntergeladenen Bibliotheken eingefügt werden.

Benötigt wird:

  1. Kommunikation zum I2C/TWI Gerät.
  2. Kommunikation mit dem SPI Gerät.
  3. Adafruit GFX Grafik.
  4. 128x64 and 128x32 OLEDs Displays.

Quelltext 1: Pong.ino

2) Initialisierung Arduino

Nachdem nun die Bibliotheken hinzugefügt wurden, folgt nun die Initialisierung der benötigten Pins und Variablen.
Wichtig ist, sich vorab Gedanken zu machen, wie man diese anordnet. (siehe Abbildung 3)

2.1) Taster:

Zuerst müssen allen vier Tastern einen Pin am Arduino zugewiesen werden, diese kann man beliebig an den digitalen Schnittstellen anschließen.
Danach werden die Pins mit pinMode(); und digitalWrite(); initialisiert.

Quelltext 2: Pong.ino

2.2) OLED Display

Um das OLED Display zu initialisieren, wird die Bibliothek Adafruit_SSD1306 benötigt.
Hierfür nutzt man die Adafruit_SSD1306 display() Funktion.

Quelltext 3: Pong.ino

2.3) Variablen

Auch können vorab Variablen bestimmt werden, die für die Programmierung benötigt werden.
Wie die Größe des Displays und die Eigenschaften vom Schläger und Ball.
Zusätzlich ist geplant, eine Punkteanzeige zu entwerfen, wofür zwei Variablen benötigt werden.

Quelltext 4: Pong.ino

2.4) Position vom Ball, Paddle und Spieler auf dem Display

Im nächsten Schritt sollen die Postionen auf dem Display festgelegt werden.
Benötigte Postionen sind: Ball, Spieler 1 (Player) und Spieler 2 (CPU).
Auch werden zwei update Variablen benötigt, um später den Ball und Schläger bewegen zu können.
Dieser Werte können nach Geschmack angepasst werden.

Quelltext 5: Pong.ino

3) Display hochfahren

Um später zu sehen, wo man welche Objekte platziert hat, muss das Display hochgefahren werden.
Zusätzlich wird beim Start vom Display ein Timer gesetzt, dieser wird für die Bewegung vom Ball benötigt.
Benötigt wird: display.display(); und mills(); zum Zeitauslesen.

Quelltext 6: Pong.ino

3.1) Display Spielname anzeigen

Als Zusatzaufgabe habe ich überlegt, bevor das Spiel startet den Namen Pong Spiel auf dem Display anzeigen zu lassen.
Tipp: Hierfür werden die display.set(); und display.println(); Funktionen benötigt.

Quelltext 7: Pong.ino

4) Display Punkteanzeige

Um die Punktanzeige ins Spiel mit einzubringen, werden zwei Methoden benötigt.
Die erste Methode soll die Zahlen auf dem Display anzeigen.
Die zweite Methode soll die erstellen Zahlen wieder löschen, um das nächste Ergebnis korrekt anzuzeigen.
Tipp: Hierfür werden die display.set(); und display.println(); Funktionen benötigt.

Quelltext 8: Pong.ino

5) Bewegter Ball

Damit der Ball sich auf dem Display bewegt, benötigt man eine Rechenfunktion.
Tipp: Rechne den X und Y Wert + 1 und erstelle eine neue Variable.

Quelltext 9: Pong.ino

5.1) Wände erkennen

Damit der Ball wie gewünscht von den Wänden abprallt, müssen die Wände mit einer If Abfrage erkannt werden.
Wenn der Ball auf eine Wand trifft, muss die Richtung vom Ball geändert werden.
Zusätzlich soll der Spieler ein Punkt bekommen, wenn die Linke oder Rechte Wand berührt wurde.
Tipp: Wenn die X oder Y Position von der Wand erreicht wurde, negiere den Addierer.

Quelltext 10: Pong.ino

5.2) Paddel erkennen

Auch muss der Ball, wenn er den Schläger berührt, seine Richtung ändern.
Tipp: Postion von den Paddeln muss kleiner sein als die Postion vom Ball.

Quelltext 11: Pong.ino

5.3) Neue Ballposition anzeigen

Nun kann sich der Ball bewegen, muss aber noch auf dem Display als Pixel angezeigt werden und die alten Pixel wieder gelöscht werden.
Auch müssen die neuen Variablen übertragen werden auf die alten, um weitere Abläufe zu ermöglichen.
Tipp: Nutze display.drawPixel(Name, Name,BLACK/WHITE);.

Quelltext 12: Pong.ino

6) Boolean Taster

Ich habe mich dafür entschieden, mit einem bool zu programmieren, um die Taster abzufragen und falsche Eingaben zu überprüfen.

Tipp:
Neue Variablen für die Taster mit bool initialisieren.
Die alten und neuen Variablen auf LOW setzen, um die Taster schalten zu können.
Wenn die bool Variable = true ist, soll das Display aktualisiert werden. ( display.display();)

Quelltext 13: Pong.ino

7) Paddel Spieler

Der letzte Schritt ist, die Schläger mit den Tastern steuerbar zu machen.
Diese dürfen aber nicht aus dem Display gelangen.

Tipp:
Der Ablauf ist ähnlich wie beim Ball, nur werden die If-Anweisungen von den Tastern betätigt.
Zusätzlich müssen noch die Schläger auf dem Display angezeigt werden, mit der Funktion display.drawFastVLine(PLAYER_X, Player_y, PADDLE_HEIGHT, BLACK);.

Quelltext 14: Pong.ino

Musterlösung

Quelle: Link



→ zurück zum Hauptartikel: BA: Arduino-Projekte für die Lehre