// Uncomment the following line to enable extended listening mode
//#define EXTENDED_LISTENING_MODE
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <SD.h>
#include <SPI.h>
#include <DFRobotDFPlayerMini.h>
#include "track.h" // Include the track names
DFRobotDFPlayerMini dfPlayer;
// LCD configuration
LiquidCrystal_I2C lcd(0x22, 20, 4);
// Keypad configuration
const byte ROWS = 3;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'Y', 'N', '0', '1'},
{'2', '3', '4', '5'},
{'6', '7', '8', '9'}
};
byte rowPins[ROWS] = {5, 4, 3};
byte colPins[COLS] = {9, 8, 7, 6};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// Pin configuration
const int ledPin = 50;
const int buzzerPin = 51;
// Variables
int skor = 5;
int nomorFile;
unsigned long waktuMulaiBuzzer = 0;
const unsigned long durasiCuitan = 500;
bool audioSedangDiputar = false;
unsigned long waktuPesanMulai = 0;
const unsigned long durasiPesan = 2000;
bool pesanAktif = false;
// Function declarations
void tampilkanMenuUtama();
void modeMendengarkan();
void modeMenebak();
void playAudioFile(int trackNumber);
void mintaKonfirmasi(const char* pesan, void (*callbackYa)(), void (*callbackTidak)());
void dapatkanInputKeypad(char* bufferInput, size_t ukuranBuffer);
void prosesInputKeypad(char key);
void sistemBerjalan();
void jawabanSalah();
void saatYaMendengarkan();
void saatTidakMendengarkan();
void saatYaMenebak();
void saatTidakMenebak();
void saatPutarFile();
void saatTebakanJawaban();
void pilihCaraMendengarkan();
void mendengarkanManual();
void mendengarkanRandom();
void tampilkanPesan(const char* pesan);
// Setup function
void setup() {
lcd.init();
lcd.backlight();
Serial.begin(9600);
Serial1.begin(9600);
pinMode(ledPin, OUTPUT);
pinMode(buzzerPin, OUTPUT);
if (!dfPlayer.begin(Serial1)) {
Serial.println("DFPlayer Mini tidak terdeteksi.");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Selamat Datang!");
lcd.setCursor(0, 1);
lcd.print("mohon maaf, tetapi");
lcd.setCursor(0, 2);
lcd.print("DFPlayer Mini");
lcd.setCursor(0, 3);
lcd.print("tidak terdeteksi.");
while (true);
}
sistemBerjalan();
tampilkanMenuUtama();
}
// Main loop
void loop() {
unsigned long currentMillis = millis();
// Handle buzzer timing
if (waktuMulaiBuzzer > 0 && currentMillis - waktuMulaiBuzzer >= durasiCuitan) {
digitalWrite(buzzerPin, LOW);
waktuMulaiBuzzer = 0;
}
// Check audio playback status
if (audioSedangDiputar && dfPlayer.available() && dfPlayer.readType() == DFPlayerPlayFinished) {
audioSedangDiputar = false;
tampilkanMenuUtama();
}
// Check keypad input
char key = keypad.getKey();
if (key) {
prosesInputKeypad(key);
}
// Handle message display duration
if (pesanAktif && currentMillis - waktuPesanMulai >= durasiPesan) {
pesanAktif = false;
tampilkanMenuUtama();
}
}
// Process keypad input
void prosesInputKeypad(char key) {
if (!audioSedangDiputar && !pesanAktif) {
if (key == '1') {
mintaKonfirmasi("Yakin mendengar?", saatYaMendengarkan, saatTidakMendengarkan);
} else if (key == '2') {
mintaKonfirmasi("Yakin menebak?", saatYaMenebak, saatTidakMenebak);
}
}
}
// System running indication
void sistemBerjalan() {
digitalWrite(ledPin, HIGH);
}
// Handle incorrect answer
void jawabanSalah() {
digitalWrite(buzzerPin, HIGH);
waktuMulaiBuzzer = millis();
dfPlayer.play(286); // Play a specific "wrong answer" sound
}
// Display main menu
void tampilkanMenuUtama() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Selamat Datang!");
lcd.setCursor(0, 1);
lcd.print("Pilih Permainan:");
lcd.setCursor(0, 2);
lcd.print("1: Dengar Ayat");
lcd.setCursor(0, 3);
lcd.print("2: Tebak Ayat");
}
// Listening mode
void modeMendengarkan() {
#ifdef EXTENDED_LISTENING_MODE
lcd.clear();
lcd.print("Pilih metode:");
lcd.setCursor(0, 1);
lcd.print("1: Manual");
lcd.setCursor(0, 3);
lcd.print("2: Random");
while (true) {
char key = keypad.getKey();
if (key == '1') {
mendengarkanManual();
break;
}
if (key == '2') {
mendengarkanRandom();
break;
}
}
#else
mendengarkanManual();
#endif
}
// Manual listening
void mendengarkanManual() {
lcd.clear();
lcd.print("Masukkan nomor:");
char input[4] = "";
dapatkanInputKeypad(input, sizeof(input));
nomorFile = atoi(input);
mintaKonfirmasi("Putar file ini?", saatPutarFile, tampilkanMenuUtama);
}
// Random listening
void mendengarkanRandom() {
nomorFile = random(1, 287);
saatPutarFile();
}
// Guessing mode
void modeMenebak() {
nomorFile = random(1, 287);
playAudioFile(nomorFile);
audioSedangDiputar = true;
mintaKonfirmasi("Tebak nomor?", saatTebakanJawaban, tampilkanMenuUtama);
}
// Request confirmation
void mintaKonfirmasi(const char* pesan, void (*callbackYa)(), void (*callbackTidak)()) {
lcd.clear();
lcd.print(pesan);
lcd.setCursor(0, 1);
lcd.print("Y: Ya N: Tidak");
while (true) {
char key = keypad.getKey();
if (key == 'Y') {
callbackYa();
break;
}
if (key == 'N') {
callbackTidak();
break;
}
}
}
// Get keypad input
void dapatkanInputKeypad(char* bufferInput, size_t ukuranBuffer) {
size_t indeks = 0;
while (indeks < ukuranBuffer - 1) {
char key = keypad.getKey();
if (key) {
bufferInput[indeks++] = key;
lcd.setCursor(indeks, 1);
lcd.print(key);
}
}
bufferInput[indeks] = '\0';
}
// Play audio file based on track number
void playAudioFile(int trackNumber) {
dfPlayer.play(trackNumber);
audioSedangDiputar = true;
lcd.clear();
lcd.print("Memutar file ");
lcd.setCursor(0, 1);
lcd.print(trackNames[trackNumber - 1]); // Display the track name
}
// Callback functions
void saatYaMendengarkan() {
modeMendengarkan();
}
void saatTidakMendengarkan() {
tampilkanMenuUtama();
}
void saatYaMenebak() {
modeMenebak();
}
void saatTidakMenebak() {
tampilkanMenuUtama();
}
void saatPutarFile() {
playAudioFile(nomorFile);
}
void saatTebakanJawaban() {
lcd.clear();
lcd.print("Masukkan tebakan:");
char input[4] = "";
dapatkanInputKeypad(input, sizeof(input));
int tebakan = atoi(input);
if (tebakan == nomorFile) {
skor++;
dfPlayer.play(287); // Play a specific "correct answer" sound
tampilkanPesan(("Benar! Skor: " + String(skor)).c_str());
} else {
skor--;
dfPlayer.play(286); // Play a specific "wrong answer" sound
jawabanSalah();
tampilkanPesan(("Salah! Skor: " + String(skor)).c_str());
}
if (skor == 0) {
tampilkanPesan("Permainan Selesai");
dfPlayer.play(288); // Play a specific "game over" sound
} else if (skor == 10) {
tampilkanPesan("Anda Menang!");
dfPlayer.play(289); // Play a specific "winning" sound
} else {
mintaKonfirmasi("Main lagi?", saatYaMendengarkan, tampilkanMenuUtama);
}
}
// Display a temporary message
void tampilkanPesan(const char* pesan) {
lcd.clear();
lcd.print(pesan);
waktuPesanMulai = millis();
pesanAktif = true;
}