/**
* Arduino Menu Program
*
* @file mikroprosesor2-menu
* @author LunaticFTW ([email protected])
* @brief
* @version 1.0
* @date 2023-02-28
*
* Program ini dibuat sebagai tugas mata kuliah Mikroprosesor II.
*
* @copyright Copyright (c) 2023
*
*/
#include <LiquidCrystal_I2C.h>
/**
* Defini pin tombol
*
*/
#define tombolSelect 3
#define tombolNext 2
#define tombolPrev 4
#define tombolBack 5
/**
* Membuat objek lcd berdasarkan kelas LiquidCrystal_I2C
*
*/
LiquidCrystal_I2C lcd(0x27, 16, 2);
/**
* Delay antar saat tombol ditekan
*
*/
int delayTombol = 50;
void setup() {
/**
* Memulai komunikasi serial dengan baudrate 115200
*
*/
Serial.begin(115200);
/**
* Menginisiasi pin tombol sebagai INPUT_PULLUP
*
*/
pinMode(tombolSelect, INPUT_PULLUP);
pinMode(tombolBack, INPUT_PULLUP);
pinMode(tombolNext, INPUT_PULLUP);
pinMode(tombolPrev, INPUT_PULLUP);
/**
* Memulai inisiasi LCD
*
*/
lcd.init();
lcd.backlight();
/**
* Memanggil fungsi menuUtama() sebagai halaman default
*
*/
menuUtama();
}
void loop() {
}
/**
* @function menuUtama()
* @abstract Halaman utama menu
*
*/
void menuUtama() {
/**
* Membersihkan LCD setiap kali menu berpindah
*
*/
lcd.clear();
/**
* Atribut
*
*/
int8_t indeks = 0;
int8_t indeksMaksimal = 4;
int8_t indeksMinimal = 0;
String title = "MAIN MENU";
void (*fungsiPilihan[])() = {nullptr, nullptr, nullptr, submenuMode, submenuSettings};
String pilihan[] = {"START", "STOP", "RESET", "MODE", "SETTINGS"};
void (*menuSebelumnya)() = nullptr;
/**
* Melakukan perulangan terus menerus untuk menampilkan menu pada lcd,
* dan mengarahkan ke menu sebelumnya dan selanjutnya
*
*/
while(true) {
pilih(indeks, indeksMaksimal, indeksMinimal, title, fungsiPilihan, pilihan, menuSebelumnya);
}
}
/**
* @function submenuMode()
* @abstract Halaman Submenu Mode
*
*/
void submenuMode() {
/**
* Membersihkan LCD setiap kali menu berpindah
*
*/
lcd.clear();
/**
* Atribut
*
*/
int8_t indeks = 0;
int8_t indeksMaksimal = 1;
int8_t indeksMinimal = 0;
String title = "MODE";
void (*fungsiPilihan[])() = {nullptr, submenuModeCountdown};
String pilihan[] = {"STOPWATCH", "COUNTDOWN"};
void (*menuSebelumnya)() = menuUtama;
/**
* Melakukan perulangan terus menerus untuk menampilkan menu pada lcd,
* dan mengarahkan ke menu sebelumnya dan selanjutnya
*
*/
while(true) {
pilih(indeks, indeksMaksimal, indeksMinimal, title, fungsiPilihan, pilihan, menuSebelumnya);
}
}
/**
* @function submenuModeCountdown()
* @abstract Halaman Sub Submenu Mode, Countdown
*
*/
void submenuModeCountdown() {
/**
* Membersihkan LCD setiap kali menu berpindah
*
*/
lcd.clear();
/**
* Atribut
*
*/
int8_t indeks = 0;
int8_t indeksMaksimal = 1;
int8_t indeksMinimal = 0;
String title = "COUNTDOWN";
void (*fungsiPilihan[])() = {nullptr, nullptr};
String pilihan[] = {"30 DETIK", "1 MENIT"};
void (*menuSebelumnya)() = submenuMode;
/**
* Melakukan perulangan terus menerus untuk menampilkan menu pada lcd,
* dan mengarahkan ke menu sebelumnya dan selanjutnya
*
*/
while(true) {
pilih(indeks, indeksMaksimal, indeksMinimal, title, fungsiPilihan, pilihan, menuSebelumnya);
}
}
/**
* @function submenuSettings()
* @abstract Halaman Submenu Settings
*
*/
void submenuSettings() {
/**
* Membersihkan LCD setiap kali menu berpindah
*
*/
lcd.clear();
/**
* Atribut
*
*/
int8_t indeks = 0;
int8_t indeksMaksimal = 1;
int8_t indeksMinimal = 0;
String title = "SETTINGS";
void (*fungsiPilihan[])() = {submenuSettingsLED, submenuSettingsBuzzer};
String pilihan[] = {"LED", "BUZZER"};
void (*menuSebelumnya)() = menuUtama;
/**
* Melakukan perulangan terus menerus untuk menampilkan menu pada lcd,
* dan mengarahkan ke menu sebelumnya dan selanjutnya
*
*/
while(true) {
pilih(indeks, indeksMaksimal, indeksMinimal, title, fungsiPilihan, pilihan, menuSebelumnya);
}
}
/**
* @function submenuSettingsBuzzer()
* @abstract Halaman Sub Submenu Settings, Buzzer
*
*/
void submenuSettingsBuzzer() {
/**
* Membersihkan LCD setiap kali menu berpindah
*
*/
lcd.clear();
/**
* Atribut
*
*/
int8_t indeks = 0;
int8_t indeksMaksimal = 1;
int8_t indeksMinimal = 0;
String title = "BUZZER";
void (*fungsiPilihan[])() = {nullptr, nullptr};
String pilihan[] = {"ON", "OFF"};
void (*menuSebelumnya)() = submenuSettings;
/**
* Melakukan perulangan terus menerus untuk menampilkan menu pada lcd,
* dan mengarahkan ke menu sebelumnya dan selanjutnya
*
*/
while(true) {
pilih(indeks, indeksMaksimal, indeksMinimal, title, fungsiPilihan, pilihan, menuSebelumnya);
}
}
/**
* @function submenuSettingsLED()
* @abstract Halaman Sub Submenu Settings, LED
*
*/
void submenuSettingsLED() {
/**
* Membersihkan LCD setiap kali menu berpindah
*
*/
lcd.clear();
/**
* Atribut
*
*/
int8_t indeks = 0;
int8_t indeksMaksimal = 1;
int8_t indeksMinimal = 0;
String title = "LED";
void (*fungsiPilihan[])() = {nullptr, nullptr};
String pilihan[] = {"ON", "OFF"};
void (*menuSebelumnya)() = submenuSettings;
/**
* Melakukan perulangan terus menerus untuk menampilkan menu pada lcd,
* dan mengarahkan ke menu sebelumnya dan selanjutnya
*
*/
while(true) {
pilih(indeks, indeksMaksimal, indeksMinimal, title, fungsiPilihan, pilihan, menuSebelumnya);
}
}
/**
* @function pilih(indeks, indeksMaksimal, indeksMinimal, title, fungsiPilihan, pilihan, menuSebelumnya)
* @abstract Menentukan kemanakah menu selanjutnya dan juga menu sebelumnya
*
* @param indeks
* @param indeksMaksimal
* @param indeksMinimal
* @param title
* @param fungsiPilihan
* @param pilihan
* @param menuSebelumnya
*/
void pilih(int8_t &indeks, int8_t &indeksMaksimal, int8_t &indeksMinimal, String title, void (*fungsiPilihan[])(), String pilihan[], void (*menuSebelumnya)()) {
/**
* Memanggil fungsi cetakLCD untuk mencetak pilihan berdasarkan indeks
*
*/
cetakLCD(title, "[" + (String)indeks + "]" + pilihan[indeks]);
/**
* Membuat statement kondisi, jika select dipencet dan juga ada pilihan, maka menu akan
* berpindah ke fungsi yang dipilih berdasarkan indeks
*
*/
if(kondisiSelect() && fungsiPilihan[indeks] != nullptr) {
(*fungsiPilihan[indeks])();
}
/**
* Membuat statement kondisi, jika back dipencet dan juga ada menu sebelumnya, maka menu akan
* berpindah ke menu sebelumnya atau di atasnya
*
*/
if(kondisiBack() && menuSebelumnya != nullptr) {
(*menuSebelumnya)();
}
/**
* Print kondisi tombol dan juga indeks yang dipilih untuk melakukan debug
*
*/
// Print Kondisi Tombol
// printKondisiTombol();
// Serial.println(indeks);
// Serial.println(pilihan[indeks]);
/**
* Memanggil fungsi incrementDecrement untuk menambah dan mengurangi indeks
*
*/
incrementDecrement(indeks, indeksMaksimal, indeksMinimal);
}
/**
* @function kondisiSelect()
* @abstract Membaca kondisi tombol select
*
* @return true
* @return false
*
*/
bool kondisiSelect() {
return !(digitalRead(tombolSelect));
}
/**
* @function kondisiBack()
* @abstract Membaca kondisi tombol back
*
* @return true
* @return false
*
*/
bool kondisiBack() {
return !(digitalRead(tombolBack));
}
/**
* @function kondisiNext()
* @abstract Membaca kondisi tombol next
*
* @return true
* @return false
*
*/
bool kondisiNext() {
return !(digitalRead(tombolNext));
}
/**
* @function kondisiPrev()
* @abstract Membaca kondisi tombol prev
*
* @return true
* @return false
*
*/
bool kondisiPrev() {
return !(digitalRead(tombolPrev));
}
/**
* @function incrementDecrement(indeks, indeksMaksimal, indeksMinimal)
* @abstract Melakukan penambahan dan pengurangan indeks
*
*/
/**
* @function incrementDecrement(indeks, indeksMaksimal, indeksMinimal)
* @abstract Melakukan penambahan dan pengurangan indeks
*
* @param indeks
* @param indeksMaksimal
* @param indeksMinimal
*/
void incrementDecrement(int8_t &indeks, int8_t &indeksMaksimal, int8_t &indeksMinimal) {
/**
* Melakukan penambahan indeks jika tombol next ditekan dan juga indeks lebih kecil
* daripada indeks maksimal
*
*/
if(kondisiNext() && indeks < indeksMaksimal) {
indeks++;
delay(delayTombol);
}
/**
* Melakukan pengurangan indeks jika tombol prev ditekan dan juga indeks lebih besar
* daripada indeks minimal
*
*/
else if(kondisiPrev() && indeks > indeksMinimal) {
indeks--;
delay(delayTombol);
}
/**
* Mengubah nilai indeks menjadi indeks minimal jika tombol next ditekan
* dan indeks sama dengan indeks maksimal
*
*/
else if(kondisiNext() && indeks == indeksMaksimal) {
indeks = indeksMinimal;
delay(delayTombol);
}
/**
* Menubah nilai indeks menjadi indeks maksimal jika tombol prev ditekan
* dan indeks sama dengan indeks minimal
*
*/
else if(kondisiPrev() && indeks == indeksMinimal) {
indeks = indeksMaksimal;
delay(delayTombol);
}
}
/**
* @function printKondisiTombol()
* @abstract Mencetak kondisi tombol untuk melakukan debug
*
*/
void printKondisiTombol() {
Serial.println(String(kondisiSelect()) + " | " +
String(kondisiBack()) + " | " +
String(kondisiNext()) + " | " +
String(kondisiPrev()));
}
/**
* @function cetakLCD()
* @abstract Mencetak tampilan menu pada LCD
*
* @param barisPertama
* @param barisKedua
*/
void cetakLCD(String barisPertama, String barisKedua) {
barisPertama = barisPertama + " ";
barisKedua = barisKedua + " ";
lcd.setCursor(0, 0);
lcd.print(barisPertama);
lcd.setCursor(0,1);
lcd.print(barisKedua);
}