#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4); // change address if needed
// ====== Score Variables ======
int i = 0; // score
int buzzerbutton = 12;
bool playingMelody = false;
unsigned long lastToneTime = 0;
int melodyStep = 0;
float x,y;
struct ToneStep {
int frequency;
int duration;
};
ToneStep melody[] = {
{165, 200}, // E3
{294, 200}, // D4
{932, 500} // A#5
};
const int melodyLength = sizeof(melody) / sizeof(melody[0]);
// ====== Debounce Variables ======
unsigned long lastButtonPress = 0;
const unsigned long debounceDelay = 200; // ms
// ====== Menu Navigation ======
int level = 0;
int arrow = 0;
int currentIndexMainMenu = 0;
const int listSizeMainMenu = 7;
String mainMenuList[listSizeMainMenu] = {
"Challenge 1", "Challenge 2", "Challenge 3",
"Challenge 4", "Challenge 5", "", ""
};
// ====== Volt Sensor Setup ======
int voltInput = A3;
float vout = 0.0;
float vin = 0.0;
float R1 = 30000.0;
float R2 = 7500.0;
int voltvalue = 0;
// ====== Mode Switch ======
int modeSwitch = 9;
// ====== Joystick ======
int JoyStick_X = A0;
int JoyStick_Y = A1;
int selectButton = 10;
// ====== Touch Sensor ======
int touchSensor = 11;
// ====== Challenge Steps ======
const int listSizec1 = 3;
String c1[listSizec1] = {"c1 step 1", "c1 step 2", "c1 step 3"};
const int listSizec2 = 3;
String c2[listSizec2] = {"c2 step 1", "c2 step 2", "c2 step 3"};
const int listSizec3 = 3;
String c3[listSizec3] = {"c3 step 1", "c3 step 2", "c3 step 3"};
const int listSizec4 = 3;
String c4[listSizec4] = {"c4 step 1", "c4 step 2", "c4 step 3"};
const int listSizec5 = 3;
String c5[listSizec5] = {"c5 step 1", "c5 step 2", "c5 step 3"};
// ====== Function Prototypes ======
void updateSevenSegment(int num);
void displayItemMainMenu();
// =====================================================
// MODE 1 FUNCTIONS
// =====================================================
void touch() {
lcd.setCursor(0, 0);
lcd.print("The object is a ");
lcd.setCursor(0, 1);
if (digitalRead(touchSensor) == 1) {
lcd.print("conductor! ");
} else {
lcd.print("non-conductor!");
}
}
void volt() {
voltvalue = analogRead(voltInput);
vout = (voltvalue * 5.0) / 1024.0;
vin = vout / (R2 / (R1 + R2));
lcd.setCursor(0, 2);
lcd.print("INPUT V= ");
lcd.setCursor(0, 3);
lcd.print(vin, 2);
}
// =====================================================
// MODE 2 FUNCTIONS (Challenges)
// =====================================================
void lcd_main_menu() {
static unsigned long lastNav = 0;
if (millis() - lastNav > 250) { // joystick debounce
x = analogRead (JoyStick_X) * (5.0 / 1023.0);
y = analogRead (JoyStick_Y) * (5.0 / 1023.0);
if (x > 4 && y > 2) {
currentIndexMainMenu++;
if (currentIndexMainMenu + 2 >= listSizeMainMenu) currentIndexMainMenu = 0;
displayItemMainMenu();
lastNav = millis();
}
}
}
void displayItemMainMenu() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Select:");
lcd.setCursor(0, 1);
lcd.print(">");
arrow = currentIndexMainMenu + 1;
lcd.print(mainMenuList[currentIndexMainMenu]);
lcd.setCursor(0, 2);
lcd.print(mainMenuList[currentIndexMainMenu + 1]);
lcd.setCursor(0, 3);
lcd.print(mainMenuList[currentIndexMainMenu + 2]);
}
void showChallengeIntro(String title) {
lcd.clear();
lcd.setCursor(0, 0);
level = 2;
lcd.print("Welcome to " + title);
lcd.setCursor(0, 1);
lcd.print("Move down to see steps");
}
void showChallengeSteps(String steps[], int size) {
static int idx = 0;
static unsigned long lastStep = 0;
if (millis() - lastStep > 250) { // debounce
x = analogRead (JoyStick_X) * (5.0 / 1023.0);
y = analogRead (JoyStick_Y) * (5.0 / 1023.0);
if (x > 4 && y > 2) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Step ");
lcd.print(idx + 1);
lcd.setCursor(0, 1);
lcd.print(steps[idx]);
idx++;
if (idx >= size) idx = 0;
lastStep = millis();
}
}
}
// =====================================================
// SCORE FUNCTIONS (Non-blocking with millis)
// =====================================================
void startScore() {
if (!playingMelody) {
i++;
if (i > 9) i = 0; // wrap around after 9
updateSevenSegment(i); // update 7-segment immediately
playingMelody = true;
melodyStep = 0;
lastToneTime = millis();
tone(13, melody[melodyStep].frequency, melody[melodyStep].duration);
}
}
void handleScore() {
if (playingMelody) {
if (millis() - lastToneTime >= (unsigned long)melody[melodyStep].duration + 50) {
melodyStep++;
if (melodyStep < melodyLength) {
lastToneTime = millis();
tone(13, melody[melodyStep].frequency, melody[melodyStep].duration);
} else {
noTone(13);
playingMelody = false;
}
}
}
}
void updateSevenSegment(int num) {
switch (num) {
case 0: digitalWrite(2,HIGH); digitalWrite(3,HIGH); digitalWrite(7,HIGH); digitalWrite(4,HIGH); digitalWrite(6,HIGH); digitalWrite(5,HIGH); digitalWrite(8,LOW); break;
case 1: digitalWrite(2,LOW); digitalWrite(3,HIGH); digitalWrite(7,LOW); digitalWrite(4,HIGH); digitalWrite(6,LOW); digitalWrite(5,LOW); digitalWrite(8,LOW); break;
case 2: digitalWrite(2,HIGH); digitalWrite(3,HIGH); digitalWrite(7,LOW); digitalWrite(4,LOW); digitalWrite(6,HIGH); digitalWrite(5,HIGH); digitalWrite(8,HIGH); break;
case 3: digitalWrite(2,HIGH); digitalWrite(3,HIGH); digitalWrite(7,LOW); digitalWrite(4,HIGH); digitalWrite(6,LOW); digitalWrite(5,HIGH); digitalWrite(8,HIGH); break;
case 4: digitalWrite(2,LOW); digitalWrite(3,HIGH); digitalWrite(7,HIGH); digitalWrite(4,HIGH); digitalWrite(6,LOW); digitalWrite(5,LOW); digitalWrite(8,HIGH); break;
case 5: digitalWrite(2,HIGH); digitalWrite(3,LOW); digitalWrite(7,HIGH); digitalWrite(4,HIGH); digitalWrite(6,LOW); digitalWrite(5,HIGH); digitalWrite(8,HIGH); break;
case 6: digitalWrite(2,HIGH); digitalWrite(3,LOW); digitalWrite(7,HIGH); digitalWrite(4,HIGH); digitalWrite(6,HIGH); digitalWrite(5,HIGH); digitalWrite(8,HIGH); break;
case 7: digitalWrite(2,HIGH); digitalWrite(3,HIGH); digitalWrite(7,LOW); digitalWrite(4,HIGH); digitalWrite(6,LOW); digitalWrite(5,LOW); digitalWrite(8,LOW); break;
case 8: digitalWrite(2,HIGH); digitalWrite(3,HIGH); digitalWrite(7,HIGH); digitalWrite(4,HIGH); digitalWrite(6,HIGH); digitalWrite(5,HIGH); digitalWrite(8,HIGH); break;
case 9: digitalWrite(2,HIGH); digitalWrite(3,HIGH); digitalWrite(7,HIGH); digitalWrite(4,HIGH); digitalWrite(6,LOW); digitalWrite(5,HIGH); digitalWrite(8,HIGH); break;
}
}
// =====================================================
// SETUP
// =====================================================
void setup() {
// score pins
pinMode(buzzerbutton, INPUT_PULLUP);
pinMode(2, OUTPUT); pinMode(3, OUTPUT); pinMode(7, OUTPUT);
pinMode(4, OUTPUT); pinMode(6, OUTPUT); pinMode(5, OUTPUT); pinMode(8, OUTPUT);
pinMode(13, OUTPUT);
// mode 1
pinMode(touchSensor, INPUT);
pinMode(voltInput, INPUT);
lcd.init();
lcd.backlight();
// mode 2
pinMode(selectButton, INPUT_PULLUP);
pinMode(modeSwitch, INPUT_PULLUP);
displayItemMainMenu();
}
// =====================================================
// LOOP
// =====================================================
void loop() {
// ====== Handle Score Button with Debounce ======
static bool lastBuzzerState = LOW;
bool buzzerState = digitalRead(buzzerbutton);
if (buzzerState == LOW && lastBuzzerState == LOW && millis() - lastButtonPress > debounceDelay) {
startScore();
lastButtonPress = millis();
}
lastBuzzerState = buzzerState;
handleScore();
// ====== Mode Handling ======
if (digitalRead(modeSwitch) == HIGH) {
// Mode 1: Sensors
touch();
volt();
} else {
// Mode 2: Challenges
if (digitalRead(selectButton) == LOW) {
level = 1;
}
if (level == 0) lcd_main_menu();
if (level == 1 && arrow == 1) showChallengeIntro("Game 1");
else if (level == 2 && arrow == 1) showChallengeSteps(c1, listSizec1);
if (level == 1 && arrow == 2) showChallengeIntro("Game 2");
else if (level == 2 && arrow == 2) showChallengeSteps(c2, listSizec2);
if (level == 1 && arrow == 3) showChallengeIntro("Game 3");
else if (level == 2 && arrow == 3) showChallengeSteps(c3, listSizec3);
if (level == 1 && arrow == 4) showChallengeIntro("Game 4");
else if (level == 2 && arrow == 4) showChallengeSteps(c4, listSizec4);
if (level == 1 && arrow == 5) showChallengeIntro("Game 5");
else if (level == 2 && arrow == 5) showChallengeSteps(c5, listSizec5);
}
}
Touch sensor
Volt sensor
Mode Switch
Done button
Reset button