Table of Contents

Password-Protected Alarm System

Introduction

This project implements a password-protected alarm system using the Arduino Nano ATmega328P board.

  • What it does: When triggered (via a start button or a PIR motion sensor), a 30-second countdown begins and the passive buzzer starts beeping. The alarm can only be silenced by entering the correct 4-digit password via 4 push buttons. A green LED and a success jingle confirm correct entry, while a red LED and a continuous alarm signal a wrong attempt. The system also controls a servo motor acting as a physical door lock, stores the password persistently in the internal EEPROM (survives power cycles), and allows secure in-system password changes. A 16×2 I2C LCD and UART serial output provide real-time status feedback.
  • Key features: Password-protected alarm, PIR motion detection with arming delay, servo door lock, EEPROM password persistence, 4-state FSM, UART debug output.

General Description

The system is structured around a 4-state Finite State Machine (FSM) running on the ATmega328P. All peripherals are driven using direct register manipulation.

Hardware Modules:

Bill of Materials:

Component Quantity Notes
—————————-———-————————————–
Arduino Nano ATmega328P 1 16 MHz, 5V
Passive buzzer 1 Sound
Push buttons 7 Password input, pull-up resistors
Reset button 1 Reset purpose
Green LED + 220Ω resistor 1 Correct password indicator
Red LED + 220Ω resistor 1 Wrong password indicator
16×2 LCD (HD44780) 1 I2C adapter
Breadboard + jumper wires - Prototyping
USB cable 1 For flashing the ATmega328P
PIR Sensor (HC-SR501) 1 Motion detection for automatic arming
Servo Motor SG90 1 physical door lock mechanism

Electrical Notes:

Software Design:

Password Validation FSM:

The system uses a finite state machine with 4 states:

^ State ^ Code ^ Description ^

IDLE / Active stare = 0 System waiting; allows arming/disarming PIR and password change
ALARM countdown stare = 1 30s countdown, periodic beep, user enters password
ALARM triggered stare = 2 Time expired or wrong password; red LED + continuous buzzer
Password change stare = 3 Two-step sub-FSM: verify old password, then set new one

FSM Transitions:

Libraries

The project uses exclusively bare-metal avr-libc — no Arduino Framework. This choice provides full control over peripheral registers, deterministic timing, smaller code size, and compatibility with any AVR toolchain (avr-gcc + avrdude).

<avr/io.h>
Provides symbolic definitions for all ATmega328P peripheral registers (DDRx, PORTx, PINx, TCCRx, OCRx, TWCR, UBRR0, etc.). Without this header, raw hexadecimal register addresses would be required, making the code unportable and unreadable. It is an absolute necessity for any bare-metal AVR project.

<util/delay.h>
Provides _delay_ms() and _delay_us(), computed at compile time based on F_CPU = 16000000UL. Used in:

A hardware timer alternative would be more CPU-efficient for long waits, but for short and precise initialization delays, _delay_us() is the correct approach.

<avr/eeprom.h>
Provides eeprom_update_byte() and eeprom_read_byte() for safe access to the 1 KB internal EEPROM of the ATmega328P. Critically, eeprom_update_byte() (unlike eeprom_write_byte()) checks whether the existing value equals the new value before performing a write. This extends EEPROM lifetime (rated ~100,000 write cycles per cell) — important when the same password bytes might be rewritten repeatedly. Used to persist the 4-digit password across power cycles.

Block Design

Laboratories Used

The implementation is directly based on concepts from the following laboratories:

Laboratory 0 — GPIO
Used for all digital inputs and outputs. Pin direction is set via DDRx, output values via PORTx, and input states read via PINx. Internal pull-ups (PORTx |= (1 « Pxy) with DDRx &= ~(1 « Pxy)) eliminate the need for external resistors on all 6 buttons. LED driving, buzzer toggling, and servo signal generation all rely on basic GPIO operations.

Laboratory 1 — UART
Integrated for real-time debugging. Every significant state transition (alarm activation, key press, password change, arming) generates a descriptive UART message transmitted at 9600 baud. Initialization uses the formula UBRR = F_CPU / 16 / BAUD − 1 = 103 for 9600 baud at 16 MHz. Transmission uses polling on the UDRE0 flag in UCSR0A.

Laboratory 2 — Interrupts
Timer1 uses the hardware CTC overflow flag (OCF1A in TIFR1) checked by polling in the main loop. This decouples the 1-second countdown from the rest of the loop execution, ensuring temporal accuracy independent of code execution time. The flag is cleared by writing a logical 1 to it (TIFR1 |= (1 « OCF1A)) — the AVR write-1-to-clear mechanism. Button edge detection (comparing current and previous state) provides interrupt-like single-trigger behaviour without ISR overhead.

Laboratory 3 — Timers
Timer1 is configured in CTC mode (WGM12 = 1) with prescaler 1024 (CS12 = 1, CS10 = 1) and OCR1A = 15624, generating a precise 1 Hz event: 16,000,000 / 1024 / (15624 + 1) = 1 Hz. TCNT1 is reset to 0 at alarm activation, and the OCF1A flag is polled each main loop iteration to count elapsed seconds for the 30-second countdown.

Laboratory 6 — I2C
The HD44780 LCD with PCF8574 I2C adapter is controlled via a manually implemented I2C driver (no third-party library). Hardware TWI registers used: TWBR = 12 for ~400 kHz fast mode, TWSR = 0 for prescaler 1, TWCR for start/stop/write control. Each LCD character requires 2 I2C transactions (upper nibble + lower nibble), each including an enable pulse. This custom implementation allows full control over I2C address, backlight, and LCD command timing.

Project Skeleton

The main while(1) loop is organized as a sequential state machine. Each iteration evaluates the current state and performs the appropriate actions:

while(1) {
    // 1. Update PIR indicator LED (state-independent)
    // 2. In state 0: check Arming button (PB4) and Password-Change button (PC1)
    // 3. Check alarm trigger: Start button (PD2) OR PIR + motion (PB3)
    // 4. In state 1: check Timer1 flag (TIFR1) → decrement countdown, beep
    // 5. In states 1 and 2: read keypad → validate password
    // 6. In state 2: toggle buzzer (PD7) for continuous alarm
    // 7. In state 3: two-step password change sub-FSM
}

Key interactions between functionalities:

Schematics

Detailed pin mapping with justification for each choice:

^ Arduino Nano Pin ^ AVR Pin ^ Direction ^ Connected Component ^ Justification ^

A0 PC0 Output Servo SG90 signal Available digital pin on port C; soft PWM implemented manually with delay loops (1000 µs / 1500 µs pulses). Hardware timer not required.
A1 PC1 Input, internal pull-up Password-change button Free pin on port C, adjacent to servo. Active-low, internal pull-up enabled.
D2 PD2 Input, internal pull-up Start / Reset button PD2 doubles as INT0 external interrupt pin — future upgrade potential. Currently used with polling.
D3 PD3 Input, internal pull-up Password button 1 PD3 doubles as INT1. Available on port D.
D4 PD4 Input, internal pull-up Password button 2 Available digital pin on port D.
D5 PD5 Output Green LED PWM-capable pin (OC0B), used as simple GPIO for the OK status indicator.
D6 PD6 Output Red LED PWM-capable pin (OC0A), used as simple GPIO for the alarm indicator.
D7 PD7 Output Passive buzzer Simple digital pin; tone frequency generated by GPIO toggle with delays (500 µs ≈ 1 kHz).
D8 PB0 Input, internal pull-up Password button 3 Available digital pin on port B.
D9 PB1 Input, internal pull-up Password button 4 Available digital pin on port B.
D10 PB2 Output PIR armed indicator LED Available pin on port B; visually shows when the PIR sensor is armed.
D11 PB3 Input, internal pull-up PIR sensor output HC-SR501 digital output (HIGH = motion). Monitored by polling in state 0.
D12 PB4 Input, internal pull-up Arming button Available pin on port B for the arm/disarm toggle button.
A4 PC4 I/O (SDA) LCD via I2C Hardware I2C SDA pin on ATmega328P. Mandatory for the PCF8574 I2C adapter.
A5 PC5 I/O (SCL) LCD via I2C Hardware I2C SCL pin on ATmega328P. Mandatory for the PCF8574 I2C adapter.
D1 PD1 Output (TX) UART debug Hardware USART0 TX pin. Transmits debug messages at 9600 baud to Serial Monitor.

All buttons use internal pull-up resistors activated via DDRx &= ~(1 « Pxy); PORTx |= (1 « Pxy);. Buttons are active-low: logic goes LOW when pressed (connected to GND). No external pull-up resistors needed.

Results

Conclusions

Download

Journal

Bibliography / Resources