基于51单片机的智能门禁系统

基于51单片机的智能门禁系统

基于AT89C51/STC89C52的门禁系统设计,包含RFID卡、矩阵键盘、LCD显示、继电器控制等功能。

一、系统总体设计

1.1 系统功能

1.2 硬件架构

AT89C51/STC89C52
├── RFID模块 (RC522/MFRC522/EM4100) → P1口
├── 矩阵键盘 (4×4) → P2口
├── LCD1602 → P0口+P2.4-P2.7
├── 继电器 → P3.4 (控制门锁)
├── 蜂鸣器 → P3.5
├── LED指示灯 → P3.6(红), P3.7(绿)
├── EEPROM (AT24C02) → P3.2(SCL), P3.3(SDA)
├── 实时时钟 (DS1302) → P3.0(SCLK), P3.1(IO)
├── 门磁传感器 → P3.6 (检测门状态)
└── 复位/设置按键 → 外部中断

二、硬件设计与连接

2.1 引脚分配

/* 端口定义 */
sbit LCD_RS = P2^0;    // LCD寄存器选择
sbit LCD_RW = P2^1;    // LCD读写
sbit LCD_EN = P2^2;    // LCD使能
sbit LCD_D4 = P2^4;    // LCD数据位4
sbit LCD_D5 = P2^5;    // LCD数据位5
sbit LCD_D6 = P2^6;    // LCD数据位6
sbit LCD_D7 = P2^7;    // LCD数据位7

sbit RELAY = P3^4;     // 继电器控制
sbit BUZZER = P3^5;    // 蜂鸣器
sbit LED_RED = P3^6;   // 红色LED
sbit LED_GREEN = P3^7; // 绿色LED
sbit DOOR_SENSOR = P3^6; // 门磁传感器

/* 矩阵键盘 */
#define KEY_PORT P1    // 4×4矩阵键盘连接P1口

/* RFID模块连接 */
sbit RFID_RST = P3^2;  // RFID复位
sbit RFID_SCK = P3^1;  // RFID时钟
sbit RFID_MOSI = P3^0; // RFID主出从入
sbit RFID_MISO = P1^7; // RFID主入从出
sbit RFID_CS = P1^6;   // RFID片选

三、核心代码实现

3.1 主程序框架

/**
 * @file main.c
 * @brief 51单片机门禁系统主程序
 */

#include <reg52.h>
#include <intrins.h>
#include <stdio.h>
#include <string.h>
#include "lcd1602.h"
#include "keypad.h"
#include "rfid.h"
#include "eeprom.h"
#include "ds1302.h"
#include "door_lock.h"

/* 系统状态 */
typedef enum {
    STATE_IDLE = 0,         // 空闲状态
    STATE_WAIT_CARD,        // 等待刷卡
    STATE_WAIT_PASSWORD,    // 等待密码
    STATE_ADMIN_MODE,       // 管理状态
    STATE_ADD_CARD,         // 添加卡片
    STATE_DEL_CARD,         // 删除卡片
    STATE_CHANGE_PWD,       // 修改密码
    STATE_DOOR_OPEN,        // 门已打开
    STATE_ALARM             // 报警状态
} SystemState;

SystemState current_state = STATE_IDLE;

/* 全局变量 */
unsigned char password[6] = {1,2,3,4,5,6};  // 默认密码
unsigned char input_buffer[16];            // 输入缓冲区
unsigned char input_index = 0;             // 输入索引
unsigned long card_id = 0;                 // 当前卡片ID
unsigned char admin_mode = 0;              // 管理模式标志
unsigned char door_open_time = 0;          // 开门计时

/* 系统配置 */
#define MAX_CARDS 50                       // 最大存储卡数
#define DOOR_OPEN_TIME 10                  // 开门时间(秒)
#define MAX_PASSWORD_ATTEMPTS 3            // 最大尝试次数
unsigned char password_attempts = 0;       // 密码尝试次数

/* 函数声明 */
void system_init(void);
void display_welcome(void);
void process_rfid(void);
void process_keypad(void);
void check_door_status(void);
void admin_menu(void);
void add_new_card(void);
void delete_card(void);
void change_password(void);
void log_event(unsigned char event_type, unsigned long card_id);
void beep(unsigned char times, unsigned int duration);
void door_lock_control(unsigned char action);

/**
 * @brief 主函数
 */
void main(void)
{
    /* 系统初始化 */
    system_init();
    
    /* 显示欢迎信息 */
    display_welcome();
    
    while(1)
    {
        /* 状态机处理 */
        switch(current_state)
        {
            case STATE_IDLE:
                /* 空闲状态,等待刷卡或按键 */
                LED_GREEN = 1;  // 绿灯亮表示就绪
                break;
                
            case STATE_WAIT_CARD:
                /* 等待刷卡 */
                process_rfid();
                break;
                
            case STATE_WAIT_PASSWORD:
                /* 等待密码输入 */
                process_keypad();
                break;
                
            case STATE_ADMIN_MODE:
                /* 管理模式 */
                admin_menu();
                break;
                
            case STATE_ADD_CARD:
                /* 添加卡片 */
                add_new_card();
                break;
                
            case STATE_DEL_CARD:
                /* 删除卡片 */
                delete_card();
                break;
                
            case STATE_CHANGE_PWD:
                /* 修改密码 */
                change_password();
                break;
                
            case STATE_DOOR_OPEN:
                /* 门已打开,计时关闭 */
                if(door_open_time > 0)
                {
                    door_open_time--;
                    if(door_open_time == 0)
                    {
                        door_lock_control(0);  // 关闭门锁
                        current_state = STATE_IDLE;
                        lcd_clear();
                        lcd_write_string("Door Closed");
                    }
                }
                break;
                
            case STATE_ALARM:
                /* 报警状态 */
                LED_RED = ~LED_RED;  // 红灯闪烁
                BUZZER = ~BUZZER;    // 蜂鸣器报警
                break;
        }
        
        /* 检查门状态 */
        check_door_status();
        
        /* 延时 */
        delay_ms(100);
    }
}

/**
 * @brief 系统初始化
 */
void system_init(void)
{
    /* 初始化IO口 */
    RELAY = 0;      // 继电器关闭
    BUZZER = 0;     // 蜂鸣器关闭
    LED_RED = 0;    // 红灯关闭
    LED_GREEN = 1;  // 绿灯亮
    
    /* 初始化外设 */
    lcd_init();
    keypad_init();
    rfid_init();
    eeprom_init();
    ds1302_init();
    
    /* 从EEPROM读取密码 */
    eeprom_read_password(password);
    
    /* 设置中断(可选) */
    IT0 = 1;        // 外部中断0下降沿触发
    EX0 = 1;        // 允许外部中断0
    EA = 1;         // 开启总中断
    
    /* 蜂鸣器提示音 */
    beep(1, 200);
    
    current_state = STATE_WAIT_CARD;
}

/**
 * @brief 显示欢迎信息
 */
void display_welcome(void)
{
    lcd_clear();
    lcd_write_string("Access Control");
    lcd_set_cursor(2, 1);
    lcd_write_string("System v1.0");
    delay_ms(2000);
    
    lcd_clear();
    lcd_write_string("Please scan");
    lcd_set_cursor(2, 1);
    lcd_write_string("your card...");
}

/**
 * @brief 处理RFID刷卡
 */
void process_rfid(void)
{
    unsigned long new_card_id;
    
    /* 检测是否有卡片 */
    if(rfid_check_card(&new_card_id))
    {
        /* 蜂鸣器提示 */
        beep(1, 100);
        
        /* 显示卡片ID */
        lcd_clear();
        lcd_write_string("Card ID: ");
        lcd_write_hex(new_card_id);
        
        /* 验证卡片 */
        if(rfid_verify_card(new_card_id))
        {
            /* 卡片有效,开门 */
            lcd_set_cursor(2, 1);
            lcd_write_string("Access Granted!");
            
            door_lock_control(1);  // 开门
            log_event(1, new_card_id);  // 记录开门事件
            
            current_state = STATE_DOOR_OPEN;
            door_open_time = DOOR_OPEN_TIME;
            
            /* 绿色指示灯 */
            LED_GREEN = 0;
            LED_RED = 1;
        }
        else
        {
            /* 卡片无效,要求输入密码 */
            lcd_set_cursor(2, 1);
            lcd_write_string("Enter Password:");
            
            card_id = new_card_id;
            input_index = 0;
            password_attempts = 0;
            
            current_state = STATE_WAIT_PASSWORD;
        }
        
        delay_ms(1000);
    }
}

/**
 * @brief 处理键盘输入
 */
void process_keypad(void)
{
    unsigned char key = keypad_scan();
    
    if(key != 0xFF)  // 有按键按下
    {
        /* 蜂鸣器提示 */
        beep(1, 50);
        
        if(key == '#')  // 确认键
        {
            /* 验证密码 */
            if(input_index == 6)  // 密码为6位
            {
                unsigned char valid = 1;
                
                for(unsigned char i = 0; i < 6; i++)
                {
                    if(input_buffer[i] != password[i])
                    {
                        valid = 0;
                        break;
                    }
                }
                
                if(valid)
                {
                    /* 密码正确 */
                    lcd_clear();
                    lcd_write_string("Password OK!");
                    
                    /* 如果是新卡,可以添加到系统 */
                    if(card_id != 0)
                    {
                        rfid_add_card(card_id);
                        lcd_set_cursor(2, 1);
                        lcd_write_string("Card Added!");
                    }
                    
                    door_lock_control(1);  // 开门
                    log_event(2, card_id);  // 记录密码开门
                    
                    current_state = STATE_DOOR_OPEN;
                    door_open_time = DOOR_OPEN_TIME;
                    
                    password_attempts = 0;
                }
                else
                {
                    /* 密码错误 */
                    password_attempts++;
                    
                    lcd_clear();
                    lcd_write_string("Wrong Password!");
                    lcd_set_cursor(2, 1);
                    lcd_printf("Try: %d/%d", password_attempts, MAX_PASSWORD_ATTEMPTS);
                    
                    if(password_attempts >= MAX_PASSWORD_ATTEMPTS)
                    {
                        /* 超过尝试次数,触发报警 */
                        current_state = STATE_ALARM;
                        log_event(3, card_id);  // 记录密码错误
                    }
                    else
                    {
                        /* 重新输入 */
                        input_index = 0;
                        lcd_clear();
                        lcd_write_string("Enter Password:");
                        lcd_set_cursor(2, 1);
                        lcd_write_string("******");
                    }
                }
            }
        }
        else if(key == '*')  // 取消键
        {
            /* 取消输入,返回等待刷卡 */
            input_index = 0;
            current_state = STATE_WAIT_CARD;
            
            lcd_clear();
            lcd_write_string("Please scan");
            lcd_set_cursor(2, 1);
            lcd_write_string("your card...");
        }
        else if(key >= 0 && key <= 9)  // 数字键
        {
            if(input_index < 6)
            {
                input_buffer[input_index++] = key;
                
                /* 显示星号 */
                lcd_set_cursor(2, 1);
                for(unsigned char i = 0; i < input_index; i++)
                {
                    lcd_write_char('*');
                }
            }
        }
        else if(key == 10)  // A键,进入管理模式
        {
            input_index = 0;
            current_state = STATE_ADMIN_MODE;
            admin_menu();
        }
        
        delay_ms(200);  // 去抖延时
    }
}

/**
 * @brief 门锁控制
 * @param action 0:关闭, 1:打开
 */
void door_lock_control(unsigned char action)
{
    if(action)
    {
        RELAY = 1;  // 继电器吸合,开门
        LED_GREEN = 0;
        LED_RED = 1;
        beep(2, 100);
    }
    else
    {
        RELAY = 0;  // 继电器释放,关门
        LED_GREEN = 1;
        LED_RED = 0;
        beep(1, 100);
    }
}

/**
 * @brief 蜂鸣器提示
 */
void beep(unsigned char times, unsigned int duration)
{
    unsigned char i;
    for(i = 0; i < times; i++)
    {
        BUZZER = 1;
        delay_ms(duration);
        BUZZER = 0;
        if(i < times - 1) delay_ms(100);
    }
}

/**
 * @brief 检查门状态
 */
void check_door_status(void)
{
    static unsigned char last_door_state = 1;
    unsigned char current_door_state = DOOR_SENSOR;
    
    if(current_door_state != last_door_state)
    {
        if(current_door_state == 0)  // 门被打开
        {
            if(current_state != STATE_DOOR_OPEN)
            {
                /* 非法开门,触发报警 */
                current_state = STATE_ALARM;
                log_event(4, 0);  // 记录非法开门
            }
        }
        last_door_state = current_door_state;
    }
}

/* 外部中断0服务程序(紧急开门) */
void int0_isr(void) interrupt 0
{
    /* 紧急情况下强制开门 */
    door_lock_control(1);
    current_state = STATE_DOOR_OPEN;
    door_open_time = 30;  // 30秒
    
    lcd_clear();
    lcd_write_string("EMERGENCY OPEN!");
    
    log_event(5, 0);  // 记录紧急开门
}

3.2 LCD1602驱动

/**
 * @file lcd1602.h
 * @brief LCD1602液晶驱动
 */

#ifndef __LCD1602_H
#define __LCD1602_H

#include <reg52.h>

/* 函数声明 */
void lcd_init(void);
void lcd_clear(void);
void lcd_write_char(unsigned char ch);
void lcd_write_string(unsigned char *str);
void lcd_set_cursor(unsigned char row, unsigned char col);
void lcd_write_hex(unsigned long num);
void lcd_printf(unsigned char *fmt, ...);

/* 延时函数 */
void delay_ms(unsigned int ms)
{
    unsigned int i, j;
    for(i = 0; i < ms; i++)
        for(j = 0; j < 114; j++);
}

#endif
/**
 * @file lcd1602.c
 * @brief LCD1602驱动实现
 */

#include "lcd1602.h"

/* 写命令到LCD */
void lcd_write_cmd(unsigned char cmd)
{
    LCD_RS = 0;     // 命令模式
    LCD_RW = 0;     // 写操作
    
    /* 发送高4位 */
    LCD_D4 = (cmd >> 4) & 0x01;
    LCD_D5 = (cmd >> 5) & 0x01;
    LCD_D6 = (cmd >> 6) & 0x01;
    LCD_D7 = (cmd >> 7) & 0x01;
    
    LCD_EN = 1;
    delay_ms(1);
    LCD_EN = 0;
    
    /* 发送低4位 */
    LCD_D4 = cmd & 0x01;
    LCD_D5 = (cmd >> 1) & 0x01;
    LCD_D6 = (cmd >> 2) & 0x01;
    LCD_D7 = (cmd >> 3) & 0x01;
    
    LCD_EN = 1;
    delay_ms(1);
    LCD_EN = 0;
    
    delay_ms(2);
}

/* 写数据到LCD */
void lcd_write_data(unsigned char dat)
{
    LCD_RS = 1;     // 数据模式
    LCD_RW = 0;     // 写操作
    
    /* 发送高4位 */
    LCD_D4 = (dat >> 4) & 0x01;
    LCD_D5 = (dat >> 5) & 0x01;
    LCD_D6 = (dat >> 6) & 0x01;
    LCD_D7 = (dat >> 7) & 0x01;
    
    LCD_EN = 1;
    delay_ms(1);
    LCD_EN = 0;
    
    /* 发送低4位 */
    LCD_D4 = dat & 0x01;
    LCD_D5 = (dat >> 1) & 0x01;
    LCD_D6 = (dat >> 2) & 0x01;
    LCD_D7 = (dat >> 3) & 0x01;
    
    LCD_EN = 1;
    delay_ms(1);
    LCD_EN = 0;
    
    delay_ms(2);
}

/* LCD初始化 */
void lcd_init(void)
{
    delay_ms(15);
    
    /* 初始化序列 */
    lcd_write_cmd(0x28);  // 4位模式,2行显示
    lcd_write_cmd(0x0C);  // 显示开,光标关
    lcd_write_cmd(0x06);  // 光标右移
    lcd_write_cmd(0x01);  // 清屏
    
    delay_ms(2);
}

/* 清屏 */
void lcd_clear(void)
{
    lcd_write_cmd(0x01);
    delay_ms(2);
}

/* 写字符 */
void lcd_write_char(unsigned char ch)
{
    lcd_write_data(ch);
}

/* 写字符串 */
void lcd_write_string(unsigned char *str)
{
    while(*str != '\0')
    {
        lcd_write_char(*str);
        str++;
    }
}

/* 设置光标位置 */
void lcd_set_cursor(unsigned char row, unsigned char col)
{
    unsigned char address;
    
    if(row == 1)
        address = 0x80 + col - 1;
    else
        address = 0xC0 + col - 1;
    
    lcd_write_cmd(address);
}

/* 写十六进制数 */
void lcd_write_hex(unsigned long num)
{
    unsigned char i, temp;
    unsigned char buf[8];
    
    for(i = 0; i < 8; i++)
    {
        temp = (num >> (28 - i*4)) & 0x0F;
        if(temp < 10)
            buf[i] = temp + '0';
        else
            buf[i] = temp - 10 + 'A';
    }
    
    buf[8] = '\0';
    lcd_write_string(buf);
}

/* 简单printf实现(只支持%d, %x, %s) */
void lcd_printf(unsigned char *fmt, ...)
{
    unsigned char buf[20];
    unsigned char *ptr = fmt;
    unsigned int num;
    
    va_list args;
    va_start(args, fmt);
    
    while(*ptr != '\0')
    {
        if(*ptr == '%')
        {
            ptr++;
            switch(*ptr)
            {
                case 'd':
                    num = va_arg(args, int);
                    sprintf(buf, "%d", num);
                    lcd_write_string(buf);
                    break;
                    
                case 'x':
                    num = va_arg(args, int);
                    sprintf(buf, "%X", num);
                    lcd_write_string(buf);
                    break;
                    
                case 's':
                    lcd_write_string(va_arg(args, unsigned char*));
                    break;
            }
        }
        else
        {
            lcd_write_char(*ptr);
        }
        ptr++;
    }
    
    va_end(args);
}

3.3 矩阵键盘驱动

/**
 * @file keypad.h
 * @brief 4×4矩阵键盘驱动
 */

#ifndef __KEYPAD_H
#define __KEYPAD_H

#include <reg52.h>

#define KEY_PORT P1

unsigned char keypad_scan(void);
void keypad_init(void);

/* 键值定义 */
#define KEY_0     0
#define KEY_1     1
#define KEY_2     2
#define KEY_3     3
#define KEY_4     4
#define KEY_5     5
#define KEY_6     6
#define KEY_7     7
#define KEY_8     8
#define KEY_9     9
#define KEY_A     10
#define KEY_B     11
#define KEY_C     12
#define KEY_D     13
#define KEY_STAR  14
#define KEY_HASH  15
#define KEY_NONE  0xFF

#endif
/**
 * @file keypad.c
 * @brief 矩阵键盘驱动实现
 */

#include "keypad.h"

/* 键值映射表 */
const unsigned char keymap[4][4] = {
    {KEY_1, KEY_2, KEY_3, KEY_A},
    {KEY_4, KEY_5, KEY_6, KEY_B},
    {KEY_7, KEY_8, KEY_9, KEY_C},
    {KEY_STAR, KEY_0, KEY_HASH, KEY_D}
};

/* 键盘初始化 */
void keypad_init(void)
{
    KEY_PORT = 0xFF;  // 设置为输入模式
}

/* 扫描键盘 */
unsigned char keypad_scan(void)
{
    unsigned char row, col;
    
    /* 扫描所有行 */
    for(row = 0; row < 4; row++)
    {
        KEY_PORT = ~(0x01 << row);  // 设置当前行为低电平
        
        /* 检查列 */
        for(col = 0; col < 4; col++)
        {
            if(!(KEY_PORT & (0x10 << col)))  // 检测到低电平
            {
                delay_ms(20);  // 去抖
                if(!(KEY_PORT & (0x10 << col)))  // 再次确认
                {
                    while(!(KEY_PORT & (0x10 << col)));  // 等待释放
                    return keymap[row][col];
                }
            }
        }
    }
    
    return KEY_NONE;  // 无按键
}

3.4 RFID驱动(RC522)

/**
 * @file rfid.h
 * @brief RFID-RC522驱动
 */

#ifndef __RFID_H
#define __RFID_H

#include <reg52.h>

/* 函数声明 */
void rfid_init(void);
unsigned char rfid_check_card(unsigned long *card_id);
unsigned char rfid_verify_card(unsigned long card_id);
unsigned char rfid_add_card(unsigned long card_id);
unsigned char rfid_delete_card(unsigned long card_id);
unsigned char rfid_find_card(unsigned long card_id);
void rfid_write_block(unsigned char block, unsigned char *data);
void rfid_read_block(unsigned char block, unsigned char *data);

/* RC522命令 */
#define PCD_IDLE              0x00
#define PCD_AUTHENT           0x0E
#define PCD_RECEIVE           0x08
#define PCD_TRANSMIT          0x04
#define PCD_TRANSCEIVE        0x0C
#define PCD_RESETPHASE        0x0F
#define PCD_CALCCRC           0x03

/* RC522寄存器 */
#define CommandReg            0x01
#define ComIEnReg             0x02
#define DivIEnReg             0x03
#define ComIrqReg             0x04
#define DivIrqReg             0x05
#define ErrorReg              0x06
#define Status1Reg            0x07
#define Status2Reg            0x08
#define FIFODataReg           0x09
#define FIFOLevelReg          0x0A
#define WaterLevelReg         0x0B
#define ControlReg            0x0C
#define BitFramingReg         0x0D
#define CollReg               0x0E
#define ModeReg               0x11
#define TxControlReg          0x14
#define TxASKReg              0x15
#define TxSelReg              0x1A
#define RxSelReg              0x1B
#define RxThresholdReg        0x1C
#define DemodReg              0x1D
#define MfTxReg               0x1C
#define MfRxReg               0x1D
#define SerialSpeedReg        0x1F
#define CRCResultReg          0x21
#define ModWidthReg           0x24
#define RFCfgReg              0x26
#define GsNReg                0x27
#define CWGsPReg              0x28
#define ModGsPReg             0x29
#define TModeReg              0x2A
#define TPrescalerReg         0x2B
#define TReloadRegH           0x2C
#define TReloadRegL           0x2D
#define TCounterValueRegH     0x2E
#define TCounterValueRegL     0x2F

#endif
/**
 * @file rfid.c
 * @brief RFID-RC522驱动实现
 */

#include "rfid.h"
#include "eeprom.h"

/* 写一个字节到RC522 */
void rfid_write(unsigned char addr, unsigned char val)
{
    RFID_CS = 0;
    
    /* 发送地址 */
    addr = (addr << 1) & 0x7E;
    rfid_send_byte(addr);
    
    /* 发送数据 */
    rfid_send_byte(val);
    
    RFID_CS = 1;
}

/* 从RC522读取一个字节 */
unsigned char rfid_read(unsigned char addr)
{
    unsigned char val;
    
    RFID_CS = 0;
    
    /* 发送地址 */
    addr = ((addr << 1) & 0x7E) | 0x80;
    rfid_send_byte(addr);
    
    /* 读取数据 */
    val = rfid_receive_byte();
    
    RFID_CS = 1;
    
    return val;
}

/* SPI发送一个字节 */
void rfid_send_byte(unsigned char val)
{
    unsigned char i;
    
    for(i = 0; i < 8; i++)
    {
        RFID_SCK = 0;
        
        if(val & 0x80)
            RFID_MOSI = 1;
        else
            RFID_MOSI = 0;
        
        RFID_SCK = 1;
        val <<= 1;
    }
    
    RFID_SCK = 0;
}

/* SPI接收一个字节 */
unsigned char rfid_receive_byte(void)
{
    unsigned char i, val = 0;
    
    for(i = 0; i < 8; i++)
    {
        RFID_SCK = 0;
        RFID_SCK = 1;
        
        val <<= 1;
        if(RFID_MISO)
            val |= 0x01;
    }
    
    RFID_SCK = 0;
    
    return val;
}

/* RC522初始化 */
void rfid_init(void)
{
    RFID_RST = 1;
    RFID_CS = 1;
    RFID_SCK = 0;
    
    /* 复位RC522 */
    RFID_RST = 0;
    delay_ms(1);
    RFID_RST = 1;
    delay_ms(50);
    
    /* 初始化寄存器 */
    rfid_write(ModeReg, 0x3D);          // 定义发送和接收模式
    rfid_write(TReloadRegL, 30);
    rfid_write(TReloadRegH, 0);
    rfid_write(TModeReg, 0x8D);
    rfid_write(TPrescalerReg, 0x3E);
    rfid_write(TxASKReg, 0x40);
    rfid_write(ModeReg, 0x3D);
    
    rfid_antenna_on();  // 开启天线
}

/* 开启天线 */
void rfid_antenna_on(void)
{
    unsigned char temp = rfid_read(TxControlReg);
    
    if(!(temp & 0x03))
    {
        rfid_write(TxControlReg, temp | 0x03);
    }
}

/* 寻卡 */
unsigned char rfid_request(unsigned char req_code, unsigned char *type)
{
    unsigned char status;
    unsigned int back_bits;
    
    rfid_write(BitFramingReg, 0x07);
    
    rfid_write(CommandReg, PCD_IDLE);
    rfid_write(FIFOLevelReg, 0x80);
    rfid_write(FIFODataReg, req_code);
    rfid_write(CommandReg, PCD_TRANSCEIVE);
    rfid_write(BitFramingReg, 0x87);
    
    /* 等待接收完成 */
    unsigned int i = 2000;
    do
    {
        status = rfid_read(ComIrqReg);
        i--;
    } while((i!=0) && !(status & 0x01) && !(status & WAITIRq));
    
    if(i != 0)
    {
        if(!(rfid_read(ErrorReg) & 0x1B))
        {
            status = rfid_read(ComIrqReg);
            if(status & 0x01)
            {
                if(rfid_read(FIFOLevelReg) == 0x10)
                {
                    *type = rfid_read(FIFODataReg);
                    *(type+1) = rfid_read(FIFODataReg);
                }
            }
        }
    }
    
    return status;
}

/* 防冲撞 */
unsigned char rfid_anticoll(unsigned char *ser_num)
{
    unsigned char status;
    unsigned char i;
    unsigned char ser_num_check = 0;
    unsigned int unLen;
    
    rfid_write(BitFramingReg, 0x00);
    rfid_write(FIFOLevelReg, 0x80);
    rfid_write(CommandReg, PCD_TRANSCEIVE);
    rfid_write(FIFODataReg, 0x93);
    rfid_write(FIFODataReg, 0x20);
    rfid_write(CommandReg, PCD_TRANSCEIVE);
    
    /* 等待接收完成 */
    unsigned int j = 2000;
    do
    {
        status = rfid_read(ComIrqReg);
        j--;
    } while((j!=0) && !(status & 0x01));
    
    if(j != 0)
    {
        if(!(rfid_read(ErrorReg) & 0x1B))
        {
            unLen = rfid_read(FIFOLevelReg);
            if(unLen == 5)
            {
                for(i = 0; i < 4; i++)
                {
                    ser_num[i] = rfid_read(FIFODataReg);
                    ser_num_check ^= ser_num[i];
                }
                
                if(ser_num_check != rfid_read(FIFODataReg))
                {
                    return 0;
                }
            }
        }
    }
    
    return 1;
}

/* 检查卡片 */
unsigned char rfid_check_card(unsigned long *card_id)
{
    unsigned char status;
    unsigned char card_type[2];
    unsigned char ser_num[5];
    unsigned long id = 0;
    
    /* 寻卡 */
    status = rfid_request(0x52, card_type);
    if(status != 0)
    {
        /* 防冲撞 */
        status = rfid_anticoll(ser_num);
        if(status == 1)
        {
            /* 计算卡片ID */
            for(unsigned char i = 0; i < 4; i++)
            {
                id <<= 8;
                id |= ser_num[i];
            }
            
            *card_id = id;
            return 1;
        }
    }
    
    return 0;
}

/* 验证卡片 */
unsigned char rfid_verify_card(unsigned long card_id)
{
    /* 在EEPROM中查找卡片 */
    return eeprom_find_card(card_id);
}

/* 添加卡片 */
unsigned char rfid_add_card(unsigned long card_id)
{
    /* 添加到EEPROM */
    return eeprom_add_card(card_id);
}

/* 删除卡片 */
unsigned char rfid_delete_card(unsigned long card_id)
{
    /* 从EEPROM删除 */
    return eeprom_delete_card(card_id);
}

3.5 EEPROM存储管理

/**
 * @file eeprom.h
 * @brief AT24C02 EEPROM驱动
 */

#ifndef __EEPROM_H
#define __EEPROM_H

#include <reg52.h>

/* 函数声明 */
void eeprom_init(void);
void eeprom_write_byte(unsigned char addr, unsigned char dat);
unsigned char eeprom_read_byte(unsigned char addr);
void eeprom_write_password(unsigned char *pwd);
void eeprom_read_password(unsigned char *pwd);
unsigned char eeprom_add_card(unsigned long card_id);
unsigned char eeprom_delete_card(unsigned long card_id);
unsigned char eeprom_find_card(unsigned long card_id);
unsigned char eeprom_get_card_count(void);
void eeprom_clear_all_cards(void);

/* EEPROM地址分配 */
#define EEPROM_PASSWORD_ADDR  0x00  // 密码存储地址(6字节)
#define EEPROM_CARD_COUNT_ADDR 0x10 // 卡片数量地址(1字节)
#define EEPROM_CARD_LIST_ADDR 0x20  // 卡片列表起始地址(每个卡4字节)

#endif
/**
 * @file eeprom.c
 * @brief EEPROM驱动实现
 */

#include "eeprom.h"
#include <intrins.h>

sbit EEPROM_SCL = P3^2;  // I2C时钟
sbit EEPROM_SDA = P3^3;  // I2C数据

/* I2C起始信号 */
void i2c_start(void)
{
    EEPROM_SDA = 1;
    EEPROM_SCL = 1;
    _nop_();
    EEPROM_SDA = 0;
    _nop_();
    EEPROM_SCL = 0;
}

/* I2C停止信号 */
void i2c_stop(void)
{
    EEPROM_SDA = 0;
    EEPROM_SCL = 1;
    _nop_();
    EEPROM_SDA = 1;
    _nop_();
}

/* I2C发送应答 */
void i2c_ack(void)
{
    EEPROM_SDA = 0;
    EEPROM_SCL = 1;
    _nop_();
    EEPROM_SCL = 0;
    EEPROM_SDA = 1;
}

/* I2C发送非应答 */
void i2c_nack(void)
{
    EEPROM_SDA = 1;
    EEPROM_SCL = 1;
    _nop_();
    EEPROM_SCL = 0;
    EEPROM_SDA = 0;
}

/* I2C接收应答 */
unsigned char i2c_wait_ack(void)
{
    unsigned char ack;
    
    EEPROM_SDA = 1;
    EEPROM_SCL = 1;
    _nop_();
    ack = EEPROM_SDA;
    EEPROM_SCL = 0;
    
    return ack;  // 0:有应答, 1:无应答
}

/* I2C发送一个字节 */
void i2c_send_byte(unsigned char dat)
{
    unsigned char i;
    
    for(i = 0; i < 8; i++)
    {
        EEPROM_SDA = (dat & 0x80) ? 1 : 0;
        dat <<= 1;
        EEPROM_SCL = 1;
        _nop_();
        EEPROM_SCL = 0;
    }
    
    i2c_wait_ack();
}

/* I2C接收一个字节 */
unsigned char i2c_receive_byte(void)
{
    unsigned char i, dat = 0;
    
    EEPROM_SDA = 1;  // 释放数据线
    
    for(i = 0; i < 8; i++)
    {
        EEPROM_SCL = 1;
        _nop_();
        dat <<= 1;
        if(EEPROM_SDA)
            dat |= 0x01;
        EEPROM_SCL = 0;
        _nop_();
    }
    
    return dat;
}

/* EEPROM初始化 */
void eeprom_init(void)
{
    EEPROM_SCL = 1;
    EEPROM_SDA = 1;
}

/* 写一个字节到EEPROM */
void eeprom_write_byte(unsigned char addr, unsigned char dat)
{
    i2c_start();
    i2c_send_byte(0xA0);  // 器件地址+写
    i2c_send_byte(addr);  // 内存地址
    i2c_send_byte(dat);   // 数据
    i2c_stop();
    
    delay_ms(10);  // 写周期等待
}

/* 从EEPROM读取一个字节 */
unsigned char eeprom_read_byte(unsigned char addr)
{
    unsigned char dat;
    
    i2c_start();
    i2c_send_byte(0xA0);  // 器件地址+写
    i2c_send_byte(addr);  // 内存地址
    i2c_start();
    i2c_send_byte(0xA1);  // 器件地址+读
    dat = i2c_receive_byte();
    i2c_nack();
    i2c_stop();
    
    return dat;
}

/* 写入密码 */
void eeprom_write_password(unsigned char *pwd)
{
    unsigned char i;
    
    for(i = 0; i < 6; i++)
    {
        eeprom_write_byte(EEPROM_PASSWORD_ADDR + i, pwd[i]);
    }
}

/* 读取密码 */
void eeprom_read_password(unsigned char *pwd)
{
    unsigned char i;
    
    for(i = 0; i < 6; i++)
    {
        pwd[i] = eeprom_read_byte(EEPROM_PASSWORD_ADDR + i);
    }
}

/* 添加卡片 */
unsigned char eeprom_add_card(unsigned long card_id)
{
    unsigned char count = eeprom_get_card_count();
    
    if(count >= MAX_CARDS)
        return 0;  // 卡片已满
    
    /* 写入卡片ID */
    eeprom_write_byte(EEPROM_CARD_LIST_ADDR + count*4 + 0, (card_id >> 24) & 0xFF);
    eeprom_write_byte(EEPROM_CARD_LIST_ADDR + count*4 + 1, (card_id >> 16) & 0xFF);
    eeprom_write_byte(EEPROM_CARD_LIST_ADDR + count*4 + 2, (card_id >> 8) & 0xFF);
    eeprom_write_byte(EEPROM_CARD_LIST_ADDR + count*4 + 3, card_id & 0xFF);
    
    /* 更新卡片数量 */
    eeprom_write_byte(EEPROM_CARD_COUNT_ADDR, count + 1);
    
    return 1;
}

/* 删除卡片 */
unsigned char eeprom_delete_card(unsigned long card_id)
{
    unsigned char count = eeprom_get_card_count();
    unsigned char i, j;
    unsigned long temp_id;
    
    /* 查找卡片位置 */
    for(i = 0; i < count; i++)
    {
        temp_id = 0;
        temp_id |= eeprom_read_byte(EEPROM_CARD_LIST_ADDR + i*4 + 0) << 24;
        temp_id |= eeprom_read_byte(EEPROM_CARD_LIST_ADDR + i*4 + 1) << 16;
        temp_id |= eeprom_read_byte(EEPROM_CARD_LIST_ADDR + i*4 + 2) << 8;
        temp_id |= eeprom_read_byte(EEPROM_CARD_LIST_ADDR + i*4 + 3);
        
        if(temp_id == card_id)
        {
            /* 找到卡片,删除 */
            for(j = i; j < count-1; j++)
            {
                /* 后面的卡片前移 */
                unsigned char k;
                for(k = 0; k < 4; k++)
                {
                    eeprom_write_byte(EEPROM_CARD_LIST_ADDR + j*4 + k,
                                     eeprom_read_byte(EEPROM_CARD_LIST_ADDR + (j+1)*4 + k));
                }
            }
            
            /* 更新卡片数量 */
            eeprom_write_byte(EEPROM_CARD_COUNT_ADDR, count - 1);
            
            return 1;
        }
    }
    
    return 0;  // 未找到卡片
}

/* 查找卡片 */
unsigned char eeprom_find_card(unsigned long card_id)
{
    unsigned char count = eeprom_get_card_count();
    unsigned char i;
    unsigned long temp_id;
    
    for(i = 0; i < count; i++)
    {
        temp_id = 0;
        temp_id |= eeprom_read_byte(EEPROM_CARD_LIST_ADDR + i*4 + 0) << 24;
        temp_id |= eeprom_read_byte(EEPROM_CARD_LIST_ADDR + i*4 + 1) << 16;
        temp_id |= eeprom_read_byte(EEPROM_CARD_LIST_ADDR + i*4 + 2) << 8;
        temp_id |= eeprom_read_byte(EEPROM_CARD_LIST_ADDR + i*4 + 3);
        
        if(temp_id == card_id)
            return 1;  // 找到卡片
    }
    
    return 0;  // 未找到卡片
}

/* 获取卡片数量 */
unsigned char eeprom_get_card_count(void)
{
    return eeprom_read_byte(EEPROM_CARD_COUNT_ADDR);
}

/* 清空所有卡片 */
void eeprom_clear_all_cards(void)
{
    eeprom_write_byte(EEPROM_CARD_COUNT_ADDR, 0);
}

3.6 管理员菜单

/**
 * @brief 管理员菜单
 */
void admin_menu(void)
{
    unsigned char key;
    
    lcd_clear();
    lcd_write_string("Admin Mode");
    lcd_set_cursor(2, 1);
    lcd_write_string("A:Add D:Del C:ChPwd");
    
    while(1)
    {
        key = keypad_scan();
        
        if(key != 0xFF)
        {
            beep(1, 50);
            
            if(key == KEY_A)  // 添加卡片
            {
                current_state = STATE_ADD_CARD;
                add_new_card();
                return;
            }
            else if(key == KEY_D)  // 删除卡片
            {
                current_state = STATE_DEL_CARD;
                delete_card();
                return;
            }
            else if(key == KEY_C)  // 修改密码
            {
                current_state = STATE_CHANGE_PWD;
                change_password();
                return;
            }
            else if(key == KEY_HASH)  // 返回
            {
                current_state = STATE_WAIT_CARD;
                lcd_clear();
                lcd_write_string("Please scan");
                lcd_set_cursor(2, 1);
                lcd_write_string("your card...");
                return;
            }
        }
    }
}

/**
 * @brief 添加新卡片
 */
void add_new_card(void)
{
    unsigned long card_id = 0;
    unsigned char key;
    
    lcd_clear();
    lcd_write_string("Scan new card...");
    
    while(1)
    {
        /* 检测卡片 */
        if(rfid_check_card(&card_id))
        {
            beep(1, 100);
            
            /* 检查卡片是否已存在 */
            if(rfid_find_card(card_id))
            {
                lcd_clear();
                lcd_write_string("Card exists!");
                delay_ms(2000);
            }
            else
            {
                /* 添加卡片 */
                if(rfid_add_card(card_id))
                {
                    lcd_clear();
                    lcd_write_string("Card added OK!");
                    lcd_set_cursor(2, 1);
                    lcd_write_hex(card_id);
                }
                else
                {
                    lcd_clear();
                    lcd_write_string("Card add failed!");
                }
                delay_ms(2000);
            }
            
            current_state = STATE_ADMIN_MODE;
            admin_menu();
            return;
        }
        
        /* 检查按键 */
        key = keypad_scan();
        if(key == KEY_HASH)  // 返回
        {
            current_state = STATE_ADMIN_MODE;
            admin_menu();
            return;
        }
    }
}

/**
 * @brief 删除卡片
 */
void delete_card(void)
{
    unsigned long card_id = 0;
    unsigned char key;
    
    lcd_clear();
    lcd_write_string("Scan card to del");
    
    while(1)
    {
        /* 检测卡片 */
        if(rfid_check_card(&card_id))
        {
            beep(1, 100);
            
            lcd_clear();
            lcd_write_string("Delete card:");
            lcd_set_cursor(2, 1);
            lcd_write_hex(card_id);
            
            /* 确认删除 */
            lcd_clear();
            lcd_write_string("Confirm delete?");
            lcd_set_cursor(2, 1);
            lcd_write_string("#:Yes *:No");
            
            while(1)
            {
                key = keypad_scan();
                if(key == KEY_HASH)  // 确认
                {
                    if(rfid_delete_card(card_id))
                    {
                        lcd_clear();
                        lcd_write_string("Card deleted!");
                    }
                    else
                    {
                        lcd_clear();
                        lcd_write_string("Delete failed!");
                    }
                    delay_ms(2000);
                    
                    current_state = STATE_ADMIN_MODE;
                    admin_menu();
                    return;
                }
                else if(key == KEY_STAR)  // 取消
                {
                    current_state = STATE_ADMIN_MODE;
                    admin_menu();
                    return;
                }
            }
        }
        
        /* 检查按键 */
        key = keypad_scan();
        if(key == KEY_HASH)  // 返回
        {
            current_state = STATE_ADMIN_MODE;
            admin_menu();
            return;
        }
    }
}

/**
 * @brief 修改密码
 */
void change_password(void)
{
    unsigned char new_password[6];
    unsigned char confirm_password[6];
    unsigned char i, key;
    
    lcd_clear();
    lcd_write_string("Enter old pwd:");
    
    /* 验证旧密码 */
    input_index = 0;
    while(input_index < 6)
    {
        key = keypad_scan();
        if(key <= 9)  // 数字键
        {
            input_buffer[input_index++] = key;
            lcd_set_cursor(2, input_index);
            lcd_write_char('*');
        }
        else if(key == KEY_HASH)  // 提前确认
        {
            break;
        }
    }
    
    /* 验证密码 */
    for(i = 0; i < 6; i++)
    {
        if(input_buffer[i] != password[i])
        {
            lcd_clear();
            lcd_write_string("Wrong password!");
            delay_ms(2000);
            current_state = STATE_ADMIN_MODE;
            admin_menu();
            return;
        }
    }
    
    /* 输入新密码 */
    lcd_clear();
    lcd_write_string("Enter new pwd:");
    
    input_index = 0;
    while(input_index < 6)
    {
        key = keypad_scan();
        if(key <= 9)  // 数字键
        {
            new_password[input_index++] = key;
            lcd_set_cursor(2, input_index);
            lcd_write_char('*');
        }
    }
    
    /* 确认新密码 */
    lcd_clear();
    lcd_write_string("Confirm new pwd:");
    
    input_index = 0;
    while(input_index < 6)
    {
        key = keypad_scan();
        if(key <= 9)  // 数字键
        {
            confirm_password[input_index++] = key;
            lcd_set_cursor(2, input_index);
            lcd_write_char('*');
        }
    }
    
    /* 验证两次输入是否一致 */
    for(i = 0; i < 6; i++)
    {
        if(new_password[i] != confirm_password[i])
        {
            lcd_clear();
            lcd_write_string("Not match!");
            delay_ms(2000);
            current_state = STATE_ADMIN_MODE;
            admin_menu();
            return;
        }
    }
    
    /* 更新密码 */
    for(i = 0; i < 6; i++)
    {
        password[i] = new_password[i];
    }
    
    /* 保存到EEPROM */
    eeprom_write_password(password);
    
    lcd_clear();
    lcd_write_string("Password changed!");
    delay_ms(2000);
    
    current_state = STATE_ADMIN_MODE;
    admin_menu();
}

参考 基于51单片机的门禁系统 www.youwenfan.com/contentcnv/70702.html

四、PCB设计与元件清单

4.1 元件清单

元件 型号/参数 数量 备注
MCU STC89C52/AT89C51 1 8位单片机
晶振 11.0592MHz 1 系统时钟
电容 30pF 2 晶振负载
电容 10μF/16V 1 复位电容
电容 0.1μF 若干 去耦电容
电阻 10kΩ 1 上拉电阻
电阻 1kΩ 4 LED限流
电阻 220Ω 8 LCD偏置
按钮 6×6×5mm 1 复位按钮
RFID模块 RC522 1 13.56MHz
LCD 1602 1 字符液晶
矩阵键盘 4×4 1 薄膜键盘
继电器 5V/10A 1 控制门锁
二极管 1N4007 1 继电器保护
三极管 8050 1 继电器驱动
蜂鸣器 5V有源 1 提示音
LED 红色/绿色 各1 状态指示
门磁传感器 干簧管 1 门状态检测
EEPROM AT24C02 1 数据存储
稳压芯片 LM7805 1 5V稳压
电源接口 DC-005 1 12V输入

4.2 PCB布局建议

正面布局:
┌─────────────────────┐
│  LCD1602 显示器     │
├─────────────────────┤
│  矩阵键盘 (4×4)     │
├─────────────────────┤
│ RFID天线  LED指示灯 │
├─────────────────────┤
│  STC89C52 单片机    │
└─────────────────────┘

背面布局:
电源接口 → 稳压电路 → 单片机电源
继电器驱动电路
蜂鸣器驱动电路
EEPROM电路
门磁检测电路

五、系统测试与调试

5.1 测试程序

/**
 * @file test_system.c
 * @brief 系统测试程序
 */

void test_all_modules(void)
{
    unsigned char i;
    
    /* 测试LCD */
    lcd_clear();
    lcd_write_string("System Test");
    delay_ms(1000);
    
    /* 测试LED */
    LED_GREEN = 0;
    delay_ms(500);
    LED_GREEN = 1;
    LED_RED = 0;
    delay_ms(500);
    LED_RED = 1;
    
    /* 测试蜂鸣器 */
    for(i = 0; i < 3; i++)
    {
        BUZZER = 1;
        delay_ms(100);
        BUZZER = 0;
        delay_ms(100);
    }
    
    /* 测试继电器 */
    RELAY = 1;
    delay_ms(1000);
    RELAY = 0;
    
    /* 测试键盘 */
    lcd_clear();
    lcd_write_string("Test Keypad:");
    lcd_set_cursor(2, 1);
    
    while(1)
    {
        unsigned char key = keypad_scan();
        if(key != 0xFF)
        {
            lcd_write_char('0' + key);
            beep(1, 50);
        }
        
        if(key == KEY_HASH)  // 按#键退出
            break;
    }
    
    /* 测试RFID */
    lcd_clear();
    lcd_write_string("Test RFID:");
    lcd_set_cursor(2, 1);
    lcd_write_string("Scan card...");
    
    unsigned long card_id;
    while(!rfid_check_card(&card_id))
    {
        // 等待刷卡
    }
    
    lcd_clear();
    lcd_write_string("Card ID:");
    lcd_set_cursor(2, 1);
    lcd_write_hex(card_id);
    
    delay_ms(2000);
    
    /* 测试完成 */
    lcd_clear();
    lcd_write_string("Test Complete!");
}

六、使用说明

6.1 基本操作

  1. 刷卡开门:刷卡→门自动打开
  2. 密码开门:刷卡→输入6位密码→确认
  3. 管理功能:按A键→输入管理密码→进入管理菜单
  4. 添加卡片:管理菜单→A键→刷卡
  5. 删除卡片:管理菜单→D键→刷卡
  6. 修改密码:管理菜单→C键→输入旧密码→输入新密码

6.2 默认设置

七、扩展功能建议

7.1 无线通信模块

/* 添加WiFi/蓝牙模块 */
void wireless_send_status(unsigned char status, unsigned long card_id)
{
    /* 通过网络发送门禁状态到手机 */
    // 实现TCP/UDP通信
}

7.2 指纹识别模块

/* 集成指纹模块 */
void fingerprint_init(void)
{
    // 初始化指纹模块
}

unsigned char fingerprint_verify(void)
{
    // 指纹验证
    return 1;  // 成功
}

7.3 摄像头模块

/* 人脸识别 */
void face_recognition_init(void)
{
    // 初始化摄像头
}

专注于matlab/simulink,电子电路,编程