/**
* SISTEM PENGHITUNG ARAH GERAK OBJEK
* Lomba Simulasi Arduino - Wokwi
* TE-UIG
* FITUR:
* - Deteksi arah A->B (+1) dan B->A (-1)
* - Debouncing untuk stabilisasi input
* - LCD real-time display
* - LED indicator untuk counter > 0
* - Timeout handling 2 detik
*
* AUTHOR: Fikri Sabaya
* DATE: 09-10-25
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Inisialisasi LCD I2C (alamat 0x27, 16x2)
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Pin deklarasi
const int sensorA = 2; // Push button untuk Sensor A
const int sensorB = 3; // Push button untuk Sensor B
const int ledPin = 13; // LED indicator
// Variabel debouncing
unsigned long lastDebounceTimeA = 0;
unsigned long lastDebounceTimeB = 0;
const unsigned long debounceDelay = 50;
// State sensor
int lastStateA = HIGH;
int lastStateB = HIGH;
int currentStateA = HIGH;
int currentStateB = HIGH;
// Variabel penghitungan
int counter = 0;
bool sensorA_triggered = false;
bool sensorB_triggered = false;
unsigned long triggerTimeA = 0;
unsigned long triggerTimeB = 0;
const unsigned long timeout = 2000; // Timeout 2 detik
// Variabel untuk event detection
bool sensorA_event = false;
bool sensorB_event = false;
void setup() {
// Deklarasi pin
pinMode(sensorA, INPUT_PULLUP);
pinMode(sensorB, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
// Deklarasi LCD
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Counter: ");
// Serial Monitor untuk debugging
Serial.begin(9600);
Serial.println("Sistem Penghitung Arah Gerak Objek");
Serial.println("==================================");
}
void loop() {
// Func baca state sensor dengan debouncing
readSensorsWithDebounce();
// Func proses logika arah gerak objek
processMovementLogic();
// Update tampilan LCD
updateDisplay();
// Kontrol LED indicator
controlLED();
// Reset event flags
sensorA_event = false;
sensorB_event = false;
delay(10); // Delay kecil untuk stabilitas
}
// DEBOUNCING: Tunggu 50ms untuk state stabil
void readSensorsWithDebounce() {
// Baca sensor A dengan debouncing
int readingA = digitalRead(sensorA);
if (readingA != lastStateA) {
lastDebounceTimeA = millis();
}
if ((millis() - lastDebounceTimeA) > debounceDelay) {
if (readingA != currentStateA) {
currentStateA = readingA;
if (currentStateA == LOW) {
sensorA_event = true; // Set Event A
Serial.println("Event Sensor A");
}
}
}
lastStateA = readingA;
// Baca sensor B dengan debouncing
int readingB = digitalRead(sensorB);
if (readingB != lastStateB) {
lastDebounceTimeB = millis();
}
if ((millis() - lastDebounceTimeB) > debounceDelay) {
if (readingB != currentStateB) {
currentStateB = readingB;
if (currentStateB == LOW) {
sensorB_event = true; // SET Event B
Serial.println("Event Sensor B");
}
}
}
lastStateB = readingB;
}
/**
* PROSES LOGIKA ARAH GERAK OBJEK
* - A -> B: Counter +1 (objek masuk)
* - B -> A: Counter -1 (objek keluar)
* - Timeout: Reset state machine setelah 2 detik
*/
void processMovementLogic() {
// Handle event A
if (sensorA_event) {
Serial.println("Sensor A Terpicu");
if (!sensorA_triggered && !sensorB_triggered) {
// Case 1: A pertama kali
sensorA_triggered = true;
triggerTimeA = millis();
Serial.println(" → Menunggu Sensor B ...");
}
else if (sensorB_triggered && !sensorA_triggered) {
// Case 2: B sudah terpicu duluan, sekarang A → B->A (Counter -1)
unsigned long currentTime = millis();
if ((currentTime - triggerTimeB) < timeout) {
counter--;
Serial.println("B -> A: Counter -1 = " + String(counter));
resetSensors();
} else {
Serial.println("Timeout B -> A, reset ...");
resetSensors();
}
}
}
// Handle event B
if (sensorB_event) {
Serial.println("Sensor B Terpicu");
if (!sensorB_triggered && !sensorA_triggered) {
// Case 1: B pertama kali
sensorB_triggered = true;
triggerTimeB = millis();
Serial.println(" → Menunggu Sensor A ...");
}
else if (sensorA_triggered && !sensorB_triggered) {
// Case 2: A sudah terpicu duluan, sekarang B → A->B (Counter +1)
unsigned long currentTime = millis();
if ((currentTime - triggerTimeA) < timeout) {
counter++;
Serial.println("A -> B: Counter +1 = " + String(counter));
resetSensors();
} else {
Serial.println("Timeout A -> B, reset ...");
resetSensors();
}
}
}
// Reset jika timeout
checkTimeout();
}
void checkTimeout() {
unsigned long currentTime = millis();
if (sensorA_triggered && (currentTime - triggerTimeA) > timeout) {
Serial.println("Timeout - Reset Sensor A");
resetSensors();
}
if (sensorB_triggered && (currentTime - triggerTimeB) > timeout) {
Serial.println("Timeout - Reset Sensor B");
resetSensors();
}
}
void resetSensors() {
sensorA_triggered = false;
sensorB_triggered = false;
sensorA_event = false;
sensorB_event = false;
triggerTimeA = 0;
triggerTimeB = 0;
Serial.println("semua event sensor direset ");
}
void updateDisplay() {
static int lastCounter = -1;
if (counter != lastCounter) {
lcd.setCursor(9, 0);
lcd.print(" ");
lcd.setCursor(9, 0);
if (counter >= 0) {
lcd.print(" "); // spasi untuk alignment
}
lcd.print(counter);
lcd.setCursor(0, 1);
if (counter > 0) {
lcd.print("Arah: A -> B ");
} else if (counter < 0) {
lcd.print("Arah: B -> A ");
} else {
lcd.print("Seimbang ");
}
lastCounter = counter;
}
}
void controlLED() {
if (counter > 0) {
digitalWrite(ledPin, HIGH); // LED nyala ketika penghitung > 0
} else {
digitalWrite(ledPin, LOW); // LED nyala ketika penghitung > 0
}
}Sensor B
Sensor A