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:
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 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 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.
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.
/* 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();
}
}
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.
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.Andreas Wolter
3 Reacties
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