#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
// Encoder & Output
#define ENCODER_A 2
#define ENCODER_B 3
#define SigmaAuto 5
#define RelayOut 8
// Tombol Navigasi Menu
#define BTN_MENU 6
#define BTN_ENTER 7
#define BTN_UP 9
#define BTN_DOWN 10
// LCD
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Variabel penghitungan encoder
volatile long pulseCount = 0;
bool isCounting = false;
bool isLimitReached = false;
bool lastSigmaAutoState = HIGH;
// Variabel pengaturan (bisa diubah dari menu)
int ppr = 120;
float wheelCirc = 100.0;
int maxLength = 2000;
// Variabel menu
int settingIndex = 0;
bool editMode = false;
// Variabel timeout menu
unsigned long menuActiveTime = 0;
const unsigned long menuTimeout = 5000; // Waktu diam 10 detik untuk keluar dari menu
bool menuActive = false;
// Variable backlight lcd
unsigned long backlightTimer = 0;
const unsigned long backlightTimeout = 30000; // 30 detik
bool backlightOn = true;
void turnBacklight(bool state) {
if (state && !backlightOn) {
lcd.backlight();
backlightOn = true;
} else if (!state && backlightOn) {
lcd.noBacklight();
backlightOn = false;
}
}
void saveSettings() {
EEPROM.put(0, 12345); // Magic number
EEPROM.put(2, ppr); // 2–3
EEPROM.put(6, wheelCirc); // 6–9
EEPROM.put(10, maxLength); // 10–11
Serial.println("Setting disimpan ke EEPROM");
}
void loadSettings() {
int magic;
EEPROM.get(0, magic);
if (magic == 12345) {
EEPROM.get(2, ppr);
EEPROM.get(6, wheelCirc);
EEPROM.get(10, maxLength);
Serial.println("Setting dibaca dari EEPROM");
// Validasi nilai masuk akal
if (ppr <= 0 || ppr > 10000) ppr = 120;
if (wheelCirc <= 0 || wheelCirc > 10000) wheelCirc = 100.0;
if (maxLength <= 0 || maxLength > 100000) maxLength = 2000;
} else {
Serial.println("EEPROM kosong atau rusak, gunakan default");
ppr = 120;
wheelCirc = 100.0;
maxLength = 2000;
}
}
void readEncoder() {
if (!isCounting || isLimitReached) return;
if (digitalRead(ENCODER_A) == HIGH) {
if (digitalRead(ENCODER_B) == HIGH) {
pulseCount++;
} else {
pulseCount--;
}
}
}
void setup() {
loadSettings();
Serial.begin(115200);
backlightTimer = millis(); // Start timer awal
turnBacklight(true); // Nyalakan backlight saat start
// Pin setup
pinMode(ENCODER_A, INPUT);
pinMode(ENCODER_B, INPUT);
pinMode(SigmaAuto, INPUT);
pinMode(RelayOut, OUTPUT);
pinMode(BTN_MENU, INPUT_PULLUP);
pinMode(BTN_ENTER, INPUT_PULLUP);
pinMode(BTN_UP, INPUT_PULLUP);
pinMode(BTN_DOWN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ENCODER_A), readEncoder, CHANGE);
// LCD setup
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Program Load...");
lcd.setCursor(0, 1);
lcd.print("by Jikun MTC SKF");
delay(3000);
lcd.clear();
Serial.println("Program dimulai...");
}
bool readButton(int pin) {
static unsigned long lastPress[11] = {0}; // cukup sampai pin 10
if (digitalRead(pin) == LOW && millis() - lastPress[pin] > 200) {
lastPress[pin] = millis();
// Hanya untuk tombol tertentu (6,7,9,10) yang bisa aktifkan backlight
if (pin == 6 || pin == 7 || pin == 9 || pin == 10) {
backlightTimer = millis();
turnBacklight(true);
}
return true;
}
return false;
}
void showMenu() {
lcd.clear();
lcd.setCursor(0, 0);
switch (settingIndex) {
case 0: lcd.print("PPR: "); lcd.print(ppr); break;
case 1: lcd.print("Wheel: "); lcd.print(wheelCirc); break;
case 2: lcd.print("Max: "); lcd.print(maxLength); break;
}
lcd.setCursor(0, 1);
lcd.print(editMode ? "<Edit Mode>" : "<View Mode>");
menuActive = true;
menuActiveTime = millis(); // Reset waktu aktivitas menu
}
void loop() {
static unsigned long lastPrintTime = 0;
// === Menu Navigasi ===
if (readButton(BTN_MENU)) {
settingIndex = (settingIndex + 1) % 3;
editMode = false;
showMenu();
lastPrintTime = millis();
return;
}
if (readButton(BTN_ENTER)) {
editMode = !editMode;
showMenu();
lastPrintTime = millis();
return;
}
// Tombol ENTER ditahan untuk simpan ke EEPROM
static unsigned long enterHoldStart = 0;
if (digitalRead(BTN_ENTER) == LOW) {
if (enterHoldStart == 0) enterHoldStart = millis();
if (millis() - enterHoldStart > 1000) { // tahan 2 detik
saveSettings();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Setting Disimpan!");
delay(1000);
showMenu();
enterHoldStart = 0;
}
} else {
enterHoldStart = 0;
}
if (editMode) {
static bool upHeld = false, downHeld = false;
static unsigned long upStart = 0, downStart = 0;
static unsigned long lastBoostTime = 0;
const unsigned long boostStartDelay = 1000; // 1 detik untuk mulai boost
const unsigned long boostInterval = 200; // tiap 200ms selama boost aktif
bool upPressed = digitalRead(BTN_UP) == LOW;
bool downPressed = digitalRead(BTN_DOWN) == LOW;
// === Tombol UP ===
if (upPressed) {
if (!upHeld) {
upHeld = true;
upStart = millis();
// Tekan biasa
if (settingIndex == 0) ppr += 1;
if (settingIndex == 1) wheelCirc += 1.0;
if (settingIndex == 2) maxLength += 10;
showMenu();
lastPrintTime = millis();
} else if (millis() - upStart >= boostStartDelay && millis() - lastBoostTime >= boostInterval) {
// Boost aktif
if (settingIndex == 0) ppr += 1 * 10;
if (settingIndex == 1) wheelCirc += 1.0 * 10;
if (settingIndex == 2) maxLength += 10 * 10;
showMenu();
lastPrintTime = millis();
lastBoostTime = millis();
}
} else {
upHeld = false;
}
// === Tombol DOWN ===
if (downPressed) {
if (!downHeld) {
downHeld = true;
downStart = millis();
// Tekan biasa
if (settingIndex == 0 && ppr > 1) ppr -= 1;
if (settingIndex == 1 && wheelCirc > 1) wheelCirc -= 1.0;
if (settingIndex == 2 && maxLength > 10) maxLength -= 10;
showMenu();
lastPrintTime = millis();
} else if (millis() - downStart >= boostStartDelay && millis() - lastBoostTime >= boostInterval) {
// Boost aktif
if (settingIndex == 0 && ppr > 1) ppr -= 1 * 10;
if (settingIndex == 1 && wheelCirc > 1) wheelCirc -= 1.0 * 10;
if (settingIndex == 2 && maxLength > 10) maxLength -= 10 * 10;
showMenu();
lastPrintTime = millis();
lastBoostTime = millis();
}
} else {
downHeld = false;
}
}
// === Fungsi utama selama SigmaAuto aktif ===
bool SigmaAutoState = digitalRead(SigmaAuto);
if (!SigmaAutoState && lastSigmaAutoState) {
Serial.println("SigmaAuto OFF: Reset panjang ke 0 mm");
pulseCount = 0;
isLimitReached = false;
isCounting = false;
digitalWrite(RelayOut, LOW);
}
if (SigmaAutoState && !lastSigmaAutoState) {
Serial.println("SigmaAuto ON: Hitungan dimulai...");
isCounting = true;
}
lastSigmaAutoState = SigmaAutoState;
int length_mm = (int)((pulseCount / (float)ppr) * wheelCirc);
if (length_mm >= maxLength && !isLimitReached) {
isLimitReached = true;
isCounting = false;
digitalWrite(RelayOut, HIGH);
Serial.println("Mencapai batas panjang, RelayOut ON!");
}
// === Update LCD setiap 500ms (jika tidak di menu) ===
if (millis() - lastPrintTime > 500 && !menuActive) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("SigmaAuto: ");
lcd.print(SigmaAutoState ? "ON " : "OFF");
lcd.setCursor(0, 1);
lcd.print("P: ");
lcd.print(length_mm);
lcd.print(" mm");
if (isLimitReached) {
lcd.setCursor(14, 1);
lcd.print("OK");
}
Serial.print("SigmaAuto: ");
Serial.print(SigmaAutoState ? "ON" : "OFF");
Serial.print(" | Pulse: ");
Serial.print(pulseCount);
Serial.print(" | Panjang: ");
Serial.print(length_mm);
Serial.println(" mm");
lastPrintTime = millis();
}
// === Timeout menu otomatis keluar jika tidak ada input selama 10 detik ===
if (menuActive && millis() - menuActiveTime > menuTimeout) {
menuActive = false;
editMode = false;
lcd.clear();
}
// Cek timeout backlight
if (millis() - backlightTimer > backlightTimeout) {
turnBacklight(false);
}
delay(50);
}