This little craft project shows how you can turn your game night with friends into a little game show. It is suitable, for example, for question rounds in which the player who "buzzes" the answer first gets points. You probably know the principle from television. Let's go.
Quantity | Componenent |
---|---|
1 | Nano V3 ATMega328 or Microcontroller Board with ATmega328P |
4 | Push button |
1 | RGB WS2812B LED ring with 12 LEDs |
1 | Passive buzzer module KY-006 |
several | Jumper wires |
1 | Breadboard oder Breadboard Kit |
Circuit diagram
First, we connect all components as can be seen on the following circuit diagram:
Microcontroller | buzzer |
D2 | (Signal |
GND | - |
RGB LED ring | |
D3 | IN |
+ 5V | Vcc |
GND | GND |
Button 1-4 | |
D4, D5, D6, D7 | Pin 1 each |
GND | Pin 2 each |
You can choose any components as pushbuttons to bridge the contact between GND and the respective digital input.
We will use the internal pull-up resistors, so this is possible. We just have to make sure later that the inputs are active low then.
I used a passive buzzer module. The difference to the active buzzer is that no rectangular signal must be generated there. Bernd Albrecht is in his addressed the use of these modules.
Expose
My goal is to be able to press four different buttons and then have each one display a different color on the LED ring. In addition, the buzzer module should emit a matching sound. First I connected the LED ring and installed the appropriate library called "Adafruit Neopixel". It brings the example sketch "buttoncycler", which we can use well as a base. Instead of the RGB ring you can also use four SMD RGB modules. Then the library is omitted, but the RGB pins have to be connected individually. This means that 4 x 3 pins would be necessary. The buttons are each connected to one of four additional digital pins and GND. With this we would have the hardware complete.
For the buzzer we can install the library "Tone". This makes it very easy to elicit the module tones. Here we can operate on the sample chain "Tonetest".
The source code
From the example sketches I wrote a program that queries the four buttons one after the other. If one of them is pressed, the corresponding LED lights up for 5 seconds and a sound is heard briefly.
To test the function of the components right at the beginning of the program, I added a start animation that lights up the LEDs in the player colors and sounds the buzzer.
* 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
*
*
*/
// Digital IO pin connected to the NeoPixels.
// Number of NeoPixels
/***************************
* 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();
}
}
To run through the buttons and LEDs in the program faster and with less source code, I used arrays. The following line contains the LED number in the RGB LED ring:
int LED_number[MAX_BUTTONS] = {7, 10, 1, 4};
The LED with the number 0 is on 5 o'clock, so on the bottom right. This is due to the fact that I soldered a pin strip, with which I could plug the ring on the plug-in board.
The player colors are defined with the following line:
uint32_t color[Max_buttons] = { strip.Color(255, 0, 0), // player colors
strip.Color(0, 255, 0),
strip.Color(0, 0, 255),
strip.Color(255, 0, 255)};
The function Color () From the Neopixel library produces a 32-bit value. I have summarized four values in a group.
The pins for the buttons and their states are written in the arrays as follows:
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};
With the array it is now possible with DigitalRead With the help of a loop, to query the four pins one after the other. The arrays Oldstate [] and NewState [] Used to check if a button has been pressed and released again. Otherwise we would hold down the button and thereby trigger the buzz several times. Theoretically we would not have to do that because I have inserted a pause when a button is pressed.
The sounds for the buzzer can also be written to an array. I set C3 as a sound that sounds when a button is pressed. The other sounds serve only for the starting animation.
in the set up() The pullup resistors must be activated at the input pins: 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();
}
For this they are initialized with INPUT_PULLUP. The buzzer needs the begin() function, so does the RGB LED ring. The show() function switches the LEDs off here. It is always needed to show the set color on the desired LED. The values are first loaded into memory and then displayed on the LEDs.
I start the start animation here after the initialization. With two loops, the pixels are passed through and displayed with the previously set colors. After that they are switched off and the player LEDs are switched on again one by one. The buzzer then sounds for this.
Here we already see the advantage of the arrays. With the loops you can iterate over them very easily.
The loop() function has also become relatively short as a result. Since here the microcontroller runs in an endless loop anyway, we don't need to create an extra loop. We query the button pins and count up the index of the array with each pass. When one of the buttons is pressed, the conditional query takes effect and the appropriate LED lights up. The button pins, the LED numbers and the player colors use the same index in their arrays. This way you can access the values in all arrays with one counter. This shortens the source code immensely.
3 comments
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
Fritzing -Verdrahtung und Verbindungstabelle stimmen nicht überein:D2 an Buzzer S-Kontakt, D3 an LED Ring In
Klaus
Hallo
super Projekt – kann man das auch auf 8 Spieler erweitern ?
Danke