// ESP32 + SSD1306 OLED + HC-SR04 + 2 Buton
// Namaz Rekat Sayacı — el yaklaşımıyla secde algılama
// State machine: SELECT_MODE -> READY -> COUNTING -> COMPLETE
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_W 128
#define SCREEN_H 64
#define OLED_ADDR 0x3C
#define TRIG_PIN 25
#define ECHO_PIN 26
#define BTN_MODE 32 // Yesil: rekat sayisini degistir
#define BTN_OK 33 // Kirmizi: onayla / sifirla
#define DETECT_CM 15 // Bu mesafeden yakın → secde
#define RELEASE_CM 25 // Bu mesafeden uzak → ayrıldı
#define DEBOUNCE_MS 2500 // İki secde arası min süre
Adafruit_SSD1306 oled(SCREEN_W, SCREEN_H, &Wire, -1);
enum State { ST_SELECT, ST_READY, ST_COUNT, ST_DONE };
State state = ST_SELECT;
uint8_t targetRakats = 4;
uint8_t currentRakats = 0;
bool waitRelease = false;
unsigned long lastDetectMs = 0;
unsigned long lastBtnMode = 0;
unsigned long lastBtnOk = 0;
void lcdAt(int x, int y, uint8_t size, const String &text) {
oled.setTextSize(size);
oled.setCursor(x, y);
oled.print(text);
}
long readDistanceCm() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH, 30000); // 30ms timeout
if (duration == 0) return 999;
return duration / 58;
}
// ============ Ekranlar ============
void drawSplash() {
oled.clearDisplay();
oled.setTextColor(SSD1306_WHITE);
lcdAt(8, 8, 2, "BlueGrays");
lcdAt(12, 36, 1, "Rekat Sayaci v1");
oled.drawRoundRect(2, 2, 124, 60, 6, SSD1306_WHITE);
oled.display();
}
void drawSelect() {
oled.clearDisplay();
oled.setTextColor(SSD1306_WHITE);
lcdAt(0, 0, 1, "> Rekat Modu Sec");
oled.drawLine(0, 10, 127, 10, SSD1306_WHITE);
lcdAt(0, 14, 1, "Toplam Rekat:");
oled.setTextSize(4);
oled.setCursor(54, 24);
oled.print(targetRakats);
lcdAt(0, 56, 1, "Yesil:degis Kirmizi:OK");
oled.display();
}
void drawReady() {
oled.clearDisplay();
oled.setTextColor(SSD1306_WHITE);
lcdAt(0, 0, 1, "> Namaza Hazir");
oled.drawLine(0, 10, 127, 10, SSD1306_WHITE);
lcdAt(38, 18, 2, "Hazir!");
lcdAt(34, 42, 1, "0 / " + String(targetRakats));
lcdAt(0, 56, 1, "Secdeye gidince baslar");
oled.display();
}
void drawCount() {
oled.clearDisplay();
oled.setTextColor(SSD1306_WHITE);
lcdAt(0, 0, 1, "> Sayim aktif");
oled.drawLine(0, 10, 127, 10, SSD1306_WHITE);
// Buyuk sayi ortali: "1/4"
oled.setTextSize(4);
String s = String(currentRakats) + "/" + String(targetRakats);
int w = s.length() * 24;
oled.setCursor((128 - w) / 2, 18);
oled.print(s);
lcdAt(0, 56, 1, "Kirmizi: yeni namaz");
oled.display();
}
void drawDetected() {
oled.clearDisplay();
oled.setTextColor(SSD1306_WHITE);
oled.fillRect(0, 0, 128, 64, SSD1306_WHITE);
oled.setTextColor(SSD1306_BLACK);
oled.setTextSize(2);
oled.setCursor(20, 8);
oled.print("+1 Rekat");
oled.setTextSize(4);
String s = String(currentRakats) + "/" + String(targetRakats);
int w = s.length() * 24;
oled.setCursor((128 - w) / 2, 30);
oled.print(s);
oled.display();
delay(800);
}
void drawDone() {
oled.clearDisplay();
oled.setTextColor(SSD1306_WHITE);
lcdAt(0, 0, 1, "> Namaz Tamamlandi");
oled.drawLine(0, 10, 127, 10, SSD1306_WHITE);
lcdAt(34, 16, 2, "TAMAM");
oled.drawRoundRect(20, 13, 90, 22, 4, SSD1306_WHITE);
lcdAt(0, 42, 1, "Allah kabul etsin");
lcdAt(0, 55, 1, "Kirmizi: yeni namaz");
oled.display();
}
// ============ SETUP ============
void setup() {
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(BTN_MODE, INPUT_PULLUP);
pinMode(BTN_OK, INPUT_PULLUP);
Wire.begin(21, 22);
if (!oled.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
while (1);
}
drawSplash();
delay(2500);
state = ST_SELECT;
drawSelect();
}
// ============ LOOP ============
void loop() {
// ---- Buton: Mod degistir ----
if (digitalRead(BTN_MODE) == LOW && millis() - lastBtnMode > 300) {
lastBtnMode = millis();
if (state == ST_SELECT) {
if (targetRakats == 4) targetRakats = 2;
else targetRakats++;
drawSelect();
}
}
// ---- Buton: OK / Reset ----
if (digitalRead(BTN_OK) == LOW && millis() - lastBtnOk > 300) {
lastBtnOk = millis();
if (state == ST_SELECT) {
currentRakats = 0;
state = ST_READY;
drawReady();
delay(1500);
state = ST_COUNT;
waitRelease = false;
lastDetectMs = 0;
drawCount();
} else {
// COUNT veya DONE → yeni namaza geç
currentRakats = 0;
state = ST_SELECT;
drawSelect();
}
}
// ---- Mesafe algılama (yalnızca COUNT state) ----
if (state == ST_COUNT) {
long d = readDistanceCm();
if (waitRelease) {
if (d > RELEASE_CM) waitRelease = false;
} else {
if (d < DETECT_CM && (millis() - lastDetectMs > DEBOUNCE_MS)) {
lastDetectMs = millis();
currentRakats++;
waitRelease = true;
drawDetected();
if (currentRakats >= targetRakats) {
state = ST_DONE;
drawDone();
} else {
drawCount();
}
}
}
delay(80);
} else {
delay(40);
}
}