门禁系统
系统流程图
-
系统框图
-
系统流程图
-
系统引脚配置
/*************************************************
*
*
*
* P0^0 ------- 步进电机1
* P0^1 ------- 步进电机2
* P0^2 ------- 步进电机3
* P0^3 ------- 步进电机4
*
* P1^1 ------- OLED的SDA
* P1^2 ------- OLED的SCL
*
* P1^3 ------- RFID的SDA
* P1^4 ------- RFID的SCK
* P1^5 ------- RFID的MOSI
* P1^6 ------- RFID的MISO
* P1^7 ------- RFID的RQ
*
* P2^0 ------- AT24C02的SCL
* P2^1 ------- AT24C02的SDA
*
* P2^3 ------- BUZZER
* P2^5 ------- Error LED
* P2^6 ------- OK LED
*
* P3^0 ------- 矩阵键盘引脚0
* P3^1 ------- 矩阵键盘引脚1
* P3^2 ------- 矩阵键盘引脚2
* P3^3 ------- 矩阵键盘引脚3
* P3^4 ------- 矩阵键盘引脚4
* P3^5 ------- 矩阵键盘引脚5
* P3^6 ------- 矩阵键盘引脚6
* P3^7 ------- 矩阵键盘引脚7
*
*
*
**************************************************/
代码分析
- 代码结构构成
main.h
#ifndef __MAIN_H__
#define __MAIN_H__
#include "common.h"
#include "user_passwd.h"
#include "keyboard.h"
#include "iic.h"
#include "oled.h"
#include "rc522.h"
#include<mfrc522.h>
#endif
/*************************************************
*
* 引脚配置信息
*
* P0^0 ------- 步进电机1
* P0^1 ------- 步进电机2
* P0^2 ------- 步进电机3
* P0^3 ------- 步进电机4
*
* P1^1 ------- OLED的SDA
* P1^2 ------- OLED的SCL
*
* P1^3 ------- RFID的SDA
* P1^4 ------- RFID的SCK
* P1^5 ------- RFID的MOSI
* P1^6 ------- RFID的MISO
* P1^7 ------- RFID的RQ
*
* P2^0 ------- AT24C02的SCL
* P2^1 ------- AT24C02的SDA
*
* P2^3 ------- BUZZER
* P2^5 ------- Error LED
* P2^6 ------- OK LED
*
* P3^0 ------- 矩阵键盘引脚0
* P3^1 ------- 矩阵键盘引脚1
* P3^2 ------- 矩阵键盘引脚2
* P3^3 ------- 矩阵键盘引脚3
* P3^4 ------- 矩阵键盘引脚4
* P3^5 ------- 矩阵键盘引脚5
* P3^6 ------- 矩阵键盘引脚6
* P3^7 ------- 矩阵键盘引脚7
*
*
*
**************************************************/
main.c
#include "main.h"
#define NO_TIMER2 //RFID.c中,STC12系列无定时器2
/*******************
* 引用全局变量
********************/
extern uchar key_flag; //按键标志位
extern uchar admin_passwd[]; //存储管理员密码
extern uchar passwd[]; //存储用户密码
extern uchar key_num; //矩阵按键返回值
extern UGroup G[]; //UGroup结构体变量,定义与rc522.h头文件中
extern Tips code lines[]; //Tips结构体类型OLED.h头文件中,用于存储显示信息
extern key_table code table[];//key_table结构体类型,定义与OLED.h头文件中,用于定义跳转函数
extern uchar code BMP1[]; //存储的图片
extern uchar func_index; //func函数下标变量
extern uchar UID_S50[]; //存储S50卡卡号,4字节
extern uchar Temp_S50[]; //临时存储S50卡卡号变量
/**********************
* 系统临时变量
***********************/
uchar TEMP;
bit OUT = 0;
/**********************
* 函数声明
***********************/
void (*current_operation_index)(); //指针函数声明
void Timer0Init(); //定时中断0函数声明
/**********************
* Main主函数
***********************/
void main(){
RFID_Init(); //RFID初始化
OLED_Init(); //OLED初始化
enterMenu(); //开机LOGO
Delay1000ms(); //延时1秒,稳定系统
read_UID_From_EEPROM(G); //读取存储在AT24C02中的UID用户ID
#if 0 //调试代码,可忽略
at24c02Write(19,0);//存储卡号的标志位
save_passwd_EEPROM(passwd,6);//保存用户密码到AT24C02
#endif
if(read_passwd_EEPROM(passwd,6)) showOK(); //从AT24C02中读取user passwd用户密码,必须的
OLED_CLS(); //OLED显示:欢迎回家
OLED_P16x16Ch(23,3,4);
OLED_P16x16Ch(40,3,5);
OLED_P16x16Ch(57,3,6);
OLED_P16x16Ch(74,3,7);
Timer0Init(); //定时器0初始化
while(1) //while大循环
{
if(key_flag == 1) //矩阵按键标志位
{
if(key_num == 12)//进入菜单
{
showOK(); //提示OK
//第一个函数值获取下一个函数号码;第二个函数是执行获取后的函数。
current_operation_index = table[func_index].current_operation; (*current_operation_index)();
while(!OUT) //检测菜单函数的退出与否的while循环
{
TEMP = getDir();//内置while循环
if(TEMP){
current_operation_index = table[func_index].current_operation; (*current_operation_index)();
}
key_flag = 0;
}
//第一个函数值获取下一个函数号码;第二个函数是执行获取后的函数。
current_operation_index = table[func_index].current_operation; (*current_operation_index)();
//各个标志位复位
OUT = 0;
TEMP = 0;
func_index = 0;
key_flag = 0;
}
if((key_num == 14)&&verif_user_passwd())//按井号键开始验证密码
{
key_flag = 0;
showOK();
EA = 0; //关闭所有中断
OLED_CLS();
OLED_P8x16Str(0,0,"Door Is Opening.");
Delay500ms();
OLED_CLS(); //显示:欢迎回家
OLED_P16x16Ch(23,3,4);
OLED_P16x16Ch(40,3,5);
OLED_P16x16Ch(57,3,6);
OLED_P16x16Ch(74,3,7);
MotroOpenDoor();
EA = 1;
key_flag = 0;
}
else
{
showError(); //错误提示
key_flag = 0;
}
key_num = 0;
}
else
{
Auto_Reader(); //RFID扫描函数
}
}
}
void Timer0Init() //2毫秒@11.0592MHz//
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0xCD; //设置定时初值
TH0 = 0xF8; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
EA = 1;
}
void time0() interrupt 1
{
TL0 = 0xCD; //设置定时初值
TH0 = 0xF8; //设置定时初值
keyscanf_maxtrix();
}
keyboard.h
#ifndef __KEYBOARD_H__
#define __KEYBOARD_H__
#include "common.h"
#include "oled.h"
void keyscanf_maxtrix();
uchar get_onece_keyboard();
#endif
/*****************************************************
* 4*4矩阵键盘按键说明:
*
* - 上键: keyscanf_maxtrix扫描值:3 再赋值 10
* - 下键: keyscanf_maxtrix扫描值:15 再赋值 15
* - 左键: keyscanf_maxtrix扫描值:7 再赋值 11
* - 右键: keyscanf_maxtrix扫描值:11 再赋值 13
* - 井号键:keyscanf_maxtrix扫描值:14 再赋值 14
* - 星号键:keyscanf_maxtrix扫描值:12 再赋值 12
*
* - 星号键进入菜单 值为 12
* - 井号键为确定键 值为 14
*
****************************************************/
keyboard.c
#include "keyboard.h"
uchar key_flag = 0;//标志位
uchar key_num = 16;//默认为"-"
uchar get_onece_keyboard() //得到一个值,while循环
{
static uchar i = 0;
uchar temp = 99;
if(key_flag == 1)
{
key_flag = 0;
while(temp == 99)
{
switch(key_num)
{
case 0: temp = 1; break;
case 1: temp = 2; break;
case 2: temp = 3; break;
case 3: temp = 10; break; //上
case 4: temp = 4; break;
case 5: temp = 5; break;
case 6: temp = 6; break;
case 7: temp = 11; break; //左
case 8: temp = 7; break;
case 9: temp = 8; break;
case 10: temp = 9; break;
case 11: temp = 13; break; //右
case 12: temp = 12; break; //星号
case 13: temp = 0; break;
case 14: temp = 14; break; //井号
case 15: temp = 15; break; //下
}
}
/*************************************
* 按键又被按下,OLED上会有提示
*************************************/
EA = 0;
if(i%2==0)
{
OLED_P8x16Str(0,6,". ");
}
else
{
OLED_P8x16Str(0,6," .");
}
i++;if(i==6){
i = 0;}
EA = 1;
}
key_flag = 0;
return temp;
}
/**********************************
* 矩阵扫描函数
* 占用8个IO口,进行行的扫描
**********************************/
void keyscanf_maxtrix()
{
if(key_flag == 0){
uchar i;
uchar cycle = 0xfe;
for(i=0;i<4;i++){
uchar temp;
P3 = cycle;
temp = P3;
temp = temp&0xf0;
if(temp!=0xf0)
{
if(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xee:
key_num=0;
key_flag = 1;
break;
case 0xde:
key_num=1;
key_flag = 1;
break;
case 0xbe:
key_num=2;
key_flag = 1;
break;
case 0x7e:
key_num=3;
key_flag = 1;
break;
case 0xed:
key_num=4;
key_flag = 1;
break;
case 0xdd:
key_num=5;
key_flag = 1;
break;
case 0xbd:
key_num=6;
key_flag = 1;
break;
case 0x7d:
key_num=7;
key_flag = 1;
break;
case 0xeb:
key_num=8;
key_flag = 1;
break;
case 0xdb:
key_num=9;
key_flag = 1;
break;
case 0xbb:
key_num=10;
key_flag = 1;
break;
case 0x7b:
key_num=11;
key_flag = 1;
break;
case 0xe7:
key_num=12;
key_flag = 1;
break;
case 0xd7:
key_num=13;
key_flag = 1;
break;
case 0xb7:
key_num=14;
key_flag = 1;
break;
case 0x77:
key_num=15;
key_flag = 1;
break;
}
}
}
while(temp!=0xf0) //按键松手后,跳出循环,防止多按
{
temp=P3;
temp=temp&0xf0;
}
cycle = _crol_(cycle,1);//循环左移
}
}
}
user_passwd.h
#ifndef __USER_PASSWD__
#define __USER_PASSWD__
#include "common.h"
#include "keyboard.h"
#include "iic.h"
#include "rc522.h"
#include "mfrc522.h"
void get_six_number(uchar *arr);
bit modify_admin_passwd();
bit verif_user_passwd();
bit compare_two_four_number(uchar *arr1, uchar *arr2);
bit verif_admin_passwd();
bit modify();
bit read_passwd_EEPROM(uchar *arr,uchar num);
bit save_passwd_EEPROM(uchar *arr, uchar num);
void Auto_Reader();
bit verif_CardID_from_EEPROM(uchar arr[]);
#endif
user_passwd.c
#include "user_passwd.h"
extern uchar key_flag;
extern uchar key_num;
extern uchar UID_S50[]; //S50卡,4字节
extern uchar Temp_S50[]; //S50卡,4字节
extern UGroup G[]; //S50卡组
uchar admin_passwd[6] = {
2,3,2,3,2,3}; //初始化,管理员密码,非缓存区
uchar passwd[6] = {
5,5,5,5,5,5}; //初始化用户密码,缓存区
/*****************************
* 函数功能:
*
******************************/
/*****************************
* 函数功能:从键盘得到六位数字
* 参数:数组名
******************************/
void get_six_number(uchar *arr)
{
uchar i;
for(i = 0; i < 6; i++){
key_flag = 0;
while(key_flag != 1);
*arr = get_onece_keyboard();
arr++;
}
}
/*****************************
* 函数功能:修改超级用户密码
******************************/
bit modify_admin_passwd()
{
get_six_number(admin_passwd);
return 1;
}
/*****************************
* 函数功能:修改用户密码
******************************/
bit modify_user_passwd()
{
get_six_number(passwd);
return 1;
}
/*****************************
* 函数功能:比较两组六位数的数组
******************************/
bit compare_two_six_number(uchar *arr1, uchar *arr2)
{
uchar i;
for(i = 0; i < 6; i++){
if((*arr1) != (*arr2)) return 0;
arr1++;
arr2++;
}
return 1;
}
/*****************************
* 函数功能:比较两组4位数的数组
******************************/
bit compare_two_four_number(uchar *arr1, uchar *arr2)
{
uchar i;
for(i = 0; i < 4; i++){
if((*arr1) != (*arr2)) return 0;
arr1++;
arr2++;
}
return 1;
}
/*****************************
* 函数功能:验证管理员密码
******************************/
bit verif_admin_passwd()
{
uchar temp[6];
get_six_number(temp);
if(compare_two_six_number(temp,admin_passwd))
return 1;
else
return 0;
}
/*****************************
* 函数功能:验证用户密码
******************************/
bit verif_user_passwd()
{
uchar temp[6];
get_six_number(temp);
if(compare_two_six_number(temp,passwd))
return 1;
else
return 0;
}
/*****************************
* 函数功能:修改用户密码函数
******************************/
bit modify()
{
if(verif_admin_passwd())//输入并验证 管理员密码admin_passwd
{
key_flag = 0;
showOK();
{
EA=0;OLED_CLS();OLED_P8x16Str(30,3,"Right!");Delay500ms();OLED_CLS();OLED_P8x16Str(30,0,"Contine,");OLED_P8x16Str(0,4,"Enter N Passwd");EA=1;}//OLED提示
if(modify_user_passwd()) //修改用户密码user_passwd
{
save_passwd_EEPROM(passwd,6);
{
EA=0;OLED_CLS();OLED_P8x16Str(10,4,"Updated Passwd!");Delay500ms();EA=1;}
showOK();
key_flag = 0;
return 1;
}
else{
EA=0;OLED_CLS();OLED_P8x16Str(0,0,"Failed!");Delay500ms();EA=1;return 0;}
}
else{
{
EA=0;OLED_CLS();OLED_P8x16Str(0,0,"Failed!");Delay500ms();EA=1;return 0;}
}
}
/*****************************
* 函数功能:从EEPROM中去读用户密码
* 用户密码存储地址:9-14位
******************************/
bit read_passwd_EEPROM(uchar *arr,uchar num)
{
uchar i = 0;
EA = 0; //关闭所有中断
for(i = 0; i < num; i++)
{
*arr = at24c02Read(9+i);
arr++;
showOK();
Delay20ms();//延时以稳定AT24C02芯片
}
EA = 1;//恢复所有中断
return 1;
}
/*****************************
* 函数功能:将用户密码存储在EEPROM中
* 用户密码存储地址:9-14位
******************************/
bit save_passwd_EEPROM(uchar *arr, uchar num) //保存用户密码
{
uchar i = 0;
EA = 0;
for(i = 0; i < num; i++)
{
at24c02Write(9+i,*arr);
Delay20ms();
showOK();
arr++;
}
EA = 1;
return 1;
}
/*****************************
* 函数功能:将读取的卡号
******************************/
bit verif_CardID_from_EEPROM(uchar arr[]){
uchar ii = 0;
for(ii = 0; ii<10; ii++){
if(compare_two_four_number(G[ii].UID,arr)) return 1;
else continue;
}
return 0;
}
void Auto_Reader()
{
if(PcdRequest(0x52,Temp_S50) == MI_OK)
{
//寻卡,成功后Temp数组为卡类型
if(PcdAnticoll(UID_S50)== MI_OK )
{
//防冲突,UID数组数据为卡序列号
showOK();
// if(compare_two_four_number(UUID,UID_S50)) {showOK();MotroOpenDoor();}
if(verif_CardID_from_EEPROM(UID_S50)) {
showOK();MotroOpenDoor();}
}
}
}
common.h
#ifndef __COMMON_H__
#define __COMMON_H__
#include "reg52.h"
#include "intrins.h"
#include "string.h"
#define OSC_FREQ 11059200L //系统晶振选择
#define RCAP2_50us 65536L - OSC_FREQ/40417L
#define RCAP2_1ms 65536L - OSC_FREQ/2000L
#define RCAP2_10ms 65536L - OSC_FREQ/1200L
#define TIME0_500us 65536L - OSC_FREQ/8000L
#define TIME0_10ms 65536L - OSC_FREQ/200
#define TRUE 1
#define FALSE 0
sfr AUXR = 0x8e; //辅助寄存器
typedef unsigned int uint;
typedef unsigned char uchar;
/***************************
* 系统状态提示声明
****************************/
void showError();
void showOK();
/***************************
* 软件延时函数声明
****************************/
void delay(uint z);
void Delay1ms() ;
void Delay2ms();
void Delay20ms(); //@11.0592MHz
void Delay100ms();
void Delay200ms(); //@11.0592MHz
void Delay500ms(); //@11.0592MHz
void Delay1000ms();
/***************************
* 步进电机驱动函数
****************************/
void MotroOpenDoor();
#endif
common.c
#include "common.h"
#define MotorData P0
sbit Error = P2^5; //Red led
sbit OK = P2^6; //Green led
sbit buzzer_ = P2^3;//蜂鸣器
/***************************
* 步进电机位置数组//这没说不太准确,详细请搜索五线四向步进电机原理
****************************/
uchar idata motor_arrA[4] = {
0x08,0x04,0x02,0x01};
uchar idata motor_arrB[4] = {
0x01,0x02,0x04,0x08};
void delay(uint z)
{
uchar x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void Delay1ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
void Delay2ms() //@11.0592MHz
{
unsigned char i, j;
i = 22;
j = 128;
do
{
while (--j);
} while (--i);
}
void Delay4ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 44;
j = 3;
do
{
while (--j);
} while (--i);
}
void Delay20ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 1;
j = 216;
k = 35;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay100ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 5;
j = 52;
k = 195;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay200ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 9;
j = 104;
k = 139;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 22;
j = 3;
k = 227;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 43;
j = 6;
k = 203;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void showOK(){
OK = 0;
buzzer_ = 0;
Delay200ms();
OK = 1;
buzzer_ = 1;
Delay200ms();
}
void showError()
{
Error = 0;
buzzer_ = 0;
Delay200ms();
Error = 1;
buzzer_ = 1;
Delay200ms();
Error = 0;
buzzer_ = 0;
Delay200ms();
Error = 1;
buzzer_ = 1;
Delay200ms();
}
void MotorTurnA() //步进电机正向
{
uchar i;
for(i = 0; i <4; i++)
{
MotorData = motor_arrA[i];
Delay4ms();
}
}
void MotorTurnB() //步进电机正向
{
uchar i;
for(i=0;i<4;i++)
{
MotorData = motor_arrB[i];
Delay4ms();//转速调节
}
}
void MotorStop() //步进电机停止
{
MotorData=0x00;
}
void MotroOpenDoor()
{
uchar i;
for(i=0;i<200;i++)
{
dula = 0;
wela = 0;
MotorTurnA(); //顺时针转动
}
MotorStop(); //停止转动
Delay500ms();
for(i=0;i<200;i++)
{
dula = 0;
wela = 0;
MotorTurnB(); //逆时针转动
}
MotorStop(); //停止转动
Delay500ms();
}
iic.h
#ifndef _IIC_H__
#define _IIC_H__
#include "common.h"
#include "rc522.h"
/***********************
* iic基本驱动函数
***********************/
void IIC_Start(void);
void IIC_Stop(void);
void IIC_Ack(bit ackbit);
void IIC_SendByte(unsigned char byt);
bit IIC_WaitAck(void);
unsigned char IIC_RecByte(void);
/***********************
* EEPROM读写函数
***********************/
void at24c02Write(uchar addr, uchar dat); //写
uchar at24c02Read(uchar addr); // 读
void at24c02ReadStr(uchar addr, uchar num, uchar *getStr);
void at24c02WriteStr(uchar addr, uchar *p,uchar num);
/***********************
* 用户组G的读取和存储
***********************/
void save_UID_In_EEPROM(uchar *arr);
void read_UID_From_EEPROM(UGroup G[]);
void clearAll();//清除全部UID
#endif
iic.c
#include "iic.h"
#define somenop; _nop_(); //调节通信延时长短
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
//总线引脚定义
sbit SDA = P2^1; /* 数据线 */
sbit SCL = P2^0; /* 时钟线 */
extern UGroup G[];
//总线启动条件
void IIC_Starts(void)
{
SDA = 1;
SCL = 1;
somenop;
SDA = 0;
somenop;
SCL = 0;
}
//总线停止条件
void IIC_Stops(void)
{
SDA = 0;
SCL = 1;
somenop;
SDA = 1;
}
//应答位控制
void IIC_Ack(bit ackbit)
{
if(ackbit)
{
SDA = 0;
}
else
{
SDA = 1;
}
somenop;
SCL = 1;
somenop;
SCL = 0;
SDA = 1;
somenop;
}
//等待应答
bit IIC_WaitAck(void)
{
SDA = 1;
somenop;
SCL = 1;
somenop;
if(SDA)
{
SCL = 0;
IIC_Stops();
return 0;
}
else
{
SCL = 0;
return 1;
}
}
//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0;i<8;i++)
{
if(byt&0x80)
{
SDA = 1;
}
else
{
SDA = 0;
}
somenop;
SCL = 1;
byt <<= 1;
somenop;
SCL = 0;
}
}
//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++)
{
SCL = 1;
somenop;
da <<= 1;
if(SDA)
da |= 0x01;
SCL = 0;
somenop;
}
return da;
}