СИСТЕМА КОНТРОЛЯ ДОСТУПА 🔐
БАЗОВАЯ РЕАЛИЗАЦИЯ
Логика работы:
Пользователь вводит код с матричной клавиатуры
Система проверяет код в EEPROM
При правильном коде: сервопривод открывает замок, зеленый светодиод
При неправильном: счетчик ошибок, при 3 ошибках - блокировка на 30 сек
Зуммер дает звуковую обратную связь
Красный/желтый/зеленый светодиоды показывают статус
Компоненты:
- ✅ Матричная клавиатура 4x4
- ✅ Сервопривод SG90
- ✅ Светодиоды: красный, желтый, зеленый
- ✅ Зуммер (пищалка)
- ✅ Arduino Uno
- ✅ Резисторы, провода, макетка
- ✅ ✅ Дополнительно: LCD дисплей для отображения статуса
Схема подключения:
Матричная клавиатура:
R1 → pin 9, R2 → pin 8, R3 → pin 7, R4 → pin 6
C1 → pin 5, C2 → pin 4, C3 → pin 3, C4 → pin 2
Сервопривод (замок):
Signal → pin 10
VCC → 5V (через блок питания при необходимости)
GND → GND
Светодиоды:
Красный → pin 11 → резистор 220Ω → GND
Желтый → pin 12 → резистор 220Ω → GND
Зеленый → pin 13 → резистор 220Ω → GND
Зуммер:
+ → pin A0, - → GND
ЛОГИКА РАБОТЫ 🔄
Псевдокод для обсуждения:
// АРХИТЕКТУРА СИСТЕМЫ:
СОСТОЯНИЯ: [ОЖИДАНИЕ] → [ПРОВЕРКА] → [ДОСТУП_РАЗРЕШЕН] → [ЗАКРЫТИЕ]
│
└→ [ДОСТУП_ЗАПРЕЩЕН] → [БЛОКИРОВКА]
// ОСНОВНОЙ ЦИКЛ:
обрабатываем_нажатия_клавиатуры()
в_зависимости_от_состояния:
случай ОЖИДАНИЕ:
если (введен_код):
переходим_в_состояние(ПРОВЕРКА)
случай ПРОВЕРКА:
проверяем_код_в_EEPROM()
если (код_верный):
переходим_в_состояние(ДОСТУП_РАЗРЕШЕН)
иначе:
увеличиваем_счетчик_ошибок()
переходим_в_состояние(ДОСТУП_ЗАПРЕЩЕН)
случай ДОСТУП_РАЗРЕШЕН:
открываем_замок()
сбрасываем_счетчик_ошибок()
через_5_секунд → закрываем_замок()
случай ДОСТУП_ЗАПРЕЩЕН:
если (ошибок >= 3):
переходим_в_состояние(БЛОКИРОВКА)
иначе:
через_2_секунды → переходим_в_состояние(ОЖИДАНИЕ)
случай БЛОКИРОВКА:
блокируем_систему_на_30_сек()
после_разблокировки → переходим_в_состояние(ОЖИДАНИЕ)
управляем_индикацией() // светодиоды + зуммер
ДЕТАЛЬНАЯ РЕАЛИЗАЦИЯ АЛГОРИТМОВ ⚡
Структура данных системы:
#include <Keypad.h>
#include <Servo.h>
#include <EEPROM.h>
#define CODE_LENGTH 4
#define MAX_ATTEMPTS 3
#define LOCK_TIME 30000 // 30 секунд
enum SystemState {
WAITING_INPUT,
CHECKING_CODE,
ACCESS_GRANTED,
ACCESS_DENIED,
SYSTEM_LOCKED
};
class AccessControlSystem {
private:
SystemState currentState;
char enteredCode[CODE_LENGTH + 1];
byte codeIndex;
int attemptCount;
unsigned long stateStartTime;
unsigned long lockStartTime;
Servo doorLock;
public:
void initialize();
void update();
void handleKeypad();
void changeState(SystemState newState);
bool validateCode();
void controlIndicators();
void openDoor();
void closeDoor();
};
Обработка клавиатуры:
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
void handleKeypad() {
char key = keypad.getKey();
if (key && currentState == WAITING_INPUT) {
if (key == '#') { // Enter code
enteredCode[codeIndex] = '\0';
changeState(CHECKING_CODE);
} else if (key == '*') { // Clear code
codeIndex = 0;
memset(enteredCode, 0, sizeof(enteredCode));
} else if (codeIndex < CODE_LENGTH) { // Add digit
enteredCode[codeIndex++] = key;
tone(BUZZER_PIN, 1000, 100); // звуковой отклик
}
}
}
Управление состояниями:
void changeState(SystemState newState) {
currentState = newState;
stateStartTime = millis();
switch(newState) {
case CHECKING_CODE:
if (validateCode()) {
changeState(ACCESS_GRANTED);
} else {
changeState(ACCESS_DENIED);
}
break;
case ACCESS_GRANTED:
openDoor();
attemptCount = 0;
break;
case ACCESS_DENIED:
attemptCount++;
tone(BUZZER_PIN, 2000, 500); // звук ошибки
if (attemptCount >= MAX_ATTEMPTS) {
changeState(SYSTEM_LOCKED);
}
break;
case SYSTEM_LOCKED:
lockStartTime = millis();
break;
}
}
Работа с EEPROM и проверка кода:
bool validateCode() {
char storedCode[CODE_LENGTH + 1];
// Читаем код из EEPROM
for (int i = 0; i < CODE_LENGTH; i++) {
storedCode[i] = EEPROM.read(i);
}
storedCode[CODE_LENGTH] = '\0';
return strcmp(enteredCode, storedCode) == 0;
}
void changeCode(char newCode[CODE_LENGTH + 1]) {
// Записываем новый код в EEPROM
for (int i = 0; i < CODE_LENGTH; i++) {
EEPROM.write(i, newCode[i]);
}
}
Управление замком и индикацией:
void openDoor() {
doorLock.write(90); // Открыть замок
digitalWrite(GREEN_LED_PIN, HIGH);
digitalWrite(RED_LED_PIN, LOW);
tone(BUZZER_PIN, 1500, 300); // звук успеха
}
void closeDoor() {
doorLock.write(0); // Закрыть замок
digitalWrite(GREEN_LED_PIN, LOW);
}
void controlIndicators() {
switch(currentState) {
case WAITING_INPUT:
digitalWrite(YELLOW_LED_PIN, HIGH);
digitalWrite(RED_LED_PIN, LOW);
break;
case SYSTEM_LOCKED:
// Мигающий красный при блокировке
digitalWrite(RED_LED_PIN, (millis() % 500) < 250);
break;
case ACCESS_DENIED:
digitalWrite(RED_LED_PIN, HIGH);
break;
}
}
Таймеры и автоматические переходы:
void updateStateTimers() {
unsigned long currentTime = millis();
switch(currentState) {
case ACCESS_GRANTED:
if (currentTime - stateStartTime > 5000) { // 5 секунд открыто
closeDoor();
changeState(WAITING_INPUT);
}
break;
case ACCESS_DENIED:
if (currentTime - stateStartTime > 2000) { // 2 секунды показа ошибки
changeState(WAITING_INPUT);
}
break;
case SYSTEM_LOCKED:
if (currentTime - lockStartTime > LOCK_TIME) { // Разблокировка
changeState(WAITING_INPUT);
}
break;
}
}
УСЛОЖНЕНИЯ И ВАРИАЦИИ 🎛️
1. Многоуровневый доступ:
enum AccessLevel { LEVEL_USER, LEVEL_ADMIN, LEVEL_MASTER };
AccessLevel checkAccessLevel(char code[CODE_LENGTH + 1]) {
// Проверяем код в разных сегментах EEPROM
if (validateCodeInRange(code, 0, 3)) return LEVEL_USER;
if (validateCodeInRange(code, 4, 7)) return LEVEL_ADMIN;
if (validateCodeInRange(code, 8, 11)) return LEVEL_MASTER;
return LEVEL_USER; // по умолчанию
}
2. Ведение лога доступа:
struct AccessLog {
char code[CODE_LENGTH + 1];
unsigned long timestamp;
bool accessGranted;
};
void logAccessAttempt(char code[CODE_LENGTH + 1], bool granted) {
// Сохраняем в EEPROM с циклической перезаписью
static int logIndex = 0;
AccessLog logEntry;
strcpy(logEntry.code, code);
logEntry.timestamp = millis();
logEntry.accessGranted = granted;
EEPROM.put(100 + logIndex * sizeof(AccessLog), logEntry);
logIndex = (logIndex + 1) % 10; // храним последние 10 записей
}
3. RFID расширение:
#include <MFRC522.h>
void handleRFID() {
if (mfrc522.PICC_IsNewCardPresent()) {
if (mfrc522.PICC_ReadCardSerial()) {
String rfidUid = "";
for (byte i = 0; i < mfrc522.uid.size; i++) {
rfidUid += String(mfrc522.uid.uidByte[i], HEX);
}
if (validateRFID(rfidUid)) {
changeState(ACCESS_GRANTED);
}
}
}
}
ОЛИМПИАДНАЯ СВЯЗЬ 🏆
СВЯЗЬ С РЕАЛЬНЫМИ ОЛИМПИАДНЫМИ ЗАДАНИЯМИ:
// Аналогично задачам на конечные автоматы:
"Реализовать систему с множеством состояний и сложными переходами"
// Аналогично задачам на работу с периферией:
"Интегрировать различные устройства в единую систему"
// Аналогично задачам на алгоритмы обработки данных:
"Реализовать систему хранения и проверки данных с защитой"
Критерии успеха в олимпиадах:
- ✅ Целостность системы - все компоненты работают согласованно
- ✅ Надежность - обработка ошибок и граничных случаев
- ✅ Безопасность - защита данных и противодействие взлому
- ✅ Пользовательский интерфейс - интуитивное управление и обратная связь
Типичные олимпиадные ошибки:
- ❌ Отсутствие обработки ошибок - система падает при неправильном вводе
- ❌ Жесткие задержки - использование delay() вместо millis()
- ❌ Небезопасное хранение - коды в открытом виде
- ❌ Слабая индикация - пользователь не понимает состояние системы
МЕТОДИЧЕСКИЕ СОВЕТЫ 👨🏫
Поэтапная реализация:
// ЭТАП 1: Отдельные компоненты
testKeypad();
testServo();
testLEDs();
// ЭТАП 2: Базовая интеграция
handleKeypadInput();
if (codeCorrect) openDoor();
// ЭТАП 3: Система состояний
implementStateMachine();
addErrorHandling();
// ЭТАП 4: Безопасность и надежность
addEEPROMStorage();
implementLockoutSystem();
addAuditLog();
Визуализация для понимания:
🏗️ Архитектура системы:
[Клавиатура] → [Ардуино] → [Сервопривод]
↓ ↓ ↓
[Ввод кода] → [Проверка] → [Открытие]
↓ ↓ ↓
[Обратная ← [Индикация] ← [Статус]
связь] [Логирование]
Практические упражнения:
Упражнение 1: “Тестирование надежности”
- Проверить работу системы при неправильных вводах
- Протестировать восстановление после сбоев питания
- Оценить устойчивость к электромагнитным помехам
Упражнение 2: “Улучшение безопасности”
- Реализовать шифрование кодов в EEPROM
- Добавить задержки при неправильном вводе
- Внедрить систему одноразовых кодов
Упражнение 3: “Расширение функциональности”
- Добавить режим программирования новых кодов
- Реализовать удаленное управление через Bluetooth
- Создать мобильное приложение для мониторинга
Диагностика проблем:
- Сервопривод не двигается → проверьте питание и сигнальный провод
- Клавиатура не реагирует → проверьте подключение строк и столбцов
- EEPROM не сохраняет данные → убедитесь в правильности адресации
- Система зависает → добавьте watchdog таймер
Критерии оценки проекта:
- 4 балла - стабильная работа базовой системы доступа
- +2 балла - надежная система состояний с обработкой ошибок
- +2 балла - безопасное хранение данных и защита от взлома
- +2 балла - расширенные функции и профессиональный интерфейс
РЕАЛЬНОЕ ПРИМЕНЕНИЕ 🏢
Где это используется:
- Системы контроля доступа - в офисах, предприятиях, жилых домах
- Банковские сейфы - многофакторная аутентификация
- Парковочные системы - управление шлагбаумами
- Умный дом - управление доступом в помещения
Профессиональные аналоги:
- Системы RFID контроля доступа - карточки и брелоки
- Биометрические сканеры - отпечатки пальцев, распознавание лиц
- Многофакторная аутентификация - комбинация разных методов
- Системы мониторинга и отчетности - ведение логов доступа