Multiplayer Gameshow Buzzer - AZ-Delivery
Dieses kleine Bastelprojekt zeigt, wie Sie Ihren Spieleabend mit Freunden zu einer kleinen Gameshow machen können. Es eignet sich z.B. für Fragerunden, bei denen der Spieler Punkte bekommt, der die Antwort zuerst "buzzert". Das Prinzip kennen Sie sicher aus dem Fernsehen. Los geht's.

Was wir benötigen

Anzahl Bauteil
1 Nano V3 ATMega328 oder Mikrocontroller Board mit ATmega328P
4 Taster
1 RGB WS2812B LED Ring mit 12 LEDs
1 Passives Buzzer Modul KY-006
mehrere Verbindungskabel
1 Breadboard oder Breadboard Kit

Schaltplan

Zunächst verbinden wir alle Komponenten wie auf dem folgenden Schaltbild zu sehen ist:

Schaltbild

Mikrocontroller Buzzer
D3 (S)ignal
GND -
  RGB LED Ring
D2 IN
+5V VCC
GND GND
  Taster 1-4
D4, D5, D6, D7 jeweils Pin 1
GND jeweils Pin 2


Als Taster können Sie beliebige Komponenten wählen, mit denen Sie den Kontakt zwischen GND und dem jeweiligen digitalen Eingang überbrücken können.

Wir werden die internen Pull-up-Widerstände benutzen, daher ist das so möglich. Wir müssen später nur darauf achten, dass die Eingänge dann active low sind.

Ich habe ein passives Buzzer Modul benutzt. Der Unterschied zum aktiven Buzzer ist, dass dort kein Rechtecksignal erzeugt werden muss. Bernd Albrecht ist in seinem Blogbeitrag "Wir bringen Ihnen die Flötentöne bei" auf die Verwendung dieser Module eingegangen.

Exposé

Mein Ziel ist, vier verschiedene Taster drücken zu können und anschließend jeweils eine andere Farbe auf dem LED-Ring anzeigen zu lassen. Außerdem soll das Buzzermodul einen passenden Ton ausgeben. Zuerst habe ich den LED-Ring angeschlossen und die passende Bibliothek namens "Adafruit Neopixel" installiert. Sie bringt den Beispielsketch "buttoncycler" mit, den wir gut als Basis nutzen können. Statt des RGB-Rings können Sie auch vier SMD RGB Module verwenden. Dann fällt die Bibliothek weg, jedoch müssen die RGB-Pins einzeln angeschlossen werden. Das bedeutet, dass 4 x 3 Pins notwendig wären. Die Taster werden jeweils an einen von vier weiteren digitalen Pins und GND angeschlossen. Damit hätten wir die Hardware komplett.

Aufbau

Für den Buzzer können wir die Bibliothek "Tone" installieren. Damit ist es sehr einfach, dem Modul Töne zu entlocken. Hier können wir uns am Beispielsketch "ToneTest" bedienen.

Der Quellcode

Aus den Beispielsketches habe ich ein Programm geschrieben, dass die vier Taster nacheinander abfragt. Sollte einer von ihnen betätigt werden, leuchtet die entsprechende LED für 5 Sekunden auf und ein Ton ist kurz zu hören.

Um gleich zu Programmbeginn die Funktion der Komponenten zu testen, habe ich eine Startanimation eingefügt, die die LEDs in den Spielerfarben aufleuchten und den Buzzer ertönen lässt.

Hier also der Quellcode:
 /*  MultiplayerGameshowBuzzer 
  * fuer vier Spieler mit Farben und Toenen
  * fuer AZ-Delivery.de
  *  
  * Funktion:
  * Spieler können je einen Taster betaetigen
  * Spielerfarbe leuchtet auf und Buzzer-Sound erklingt
  *  
  * Verwendete Hardware:
  *   - ATmega328p Mikrocontroller
  *   - Passives Buzzer Module
  *   - Neopixelring mit 12 RGB LEDs
  *   - 4 Taster
  *  
  * Verwendete Bibliotheken:
  *   - Adafruit_NeoPixel.h
  *   - Tone.h
  *  
  * Beispielquelle aus der Adafruit_NeoPixel.h: buttoncycler
  *  
  ***************************************************
  * @filename   :   buttoncycler.ino
  * @brief     :   neopixel demo
  * @author     :   Adafruit
  *
  * Copyright (C) Adafruit
  ****************************************************
  *
  * Pinout:
  *  
  *     Neopixel Ring   |     Mikrocontroller
  * ------------------------------------
  *     VCC                 |     5V oder 3.3V
  *     GND                 |     GND
  *     IN                     |     D2
  *        
  *        
  * Beispielquelle aus der Tone.h: ToneTest
  ***************************************************
  * @filename   :   ToneTest.ino
  * @brief     :   Tone demo
  * @author     :  
  *
  * https://code.google.com/archive/p/rogue-code/wikis/ToneLibraryDocumentation.wiki
  ***************************************************
  *
  * Pinout:
  *  
  *     Active Buzzer Module   |     Mikrocontroller
  * ------------------------------------------------
  *     GND                             |     GND
  *     IN                                 |     D2
  *
  *
  */
 
 #include <Adafruit_NeoPixel.h>
 #include <Tone.h>
 #define PIXEL_PIN   2  // Digital IO pin connected to the NeoPixels.
 #define BUZZER_PIN   3
 #define PIXEL_COUNT 12  // Number of NeoPixels
 #define MAX_BUTTONS 4
 
 /***************************
  * NEOPIXEL
  */
 // Declare our NeoPixel strip object:
 Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);
 // Argument 1 = Number of pixels in NeoPixel strip
 // Argument 2 = Arduino pin number (most are valid)
 // Argument 3 = Pixel type flags, add together as needed:
 //   NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
 //   NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
 //   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
 //   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
 //   NEO_RGBW   Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
 int LED_number[MAX_BUTTONS] = {7, 10, 1, 4};                  // Neopixel-Nummer der Spieler
 uint32_t color[MAX_BUTTONS] = { strip.Color(255, 0, 0),       // Spielerfarben
                                 strip.Color(0, 255, 0),
                                 strip.Color(0, 0, 255),
                                 strip.Color(255, 0, 255)};
 /***************************
  * BUTTONS
  */
 int BUTTON_PIN[MAX_BUTTONS] = {4, 5, 6, 7};                   // Button Pin Nummern          
 boolean oldState[MAX_BUTTONS] = {HIGH, HIGH, HIGH, HIGH};    
 boolean newState[MAX_BUTTONS] = {HIGH, HIGH, HIGH, HIGH};
 int button_count = 0;
 
 /***************************
  * TONES
  */
 int notes[] = { NOTE_C3,
                 NOTE_C4,
                 NOTE_D4,
                 NOTE_E4,
                 NOTE_F4};
 Tone buzzer;
 
 void setup() {
   pinMode(BUTTON_PIN[0], INPUT_PULLUP);
   pinMode(BUTTON_PIN[1], INPUT_PULLUP);
   pinMode(BUTTON_PIN[2], INPUT_PULLUP);
   pinMode(BUTTON_PIN[3], INPUT_PULLUP);
   buzzer.begin(BUZZER_PIN);
   strip.begin();
   strip.show();
   startAnimation();
 }
 
 void loop() {
   newState[button_count] = digitalRead(BUTTON_PIN[button_count]);
   
   if((newState[button_count] == LOW) && (oldState[button_count] == HIGH)) {
     // Short delay to debounce button.
     delay(20);
     // Check if button is still low after debounce.
     newState[button_count] = digitalRead(BUTTON_PIN[button_count]);
     if(newState[button_count] == LOW) {      // Yes, still low
       strip.setPixelColor(LED_number[button_count], color[button_count]);
       strip.show();
       buzzer.play(notes[0], 500);
       delay(5000);
       strip.setPixelColor(LED_number[button_count], strip.Color(  0,   0,   0));
       strip.show();
    }
  }
   // Set the last-read button state to the old state.
   oldState[button_count] = newState[button_count];
   button_count++;
   if (button_count > MAX_BUTTONS-1) {
     button_count = 0;
  }
 }
 
 void startAnimation() {
   int i = 0;
   int colorCount = 0;
   int delayTime = 35;
 
   // Farbkreise mit Spielerfarben
   while (colorCount < MAX_BUTTONS) {
     buzzer.play(notes[colorCount+1], 200);
     for (i = 0; i < PIXEL_COUNT; i++) {
       strip.setPixelColor(i, color[colorCount]);
       strip.show();
       delay(delayTime);
    }
     colorCount++;
  }
   
   colorCount = 0;
 
   // Alle Pixel aus
   for (i = 0; i < PIXEL_COUNT; i++) {
     strip.setPixelColor(i, strip.Color(  0,   0,   0));
     strip.show();
     delay(delayTime);
  }
 
   // Spieler-Pixel
   for (i = 0; i < MAX_BUTTONS; i++) {
     strip.setPixelColor(LED_number[i], color[i]);
     strip.show();
     buzzer.play(notes[i+1], 200);
     delay(500);
  }
 
   delay(1000);
   
   for (i = 0; i < PIXEL_COUNT; i++) {
     strip.setPixelColor(i, strip.Color(  0,   0,   0));
     strip.show();
  }
 }
Quellcode als Download

Um im Programm schneller und mit weniger Quellcode durch die Buttons und LEDs zu laufen, habe ich Arrays benutzt. Folgende Zeile beinhaltet die LED-Nummer im RGB-LED-Ring:

 int LED_number[MAX_BUTTONS] = {7, 10, 1, 4};

Die LED mit der Nummer 0 befindet sich bei mir auf 5 Uhr, also rechts unten. Das liegt daran, dass ich eine Pinleiste angelötet habe, mit der ich den Ring auf das Steckbrett stecken konnte.

Die Spielerfarben sind mit folgender Zeile definiert:

 uint32_t color[MAX_BUTTONS] = { strip.Color(255, 0, 0),       // Spielerfarben
                                 strip.Color(0, 255, 0),
                                 strip.Color(0, 0, 255),
                                 strip.Color(255, 0, 255)};

Die Funktion Color() aus der Neopixel-Bibliothek erzeugt einen 32-Bit-Wert. Ich habe hier vier Werte in einer Gruppe zusammengefasst.

Die Pins für die Taster und deren Zustände, werden wie folgt in die Arrays geschrieben:

 int BUTTON_PIN[MAX_BUTTONS] = {4, 5, 6, 7};                   // Button Pin Nummern          
 boolean oldState[MAX_BUTTONS] = {HIGH, HIGH, HIGH, HIGH};    
 boolean newState[MAX_BUTTONS] = {HIGH, HIGH, HIGH, HIGH};

Mit dem Array ist es nun möglich, mit digitalRead() mit Hilfe einer Schleife die vier Pins nacheinander abzufragen. Die Arrays oldState[] und newState[] werden gebraucht, um zu prüfen, ob ein Taster betätigt und auch wieder losgelassen wurde. Sonst würden wir den Taster gedrückt halten und dadurch mehrmals den Buzzer auslösen. Theoretisch müssten wir das nicht tun, da ich eine Pause eingefügt habe, wenn ein Taster betätigt wird.

Die Töne für den Buzzer können ebenfalls in ein Array geschrieben werden. Ich habe C3 als Ton festgelegt, der ertönt, wenn ein Taster gedrückt wird. Die anderen Töne dienen nur für die Startanimation.

Im setup() müssen die Pullup-Widerstände an den Eingangspins aktiviert werden:
 void setup() {
   pinMode(BUTTON_PIN[0], INPUT_PULLUP);
   pinMode(BUTTON_PIN[1], INPUT_PULLUP);
   pinMode(BUTTON_PIN[2], INPUT_PULLUP);
   pinMode(BUTTON_PIN[3], INPUT_PULLUP);
   buzzer.begin(BUZZER_PIN);
   strip.begin();
   strip.show();
   startAnimation();
 }

Dafür werden sie mit INPUT_PULLUP initialisiert. Der Buzzer benötigt die begin()-Funktion, ebenso der RGB-LED-Ring. Die Funktion show() schaltet die LEDs hier aus. Sie wird immer benötigt, um die eingestellte Farbe auf der gewünschten LED anzuzeigen. Die Werte werden zuerst in den Speicher geladen und anschließend auf den LEDs angezeigt.

Ich starte hier nach der Initialisierung die Startanimation. Mit zwei Schleifen werden die Pixel durchlaufen und mit den zuvor festgelegten Farben angezeigt. Danach werden sie ausgeschaltet und die Spieler-LEDs einzeln nacheinander noch einmal eingeschaltet. Dazu erklingt dann der Buzzer.

Spielerfarben

Hier sehen wir schon den Vorteil der Arrays. Mit den Schleifen kann man sehr einfach darüber iterieren.

Die loop()-Funktion ist dadurch auch verhältnismäßig kurz geworden. Da hier der Mikrocontroller sowieso in einer Endlosschleife läuft, brauchen wir keine extra Schleife zu erzeugen. Wir fragen die Button-Pins ab und zählen den Index des Arrays mit jedem Durchlauf hoch. Wird einer der Taster betätigt, greift die Bedingte Abfrage und die passende LED leuchtet auf. Die Taster-Pins, die LED-Nummern und die Spielerfarben nutzen in ihren Arrays den gleichen Index. Dadurch kann man mit einem Zähler auf die Werte in allen Arrays zugreifen. Das verkürzt den Quellcode ungemein.

Fazit

Sie haben gesehen, wie wir Taster, Buzzer und RGB-LED-Ring an einen ATmega328 Mikrocontroller anschließen und daraus einen Gameshow-Buzzer für vier Spieler bauen können. Ich hoffe, dass Sie damit ihren Spieleabend etwas auffrischen können. Viel Spaß beim Basteln.

Buzzertest

Andreas Wolter
für AZ-Deliver Blog
Für arduinoProjekte für anfänger

3 comments

Andreas Wolter

Andreas Wolter

@Buttgereit: Danke für den Hinweis. Wurde korrigiert.
@Klaus: Ja das lässt sich soweit erweiter, wie es digitale Eingänge für die Taster gibt.
Ich werde in Kürze ein Update dazu schreiben und den Quellcode verlinken.

Buttgereit

Buttgereit

Fritzing -Verdrahtung und Verbindungstabelle stimmen nicht überein:D2 an Buzzer S-Kontakt, D3 an LED Ring In

Klaus

Klaus

Hallo
super Projekt – kann man das auch auf 8 Spieler erweitern ?

Danke

Leave a comment

All comments are moderated before being published

Recommended blog posts

  1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
  2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
  4. ESP32 - das Multitalent - AZ-Delivery