#include <pitches.h>
#include <Servo.h>
const int PASSWORD_LENGTH = 4; // Длина пароля
const int GREEN_BUTTON_PIN = 11; // Первая кнопка (зелёная)
const int BLUE_BUTTON_PIN = 10; // Вторая кнопка (синяя)
const int YELLOW_BUTTON_PIN = 9; // Третья кнопка (жёлтая)
const int BLACK_BUTTON_PIN = 8; // Четвёртая кнопка (чёрная)
const int LED_PIN = 12; // Светодиод
const int BUZZER_PIN = 6; // Пищалка
const int LOCK_SERVO_PIN = 5; // Сервопривод
const int LOCK_BUTTON_PIN = 4; // Кнопка замка
const int NUM_CODE_BUTTONS = 4; // Количество кнопок для ввода кода
struct Button {
int pin;
int value;
};
Button codeButtons[NUM_CODE_BUTTONS] = {
{GREEN_BUTTON_PIN, 1},
{BLUE_BUTTON_PIN, 2},
{YELLOW_BUTTON_PIN, 3},
{BLACK_BUTTON_PIN, 4}
};
bool buttonPressStates[NUM_CODE_BUTTONS] = {false, false, false, false};
// Временные задержки для определения нажатия
const int SHORT_PRESS_THRESHOLD = 9;
const int LONG_PRESS_THRESHOLD = 45;
const int PRESS_CHECK_INTERVAL = 10; // интервал проверки нажатий в миллисекундах
// Константы для идентификации нажатий
const int LONG_PRESS = 2;
const int SHORT_PRESS = 1;
const int NO_PRESS = 0;
// Светодиодные сигналы
const int SHORT_LED_BLINK = 500; // короткое мигание: интервал и полное
const int LONG_LED_BLINK = 2000; // интервал для длинного мигания
const int SHORT_LED_BLINK_DURATION = 5000; // общая длительность коротких миганий
// Параметры для сервопривода
const int SERVO_UNLOCK_DURATION = 5000; // время открывания двери
const int SERVO_LOCK_ANGLE = 90; // положение закрытого замка
const int SERVO_UNLOCK_ANGLE = 180; // положение открытого замка
// Текущие коды и их состояние
int correctPassword = 1234;
int inputPassword = 0;
bool isPasswordCorrect = false;
bool anyButtonPressed = false; // Проверка, нажата ли хотя бы одна из кодовых кнопок
// Позиция ввода пароля
int passwordInputPosition = 0;
bool settingNewPassword = false;
int incorrectMelodyNotes[] = {
NOTE_A3, NOTE_C4, NOTE_D4, NOTE_E4, NOTE_A3, 0,
NOTE_A3, NOTE_C4, NOTE_D4, NOTE_E4, NOTE_A3, 0
};
int incorrectMelodyDurations[] = {
500, 500, 500, 500, 1500, 500,
500, 500, 500, 500, 1500, 500
};
int correctMelodyNotes[] = {
NOTE_C4, NOTE_E4, NOTE_G4, NOTE_C5, NOTE_G4, NOTE_E4, NOTE_C4, 0,
NOTE_C4, NOTE_E4, NOTE_G4, NOTE_C5, NOTE_G4, NOTE_E4, NOTE_C4, 0,
NOTE_E4, NOTE_G4, NOTE_C5, NOTE_G4, NOTE_E4, NOTE_C4, 0,
NOTE_G4, NOTE_E4, NOTE_C4, NOTE_E4, NOTE_G4, NOTE_C5, 0,
NOTE_C4, NOTE_E4, NOTE_G4, NOTE_C5, NOTE_G4, NOTE_E4, NOTE_C4, 0,
NOTE_C4, NOTE_E4, NOTE_G4, NOTE_C5, NOTE_G4, NOTE_E4, NOTE_C4, 0,
NOTE_E4, NOTE_G4, NOTE_C5, NOTE_G4, NOTE_E4, NOTE_C4, 0,
NOTE_G4, NOTE_E4, NOTE_C4, NOTE_E4, NOTE_G4, NOTE_C5, 0,
};
int correctMelodyDurations[] = {
250, 250, 250, 250, 250, 250, 250, 150,
250, 250, 250, 250, 250, 250, 250, 150,
250, 250, 250, 250, 250, 250, 150,
250, 250, 250, 250, 350, 150,
250, 250, 250, 250, 250, 250, 250, 150,
250, 250, 250, 250, 250, 250, 250, 150,
250, 250, 250, 250, 250, 250, 150,
250, 250, 250, 250, 350, 150,
};
// Параметры мелодии
unsigned long lastMelodyTime = 0; // Время последнего проигрывания мелодии
int melodyNoteIndex = 0; // Индекс текущей ноты
bool isPlayingMelody = false;
// Параметры сервопривода
Servo lockServo;
int servoAngle = SERVO_LOCK_ANGLE; // Угол положения сервопривода
int previousLockButtonState = digitalRead(LOCK_BUTTON_PIN); // предыдущее состояние кнопки замка
// Время, когда дверь была открыта
unsigned long doorOpenStartTime = 0;
bool isDoorOpen = false;
void setup() {
pinMode(LED_PIN, OUTPUT);
pinMode(LOCK_BUTTON_PIN, INPUT_PULLUP);
pinMode(GREEN_BUTTON_PIN, INPUT_PULLUP);
pinMode(BLUE_BUTTON_PIN, INPUT_PULLUP);
pinMode(YELLOW_BUTTON_PIN, INPUT_PULLUP);
pinMode(BLACK_BUTTON_PIN, INPUT_PULLUP);
Serial.begin(9600);
lockServo.attach(LOCK_SERVO_PIN);
lockServo.write(SERVO_LOCK_ANGLE);
}
void unlockDoor() {
for (servoAngle; servoAngle <= SERVO_UNLOCK_ANGLE; servoAngle++) {
lockServo.write(servoAngle);
}
}
void lockDoor() {
for (servoAngle; servoAngle >= SERVO_LOCK_ANGLE; servoAngle--) {
lockServo.write(servoAngle);
}
}
void resetPasswordInput() {
inputPassword = 0;
passwordInputPosition = 0;
}
void playMelody() {
unsigned long currentTime = millis();
if ((currentTime - lastMelodyTime) >= (isPasswordCorrect ? correctMelodyDurations[melodyNoteIndex] * 1.05 : incorrectMelodyDurations[melodyNoteIndex] * 1.05)) {
lastMelodyTime = currentTime;
tone(BUZZER_PIN, (isPasswordCorrect ? correctMelodyNotes[melodyNoteIndex] : incorrectMelodyNotes[melodyNoteIndex]), (isPasswordCorrect ? correctMelodyDurations[melodyNoteIndex] : incorrectMelodyDurations[melodyNoteIndex]));
melodyNoteIndex++;
if (melodyNoteIndex >= (isPasswordCorrect ? sizeof(correctMelodyNotes) / sizeof(int) : sizeof(incorrectMelodyNotes) / sizeof(int))) {
isPlayingMelody = false;
noTone(BUZZER_PIN);
resetPasswordInput();
lockDoor();
}
}
}
// Проверка нажатия: короткое, длинное или отсутствие нажатия
int detectButtonPress(int buttonPin) {
int i = 0;
unsigned long buttonCheckStartTime = millis();
while (i < LONG_PRESS_THRESHOLD) {
unsigned long currentTime = millis();
if ((currentTime - buttonCheckStartTime) >= PRESS_CHECK_INTERVAL) {
buttonCheckStartTime = currentTime;
bool state = digitalRead(buttonPin);
if (state && (i < SHORT_PRESS_THRESHOLD)) return NO_PRESS;
else if (state) return SHORT_PRESS;
i++;
}
}
return LONG_PRESS;
}
void unlockDoorManually() {
unlockDoor();
resetPasswordInput();
doorOpenStartTime = millis();
isDoorOpen = true;
}
void lockDoorManually() {
lockDoor();
doorOpenStartTime = 0;
isDoorOpen = false;
}
void shortBlink() {
for (int i = 0; i < SHORT_LED_BLINK_DURATION; i += SHORT_LED_BLINK / 2) {
toggleLED();
}
resetPasswordInput();
isPasswordCorrect = false;
isPlayingMelody = false;
lockDoor();
}
void toggleLED() {
digitalWrite(LED_PIN, !digitalRead(LED_PIN));
delay(isPasswordCorrect ? SHORT_LED_BLINK : LONG_LED_BLINK);
}
int timeCounter = 0;
void resetTimeCounter() {
if (timeCounter > (SERVO_UNLOCK_DURATION / 1000)) {
timeCounter = 0;
}
}
void trackDoorClosingTime(long elapsedTime) {
int secondsPassed = (elapsedTime / 1000);
if (secondsPassed != 0 && timeCounter != secondsPassed && secondsPassed <= (SERVO_UNLOCK_DURATION / 1000)) {
Serial.println(secondsPassed);
timeCounter = secondsPassed;
}
}
void monitorDoorState() {
if (!isPlayingMelody && isDoorOpen) {
unsigned long elapsedTime = millis() - doorOpenStartTime;
if (elapsedTime > SERVO_UNLOCK_DURATION) {
lockDoorManually();
} else {
resetTimeCounter();
trackDoorClosingTime(elapsedTime);
}
}
}
// Проверка кодовых кнопок: длинное нажатие сбрасывает ввод
bool checkCodeButtonPress(int buttonPin, bool &state) {
long currentTime = millis();
if (!anyButtonPressed) {
anyButtonPressed = !digitalRead(buttonPin);
if (anyButtonPressed != state) {
state = anyButtonPressed;
if (anyButtonPressed) {
switch (detectButtonPress(buttonPin)) {
case SHORT_PRESS: {
return true;
}
case LONG_PRESS: {
if (!isPlayingMelody && !isDoorOpen) {
resetPasswordInput();
Serial.println("Ввод пароля сброшен.");
settingNewPassword = false;
return false;
}
break;
}
}
}
}
} else {
state = !digitalRead(buttonPin);
}
return false;
}
bool processPasswordInput(int i) {
if (!isPlayingMelody && !isDoorOpen && checkCodeButtonPress(codeButtons[i].pin, buttonPressStates[i])) {
inputPassword = inputPassword * 10 + codeButtons[i].value;
Serial.println((String)"Введенное значение: " + codeButtons[i].value + ". Текущий пароль: " + inputPassword);
passwordInputPosition++;
if ((passwordInputPosition % PASSWORD_LENGTH) == 0) {
if (settingNewPassword) {
Serial.println("Новый пароль установлен!");
correctPassword = inputPassword;
resetPasswordInput();
settingNewPassword = false;
} else {
verifyPassword();
}
}
return true;
}
return false;
}
void checkPasswordEntry() {
for (int i = 0; i < NUM_CODE_BUTTONS; i++) {
anyButtonPressed = processPasswordInput(i);
}
}
void verifyPassword() {
if (inputPassword == correctPassword) {
isPasswordCorrect = true;
isPlayingMelody = true;
melodyNoteIndex = 0;
lastMelodyTime = millis();
Serial.println("Пароль введен верно!");
unlockDoor();
} else {
isPlayingMelody = true;
melodyNoteIndex = 0;
isPasswordCorrect = false;
Serial.println("Пароль введен неверно!");
lastMelodyTime = millis();
}
}
void handleLockButton() {
bool lockButtonState = digitalRead(LOCK_BUTTON_PIN);
if (lockButtonState != previousLockButtonState) {
if (!lockButtonState && !isPlayingMelody) {
switch (detectButtonPress(LOCK_BUTTON_PIN)) {
case SHORT_PRESS: {
settingNewPassword = false;
Serial.println((String)"Дверь открыта на " + SERVO_UNLOCK_DURATION / 1000 + " секунд!");
unlockDoorManually();
break;
}
case LONG_PRESS: {
if (!settingNewPassword) Serial.println("Введите новый пароль!");
else Serial.println("Ввод пароля сброшен.");
resetPasswordInput();
settingNewPassword = !settingNewPassword;
break;
}
}
}
previousLockButtonState = lockButtonState;
}
}
void monitorKeypad() {
if (isPlayingMelody) playMelody();
else checkPasswordEntry();
}
void loop() {
isPasswordCorrect ? shortBlink() : toggleLED();
}
void yield() {
monitorKeypad();
monitorDoorState();
handleLockButton();
}