#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Stepper.h>
#include <Servo.h>
// LCD and Stepper Motor
LiquidCrystal_I2C lcd(0x27, 16, 2);
const int steps = 200;
Stepper myStepper(steps, 4, 5, 6, 7);
// RGB LED Pins
const int redd = 3;
const int greenn = 2;
const int bluee = 1;
// Button Pins for True/False
const int t = A2;
const int f = A3;
// Ultrasonic Sensor Pins
const int trigPin = 8;
const int echoPin = A0;
// Servo (Eyelid) Pin
Servo eyelidServo;
const int servoPin = 9;
// Quiz Variables
String questions[] = {"Pogi si butlig?", "Mabait si butlig?"};
int index[2] = {0, 1};
int ques = 0;
int points = 0;
bool quizz = false;
// Blink Timing
unsigned long lastBlinkTime = 0;
void setup() {
// Initialize LCD and Backlight
lcd.begin(16, 2);
lcd.noBacklight();
lcd.clear();
// Set Pin Modes
pinMode(redd, OUTPUT);
pinMode(greenn, OUTPUT);
pinMode(bluee, OUTPUT);
pinMode(t, INPUT);
pinMode(f, INPUT);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
// Initialize RGB LED and Servo
setRGB(0, 0, 0);
eyelidServo.attach(servoPin);
eyelidServo.write(0); // Start with eyelid "closed"
// Randomize Question Order and Stepper Motor Speed
randomizeQuestions();
myStepper.setSpeed(60);
}
void loop() {
bool isClose = ultrasonicCheck();
if (isClose && !quizz) {
startQuiz();
} else if (!isClose && quizz) {
endQuiz();
}
if (quizz) {
eyelidBlink(); // Blink eyelid every 2 seconds during quiz
checkAnswer();
}
}
/* --- Ultrasonic Sensor Functions --- */
bool ultrasonicCheck() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH);
float distance = (duration * 0.034) / 2;
return distance < 50;
}
/* --- Quiz Management Functions --- */
void startQuiz() {
quizz = true;
lcd.backlight();
displayQuestion();
}
void endQuiz() {
quizz = false;
lcd.noBacklight();
lcd.clear();
setRGB(0, 0, 0);
}
void randomizeQuestions() {
for (int i = 0; i < 2; i++) {
int r = random(i, 2);
int temp = index[i];
index[i] = index[r];
index[r] = temp;
}
}
/* --- Question Display and Answer Checking --- */
void displayQuestion() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(questions[index[ques]]);
setRGB(0, 0, 255); // Blue light for new question
}
void checkAnswer() {
if (digitalRead(t) == LOW || digitalRead(f) == LOW) {
if (digitalRead(t) == LOW) {
processAnswer(true);
} else {
processAnswer(false);
}
delay(1000);
ques++;
if (ques >= 2) {
displayPoints();
} else {
displayQuestion();
}
}
}
void processAnswer(bool answer) {
bool correctAnswer = (index[ques] == 0) ? !answer : answer;
if (correctAnswer) {
points++;
setRGB(0, 255, 0); // Green for correct answer
displayResult("Correct");
} else {
setRGB(255, 0, 0); // Red for incorrect answer
displayResult("Incorrect");
moveStepper();
}
}
/* --- Display Functions --- */
void displayResult(const char* result) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(result);
}
void displayPoints() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("My Points:");
lcd.setCursor(0, 1);
lcd.print(points);
setRGB(255, 255, 255); // White light for points display
}
/* --- Stepper Motor Action on Incorrect Answer --- */
void moveStepper() {
myStepper.step(steps);
delay(500);
myStepper.step(-steps);
}
/* --- Servo (Eyelid) Blink Function --- */
void eyelidBlink() {
unsigned long currentMillis = millis();
if (currentMillis - lastBlinkTime >= 2000) { // Blink every 2 seconds
eyelidServo.write(0); // Close eyelid
delay(200); // Short delay for closing
eyelidServo.write(90); // Open eyelid
lastBlinkTime = currentMillis;
}
}
/* --- RGB LED Control Function --- */
void setRGB(int red, int green, int blue) {
analogWrite(redd, red);
analogWrite(greenn, green);
analogWrite(bluee, blue);
}