#include <LiquidCrystal.h>
#include <Servo.h>
// ========== PINS ==========
const int ROW_PINS[4] = {PB12, PB13, PB14, PB15}; // rows
const int COL_PINS[4] = {PA0, PA1, PA2, PA3}; // cols
const int GREEN_LED = PB0;
const int RED_LED = PB1;
const int BUZZER = PB8;
const int SERVO_PIN = PA8;
// LCD (rs, e, d4, d5, d6, d7)
LiquidCrystal lcd(PA4, PA5, PA6, PA7, PB6, PB7);
Servo doorServo;
// ========== CONFIG ==========
char keys[4][4] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
const String CORRECT_PIN = "1234";
String enteredPIN = "";
int wrongAttempts = 0;
bool permanentlyLocked = false;
bool doorOpen = false;
unsigned long lockUntil = 0UL;
const unsigned long LOCKOUT_TIME_1 = 5000UL;
const unsigned long LOCKOUT_TIME_2 = 10000UL;
const int SUCCESS_DISPLAY_TIME = 2000;
const int DEBOUNCE_DELAY = 300;
const int SERVO_CLOSED = 0;
const int SERVO_OPEN = 90;
// ========== SOUND HELPERS ==========
void playTone(int pin, unsigned int frequency, unsigned long duration_ms) {
if (frequency == 0 || duration_ms == 0) { delay(duration_ms); return; }
unsigned long period_us = 1000000UL / frequency;
unsigned long half = period_us / 2;
unsigned long cycles = (duration_ms * 1000UL) / period_us;
for (unsigned long i = 0; i < cycles; i++) {
digitalWrite(pin, HIGH);
delayMicroseconds(half);
digitalWrite(pin, LOW);
delayMicroseconds(half);
}
}
void beep(int frequency, int duration) {
playTone(BUZZER, frequency, duration);
}
void keyPressBeep() { beep(2000, 40); }
void successMelody() {
int notes[] = {1200, 1600, 2000};
for (int i = 0; i < 3; i++) {
playTone(BUZZER, notes[i], 180);
delay(80);
}
}
void errorBeep() { playTone(BUZZER, 700, 350); }
void lockoutBeeps() {
for (int i = 0; i < 3; i++) { playTone(BUZZER, 900, 150); delay(60); }
}
void permanentAlarm() {
playTone(BUZZER, 800, 200);
delay(40);
playTone(BUZZER, 1200, 200);
delay(40);
}
// ========== KEYPAD ==========
char getKey() {
for (int row = 0; row < 4; row++) {
digitalWrite(ROW_PINS[row], LOW);
for (int col = 0; col < 4; col++) {
if (digitalRead(COL_PINS[col]) == LOW) {
digitalWrite(ROW_PINS[row], HIGH);
return keys[row][col];
}
}
digitalWrite(ROW_PINS[row], HIGH);
}
return '\0';
}
// ========== LCD HELPERS ==========
void displayWelcome() {
lcd.clear();
lcd.setCursor(0,0); lcd.print("=== PIN Lock ===");
lcd.setCursor(0,1); lcd.print("System Ready");
delay(1200);
lcd.clear(); lcd.setCursor(0,0); lcd.print("Enter PIN:");
lcd.setCursor(0,1); lcd.print(" ");
}
void displayPIN() {
lcd.setCursor(0,1);
lcd.print(" ");
lcd.setCursor(0,1);
for (size_t i = 0; i < enteredPIN.length(); i++) lcd.print("*");
}
void displaySuccess() {
lcd.clear();
lcd.setCursor(0,0); lcd.print("CORRECT PIN!");
lcd.setCursor(0,1); lcd.print("Access Granted");
}
void displayDoorOpen() {
lcd.clear();
lcd.setCursor(0,0); lcd.print("Door Open");
lcd.setCursor(0,1); lcd.print("Press # to close");
}
void displayError(int attempt) {
lcd.clear();
lcd.setCursor(0,0); lcd.print("WRONG PIN!");
lcd.setCursor(0,1);
lcd.print("Attempt ");
lcd.print(attempt);
lcd.print("/3 ");
}
void displayLockoutOnce(int seconds) {
lcd.clear();
lcd.setCursor(0,0); lcd.print("System Locked");
lcd.setCursor(0,1);
lcd.print("Wait: ");
lcd.print(" ");
}
void updateRemainingSeconds(int seconds) {
lcd.setCursor(6,1);
if (seconds < 0) seconds = 0;
if (seconds < 10) {
lcd.print(" ");
lcd.print(seconds);
lcd.print(" s");
} else {
lcd.print(" ");
lcd.print(seconds);
lcd.print("s");
}
lcd.print(" ");
}
// ========== SERVO CONTROL ==========
void openDoor() {
Serial.println(">>> OPENING DOOR - SERVO TO 90");
for (int pos = 0; pos <= 90; pos += 5) {
doorServo.write(pos);
delay(15);
}
doorOpen = true;
Serial.println(">>> DOOR OPEN");
}
void closeDoor() {
Serial.println(">>> CLOSING DOOR - SERVO TO 0");
for (int pos = 90; pos >= 0; pos -= 5) {
doorServo.write(pos);
delay(15);
}
doorOpen = false;
Serial.println(">>> DOOR CLOSED");
beep(1500, 100); delay(120); beep(1500, 100);
lcd.clear();
lcd.setCursor(0,0); lcd.print("Door Closed");
delay(600);
lcd.clear();
lcd.setCursor(0,0); lcd.print("Enter PIN:");
lcd.setCursor(0,1); lcd.print(" ");
}
// ========== LOGIC ==========
void checkPIN() {
if (enteredPIN == CORRECT_PIN) {
Serial.println("✓ CORRECT PIN");
displaySuccess();
digitalWrite(GREEN_LED, HIGH); digitalWrite(RED_LED, LOW);
successMelody();
wrongAttempts = 0;
delay(SUCCESS_DISPLAY_TIME);
openDoor();
displayDoorOpen();
enteredPIN = "";
} else {
wrongAttempts++;
Serial.print("✗ WRONG PIN (");
Serial.print(wrongAttempts);
Serial.println("/3)");
displayError(wrongAttempts);
digitalWrite(RED_LED, HIGH); digitalWrite(GREEN_LED, LOW);
errorBeep();
delay(700);
digitalWrite(RED_LED, LOW);
if (wrongAttempts == 1) {
lockUntil = millis() + LOCKOUT_TIME_1;
Serial.println("Locked for 1st timeout");
displayLockoutOnce((int)(LOCKOUT_TIME_1/1000));
lockoutBeeps();
} else if (wrongAttempts == 2) {
lockUntil = millis() + LOCKOUT_TIME_2;
Serial.println("Locked for 2nd timeout");
displayLockoutOnce((int)(LOCKOUT_TIME_2/1000));
lockoutBeeps();
} else {
permanentlyLocked = true;
Serial.println("PERMANENT LOCK");
displayLockoutOnce(0);
lcd.clear();
lcd.setCursor(0,0); lcd.print("PERMANENTLY");
lcd.setCursor(0,1); lcd.print("LOCKED !!!");
digitalWrite(RED_LED, HIGH);
}
enteredPIN = "";
}
}
void clearPIN() {
enteredPIN = "";
Serial.println("PIN cleared");
beep(1500, 100); delay(120); beep(1500, 100);
digitalWrite(GREEN_LED, LOW); digitalWrite(RED_LED, LOW);
lcd.clear(); lcd.setCursor(0,0); lcd.print("PIN Cleared");
delay(600);
lcd.clear(); lcd.setCursor(0,0); lcd.print("Enter PIN:"); lcd.setCursor(0,1); lcd.print(" ");
}
// ========== SETUP ==========
void setup() {
Serial.begin(115200);
Serial.println(">>> PIN LOCK STARTING");
for (int i=0;i<4;i++){
pinMode(ROW_PINS[i], OUTPUT); digitalWrite(ROW_PINS[i], HIGH);
}
for (int i=0;i<4;i++) pinMode(COL_PINS[i], INPUT_PULLUP);
pinMode(GREEN_LED, OUTPUT); pinMode(RED_LED, OUTPUT);
digitalWrite(GREEN_LED, LOW); digitalWrite(RED_LED, LOW);
pinMode(BUZZER, OUTPUT);
pinMode(PA4, OUTPUT); pinMode(PA5, OUTPUT); pinMode(PA6, OUTPUT); pinMode(PA7, OUTPUT);
pinMode(PB6, OUTPUT); pinMode(PB7, OUTPUT);
Serial.println(">>> ATTACHING SERVO TO PB8");
doorServo.attach(SERVO_PIN);
Serial.println(">>> SETTING SERVO TO 0 (CLOSED)");
doorServo.write(0);
delay(500);
Serial.println(">>> SERVO INITIALIZED");
lcd.begin(16,2); delay(50);
displayWelcome();
}
// ========== LOOP ==========
void loop() {
if (permanentlyLocked) {
digitalWrite(RED_LED, HIGH);
digitalWrite(GREEN_LED, LOW);
permanentAlarm();
return;
}
if (lockUntil > 0 && millis() < lockUntil) {
digitalWrite(RED_LED, (millis() / 500) % 2);
digitalWrite(GREEN_LED, LOW);
int remaining = (int)((lockUntil - millis()) / 1000UL + 1);
updateRemainingSeconds(remaining);
delay(150);
return;
}
if (lockUntil > 0 && millis() >= lockUntil) {
lockUntil = 0;
digitalWrite(RED_LED, LOW);
Serial.println("Lockout ended");
lcd.clear();
lcd.setCursor(0,0); lcd.print("Lockout Ended");
lcd.setCursor(0,1); lcd.print("Try Again ");
delay(900);
lcd.clear(); lcd.setCursor(0,0); lcd.print("Enter PIN:"); lcd.setCursor(0,1); lcd.print(" ");
}
char key = getKey();
if (key != '\0') {
Serial.print("Key: "); Serial.println(key);
if (doorOpen && key == '#') {
closeDoor();
digitalWrite(GREEN_LED, LOW);
delay(DEBOUNCE_DELAY);
return;
}
if (!doorOpen) {
if (key >= '0' && key <= '9') {
if (enteredPIN.length() < 4) {
enteredPIN += key;
keyPressBeep();
displayPIN();
if (enteredPIN.length() == 4) { delay(300); checkPIN(); }
}
} else if (key == '*') {
clearPIN();
}
}
delay(DEBOUNCE_DELAY);
}
}Loading
stm32-bluepill
stm32-bluepill