const int carRedPin = 6;
const int carYellowPin = 5;
const int carGreenPin = 4;
const int pedRedPin = 3;
const int pedGreenPin = 2;
const int buzzerPin = 7;
const int dataPin = 8;
const int clockPin = 10;
const int latchPin = 9;
const byte digitPatterns[10] = {
B00111111, // 0
B00000110, // 1
B01011011, // 2
B01001111, // 3
B01100110, // 4
B01101101, // 5
B01111101, // 6
B00000111, // 7
B01111111, // 8
B01101111 // 9
};
const unsigned long PED_SOLID_GREEN_TIME = 9000;
const unsigned long PED_BLINK_GREEN_TIME = 3000;
const unsigned long CAR_GREEN_TIME = 9000;
unsigned long phaseStartTime = 0;
unsigned long lastSecondUpdate = 0;
unsigned long lastBeepTime = 0;
int currentCountdown = 12;
int currentPhase = 1;
bool isBlinkingPhase = false;
void setup() {
pinMode(carRedPin, OUTPUT);
pinMode(carYellowPin, OUTPUT);
pinMode(carGreenPin, OUTPUT);
pinMode(pedRedPin, OUTPUT);
pinMode(pedGreenPin, OUTPUT);
pinMode(buzzerPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(latchPin, OUTPUT);
updateLights();
displayNumber(currentCountdown);
phaseStartTime = millis();
}
void loop() {
unsigned long currentMillis = millis();
unsigned long phaseElapsed = currentMillis - phaseStartTime;
// Обновление счетчика каждую секунду
if (currentMillis - lastSecondUpdate >= 1000) {
lastSecondUpdate = currentMillis;
if (currentCountdown > 0) {
currentCountdown--;
}
}
// Управление фазами
switch(currentPhase) {
case 1: // Пешеходам зеленый (9 сек постоянно + 3 сек мигает)
if (phaseElapsed >= PED_SOLID_GREEN_TIME && !isBlinkingPhase) {
isBlinkingPhase = true;
digitalWrite(carYellowPin, HIGH); // Включаем желтый при начале мигания
}
if (phaseElapsed >= (PED_SOLID_GREEN_TIME + PED_BLINK_GREEN_TIME)) {
nextPhase();
}
break;
case 2: // Машинам зеленый (9 сек)
if (phaseElapsed >= CAR_GREEN_TIME) {
nextPhase();
}
break;
}
// Мигание зеленого для пешеходов в последние 3 секунды
if (isBlinkingPhase && currentPhase == 1) {
blinkPedGreen(currentMillis);
}
// Управление звуком как на реальном светофоре
updateBuzzer(currentMillis);
// Отображение таймера только для пешеходов
if (currentPhase == 1) {
displayNumber(currentCountdown);
} else {
clearDisplay();
}
}
void nextPhase() {
currentPhase = (currentPhase % 2) + 1;
phaseStartTime = millis();
isBlinkingPhase = false;
noTone(buzzerPin);
if (currentPhase == 1) {
currentCountdown = (PED_SOLID_GREEN_TIME + PED_BLINK_GREEN_TIME) / 1000;
} else {
currentCountdown = CAR_GREEN_TIME / 1000;
}
updateLights();
}
void updateLights() {
digitalWrite(carRedPin, LOW);
digitalWrite(carYellowPin, LOW);
digitalWrite(carGreenPin, LOW);
digitalWrite(pedRedPin, LOW);
digitalWrite(pedGreenPin, LOW);
switch(currentPhase) {
case 1:
if (!isBlinkingPhase) {
digitalWrite(carRedPin, HIGH);
digitalWrite(pedGreenPin, HIGH);
} else {
digitalWrite(carYellowPin, HIGH); // Желтый горит при мигании
}
break;
case 2:
digitalWrite(carGreenPin, HIGH);
digitalWrite(pedRedPin, HIGH);
break;
}
}
void blinkPedGreen(unsigned long currentMillis) {
static unsigned long lastBlinkTime = 0;
static bool ledState = HIGH;
if (currentMillis - lastBlinkTime >= 500) {
lastBlinkTime = currentMillis;
ledState = !ledState;
digitalWrite(pedGreenPin, ledState);
}
}
void displayNumber(int number) {
if (number < 0 || number > 99) {
clearDisplay();
return;
}
int tens = number / 10;
int ones = number % 10;
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, digitPatterns[ones]);
shiftOut(dataPin, clockPin, MSBFIRST, digitPatterns[tens]);
digitalWrite(latchPin, HIGH);
}
void clearDisplay() {
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, B00000000);
shiftOut(dataPin, clockPin, MSBFIRST, B00000000);
digitalWrite(latchPin, HIGH);
}
void updateBuzzer(unsigned long currentMillis) {
if (currentPhase != 1) {
noTone(buzzerPin);
return;
}
unsigned long beepInterval = 1000; // по умолчанию 1 секунда
int frequency = 800; // частота по умолчанию
if (currentCountdown > 9) {
// Первые 6 секунд - сигнал каждую секунду
beepInterval = 1000;
frequency = 800;
}
else if (currentCountdown > 7) {
// С 6 по 4 секунды - сигнал каждые 800 мс
beepInterval = 900;
frequency = 900;
}
else if (currentCountdown > 5) {
// С 6 по 4 секунды - сигнал каждые 800 мс
beepInterval = 800;
frequency = 1000;
}
else if (currentCountdown > 3) {
// С 6 по 4 секунды - сигнал каждые 800 мс
beepInterval = 700;
frequency = 1100;
}
else {
// Последние 3 секунды - сигнал каждые 350 мс
beepInterval = 350;
frequency = 1200;
}
if (currentMillis - lastBeepTime >= beepInterval) {
tone(buzzerPin, frequency, 100); // короткий сигнал 100 мс
lastBeepTime = currentMillis;
}
}