基于51单片机的智能门禁系统
基于AT89C51/STC89C52的门禁系统设计,包含RFID卡、矩阵键盘、LCD显示、继电器控制等功能。
一、系统总体设计
1.1 系统功能
- RFID卡识别:EM4100/ID卡或Mifare卡
- 密码输入:4×4矩阵键盘
- 用户界面:LCD1602显示
- 门锁控制:继电器驱动电磁锁
- 状态指示:LED指示灯、蜂鸣器
- 数据存储:AT24C02存储用户信息
- 管理功能:添加/删除卡、修改密码
- 实时时钟:DS1302记录时间
- 报警功能:非法闯入检测
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 基本操作
- 刷卡开门:刷卡→门自动打开
- 密码开门:刷卡→输入6位密码→确认
- 管理功能:按A键→输入管理密码→进入管理菜单
- 添加卡片:管理菜单→A键→刷卡
- 删除卡片:管理菜单→D键→刷卡
- 修改密码:管理菜单→C键→输入旧密码→输入新密码
6.2 默认设置
- 管理密码:123456
- 开门时间:10秒
- 最大卡片数:50张
- 密码尝试次数:3次
七、扩展功能建议
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)
{
// 初始化摄像头
}