RFID课程设计

您所在的位置:网站首页 rfid门禁密码更换 RFID课程设计

RFID课程设计

2024-07-13 01:24| 来源: 网络整理| 查看: 265

RFID课程设计–智能门禁系统 前言

  本次课程设计要求如下,我们团队两人完成了90%的功能。   其中我们设置的是刷卡错误3次不报警,密码输入错3次报警(原理相同,大家根据需要自行修改)   然后暂时只能显示卡号和卡是第几个录入到系统中的,想到身份证号和电话(身份信息)输进去有点长就没花太多心思,想实现这个功能会写卡就可以了。这是我的队友 kiro_1023 在这里插入图片描述

最初版设计

STM32RCT6+RC522+OLED,刷卡显示卡号

完整版工程文件下载链接

RFID课程设计工程文件,基于STM32F103RCT6的智能门禁系统

摘要

  本次课程设计项目完成了一款以STM32F103RCT6单片机为控制中心门禁系统设计。通过RC522模块实现录入卡和刷卡身份识别的功能;4*4矩阵按键模块实现密码的输入和功能的切换;继电器模块和电磁铁控制控制门的开关;DHT11模块采集室内温湿度数据;OLED显示屏显示菜单和各类数据。刷卡验证和密码的验证给门禁系统添加了双重的保险,简约的OLED显示的交互页面在保证信息显示完整的同时也极大地减少了用户的阅读量,降低了操作难度,方便使用。

文章目录 RFID课程设计--智能门禁系统前言 最初版设计完整版工程文件下载链接摘要 一、系统的功能描述二、系统整体设计2.1方案描述2.2系统整体设计流程 三、硬件单元的接口连接设计3.1 硬件总体接线设计 四、软件详细设计五、核心函数描述和注释.c文件内函数简介(有注释,主要提供大家思路main.c:个人认为比较精髓的代码(可能是因为是自己理解然后自己写出来的):矩阵键盘行列扫描函数:输入密码开关门函数:修改密码功能函数:刷卡解锁功能函数:录入卡操作函数: 六、系统调试过程七、结论与改进最初版设计完整版工程文件下载链接

一、系统的功能描述

首先有四个功能

A刷卡解锁 B输入密码解锁 C录入卡 D修改密码

A功能使用一个大数组card_sql[101],存放卡的卡号   存放格式为 1字节序号 4字节卡号   通过刷卡获取的卡号与passwd数组内的卡号按格式校对,成功则开门,并在OLED上显示DHT11温湿度数据

B功能使用两个数组   passwd_scan输入数据缓冲数组   passwd当前密码存放数组   读取按键输入的有效键值存放到passwd_scan中,输入4位后将passwd_scan的四位数据与passwd的四位密码进行一一校对 成功则返回成功标志,失败则返回失败标志 失败三次,报警,只能按*退出

C功能为录入不在card_sql中的卡号   用追加的方式,将序号和卡号添加到card_sql中 如果卡已经在库中会显示卡已存在而不进行录入

D功能是B功能的延伸   先输入旧密码,读取按键输入的有效键值存放到passwd_scan中,输入4位后将passwd_scan的四位数据与passwd的四位密码进行一一校对,如果密码认证成功 输入新密码   同样以读取按键输入的有效键值存放到passwd_scan中,输入4位后将passwd_scan的四位数据与passwd的四位密码进行替换 实现新密码的录入

二、系统整体设计 2.1方案描述

本作品通过四个功能解决门禁系统的基本设计要求,分别为A刷卡解锁,B密码解锁,C录入卡号,D修改密码。 通过OLED屏对作品的功能选择进行显示,还能够显示刷卡后状态以及密码输入的状态,利用矩阵按键控制门禁系统的功能选择以及密码输入部分,采用DHT11温湿度传感器模块接收实时的温湿度数据并从OLED屏上显示,开门部分则采用电磁铁模拟小区内开关门的控制部分。系统总体设计框图如图1-1所示。 在这里插入图片描述

图1-1 系统总体设计框图

注:来自队友的制作 这是我的队友 kiro_1023

2.2系统整体设计流程

  系统功能流程图如图1-2所示,初始化完成后,OLED屏首先显示菜单界面,等待用户利用44矩阵按键选择功能。   若选择A功能则进入刷卡解锁功能,RC522能够识别并判断通过程序内存储的卡号控制电磁铁开门,同时OLED屏显示刷卡开门的卡号和卡内的身份,三秒后显示当地的温湿度数据,如果卡号并非程序内存储的卡号,则会提示刷正确的卡。   若选择B功能则进入密码解锁功能,用户输入四位密码与存储密码的数组比较,若正确则显示开门,三秒后显示当地的温湿度数据,如果密码错误则提示用户再输入一次,若用户输入错误密码超过三次,OLED屏则显示该功能已被禁用,只能按“”键退出该功能。   若选择C功能则进入录入信息功能,用户可将程序内没有存储的卡进行刷卡,刷卡后OLED屏会显示卡录入成功并显示卡号,如果用程序内已经存储的卡录入信息,OLED屏则会提示该卡已经存在。   若选择D功能则进入修改密码功能,用户需要先输入旧密码让程序进行与旧密码进行比对,若密码正确则进入修改密码界面,用户可以输入新的四位密码修改密码,若用户输入错误密码超过三次,OLED屏则显示该功能已被禁用,只能按“*”键退出该功能。 来自队友的制作

图1-2 系统功能流程图

注:来自队友的制作 这是我的队友 kiro_1023

三、硬件单元的接口连接设计 3.1 硬件总体接线设计

硬件总体接线原理图如图2-1所示,在本系统中,我们采用STM32F103RCT6控制RC522射频模块、OLED屏、4*4矩阵键盘等模块来实现基本功能,并利用电磁铁模拟小区内门禁系统的开关门状态。 在这里插入图片描述

图2-1 硬件总体接线原理图

图中详细描述了各个模块与单片机各引脚的链接关系。

四、软件详细设计

  我们的软件系统一共设计了4个功能,分别是A刷卡解锁、B输入密码解锁、C录入新卡、D修改密码。软件总体设计思路如图3-1所示。 在这里插入图片描述

图3-1 总体软件设计流程图   对应的程序代码实现如图3-2所示。该部分代码主要依靠JZKEY_Scan()函数来获取按键的键值,从而根据用户输入的按键信息才判断进入哪个功能,代码中’N’表示无按键按下。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/613ed9a4847b4345ba23b8adc1f18305.png#pic_center) 图3-2 主函数核心代码

  刷卡解锁的软件设计思路如图3-3所示。 在这里插入图片描述

图3-3 刷卡解锁软件流程图   当用户按下A进入A刷卡解锁模式后,单片机开始循环执行card_unlock()函数。card_sql数组存放了已录入卡的卡,内部存放卡号的规则为,1字节的卡的序号,4字节卡号;i 用于规定匹配次数;falg_sql用于操作card_sql数组指针;size存放card_sql的大小;card_bit存放当前卡在card_sql中的序号,如果没有匹配到相同的卡号则card_bit为0。在寻到卡并且防碰撞循环成功后,刷卡获取的卡号存放到了数组SN中。将SN数组内存放的内容与card_sql数组的内容一一进行比对,如果匹配成功则返回当前卡在card_sql中的序号,如果未匹配到则返回0。若寻卡或防碰撞循环失败则会返回255。图3-4为card_unlock()函数的核心代码。

在这里插入图片描述

图3-4 card_unlock()函数核心代码

  密码解锁功能流程图如图3-5所示。 在这里插入图片描述

图3-5 密码解锁软件流程图   当用户按下按键B进入密码解锁模式后,单片机开始循环执行entry_passwd()函数。p_lock_passwd数组内存放了初始密码;lock_passwd指针指向p_lock_passwd的首地址,用来与后面用户输入的密码相比较。   在entry_passwd()函数中会不断调用JZKEY_Scan(0)函数来获取当前用户输入的密码值并按顺序存入scan_key数组中。同时程序中定义了num变量用于判断当前密码输入的位数,我们规定当输入密码为4位时(num为4时)开始对密码进行验证。密码验证的过程就是将scan_key数组的内容与lock_passwd指针指向的p_lock_passwd数组里的内容进行逐位比较,完全匹配则返回正确的标志’R’,密码错误则返回’W’并亮红灯警告。

在这里插入图片描述

图3-6 密码解锁功能核心代码   在亮灯警告的基础上,如果出现3次连续的密码错误会LED闪烁报警并锁定密码解锁功能。该功能的实现的关键在于变量warning,一开始先定义warning为0,当用户输入错误后warning会自增1并判断warning的值是否大于3,若大于3则程序进入报警的死循环,只能按退出键返回主界面且不能在当前情况下进行其他任何操作,输入密码错误核心代码如图3-7所示。

在这里插入图片描述

图3-7 输入密码错误核心代码   录入信息功能流程图如图3-8所示。

在这里插入图片描述

图3-8录入信息软件流程图   当用户按下B进入B录入信息功能后,单片机开始循环执行card_infor_entry()函数。录入信息的功能是建立在刷卡解锁功能的基础之上的。两者区别在于,录入卡时若匹配到相同的卡号则表明该卡已经录入过,若未匹配到则将该卡的序号和卡号追加到card_sql数组中。其中OLED显示屏一次只能显示一个字符,而卡号的高低位只用了一个字节存放在数组SN中,所以在程序中使用到了指针oled_use_p,将数组SN中存放的卡号经过特定的计算方法拆分成高低位来进行显示。录入信息核心代码如图3-9所示。 *(oled_use_p++) = ((SN[0]>>4)>9)?(SN[0]>>4)-10+'a':(SN[0]>>4)+'0'; *(oled_use_p++) = ((SN[0]&0x0f)>9)?(SN[0]&0x0f)-10+'a':(SN[0]&0x0f)+'0';

在这里插入图片描述

图3-10录入信息核心代码   其中数组card_sql的总长度为101字节,可存放20张卡的卡号。起始位置的1表示第一张卡,后面四字节的卡号为学号为20191110056的学生的校园卡的卡序列号。

在这里插入图片描述

图3-11数组card_sql的具体内容截图   修改密码软件流程图如图3-10所示。

在这里插入图片描述

图3-11修改密码软件流程图

  修改密码的功能是密码解锁功能的延伸。当用户按下D进入修改密码模式后,单片机开始循环执行change_passwd()函数。   在change_passwd()函数中会经历输入旧密码的过程,此时输入旧密码的操作和密码解锁的操作完全相同。当旧密码输入正确后,进入新密码的输入循环,此时变量changePasswd用于存放输入新密码的位数,数组scan_key用来存放输入的密码值,当changePasswd等于4时表示已经输入了4位新密码,紧接着进入修改密码的操作。由于程序中lock_passwd指针指向的是存放初始密码的数组p_lock_passwd的首地址,所以修改密码就是将数组scan_key的值逐位赋给数组lock_passwd,从而实现密码替换的效果,若此时再进入密码解锁功能进行解锁时就需要输入新密码。

在这里插入图片描述

图3-12 修改密码核心代码 五、核心函数描述和注释 .c文件内函数简介(有注释,主要提供大家思路 main.c:

在这里插入图片描述

个人认为比较精髓的代码(可能是因为是自己理解然后自己写出来的):

因为卡号是4字节数据,而OELD显示屏的函数每次只能显示1个字符即半字节,例如:卡号为3B42A921,虽然使用%X%X%X%X在串口可以打印出来,但对于OLED显示屏中我们需要数据分位高低位存入长度为八字节的数组来依次显示。 OLED是通过

//将刷卡的卡号存入主函数的显示数组 *(oled_use_p++) = ((SN[0]>>4)>9) ?(SN[0]>>4)-10+'a' :(SN[0]>>4)+'0'; *(oled_use_p++) = ((SN[0]&0x0f)>9)?(SN[0]&0x0f)-10+'a':(SN[0]&0x0f)+'0'; *(oled_use_p++) = ((SN[1]>>4)>9) ?(SN[1]>>4)-10+'a' :(SN[1]>>4)+'0'; *(oled_use_p++) = ((SN[1]&0x0f)>9)?(SN[1]&0x0f)-10+'a':(SN[1]&0x0f)+'0'; *(oled_use_p++) = ((SN[2]>>4)>9) ?(SN[2]>>4)-10+'a' :(SN[2]>>4)+'0'; *(oled_use_p++) = ((SN[2]&0x0f)>9)?(SN[2]&0x0f)-10+'a':(SN[2]&0x0f)+'0'; *(oled_use_p++) = ((SN[3]>>4)>9) ?(SN[3]>>4)-10+'a' :(SN[3]>>4)+'0'; *(oled_use_p++) = ((SN[3]&0x0f)>9)?(SN[3]&0x0f)-10+'a':(SN[3]&0x0f)+'0'; *(oled_use_p++) = '\0';

刷卡成功后的DHT11数据显示函数

relay = 1;//继电器关闭,电磁铁不通电 OLED_ShowString(0,4,"T=");//oled显示 OLED_ShowString(48,4,"H="); DHT11_Read_Data(&temp,&humi);//DHT11获取温湿度,存入temp(温度),humi(湿度) TandH[0] = temp/10+'0';//存放高位 TandH[1] = temp%10+'0';//存放低位 TandH[2] = '%'; TandH[3] = '\0'; TandH[4] = humi/10+'0'; TandH[5] = humi%10+'0'; TandH[6] = '%'; TandH[7] = '\0'; p = TandH; OLED_ShowString(16,4,p);//OLED_ShowString是遇到'\0'停止打印 p = TandH+4; OLED_ShowString(64,4,p); 矩阵键盘行列扫描函数: //mode:0,不支持连续按;1,支持连续按; u8 JZKEY_Scan(u8 mode) { delay_init(); if(mode) { key0_up=1; key1_up=1; key2_up=1; key3_up=1; key4_up=1; key5_up=1; key6_up=1; key7_up=1; key8_up=1; key9_up=1; keyA_up=1; keyB_up=1; keyC_up=1; keyD_up=1; keyX_up=1; keyJ_up=1; } //第一行 Hang_00_L;//把第一行输出低电平 Hang_01_H; Hang_02_H; Hang_03_H; if(key1_up&&Lie_00_V==0) { delay_ms(jpys); //延时20秒,软件消抖 key1_up=0; if(Lie_00_V==0) //如果第一列是低电平,说明有键被按下,如果没有直接退出if语句 { return '1'; } }else if(Lie_00_V==1)key1_up=1; if(key2_up&&Lie_01_V==0)//如果第二列是低电平, { delay_ms(jpys);//延时20秒,软件消抖 key2_up=0; if(Lie_01_V==0)//如果第二列是低电平,说明有键被按下,如果没有直接退出if语句 { return '2'; } }else if(Lie_01_V==1)key2_up=1; if(key3_up&&Lie_02_V==0) { delay_ms(jpys); key3_up=0; if(Lie_02_V==0) { return '3'; } }else if(Lie_02_V==1)key3_up=1; if(keyA_up&&Lie_03_V==0)//如果第四列是低电平 { delay_ms(jpys); keyA_up=0; if(Lie_03_V==0)//如果第四列是低电平,说明有键被按下,如果没有直接退出if语句 { return 'A'; } }else if(Lie_03_V==1)keyA_up=1; //第二行 Hang_00_H; Hang_01_L;//把第二行拉低 Hang_02_H; Hang_03_H; if(key4_up&&Lie_00_V==0)//如果第一列是低电平 { delay_ms(jpys); key4_up=0; if(Lie_00_V==0)//说明有键被按下,如果没有直接退出if语句 { return '4'; } }else if(Lie_00_V==1)key4_up=1; if(key5_up&&Lie_01_V==0) { delay_ms(jpys); key5_up=0; if(Lie_01_V==0) { return '5'; } }else if(Lie_01_V==1)key5_up=1; if(key6_up&&Lie_02_V==0) { delay_ms(jpys); key6_up=0; if(Lie_02_V==0) { return '6'; } }else if(Lie_02_V==1)key6_up=1; if(keyB_up&&Lie_03_V==0) { delay_ms(jpys); keyB_up=0; if(Lie_03_V==0) { return 'B'; } }else if(Lie_03_V==1)keyB_up=1; //第三行 Hang_00_H; Hang_01_H; Hang_02_L;//把第三行置低 Hang_03_H; if(key7_up&&Lie_00_V==0) //如果第一列是低电平 { delay_ms(jpys);//延时20秒 key7_up=0; if(Lie_00_V==0)//说明有键被按下,如果没有直接退出if语句 { return '7'; } }else if(Lie_00_V==1)key7_up=1; if(key8_up&&Lie_01_V==0) { delay_ms(jpys); key8_up=0; if(Lie_01_V==0) { return '8'; } }else if(Lie_01_V==1)key8_up=1; if(key9_up&&Lie_02_V==0) { delay_ms(jpys); key9_up=0; if(Lie_02_V==0) { return '9'; } }else if(Lie_02_V==1)key9_up=1; if(keyC_up&&Lie_03_V==0) { delay_ms(jpys); keyC_up=0; if(Lie_03_V==0) { return 'C'; } }else if(Lie_03_V==1)keyC_up=1; //第四行 Hang_00_H; Hang_01_H; Hang_02_H; Hang_03_L;//把第四行置低 if(keyX_up&&Lie_00_V==0)//如果第一列是低电平 { delay_ms(jpys); keyX_up=0; if(Lie_00_V==0)//说明有键被按下,如果没有直接退出if语句 { return '*'; } }else if(Lie_00_V==1)keyX_up=1; if(key0_up&&Lie_01_V==0) { delay_ms(10); key0_up=0; if(Lie_01_V==0) { return '0'; } }else if(Lie_01_V==1)key0_up=1; if(keyJ_up&&Lie_02_V==0)//如果第三列是低电平 { delay_ms(jpys); keyJ_up=0; if(Lie_02_V==0)//说明有键被按下,如果没有直接退出if语句 { return '#'; } }else if(Lie_02_V==1)keyJ_up=1; if(keyD_up&&Lie_03_V==0) { delay_ms(jpys); keyD_up=0; if(Lie_03_V==0) { return 'D'; } }else if(Lie_03_V==1)keyD_up=1; return 'N';//无按键按下,返回N } 输入密码开关门函数: /*********************** 输入密码开关门 思路:形参为 主函数中密码存放的数组的首地址 在函数中声明一个数组,用来存放按键输入的密码 输入4位密码后,自动使用指针位运算与密码表内容进行比对 完全匹配则返回给主函数一个开门指令'R' ***********************/ u8 entry_passwd(u8 * lock_passwd) //输入密码,开关门 { u8 temp = 'N'; //定义临时变量,用来存放按键键值 if((temp=JZKEY_Scan(0))!='N') //判断,按键按下时进入(不按按键返回N) { if(temp=='*') { for(num=0;num4)>9) ?(SN[1]>>4)-10+'a' :(SN[1]>>4)+'0'; *(oled_use_p++) = ((SN[1]&0x0f)>9)?(SN[1]&0x0f)-10+'a':(SN[1]&0x0f)+'0'; *(oled_use_p++) = ((SN[2]>>4)>9) ?(SN[2]>>4)-10+'a' :(SN[2]>>4)+'0'; *(oled_use_p++) = ((SN[2]&0x0f)>9)?(SN[2]&0x0f)-10+'a':(SN[2]&0x0f)+'0'; *(oled_use_p++) = ((SN[3]>>4)>9) ?(SN[3]>>4)-10+'a' :(SN[3]>>4)+'0'; *(oled_use_p++) = ((SN[3]&0x0f)>9)?(SN[3]&0x0f)-10+'a':(SN[3]&0x0f)+'0'; *(oled_use_p++) = '\0'; if(card_bit == 0)//卡不存在,录入卡 { *(oled_use_p) = size/5+1; oled_use_p = p; card_sql[size] = size/5+1; card_sql[size+1]=SN[0]; card_sql[size+2]=SN[1]; card_sql[size+3]=SN[2]; card_sql[size+4]=SN[3]; card_sql[size+5]='\0'; printf("SN:\r\n"); ShowID(SN); printf("card_sql:\r\n"); for(i=0;card_sql[i]!='\0';i++) { printf("%x",card_sql[i]); } printf("wrong card\r\n"); return 0; } else//此时card_bit为卡在caed_sql数组的序号值 { printf("卡已经存在!\r\n");//卡已经存在 return card_bit; } } printf("no card\r\n"); return 255;//未寻到卡返回255 } 六、系统调试过程

1菜单显示 在这里插入图片描述

2刷卡解锁显示身份 在这里插入图片描述

3显示温湿度 在这里插入图片描述

4密码解锁 在这里插入图片描述

5.0密码解锁显示温湿度 在这里插入图片描述

5.1输入错误密码显示密码错误(默认密码1234) 在这里插入图片描述

6输入三次错误密码显示密码解锁功能被禁用 在这里插入图片描述

7C功能录入新卡 在这里插入图片描述

8录入新卡成功显示卡号 在这里插入图片描述

9再用该卡录入信息_显示卡已存在 在这里插入图片描述

10用新卡开门_门开了 在这里插入图片描述

11换新密码(1234换为5555) 在这里插入图片描述

12换新密码成功 在这里插入图片描述

13用新密码解锁成功 在这里插入图片描述

七、结论与改进

  函数中间涉及到指针的操作,也可以不用指针操作,只是想到在练习C语言基础正好拿这个项目训练一下逻辑思维。这只是第一版代码,后期还有很多需要修改的地方。   完成本课程设计需要一些单片机基础和RC522使用基础(学习RC522可看这篇博客,这是该博主花费三天凝结的智慧结晶 基于STM32的RC522模块读写数据块以及电子钱包充值扣款系统的设计)   对于本次课程设计,感觉它是一个对代码的逻辑能力要求比较高的课设,从选择功能、录入新卡、刷卡解锁到密码解锁、修改密码,都要求我们需要有清醒的代码逻辑意识。   最好的解决方法是先列一个清单说出要完成的功能,然后分块去逐个完成它们。写代码时,可以先从dev C++中编写C语言程序来模拟存储卡到模拟数据库中的逻辑和密码存储部分的逻辑。   在改进方面,希望可以获得卡号后直接对卡进行读写操作来进行身份检测。因为第一版没有用上读写卡功能,并且不好删除卡。 暂时想到的第二版方案是:   录入卡,就是往特定的扇区写特定的数据 刷卡开门就是读块数据,如果读到的是和预先写入的是相同信息就开门 如果想删除卡,那就把块内信息进行清空处理(写0)

大家有更好的办法也可以在评论区一起讨论。

最初版设计

STM32RCT6+RC522+OLED,刷卡显示卡号

完整版工程文件下载链接

RFID课程设计工程文件,基于STM32F103RCT6的智能门禁系统



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3