In diesem Beitrag zeige ich dir, wie du mit wenig Hardware eine kleine Arduino Slotmaschine programmierst, die auf einem 1,3″ OLED-Display läuft. Gesteuert wird das Ganze per Tastendruck: drei Symbole rotieren unabhängig voneinander und bleiben nach kurzer Zeit stehen – fast wie bei einer echten Slotmaschine.
Als Mikrocontroller verwende ich hier den neuen Arduino Nano R4, da er bei mir ohnehin im Einsatz ist. Du kannst das Projekt aber genauso gut mit jedem anderen Arduino Nano umsetzen – egal ob Nano V3, Nano IoT, einem ESP32 im Nano-Format oder einem vergleichbaren Board.
Das Projekt ist einfach nachzubauen, macht Spaß und eignet sich perfekt, um erste Erfahrungen mit Displaysteuerung und kleinen Animationen auf dem Arduino zu sammeln.



🔔 Hinweis: Dieses Projekt zeigt eine kleine Slotmaschine auf dem Arduino – ganz ohne Einsatz von Geld, nur zum Spaß und Lernen.
Glücksspiel ist keine gute Sache und birgt ernsthafte Risiken.
Wenn du von Glücksspielsucht betroffen bist oder dir Sorgen machst, findest du unter der kostenfreien Hotline des Bundesinstituts für öffentliche Gesundheit Unterstützung: 📞 0800 – 137 27 00
Inhaltsverzeichnis
- Benötigte Bauteile
- Aufbau der Schaltung auf einem Breadboard
- Symbole für die Slotmachine
- Programmieren einer Slotmachine am Arduino
- Snipets aus dem Code
Benötigte Bauteile
Für den Nachbau der kleinen Arduino-Slotmaschine brauchst du nur wenige Standardkomponenten:
- Mikrocontroller: z. B. Arduino Nano R4* (funktioniert aber auch mit Nano V3*, Nano IoT* etc.)
- OLED Display 1,3″* (I²C-Anschluss)
- Breadboardkabel / Jumperkabel*, männlich-männlich, 10 cm – 4 Stück in den Farben rot, schwarz, gelb, grün (für die Display-Verbindung)
- Taster* (z. B. Printmontage 6×6 mm oder 12×12 mm)
- Breadboardkabel / Jumperkabel*, männlich-männlich – 2 Stück in schwarz und blau (für den Taster)
Hinweis für Arduino Nano R4 Nutzer: Wenn du – wie ich – den Arduino Nano R4 verwenden möchtest, benötigst du zusätzlich zwei 4,7 kΩ Widerstände.
Diese dienen als I²C Pull-Ups und verbinden die Leitungen SDA und SCL mit VCC, damit die Kommunikation mit dem OLED-Display zuverlässig funktioniert. (siehe NEU! Arduino Nano R4: Der I2C-Fix, den dir keiner sagt (Pull-Ups!))
Hinweis von mir: Die mit einem Sternchen (*) markierten Links sind Affiliate-Links. Wenn du über diese Links einkaufst, erhalte ich eine kleine Provision, die dazu beiträgt, diesen Blog zu unterstützen. Der Preis für dich bleibt dabei unverändert. Vielen Dank für deine Unterstützung!
👉 Ich baue die Schaltung zunächst auf dem Breadboard auf. Sobald alles funktioniert, nutze ich das FlexCase von makers-gonna-make.de, für das ich mir ein eigenes Plate entworfen habe, auf dem sowohl das Display als auch der Taster Platz finden.

Aufbau der Schaltung auf einem Breadboard
Für den ersten Testaufbau wird die Slotmachine-Schaltung ganz einfach auf einem Breadboard realisiert. So kannst du schnell prüfen, ob Display, Taster und Buzzer wie gewünscht funktionieren, bevor du später vielleicht ein Gehäuse oder ein FlexCase verwendest.

Verdrahtung
- OLED-Display (SH1106, I²C)
- VCC → 5V am Arduino Nano R4
- GND → GND
- SDA → A4 (I²C-Datenleitung)
- SCL → A5 (I²C-Taktleitung)
- Pull-Up-Widerstände (nur beim Nano R4 nötig)
- 4,7 kΩ von SDA nach VCC
- 4,7 kΩ von SCL nach VCC
- Taster
- ein Pin → D2 am Arduino (mit
INPUT_PULLUP
im Code) - anderer Pin → GND
- ein Pin → D2 am Arduino (mit
- Buzzer
- ein Pin → D3 am Arduino
- anderer Pin → GND
Hinweis
Der Taster wird hier gegen GND geschaltet und im Sketch mit INPUT_PULLUP
konfiguriert. Dadurch sparst du dir einen externen Widerstand.
Symbole für die Slotmachine
Für unsere Slotmachine benötigen wir Icons – jeweils ein 🍀 Kleeblatt, ein ❤️ Herz, 🍒 Kirschen und eine Sieben.
Diese Symbole werden als XBM-Bitmaps im Arduino-Sketch eingebunden und anschließend mit drawXBitmap()
auf dem OLED-Display dargestellt.
Natürlich kannst du auch eigene Icons erstellen und verwenden – deiner Kreativität sind keine Grenzen gesetzt.
Wie du ein beliebiges PNG-Bild in das XBM-Format umwandelst, habe ich hier Schritt für Schritt erklärt:
👉 XBM Bitmaps für Arduino Displays: So geht’s Schritt für Schritt
Programmieren einer Slotmachine am Arduino
Bevor wir mit der eigentlichen Slotmachine beginnen können, müssen wir zunächst das OLED-Display ansteuern. Dafür benötigen wir die passende Bibliothek.
Bibliothek installieren
Da ich ein 1,3″ OLED-Display mit SH1106G-Treiberchip verwende, nutze ich die Adafruit SH110X Library. Diese installierst du bequem über den Bibliotheksverwalter der Arduino IDE:
- links im Menü den Eintrag „Bibliotheksverwalter“ auswählen (drittes Icon von oben)
- Nach „Adafruit SH110X“ suchen
- Bibliothek installieren (die Adafruit GFX Library wird automatisch als Abhängigkeit mitinstalliert)


Solltest du jedoch ein OLED-Display mit SSD1306 Chip haben, so musst du nach Adafruit SSD1306 suchen.
Bibliothek einbinden
Nachdem die beiden Bibliotheken installiert wurden, können diese wiefolgt eingebunden und verwendet werden:
#include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SH110X.h> #define i2c_Address 0x3c Adafruit_SH1106G display = Adafruit_SH1106G(128, 64, &Wire, -1);
Damit ist dein Projekt vorbereitet, um Grafiken, Text und später auch die Slot-Symbole auf dem OLED-Display darzustellen.
Snipets aus dem Code
Nachfolgend möchte ich dir einige besondere Code-Snippets erläutern.
Im Grunde ist der Aufbau und Ablauf der Slotmachine recht einfach, dennoch gibt es ein paar spannende Stellen, die man sich genauer ansehen sollte.
Taster per Interrupt
Der Taster ist am Interrupt-Pin D2 angeschlossen.
Das ermöglicht, die Eingabe sofort zu registrieren – unabhängig davon, was im loop()
gerade passiert.
So bleibt die Slotmachine reaktionsschnell und du musst den Taster nicht ständig in der Schleife abfragen.
// Pin für den Taster (gegen GND, wir nutzen INPUT_PULLUP) #define taster 2 void setup(){ ... // Interrupt auf den Taster legen: // CHANGE = löst bei Flanke (HIGH->LOW und LOW->HIGH) aus. // Wir schützen uns gegen Doppeltrigger mit TIME_BETWEEN_PRESS. attachInterrupt(digitalPinToInterrupt(taster), stoppSlotMachine, CHANGE); } // ISR (Interrupt Service Routine) für den Taster. // Achtung: ISR sollte kurz sein – hier nur Status erhöhen // und eine einfache Sperrzeit gegen Prellen/Mehrfachtrigger prüfen. void stoppSlotMachine() { long currentMillis = millis(); if (currentMillis > (lastButtonPress + TIME_BETWEEN_PRESS) && !endGame) { currentIndex++; // nächste Walze wird „fixiert“ lastButtonPress = currentMillis; } }
Zeichnen der Walzen
Die drei Walzen (Slots) werden in einer eigenen Funktion gezeichnet.
Der Funktion wird die jeweilige Position (0, 1 oder 2) und der Index des Bildes aus dem Array epd_bitmap_allArray
übergeben.
So kannst du an einer Stelle zentral steuern, welches Symbol wo auf dem Display landet.
// Pointer-Array auf alle Symbol-Bitmaps (in PROGMEM abgelegt) // Reihenfolge: 0=Kleeblatt, 1=Herz, 2=Kirschen, 3=Sieben const unsigned char* const epd_bitmap_allArray[] PROGMEM = { epd_bitmap_kleeblatt, epd_bitmap_herz, epd_bitmap_kirschen, epd_bitmap_seven }; // Zeichnet einen Symbol-Rahmen + Bitmap an Position 0/1/2. // 'bild' ist der Index im epd_bitmap_allArray (0..3) void zeichneXBmp(int position, int bild) { // Layout-Offsets (Rahmen und Bild leicht eingerückt) int xOffsetRahmen = 4; int yOffsetRahmen = 20; int xOffsetBild = 4; int yOffsetBild = 22; // X-Positionen: drei Spalten im Abstand von 38 Pixeln int rahmenXPos = xOffsetRahmen + (position * 38); int bildXPos = xOffsetBild + (position * 38); // Rahmen zeichnen (35x35, mit Radius 5) display.drawRoundRect(rahmenXPos + 6, 20, 35, 35, 5, SH110X_WHITE); // Bitmap zeichnen // HINWEIS: Wenn dein Pointer-Array tatsächlich in PROGMEM liegt und // du Probleme bekommst, auf AVR-Boards besser so lesen: // const unsigned char* bmp = (const unsigned char*)pgm_read_ptr(&epd_bitmap_allArray[bild]); // display.drawBitmap(bildXPos + 6, 22, bmp, img_width, img_height, SH110X_WHITE); display.drawBitmap(bildXPos + 6, 22, epd_bitmap_allArray[bild], img_width, img_height, SH110X_WHITE); }
Zufallszahl für Symbole
Das Bild, das beim Rotieren einer Walze angezeigt wird, wird per Zufallszahl ermittelt:
int randNumber = random(NUM_ELEMENTS);
In meinem Fall gibt es 4 Symbole (Kleeblatt, Kirsche, Herz und Sieben), also Zufallszahlen von 0–3
.
Die Anzahl lässt sich beliebig erweitern – einfach weitere Bitmaps hinzufügen und NUM_ELEMENTS
anpassen.
Da das XBM-Format sehr speicherschonend ist, kannst du problemlos auch 6, 8 oder noch mehr Symbole verwenden.
// Merker, welches Symbol auf welcher Walze zuletzt liegt // slot[0] = linke Walze, slot[1] = mittlere, slot[2] = rechte int slot[] = { -1, -1, -1 }; // Wie viele Walzen sind bereits per Tastendruck gestoppt? // -1 = noch keine, 0 = erste gestoppt, 1 = zweite gestoppt, 2 = alle drei gestoppt int currentIndex = -1; void setup() { ... // Zufallszahlengenerator initialisieren randomSeed(analogRead(0)); ... } // Dreht die noch nicht gestoppten Walzen „weiter“: // Für jede nicht fixierte Walze: löschen, zufälliges Symbol wählen, // merken und neu zeichnen. Aktualisiert die Anzeige und wartet kurz. void rotiereBild() { for (int i = 0; i < 3; i++) { if (currentIndex >= i) { // Walze i ist bereits gestoppt -> überspringen continue; } loescheBild(i); // altes Symbol entfernen display.display(); int randNumber = random(NUM_ELEMENTS); // 0..3 slot[i] = randNumber; // Symbol merken (für Ergebnisprüfung) zeichneXBmp(i, randNumber); // neues Symbol zeichnen } display.display(); // alle Änderungen anzeigen delay(750); // Rotationsgeschwindigkeit (größer = langsamer) }
Quellcode
Nachfolgend der Quellcode zum Download und zum kopieren.
Datei: arduino_slotmachine.ino
/***************************************************** * Titel: Arduino Slotmachine – Mini-Spiel auf dem OLED! * * Beschreibung: * Dieses Projekt zeigt eine kleine Slotmaschine auf * einem 1,3" I²C-OLED (SH1106). Drei Walzen rotieren * mit zufälligen Symbolen (Kleeblatt, Herz, Kirschen, * Sieben). Mit jedem Tastendruck stoppst du die nächste * Walze. Gewinn/Falsch-Ende wird auf dem Display * angezeigt und per Buzzer-Sound quittiert. * * Voller Projekt-Artikel: * https://draeger-it.blog/gluecksspiel-im-mini-format-slotmaschine-mit-arduino-oled-bauen/ * * Hardware: * - Arduino Nano R4 (andere kompatible Boards möglich) * - 1,3" OLED (SH1106, I²C, Adresse 0x3C) * - Taster an D2 (gegen GND, INPUT_PULLUP) * - Buzzer an D3 * - Beim Nano R4: 2x 4,7 kΩ Pullups für SDA/SCL auf VCC * * Bibliotheken (über Bibliotheksverwalter installieren): * - Adafruit_GFX * - Adafruit_SH110X *****************************************************/ #include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SH110X.h> // --- eigene Assets (Bitmaps & Sounds) --- #include "kleeblatt.h" #include "herz.h" #include "kirsche.h" #include "sieben.h" #include "winner_tone.h" #include "fail_tone.h" // I²C-Adresse des SH1106-Displays (typischerweise 0x3C) #define i2c_Address 0x3c // Pin für den Taster (gegen GND, wir nutzen INPUT_PULLUP) #define taster 2 // Pin für den Buzzer (aktiv per HIGH) #define BUZZER_PIN 3 // Größe der XBM-Symbole (alle 32x32 Pixel) #define img_width 32 #define img_height 32 // Display-Objekt: 128x64 Pixel, I²C, kein Reset-Pin Adafruit_SH1106G display = Adafruit_SH1106G(128, 64, &Wire, -1); // Anzahl der Symbol-Bitmaps const int NUM_ELEMENTS = 4; // Pointer-Array auf alle Symbol-Bitmaps (in PROGMEM abgelegt) // Reihenfolge: 0=Kleeblatt, 1=Herz, 2=Kirschen, 3=Sieben const unsigned char* const epd_bitmap_allArray[] PROGMEM = { epd_bitmap_kleeblatt, epd_bitmap_herz, epd_bitmap_kirschen, epd_bitmap_seven }; // Wie viele Walzen sind bereits per Tastendruck gestoppt? // -1 = noch keine, 0 = erste gestoppt, 1 = zweite gestoppt, 2 = alle drei gestoppt int currentIndex = -1; // Zeitverwaltung für einfache Entprellung / Blockzeit zwischen Tastendrücken long lastButtonPress = -1; const long TIME_BETWEEN_PRESS = 500; // ms // Merker, welches Symbol auf welcher Walze zuletzt liegt // slot[0] = linke Walze, slot[1] = mittlere, slot[2] = rechte int slot[] = { -1, -1, -1 }; // Signalisiert, dass eine Runde abgeschlossen ist bool endGame = false; void setup() { Serial.begin(9600); // Taster-Pin auf internen Pullup schalten pinMode(taster, INPUT_PULLUP); // Interrupt auf den Taster legen: // CHANGE = löst bei Flanke (HIGH->LOW und LOW->HIGH) aus. // Wir schützen uns gegen Doppeltrigger mit TIME_BETWEEN_PRESS. attachInterrupt(digitalPinToInterrupt(taster), stoppSlotMachine, CHANGE); // Buzzer-Pin als Ausgang pinMode(BUZZER_PIN, OUTPUT); // Zufallszahlengenerator initialisieren randomSeed(analogRead(0)); // Display starten und kurzen Boot-Screen zeigen delay(250); display.begin(i2c_Address, true); display.display(); delay(2000); // Erste Runde vorbereiten startGame(); } // Setzt eine neue Runde auf: Anzeige leeren, Überschrift zeichnen, // drei Rahmen/Symbole initial zeigen, Status zurücksetzen. void startGame() { Serial.println("startGame"); currentIndex = -1; slot[0] = slot[1] = slot[2] = -1; endGame = false; display.clearDisplay(); display.setTextColor(SH110X_WHITE); display.setTextSize(1); display.setCursor(9, 8); display.println(F("Arduino Slotmachine")); // Anfangsanzeige: drei Symbole (0,1,2) ins Raster zeichnen zeichneXBmp(0, 0); zeichneXBmp(1, 1); zeichneXBmp(2, 2); display.display(); endGame = false; } // ISR (Interrupt Service Routine) für den Taster. // Achtung: ISR sollte kurz sein – hier nur Status erhöhen // und eine einfache Sperrzeit gegen Prellen/Mehrfachtrigger prüfen. void stoppSlotMachine() { long currentMillis = millis(); if (currentMillis > (lastButtonPress + TIME_BETWEEN_PRESS) && !endGame) { currentIndex++; // nächste Walze wird „fixiert“ lastButtonPress = currentMillis; } } // Zeichnet einen Symbol-Rahmen + Bitmap an Position 0/1/2. // 'bild' ist der Index im epd_bitmap_allArray (0..3) void zeichneXBmp(int position, int bild) { // Layout-Offsets (Rahmen und Bild leicht eingerückt) int xOffsetRahmen = 4; int yOffsetRahmen = 20; int xOffsetBild = 4; int yOffsetBild = 22; // X-Positionen: drei Spalten im Abstand von 38 Pixeln int rahmenXPos = xOffsetRahmen + (position * 38); int bildXPos = xOffsetBild + (position * 38); // Rahmen zeichnen (35x35, mit Radius 5) display.drawRoundRect(rahmenXPos + 6, 20, 35, 35, 5, SH110X_WHITE); // Bitmap zeichnen // HINWEIS: Wenn dein Pointer-Array tatsächlich in PROGMEM liegt und // du Probleme bekommst, auf AVR-Boards besser so lesen: // const unsigned char* bmp = (const unsigned char*)pgm_read_ptr(&epd_bitmap_allArray[bild]); // display.drawBitmap(bildXPos + 6, 22, bmp, img_width, img_height, SH110X_WHITE); display.drawBitmap(bildXPos + 6, 22, epd_bitmap_allArray[bild], img_width, img_height, SH110X_WHITE); } // Löscht den Bereich einer Walze (füllt den Rahmen schwarz) void loescheBild(int position) { int xOffsetRahmen = 4; int yOffsetRahmen = 20; int rahmenXPos = xOffsetRahmen + (position * 38); display.fillRoundRect(rahmenXPos + 6, 20, 35, 35, 5, SH110X_BLACK); } // Dreht die noch nicht gestoppten Walzen „weiter“: // Für jede nicht fixierte Walze: löschen, zufälliges Symbol wählen, // merken und neu zeichnen. Aktualisiert die Anzeige und wartet kurz. void rotiereBild() { for (int i = 0; i < 3; i++) { if (currentIndex >= i) { // Walze i ist bereits gestoppt -> überspringen continue; } loescheBild(i); // altes Symbol entfernen display.display(); int randNumber = random(NUM_ELEMENTS); // 0..3 slot[i] = randNumber; // Symbol merken (für Ergebnisprüfung) zeichneXBmp(i, randNumber); // neues Symbol zeichnen } display.display(); // alle Änderungen anzeigen delay(750); // Rotationsgeschwindigkeit (größer = langsamer) } // Gewinnanzeige: Display-Bereiche leeren, „Gewonnen!“ zeigen, Sieg-Sound spielen void gewonnen() { for (int i = 0; i < 3; i++) { loescheBild(i); } display.setTextColor(SH110X_WHITE); display.setTextSize(2); display.setCursor(15, 26); display.println(F("Gewonnen!")); display.display(); playVictory(); // in winner_tone.h implementiert } // Verlustanzeige: Display-Bereiche leeren, „Verloren!“ zeigen, Game-Over-Sound spielen void verloren() { for (int i = 0; i < 3; i++) { loescheBild(i); } display.setTextColor(SH110X_WHITE); display.setTextSize(2); display.setCursor(15, 26); display.println(F("Verloren!")); display.display(); playGameOver(); // in fail_tone.h implementiert } void loop() { // Solange noch nicht alle drei Walzen gestoppt sind, weiter „rotieren“ if (currentIndex != 2) { rotiereBild(); } else { // Alle Walzen stehen: Ergebnis prüfen if (slot[0] == slot[1] && slot[0] == slot[2]) { gewonnen(); } else { verloren(); } // Runde beenden und nach kurzer Pause neu starten endGame = true; delay(1500); startGame(); } }
Datei: kleeblatt.h
const unsigned char epd_bitmap_kleeblatt [] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x06, 0x00, 0x00, 0x3e, 0x1f, 0x00, 0x00, 0x7f, 0x1f, 0x80, 0x00, 0xff, 0x3f, 0x80, 0x03, 0xff, 0x3f, 0xc0, 0x07, 0xff, 0x3f, 0xe0, 0x0f, 0xff, 0x7f, 0xf0, 0x0f, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xf8, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x1f, 0xfc, 0x00, 0x03, 0xff, 0xfe, 0x00, 0x0f, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xf8, 0x0f, 0xfe, 0xff, 0xf8, 0x07, 0xfe, 0x7f, 0xf8, 0x03, 0xfe, 0x7f, 0xf0, 0x01, 0xfc, 0x7f, 0xe0, 0x01, 0xfc, 0x3f, 0x80, 0x00, 0xfd, 0x3f, 0x00, 0x00, 0xf8, 0x3e, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
Datei: herz.h
const unsigned char epd_bitmap_herz [] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x07, 0xf8, 0x1f, 0xe0, 0x0f, 0xfc, 0x3f, 0xf0, 0x0f, 0xfe, 0x7f, 0xf0, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
Datei: kirsche.h
const unsigned char epd_bitmap_kirschen [] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xbf, 0x80, 0x00, 0x01, 0x2f, 0xe0, 0x00, 0x03, 0x2f, 0xe0, 0x00, 0x06, 0x27, 0xf0, 0x00, 0x04, 0x27, 0xf8, 0x00, 0x0c, 0x23, 0xf8, 0x00, 0x08, 0x20, 0xfc, 0x00, 0x08, 0x20, 0x00, 0x00, 0x18, 0x20, 0x00, 0x00, 0x10, 0x20, 0x00, 0x0f, 0x30, 0x20, 0x00, 0x1f, 0xe0, 0x30, 0x00, 0x13, 0xfc, 0x10, 0x00, 0x33, 0xfe, 0x13, 0xc0, 0x27, 0xfc, 0xd7, 0xe0, 0x27, 0xf9, 0xff, 0xf0, 0x33, 0xfb, 0x7f, 0xf0, 0x33, 0xf2, 0x7f, 0xf8, 0x1f, 0xf6, 0x7f, 0xf8, 0x1f, 0xf6, 0x7f, 0xf8, 0x0f, 0xf2, 0x7f, 0xf0, 0x0f, 0xf2, 0x3f, 0xf0, 0x07, 0xe3, 0x3f, 0xf0, 0x00, 0x01, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00 };
Datei: sieben.h
const unsigned char epd_bitmap_seven [] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xf8, 0x80, 0x00, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x01, 0xfd, 0xff, 0x00, 0x01, 0xf0, 0x7e, 0x00, 0x01, 0xe0, 0xfe, 0x00, 0x00, 0x41, 0xfc, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
Datei: winner_tone.h
#define BUZZER_PIN 3 // Frequenzen (Hz) für die Noten (C-Dur, mittlere bis hohe Lage) #define C5 523 #define D5 587 #define E5 659 #define F5 698 #define G5 784 #define C6 1047 #define E6 1319 // Melodie: kurzer Fanfaren-Arpeggio + kleine Schluss-Kadenz int melodyVictory[] = { C5, E5, G5, C6, // Auftakt: C-Dur Arpeggio E5, G5, C6, E6, // Steigerung G5, F5, E5, D5, C5 // Abstieg zur Auflösung }; // Dauer je Note in Millisekunden (passend rhythmisch betont) int durationsVictory[] = { 160, 160, 160, 320, 160, 160, 160, 320, 180, 180, 180, 180, 420 }; void playVictory() { const float gapFactor = 0.25; // kurze Pause zwischen Noten (25% der Notenlänge) for (unsigned int i = 0; i < sizeof(melodyVictory) / sizeof(melodyVictory[0]); i++) { int note = melodyVictory[i]; int dur = durationsVictory[i]; if (note > 0) { tone(BUZZER_PIN, note, dur); } // kleine Lücke nach jeder Note, macht es „fröhlicher“ und klarer delay(dur + (int)(dur * gapFactor)); noTone(BUZZER_PIN); } }
Datei: fail_tone.h
#define BUZZER_PIN 3 // Frequenzen (Hz) – untere Oktave für "düstereren" Klang #define A4 440 #define F4 349 #define D4 294 #define C4 262 // Melodie: absteigendes Motiv -> wirkt traurig int melodyFail[] = { A4, F4, D4, C4 }; // Dauern der Noten in Millisekunden int durationsFail[] = { 400, 400, 500, 800 }; void playGameOver() { const float gapFactor = 0.3; // etwas längere Pausen -> wirkt „schwerer“ for (unsigned int i = 0; i < sizeof(melodyFail) / sizeof(melodyFail[0]); i++) { int note = melodyFail[i]; int dur = durationsFail[i]; if (note > 0) { tone(BUZZER_PIN, note, dur); } delay(dur + (int)(dur * gapFactor)); noTone(BUZZER_PIN); } }
Letzte Aktualisierung am: 04. September 2025
Das Projekt ist super! Die Schritt-für-Schritt-Anleitung und die Code-Snippets sind super verständlich. Besonders gut finde ich die Erklärung zum Interrupt-Handling – das hat mir bei meinen eigenen Projekten schon mal geholfen. Die OLED-Anbindung mit den Bitmaps ist auch ein kluger Trick. Ein bisschen unklar war mir erst der Pointer-Array im PROGMEM, aber danke für den Hinweis. Das mit dem Buzzer-Sound zum Abschluss ist auch nett! Ein tolles, klares Tutorial für alle, die eine Slotmachine bauen wollen.