#include <Adafruit_NeoPixel.h>
// -------- PINLER --------
#define PIN_GOSTERGE 19
#define PIN_CERCEVE 21
#define PIN_BUTON 14
#define PIN_ADC 2
#define PIN_LED_40SN 22
#define PIN_LED_WIN 18
#define PIN_MOTOR1 5
#define PIN_MOTOR2 4
#define PIN_MOTOR3 15
// -------- LED SAYILARI --------
#define LED_SAYISI 20
Adafruit_NeoPixel gosterge(LED_SAYISI, PIN_GOSTERGE, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel cerceve(LED_SAYISI, PIN_CERCEVE, NEO_GRB + NEO_KHZ800);
// -------- ZAMANLAR --------
const unsigned long STEP_MS = 200;
const unsigned long FRAME_ON = 500;
const unsigned long FRAME_OFF = 100;
// -------- DURUMLAR --------
enum State { IDLE, GAME, WIN };
State state = IDLE;
unsigned long now;
unsigned long lastStep = 0;
unsigned long gameStart = 0;
unsigned long winStart = 0;
unsigned long last40s = 0;
unsigned long lastBlink = 0;
// -------- WIN BLINK --------
bool winOn = false;
unsigned long lastWinBlink = 0;
// -------- VOLTAJ --------
float instantVolt = 0;
float avgVolt = 0;
float voltSum = 0;
int voltCount = 0;
unsigned long lastVoltSample = 0;
int currentLevel = 0;
int targetLevel = 0;
int maxLevelReached = 0;
bool frameState = false;
bool animDirUp = true;
int animIndex = 0;
// -------- RENK --------
uint32_t renkForLed(int i) {
if (i <= 7) return gosterge.Color(255, 0, 0);
if (i <= 12) return gosterge.Color(255, 255, 0);
return gosterge.Color(0, 255, 0);
}
// -------- VOLTAJ OKUMA --------
void readVoltage() {
int raw = analogRead(PIN_ADC);
instantVolt = raw * 3.3 / 4095.0;
if (millis() - lastVoltSample >= 1000) {
avgVolt = voltSum / max(1, voltCount);
voltSum = 0;
voltCount = 0;
lastVoltSample = millis();
}
voltSum += instantVolt;
voltCount++;
}
// -------- VOLTAJ → SEVİYE --------
int voltToLevel(float v) {
if (v < 0.21) return 1;
if (v < 0.41) return 2;
if (v < 0.61) return 3;
if (v < 0.81) return 4;
if (v < 0.91) return 5;
if (v < 1.01) return 6;
if (v < 1.31) return 7;
if (v < 1.51) return 8;
if (v < 1.71) return 9;
if (v < 1.91) return 10;
if (v < 2.01) return 11;
if (v < 2.31) return 12;
if (v < 2.41) return 13;
if (v < 2.51) return 14;
if (v < 2.61) return 15;
if (v < 2.71) return 16;
if (v < 2.81) return 17;
if (v < 2.91) return 18;
if (v < 3.01) return 19;
return 20;
}
// -------- GÖSTERGE --------
void updateGauge(int level, bool blink012 = false) {
gosterge.clear();
if (blink012) {
static bool on = false;
on = !on;
if (on) {
for (int i = 0; i <= 2; i++)
gosterge.setPixelColor(i, renkForLed(i));
}
} else {
for (int i = 0; i < level && i < LED_SAYISI; i++)
gosterge.setPixelColor(i, renkForLed(i));
}
gosterge.show();
}
// -------- MOTOR --------
void updateMotors(int level) {
digitalWrite(PIN_MOTOR1, level >= 4 ? HIGH : LOW);
digitalWrite(PIN_MOTOR2, level >= 12 ? HIGH : LOW);
digitalWrite(PIN_MOTOR3, level >= 20 ? HIGH : LOW);
}
// -------- ÇERÇEVE --------
void updateFrame(bool blink, uint32_t color) {
if (!blink) {
for (int i = 0; i < LED_SAYISI; i++)
cerceve.setPixelColor(i, color);
cerceve.show();
return;
}
if (millis() - lastBlink >= (frameState ? FRAME_ON : FRAME_OFF)) {
frameState = !frameState;
lastBlink = millis();
}
cerceve.clear();
if (frameState) {
for (int i = 0; i < LED_SAYISI; i++)
cerceve.setPixelColor(i, color);
}
cerceve.show();
}
// -------- SETUP --------
void setup() {
Serial.begin(115200);
pinMode(PIN_BUTON, INPUT_PULLUP);
pinMode(PIN_LED_40SN, OUTPUT);
pinMode(PIN_LED_WIN, OUTPUT);
pinMode(PIN_MOTOR1, OUTPUT);
pinMode(PIN_MOTOR2, OUTPUT);
pinMode(PIN_MOTOR3, OUTPUT);
gosterge.begin();
cerceve.begin();
gosterge.clear(); gosterge.show();
cerceve.clear(); cerceve.show();
}
// -------- LOOP --------
void loop() {
now = millis();
readVoltage();
// 40 sn LED
if (state == IDLE && now - last40s >= 40000) {
digitalWrite(PIN_LED_40SN, HIGH);
delay(50);
digitalWrite(PIN_LED_40SN, LOW);
last40s = now;
}
// BUTON
if (state == IDLE && digitalRead(PIN_BUTON) == LOW) {
state = GAME;
gameStart = now;
maxLevelReached = 0;
currentLevel = 0;
}
// -------- GAME --------
if (state == GAME) {
targetLevel = voltToLevel(avgVolt);
maxLevelReached = max(maxLevelReached, targetLevel);
if (now - lastStep >= STEP_MS) {
if (currentLevel < targetLevel) currentLevel++;
else if (currentLevel > targetLevel) currentLevel--;
lastStep = now;
}
updateGauge(currentLevel, currentLevel == 1);
updateMotors(currentLevel);
updateFrame(false, cerceve.Color(255, 0, 0));
if (now - gameStart >= 30000) {
digitalWrite(PIN_LED_WIN, HIGH);
delay(20);
digitalWrite(PIN_LED_WIN, LOW);
state = WIN;
winStart = now;
winOn = false;
}
}
// -------- IDLE --------
if (state == IDLE) {
updateGauge(animIndex);
updateFrame(true, cerceve.Color(255, 0, 0));
if (now - lastStep >= STEP_MS) {
animIndex += animDirUp ? 1 : -1;
if (animIndex >= LED_SAYISI - 1) animDirUp = false;
if (animIndex <= 0) animDirUp = true;
lastStep = now;
}
}
// -------- WIN --------
if (state == WIN) {
updateFrame(true, cerceve.Color(0, 255, 0));
// 200 ms blink
if (now - lastWinBlink >= 200) {
winOn = !winOn;
lastWinBlink = now;
}
gosterge.clear();
if (winOn) {
for (int i = 0; i < maxLevelReached && i < LED_SAYISI; i++)
gosterge.setPixelColor(i, renkForLed(i));
}
gosterge.show();
// Oyun boyunca çalışmış motorlar
digitalWrite(PIN_MOTOR1, maxLevelReached >= 4 ? HIGH : LOW);
digitalWrite(PIN_MOTOR2, maxLevelReached >= 12 ? HIGH : LOW);
digitalWrite(PIN_MOTOR3, maxLevelReached >= 20 ? HIGH : LOW);
// 6 sn sonra bitir
if (now - winStart >= 6000) {
state = IDLE;
currentLevel = 0;
digitalWrite(PIN_MOTOR1, LOW);
digitalWrite(PIN_MOTOR2, LOW);
digitalWrite(PIN_MOTOR3, LOW);
}
}
}