#include <Servo.h>
Servo lockServo;
// Пины кнопок и их LED (Синяя=1, Желтая=2, Зеленая=3, Красная=4)
const int buttonPins[4] = {2, 3, 4, 5};
const int ledPins[4] = {6, 7, 8, 9};
const int buzzerPin = 10;
const int servoPin = 11;
// Пины 74HC595
const int latchPin = A0; // ST_CP
const int clockPin = 13; // SH_CP
const int dataPin = 12; // DS
// Пины анодов/катодов разрядов
const int digitPins[4] = {A1, A2, A3, A4};
// Пароль по умолчанию (кнопки 1, 3, 2, 4)
const int secretCode[4] = {1, 3, 2, 4};
int userCode[4] = {0, 0, 0, 0};
int inputIndex = 0;
// Переменные для отслеживания ошибок и режима тревоги
int wrongAttempts = 0;
bool isAlarmActive = false;
// Кодировка сегментов (A,B,C,D,E,F,G)
const byte digitPatterns[5] = {
0b00000000, // Пусто
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110 // 4
};
void setup() {
lockServo.attach(servoPin);
lockServo.write(0); // Замок закрыт
pinMode(buzzerPin, OUTPUT);
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
for (int i = 0; i < 4; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
pinMode(ledPins[i], OUTPUT);
pinMode(digitPins[i], OUTPUT);
digitalWrite(digitPins[i], LOW);
}
}
void loop() {
// Генерация звука и мигания сирены без блокировки программы
if (isAlarmActive) {
handleAlarm();
}
// Обновляем динамическую индикацию на дисплее
updateDisplay();
// Опрос кнопок
for (int i = 0; i < 4; i++) {
if (digitalRead(buttonPins[i]) == LOW) {
digitalWrite(ledPins[i], HIGH);
// Звук клика играет ТОЛЬКО если сирена выключена
if (!isAlarmActive) {
tone(buzzerPin, 1200, 60);
}
userCode[inputIndex] = i + 1;
inputIndex++;
// Ждем отпускания кнопки
while (digitalRead(buttonPins[i]) == LOW) {
updateDisplay();
}
delay(50);
if (!isAlarmActive) {
digitalWrite(ledPins[i], LOW);
}
// Проверка пароля после ввода 4 цифр
if (inputIndex == 4) {
checkPassword();
}
}
}
}
void updateDisplay() {
for (int d = 0; d < inputIndex; d++) {
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, digitPatterns[userCode[d]]);
digitalWrite(latchPin, HIGH);
digitalWrite(digitPins[d], HIGH); // Общий катод (для Wokwi)
delayMicroseconds(1000);
digitalWrite(digitPins[d], LOW);
}
}
// Эффект двухтональной сирены
void handleAlarm() {
static unsigned long lastToggle = 0;
static bool alarmState = false;
if (millis() - lastToggle > 200) {
lastToggle = millis();
alarmState = !alarmState;
if (alarmState) {
tone(buzzerPin, 900, 180);
for (int i = 0; i < 4; i++) digitalWrite(ledPins[i], HIGH);
} else {
tone(buzzerPin, 400, 180);
for (int i = 0; i < 4; i++) digitalWrite(ledPins[i], LOW);
}
}
}
void checkPassword() {
bool isCorrect = true;
for (int i = 0; i < 4; i++) {
if (userCode[i] != secretCode[i]) {
isCorrect = false;
break;
}
}
if (isCorrect) {
// УСПЕХ: сброс тревоги, сброс ошибок, открытие замка
isAlarmActive = false;
wrongAttempts = 0;
noTone(buzzerPin);
tone(buzzerPin, 1500, 300);
for (int i = 0; i < 4; i++) {
digitalWrite(ledPins[i], HIGH);
}
lockServo.write(90);
// Удерживаем замок открытым 3 секунды
unsigned long startTime = millis();
while (millis() - startTime < 3000) {
updateDisplay();
}
// Закрываем замок
lockServo.write(0);
for (int i = 0; i < 4; i++) {
digitalWrite(ledPins[i], LOW);
}
} else {
// ОШИБКА
wrongAttempts++;
if (wrongAttempts >= 3) {
isAlarmActive = true;
} else {
tone(buzzerPin, 200, 400);
delay(400);
}
}
// Сброс введенных цифр
inputIndex = 0;
for (int i = 0; i < 4; i++) {
userCode[i] = 0;
}
}