#include <Wire.h>
#include <RTClib.h>
#include <Keypad.h>
#include <SD.h>
#include <SPI.h>
RTC_DS3231 rtc;
File myFile;
const int buzzerPin = 8; // Pin buzzer
const int chipSelect = 4; // Pin CS untuk modul SD Card
// Konfigurasi LCD 16x2 SPI dan Keypad
#include <LiquidCrystal.h>
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
const byte ROWS = 4; // jumlah baris keypad
const byte COLS = 4; // jumlah kolom keypad
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6}; // Pin yang terhubung ke baris keypad
byte colPins[COLS] = {5, 4, 3, 2}; // Pin yang terhubung ke kolom keypad
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
int currentMenu = 0; // 0 = Menu Utama, 1 = Menu Absen, 2 = Menu Admin, dst.
String inputPegawai = "";
String uniqueCode = "";
// Nada Mario Bros untuk startup
int melody[] = {
262, 294, 330, 349, 392, 440, 494, 523
};
void setup() {
Serial.begin(9600);
// Setup RTC
if (!rtc.begin()) {
Serial.println("RTC tidak ditemukan!");
while (1);
}
// Setup SD card
if (!SD.begin(chipSelect)) {
Serial.println("Gagal mengakses SD Card");
return;
}
// Setup LCD
lcd.begin(16, 2);
lcd.print("Mesin Absen");
// Mainkan nada Mario Bros saat startup
startupTone();
delay(2000);
lcd.clear();
// Baca daftar pegawai dari file CSV
loadDaftarPegawai();
// Tampilan Menu Utama
displayMenuUtama();
}
void loop() {
// Cek input keypad
char key = keypad.getKey();
if (key) {
switch (currentMenu) {
case 0:
handleMenuUtama(key);
break;
case 1:
handleAbsen(key);
break;
case 2:
handleAdmin(key); // Menu admin
break;
case 3:
handlePengaturanWaktu(key); // Menu pengaturan waktu
break;
case 4:
handlePendaftaranPegawai(key); // Menu pendaftaran pegawai
break;
}
}
}
// Fungsi untuk menampilkan menu utama
void displayMenuUtama() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("1. Absen");
lcd.setCursor(0, 1);
lcd.print("2. Admin");
currentMenu = 0;
}
// Fungsi untuk menangani input di menu utama
void handleMenuUtama(char key) {
if (key == '1') {
lcd.clear();
lcd.print("Masukkan ID:");
currentMenu = 1;
} else if (key == '2') {
lcd.clear();
lcd.print("Admin Menu");
currentMenu = 2;
}
}
// Fungsi untuk menangani absen
void handleAbsen(char key) {
if (key >= '0' && key <= '9') {
inputPegawai += key;
lcd.setCursor(0, 1);
lcd.print(inputPegawai);
} else if (key == '#') {
// Cek absen dan simpan data ke SD card
cekAbsen();
}
}
// Fungsi untuk mengecek absen dan menyimpan ke file CSV
void cekAbsen() {
DateTime now = rtc.now();
String status = "";
// Cek waktu absen (jam masuk/pulang/terlambat/lembur)
if (now.hour() >= 6 && now.hour() <= 7) {
status = "Masuk Tepat Waktu";
playTone(buzzerPin, 1000); // Nada tepat waktu
} else if (now.hour() > 7 && now.hour() < 15) {
status = "Terlambat";
playTone(buzzerPin, 500); // Nada terlambat
} else if (now.hour() >= 15 && now.hour() <= 17) {
status = "Pulang";
playTone(buzzerPin, 1000); // Nada absen pulang
} else {
status = "Lembur";
playTone(buzzerPin, 1500); // Nada lembur
}
// Simpan data ke file CSV
myFile = SD.open("absensi.csv", FILE_WRITE);
if (myFile) {
myFile.print(inputPegawai); // Nomor pegawai
myFile.print(",");
myFile.print(now.year()); // Tahun
myFile.print("/");
myFile.print(now.month()); // Bulan
myFile.print("/");
myFile.print(now.day()); // Hari
myFile.print(",");
myFile.print(now.hour()); // Jam
myFile.print(":");
myFile.print(now.minute()); // Menit
myFile.print(",");
myFile.println(status); // Status (Masuk, Terlambat, Lembur, dll.)
myFile.close();
} else {
lcd.print("Gagal SD");
}
inputPegawai = ""; // Reset input pegawai
delay(2000);
displayMenuUtama();
}
// Fungsi untuk memutar nada
void playTone(int pin, int duration) {
tone(pin, 1000, duration); // Menghasilkan nada dengan frekuensi 1000 Hz
delay(duration); // Menunggu durasi yang ditentukan
noTone(pin); // Menghentikan nada
}
// Nada startup
void startupTone() {
for (int i = 0; i < 8; i++) {
tone(buzzerPin, melody[i], 200); // Menghasilkan nada dengan frekuensi yang ditentukan oleh array melody
delay(200); // Memberikan jeda antar nada
}
noTone(buzzerPin); // Menghentikan nada setelah selesai
}
// Fungsi untuk membaca daftar pegawai dari file CSV
void loadDaftarPegawai() {
myFile = SD.open("pegawai.csv");
if (myFile) {
while (myFile.available()) {
String line = myFile.readStringUntil('\n');
// Proses data pegawai, misalnya simpan dalam array atau struktur data
Serial.println(line); // Tampilkan setiap baris daftar pegawai
}
myFile.close();
} else {
lcd.print("Gagal Baca Pegawai");
}
}
// Fungsi untuk menangani menu Admin
void handleAdmin(char key) {
lcd.clear();
lcd.print("Admin Option");
// Implementasikan logika untuk menu admin di sini
delay(2000);
displayMenuUtama(); // Kembali ke menu utama setelah selesai
}
// Fungsi untuk menangani pengaturan waktu
void handlePengaturanWaktu(char key) {
lcd.clear();
lcd.print("Set Waktu");
// Implementasikan logika pengaturan waktu di sini
delay(2000);
displayMenuUtama(); // Kembali ke menu utama setelah selesai
}
// Fungsi untuk pendaftaran pegawai baru
void handlePendaftaranPegawai(char key) {
lcd.clear();
lcd.print("Daftar Pegawai");
// Implementasikan logika pendaftaran pegawai di sini
delay(2000);
displayMenuUtama(); // Kembali ke menu utama setelah selesai
}