#include <SPI.h>
#include <MFRC522.h>
#include <Keypad.h>
#include <Servo.h>
// ——— RFID 설정 ———
#define RST_PIN 9 // RC522 리셋 핀
#define SS_PIN 10 // RC522 SDA(SS) 핀
MFRC522 rfid(SS_PIN, RST_PIN);
byte validUID[4] = { 0x53, 0x0B, 0x3E, 0x2A }; // 허용된 카드 UID
// ——— 키패드 설정 ———
const byte ROWS = 4, COLS = 4;
char keys[ROWS][COLS] = {
{'A','B','C','D'},
{'3','6','9','#'},
{'2','5','8','0'},
{'1','4','7','*'}
};
// 1→D2, 2→A3, 3→D4, 4→D5, 5→D6, 6→D7, 7→D8, 8→A0
byte rowPins[ROWS] = { 2, A3, 4, 5 };
byte colPins[COLS] = { 6, 7, 8, A0 };
Keypad keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// ——— 서보모터 ———
Servo doorServo;
const int servoPin = 3; // 제어 신호 핀
// ——— 부저 ———
const int buzzerPin = A5;
// ——— RGB LED (공통 GND) ———
const int redPin = A1;
const int greenPin = A2;
const int bluePin = A4;
// ——— 비밀번호 & 시도 카운트 ———
const String correctPassword = "0492";
String enteredPassword = "";
int attemptCount = 0;
// ——— 실패 & 락다운 로직 ———
int failCount = 0;
bool isLockedOut = false;
unsigned long lockoutStart = 0;
unsigned long lastDenyTime = 0;
void setup() {
Serial.begin(9600);
SPI.begin();
rfid.PCD_Init();
pinMode(buzzerPin, OUTPUT);
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
doorServo.attach(servoPin);
lockDoor();
// 대기 상태: LED 모두 끔
digitalWrite(redPin, LOW);
digitalWrite(greenPin, LOW);
digitalWrite(bluePin, LOW);
Serial.println("=== SYSTEM READY ===");
}
void loop() {
unsigned long now = millis();
// 1) 락다운 해제 체크
if (isLockedOut && now - lockoutStart >= 30000) {
isLockedOut = false;
failCount = 0;
Serial.println("Lockdown 해제");
digitalWrite(redPin, LOW);
}
if (isLockedOut) return;
// 2) RFID 스캔 처리 (틀려도 failCount 증가하지 않음)
if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) {
// 카드 감지 로그 및 UID 출력
Serial.print("RFID 감지! UID: ");
for (byte i = 0; i < rfid.uid.size; i++) {
if (rfid.uid.uidByte[i] < 0x10) Serial.print('0');
Serial.print(rfid.uid.uidByte[i], HEX);
Serial.print(' ');
}
Serial.println();
// UID 비교
bool match = true;
for (byte i = 0; i < 4; i++) {
if (rfid.uid.uidByte[i] != validUID[i]) {
match = false;
break;
}
}
if (match) {
Serial.println("→ 올바른 카드: ACCESS GRANTED");
grantAccess();
} else {
Serial.println("→ 잘못된 카드: ACCESS DENIED");
denyRFID();
}
// 청소
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
return;
}
// 3) 키패드 입력 처리 (A, B, C, D 무시)
char key = keypad.getKey();
if (key) {
// A–D 버튼일 경우 아무 반응 없이 리턴
if (key == 'A' || key == 'B' || key == 'C' || key == 'D') {
return;
}
tone(buzzerPin, 1000, 100);
Serial.print("Keypad: "); Serial.println(key);
if (key == '#') {
attemptCount++;
Serial.print("Password Attempt #"); Serial.println(attemptCount);
if (enteredPassword.indexOf(correctPassword) >= 0) {
Serial.println("→ 비밀번호 매칭: ACCESS GRANTED");
grantAccess();
} else {
Serial.println("→ 비밀번호 불일치: ACCESS DENIED");
denyAccess();
}
enteredPassword = "";
return;
}
else if (key == '*') {
enteredPassword = "";
Serial.println("Buffer cleared");
}
else {
enteredPassword += key;
Serial.print("Buffer: "); Serial.println(enteredPassword);
}
}
// 4) 실패 LED 자동 OFF (5초 후)
if (lastDenyTime > 0 && now - lastDenyTime >= 5000) {
digitalWrite(redPin, LOW);
lastDenyTime = 0;
Serial.println("Failure LED OFF");
}
}
// 접근 허용: 서보·부저·LED·카운트 리셋
void grantAccess() {
failCount = 0; // 비밀번호 실패 횟수 초기화
digitalWrite(greenPin, HIGH);
digitalWrite(redPin, LOW);
digitalWrite(bluePin, LOW);
tone(buzzerPin, 2000, 300);
unlockDoor();
delay(5000);
lockDoor();
digitalWrite(greenPin, LOW);
}
// 비밀번호 실패 처리: failCount 증가, 락다운 가능
void denyAccess() {
failCount++;
digitalWrite(redPin, HIGH);
digitalWrite(greenPin, LOW);
digitalWrite(bluePin, LOW);
tone(buzzerPin, 400, 500);
lastDenyTime = millis();
if (failCount >= 5) {
isLockedOut = true;
lockoutStart = millis();
Serial.println("5회 실패 → 30초 락다운");
}
}
// RFID 실패 처리: failCount 증가X, 락다운X
void denyRFID() {
digitalWrite(redPin, HIGH);
digitalWrite(greenPin, LOW);
digitalWrite(bluePin, LOW);
tone(buzzerPin, 400, 500);
lastDenyTime = millis();
}
// 문 잠그기/열기
void lockDoor() { doorServo.write(0); } // 잠금
void unlockDoor() { doorServo.write(90); } // 열림
// ——— 키패드 설정 ———
const byte ROWS = 4, COLS = 4;
char keys[ROWS][COLS] = {
{'A','B','C','D'},
{'3','6','9','#'},
{'2','5','8','0'},
{'1','4','7','*'}
};
// 1→D2, 2→A3, 3→D4, 4→D5, 5→D6, 6→D7, 7→D8, 8→A0
byte rowPins[ROWS] = { 2, A3, 4, 5 };
byte colPins[COLS] = { 6, 7, 8, A0 };
Keypad keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
4x4 키패드 각각의 자리에 번호 부여
if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) {
// 카드 감지 로그 및 UID 출력
Serial.print("RFID 감지! UID: ");
for (byte i = 0; i < rfid.uid.size; i++) {
if (rfid.uid.uidByte[i] < 0x10) Serial.print('0');
Serial.print(rfid.uid.uidByte[i], HEX);
Serial.print(' ');
}
Serial.println();
// UID 비교
bool match = true;
for (byte i = 0; i < 4; i++) {
if (rfid.uid.uidByte[i] != validUID[i]) {
match = false;
break;
}
}
if (match) {
Serial.println("→ 올바른 카드: ACCESS GRANTED");
grantAccess();
} else {
Serial.println("→ 잘못된 카드: ACCESS DENIED");
denyRFID();
}
맞는 카드키인지 맞지 않는 카드키인지 확인
// 4) 실패 LED 자동 OFF (5초 후)
if (lastDenyTime > 0 && now - lastDenyTime >= 5000) {
digitalWrite(redPin, LOW);
lastDenyTime = 0;
Serial.println("Failure LED OFF");
}
}
// 접근 허용: 서보·부저·LED·카운트 리셋
void grantAccess() {
failCount = 0; // 비밀번호 실패 횟수 초기화
digitalWrite(greenPin, HIGH);
digitalWrite(redPin, LOW);
digitalWrite(bluePin, LOW);
tone(buzzerPin, 2000, 300);
unlockDoor();
delay(5000);
lockDoor();
digitalWrite(greenPin, LOW);
}
비밀번호가 맞아서 문이 열릴때 초록색, 비밀번호가 틀렸을때 빨간색 LED 출력