try this
click to see the code
// using https://www.arduino.cc/reference/en/libraries/hd44780 for the LCD
#include <Wire.h>
#include <hd44780.h> // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header
//using https://github.com/Dlloydev/Toggle for the button
#include <Toggle.h>
hd44780_I2Cexp lcd;
const int LCD_COLS = 16;
const int LCD_ROWS = 2;
const byte buttonPin = 2;
Toggle button;
unsigned long lastTick;
const unsigned long tickPeriod = 100; // ms
enum {PAUSED, RUNNING, ASKING} state = PAUSED;
class Led {
const char ** questions;
const size_t questionCount;
const byte ledPin;
public:
Led (const byte pin, const char ** q, const size_t n) :
ledPin(pin), questions(q), questionCount(n) {}
void begin() {
pinMode(ledPin, OUTPUT);
}
void flip() {
digitalWrite(ledPin, digitalRead(ledPin) == LOW ? HIGH : LOW);
}
void on() {
digitalWrite(ledPin, HIGH);
}
void off() {
digitalWrite(ledPin, LOW);
}
const char* getRandomQuestion() {
if (questions == nullptr || questionCount == 0) return nullptr;
return questions[random(questionCount)];
}
};
// the questions
const char * QLed0[] = {"led0 Q0", "led0 Q1", "led0 Q2", "led0 Q3", "led0 Q4"};
const char * QLed1[] = {"led1 Q0", "led1 Q1", "led1 Q2", "led1 Q3"};
const char * QLed2[] = {"led2 Q0", "led2 Q1", "led2 Q2"};
const char * QLed3[] = {"led3 Q0", "led3 Q1"};
const char * QLed4[] = {"led4 Q0", "led4 Q1", "led4 Q2", "led4 Q3", "led4 Q4"};
Led leds[] = {
{ 9, QLed0, sizeof QLed0 / sizeof * QLed0 },
{10, QLed1, sizeof QLed1 / sizeof * QLed1 },
{11, QLed2, sizeof QLed2 / sizeof * QLed2},
{12, QLed3, sizeof QLed3 / sizeof * QLed3 },
{13, QLed4, sizeof QLed4 / sizeof * QLed4 },
};
const size_t ledsCount = sizeof leds / sizeof * leds;
size_t currentLed;
void setup() {
button.begin(buttonPin);
for (auto&l : leds) l.begin();
int result = lcd.begin(LCD_COLS, LCD_ROWS);
if (result) {
Serial.print("LCD initialization failed: ");
Serial.println(result);
hd44780::fatalError(result);
}
randomSeed(analogRead(A0)); // randomize
lcd.clear();
lcd.print("PRESS TO START");
}
void loop() {
switch (state) {
case PAUSED: // a click on the button starts the led danse
button.poll();
if (button.onPress()) {
lcd.clear();
lcd.print("Game on!");
lastTick = millis();
// turn off all leds
for (auto&l : leds) l.off();
// turn on first led
currentLed = 0;
leds[currentLed].on();
state = RUNNING;
}
break;
case RUNNING:
button.poll();
if (button.onPress()) {
// we stop the led danse and ask a question from the current Led
lcd.clear();
lcd.print(leds[currentLed].getRandomQuestion());
state = ASKING;
} else {
// check if it's time to go to next led, do that
if (millis() - lastTick >= tickPeriod) {
leds[currentLed++].off();
if (currentLed >= ledsCount) currentLed = 0;
leds[currentLed].on();
lastTick = millis();
}
}
break;
case ASKING:
// a click on the button starts the led danse again
button.poll();
if (button.onPress()) {
// turn off all leds (this is not necessary unless you messed up the leds in other part of the code, whilst asking the question)
for (auto&l : leds) l.off();
// turn on the current led
leds[currentLed].on();
lcd.clear();
lcd.print("Try again!");
state = RUNNING;
}
break;
}
}
I created a small class for the Leds to embed everything together. The number of questions associated to one Led is made arbitrary. (you just pass an array of questions and number of questions in the array for a given Led).
the game is managed by a very simple state machine. (if you don't know what it is, you might benefit from reading this small introduction to the topic: Yet another Finite State Machine introduction )
