RFID课程设计--基于STM32F103RCT6的智能门禁系统,STM32RCT6+RC522+OLED+DHT11+4*4矩阵键盘

这篇具有很好参考价值的文章主要介绍了RFID课程设计--基于STM32F103RCT6的智能门禁系统,STM32RCT6+RC522+OLED+DHT11+4*4矩阵键盘。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

前言

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

最初版设计

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

完整版工程文件下载链接

RFID课程设计工程文件,基于STM32F103RCT6的智能门禁系统文章来源地址https://www.toymoban.com/news/detail-793897.html

摘要

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


一、系统的功能描述

首先有四个功能

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所示。
rfid课程设计,STM32,stm32,单片机,嵌入式硬件

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

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

2.2系统整体设计流程

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

图1-2 系统功能流程图

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

三、硬件单元的接口连接设计

3.1 硬件总体接线设计

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

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

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

四、软件详细设计

  我们的软件系统一共设计了4个功能,分别是A刷卡解锁、B输入密码解锁、C录入新卡、D修改密码。软件总体设计思路如图3-1所示。
rfid课程设计,STM32,stm32,单片机,嵌入式硬件

图3-1 总体软件设计流程图
  对应的程序代码实现如图3-2所示。该部分代码主要依靠JZKEY_Scan()函数来获取按键的键值,从而根据用户输入的按键信息才判断进入哪个功能,代码中’N’表示无按键按下。 rfid课程设计,STM32,stm32,单片机,嵌入式硬件
图3-2 主函数核心代码

  刷卡解锁的软件设计思路如图3-3所示。
rfid课程设计,STM32,stm32,单片机,嵌入式硬件

图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()函数的核心代码。

rfid课程设计,STM32,stm32,单片机,嵌入式硬件

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

  密码解锁功能流程图如图3-5所示。
rfid课程设计,STM32,stm32,单片机,嵌入式硬件

图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’并亮红灯警告。

rfid课程设计,STM32,stm32,单片机,嵌入式硬件

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

rfid课程设计,STM32,stm32,单片机,嵌入式硬件

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

rfid课程设计,STM32,stm32,单片机,嵌入式硬件

图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';

rfid课程设计,STM32,stm32,单片机,嵌入式硬件

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

rfid课程设计,STM32,stm32,单片机,嵌入式硬件

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

rfid课程设计,STM32,stm32,单片机,嵌入式硬件

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

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

rfid课程设计,STM32,stm32,单片机,嵌入式硬件

图3-12 修改密码核心代码

五、核心函数描述和注释

.c文件内函数简介(有注释,主要提供大家思路

main.c:

rfid课程设计,STM32,stm32,单片机,嵌入式硬件

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

因为卡号是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;num<4;num++)					//输入一半返回时,输入缓冲区清零
				scan_key[num] = '\0';
				num=0;
				return 0;
			}
				
			scan_key[num] = temp;							//把输入的密码存入scan_key数组
			//printf("scan_key=%c\n",scan_key[num]);
			num++;														//计数++,输入密码的位数
			OLED_ShowString(56,2,scan_key);		//显示屏显示输入的密码
		}
//		printf("num=%d",num);
		if(num==4)													//如果输入了四位密码
		{
																			//先将计数清零
			if(*(lock_passwd++)==scan_key[0]&&*(lock_passwd++)==scan_key[1]&&*(lock_passwd++)==scan_key[2]&&*(lock_passwd++)==scan_key[3])//逐位判断密码是否和密码表密码相同
			{
				OLED_ShowString(56,2,"    ");//OLED显示passwd区域清除
				for(num=0;num<4;num++)			//密码缓冲区清零
					scan_key[num]='\0';	
				num = 0;										//num归零,防止再进入if
				lock_passwd = lock_passwd-4;//密码表指针回到0位
				return 'R';									//返回开门指令
			}
			else
			{

				OLED_ShowString(0,4,"Wrong passwd!!");
				for(num=0;num<4;num++)			//密码缓冲区清零
				scan_key[num]='\0';
				num = 0;										//num归零,防止再进入if
				LED1 = 0;
				delay_ms(20000);						//红灯亮以示警告
				delay_ms(20000);
				LED1 = 1;
				OLED_ShowString(56,2,"    ");//OLED显示passwd区域清除
				if(++warning==3)
				{
					warning = 0;
					OLED_Clear();
					while(1)									//错误3次,死循环,led闪烁报警,只能按*返回主页面
					{
						OLED_ShowString(0,0,"Password has been disabled!Please contact the administrator!");
						LED1 = !LED1;
						LED0 = !LED0;
						delay_ms(50);
						
						if(JZKEY_Scan(0)=='*')
						{
							LED1=1;
							LED0=1;
							OLED_Clear();
							return 0;
						}
					}

				}
			}
		}
		return 'W';											//返回关门指令
}
/***********************
输入密码开关门
***********************/

修改密码功能函数:

/***********************
修改密码
***********************/

u8 change_passwd(u8 * lock_passwd)				//输入密码,开关门
{
		u8 changePasswd=0;
		u8 temp = 'N';											//定义临时变量,用来存放按键键值
	
		OLED_ShowString(0,2,"OldPasswd:");		//显示屏显示输入的密码
	
		if((temp=JZKEY_Scan(0))!='N')				//判断,按键按下时进入(不按按键返回N)
		{
			if(temp=='*')
			{
				
				for(num=0;num<4;num++)					//输入一半返回时,输入缓冲区清零
				scan_key[num] = '\0';
				num=0;
				return 0;
			}
			
			scan_key[num] = temp;							//把输入的密码存入scan_key数组
			//printf("scan_key=%c\n",scan_key[num]);
			num++;														//计数++,输入密码的位数
			OLED_ShowString(80,2,scan_key);		//显示屏显示输入的密码
		}

		if(num==4)													//如果输入了四位密码
		{
																			//先将计数清零
			if(*(lock_passwd++)==scan_key[0]&&*(lock_passwd++)==scan_key[1]&&*(lock_passwd++)==scan_key[2]&&*(lock_passwd++)==scan_key[3])//逐位判断密码是否和密码表密码相同
			{
				OLED_ShowString(80,2,"    ");
				OLED_ShowString(0,2,"NewPasswd:");
				for(num=0;num<4;num++)					//输入缓冲区清零
					scan_key[num] = '\0';
				while(1)
				{
					
					if((temp=JZKEY_Scan(0))!='N')				//判断,按键按下时进入(不按按键返回N)
						{
							if(temp=='*')
								{
									
									for(num=0;num<4;num++)					//输入一半返回时,输入缓冲区清零
									scan_key[num] = '\0';
									num=0;
									changePasswd=0;
									return 0;
								}
									
							scan_key[changePasswd] = temp;							//把输入的密码存入scan_key数组
							//printf("scan_key=%c\n",scan_key[num]);
							changePasswd++;														//计数++,输入密码的位数
							OLED_ShowString(80,2,scan_key);		//显示屏显示输入的密码
						}
							if(changePasswd==4)
								{
									lock_passwd = lock_passwd-4;//密码表指针回到0位
									*(lock_passwd++)=scan_key[0];//修改密码
									*(lock_passwd++)=scan_key[1];
									*(lock_passwd++)=scan_key[2];
									*(lock_passwd++)=scan_key[3];
									for(num=0;num<4;num++)					//输入缓冲区清零
										scan_key[num] = '\0';
									num=0;
									return 'R';
								}
				}

			}
			else
			{

				OLED_ShowString(0,4,"Wrong passwd!!");
				for(num=0;num<4;num++)			//密码缓冲区清零
				scan_key[num]='\0';
				num = 0;										//num归零,防止再进入if
				LED1 = 0;
				delay_ms(20000);						//红灯亮以示警告
				delay_ms(20000);
				LED1 = 1;
				OLED_ShowString(80,2,"    ");//OLED显示passwd区域清除
				OLED_ShowString(0,4,row_clear);//OLED显示passwd区域清除
				if(++warning1==3)
				{
					warning1 = 0;
					OLED_Clear();
					while(1)									//错误3次,死循环,led闪烁报警,只能按*返回主页面
					{
						OLED_ShowString(0,0,"Password has been disabled!Please contact the administrator!");
						LED1 = !LED1;
						LED0 = !LED0;
						delay_ms(50);
						
						if(JZKEY_Scan(0)=='*')
						{
							LED1=1;
							LED0=1;
							OLED_Clear();
							return 0;
						}
					}

				}
			}
		}
		return 'W';											//返回关门指令
}
/***********************
修改密码
***********************/

刷卡解锁功能函数:

u8 card_unlock(void)
{
	u8 i = 0;//用于规定匹配次数
	u8 falg_sql = 1;//用于操作card_sql数组指针
	u8 size=0;//存放card_sql的大小
	u8 card_bit=0;//存放卡在card_sql中的序号
	//unsigned char test_addr=0x0F;
	status = PcdRequest(PICC_REQALL,CT);//寻卡
	if(status==MI_OK)// 寻卡成功
    {
        status=MI_ERR;
        status = PcdAnticoll(SN);// 防冲撞 获得UID 存入SN
    }
	if (status==MI_OK)// 防冲撞成功
    {
		size = strlen(card_sql);//size存放card_sql的实际长度
        status = MI_ERR;
        ShowID(SN); // 串口打印卡的ID号 UID
      for(i=0;i<(size/5);i++)
			{
				//先size存放card_sql数组的长度,每5位为一张卡的信息,一字节序号,四字节卡号
				if((SN[0]==card_sql[falg_sql])&&(SN[1]==card_sql[falg_sql+1])&&(SN[2]==card_sql[falg_sql+2])&&(SN[3]==card_sql[falg_sql+3]))	//刷卡后的卡号与单片机内部的卡数据库进行比较
						{
								card_bit=card_sql[falg_sql-1];
								printf("\r\nThe User is:num%d\r\n",falg_sql);
						}
					falg_sql += 5;//让数组位置指向下一张卡的序号信息处
						printf("card_bit=%d\r\n",card_bit);
					
			 }
			 if(card_bit == 0)//card_bit默认值为0,若进行数据匹配后仍为0则表示,卡的信息没有录入,为无效卡
			{
				printf("wrong card\r\n");
				return 0;
			}
			
			else//此时card_bit为卡在caed_sql数组的序号值
			{
				return card_bit;
			}
    }
		printf("no card\r\n");
		return 255;//未寻到卡返回255

}

录入卡操作函数:

u8 card_infor_entry(u8 * oled_use_p)//oled_use_p指向主函数的显示数组
{
	u8 i = 0;//用于规定匹配次数
	u8 falg_sql = 1;//用于操作card_sql数组指针
	u8 size=0;//存放card_sql的大小
	u8 card_bit=0;//存放卡在card_sql中的序号
	u8 *p = oled_use_p;
	status = PcdRequest(PICC_REQALL,CT);//寻卡
	if(status==MI_OK)// 寻卡成功
    {
        status=MI_ERR;
        status = PcdAnticoll(SN);// 防冲撞 获得UID 存入SN
    }
	if (status==MI_OK)// 防冲撞成功
    {
			size = strlen(card_sql);//size存放card_sql的实际长度
			printf("size=%d\r\n",size);
        status = MI_ERR;
        ShowID(SN); // 串口打印卡的ID号 UID
      for(i=0;i<(size/5);i++)
			{
				//先size存放card_sql数组的长度,每5位为一张卡的信息,一字节序号,四字节卡号
				if((SN[0]==card_sql[falg_sql])&&(SN[1]==card_sql[falg_sql+1])&&(SN[2]==card_sql[falg_sql+2])&&(SN[3]==card_sql[falg_sql+3]))	//刷卡后的卡号与单片机内部的卡数据库进行比较
						{
								card_bit=card_sql[falg_sql-1];
								printf("\r\nThe User is:num%d\r\n",falg_sql);
						}
					falg_sql += 5;//让数组位置指向下一张卡的序号信息处
					printf("card_bit=%d\r\n",card_bit);
					
			 }//匹配卡结束
			//将刷卡的卡号存入主函数的显示数组
			*(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';

			 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菜单显示
rfid课程设计,STM32,stm32,单片机,嵌入式硬件

2刷卡解锁显示身份
rfid课程设计,STM32,stm32,单片机,嵌入式硬件

3显示温湿度
rfid课程设计,STM32,stm32,单片机,嵌入式硬件

4密码解锁
rfid课程设计,STM32,stm32,单片机,嵌入式硬件

5.0密码解锁显示温湿度
rfid课程设计,STM32,stm32,单片机,嵌入式硬件

5.1输入错误密码显示密码错误(默认密码1234)
rfid课程设计,STM32,stm32,单片机,嵌入式硬件

6输入三次错误密码显示密码解锁功能被禁用
rfid课程设计,STM32,stm32,单片机,嵌入式硬件

7C功能录入新卡
rfid课程设计,STM32,stm32,单片机,嵌入式硬件

8录入新卡成功显示卡号
rfid课程设计,STM32,stm32,单片机,嵌入式硬件

9再用该卡录入信息_显示卡已存在
rfid课程设计,STM32,stm32,单片机,嵌入式硬件

10用新卡开门_门开了
rfid课程设计,STM32,stm32,单片机,嵌入式硬件

11换新密码(1234换为5555)
rfid课程设计,STM32,stm32,单片机,嵌入式硬件

12换新密码成功
rfid课程设计,STM32,stm32,单片机,嵌入式硬件

13用新密码解锁成功
rfid课程设计,STM32,stm32,单片机,嵌入式硬件

七、结论与改进

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

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

最初版设计

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

完整版工程文件下载链接

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

到了这里,关于RFID课程设计--基于STM32F103RCT6的智能门禁系统,STM32RCT6+RC522+OLED+DHT11+4*4矩阵键盘的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32F103RCT6 介绍

    ==================================================================================== 2、 LQFP 封装结构 3、 LQFP封装结构 4、芯片资源介绍(很久以前,面试的时候有被别人问到过,还要介绍32 的时钟系统) 4.1 内核 ① 32-bits ARM Cortex-M3 CPU ② 72 Mhz 主频 ③ 256Kb to 512Kb flash(RCT6 是256Kb) 4.2 时钟系统

    2024年02月13日
    浏览(24)
  • 学STM32(STM32F103RCT6)

    第一章 了解STM32 为什么使用STM32而不是8051? 是因为51的频率太低,无法满足计算需求?是51的管脚太少,无法满足众多外设的IO? 是51的功耗太大,电池挺不住?是51的功能太弱,而你要使用SPI、I2C、ADC、DMA? 是51的内存太小而你要存储的东西太多? 当你需要使用STM32某些功能,而51实

    2023年04月09日
    浏览(17)
  • 基于STM32F103RCT6之手把手教你写智能家居项目(2)

            上一节我们简述了智能家居项目,实现了点灯的相关代码编写,还有WIFI模块的固件烧录。 连接什么平台:         我们想要远程控制家具的开关和获取家中的状态,少不了一个可以传输数据的云平台。我认为易监控是一个简单好用的云平台。 怎么连接平台:

    2024年02月20日
    浏览(21)
  • stm32f103rct6引脚功能表格

    脚号 引脚名称 主功能 默认复用 重定义 备注 1             VBAT VBAT -- -- 说明1 2             PC13-TAMPER-RTC PC13 TAMPER-RTC -- 说明3 3             PC14-OSC32_IN PC14 OSC32_IN -- 说明3 4             PC15-OSC32_OUT PC15 OSC32_OUT -- 说明3 5             OSC_IN OSC_IN -- CAN_RX 晶振

    2024年02月06日
    浏览(18)
  • STM32F103RCT6——定时器简单用法

    STM32F10xx参考手册英文和中文版 百度网盘:https://pan.baidu.com/s/1Z2nB0WVJIxvm3VOI9MQiiw 提取码:lxlx STM32F103RCT6数据手册 链接:https://pan.baidu.com/s/1tRchgf-5C1MN4W58vQ9zPg 提取码:lxlx STM32F103RCT6包括,高级控制定时器TIM1和TIM8,通用定时器TIM2-5,基本定时器TIM6和TIM7. 高级控制定时器TIM1,TI

    2024年02月08日
    浏览(28)
  • stm32f103rct6使用内部晶振作为时钟源

    stm32f103rct6(库函数版例程)使用内部晶振8M,倍频64M 参考 https://blog.csdn.net/oHuanCheng/article/details/105112884 http://www.openedv.com/forum.php?mod=viewthreadtid=286233 https://blog.csdn.net/ll148305879/article/details/106138302 修改system_stm32f10x.c文件中的void SystemInit(void)函数 内部时钟用到了FLASH,需要添加s

    2024年02月07日
    浏览(22)
  • 从零开始制作STM32F103RCT6小车(一)

            仅以此系列给实验室的学弟学妹作为小车制作教程来使用,后续的内容我会在这个暑假陆续更新出来,本篇的内容是新建一个适用于STM32F103RCT6的工程         接下来的操作几乎是基于STM32F1xx系列的固件库,这里我给大家列出链接 STM32F1xx系列固件库               

    2023年04月08日
    浏览(26)
  • stm32F103RCT6使用FFT运算分析波形详解(细致教学)

    最近学校电赛队伍招新,出的招新题就是低频示波器的。之前一直没有弄懂FFT,借着这次机会实现了一下,做了一个小示波器 FFT原理简述 FFT,就是快速傅里叶变换,这个操作能够将时域信号转化成频域信号,然后对信号进行分析 这样说可能有点抽象。讲细点就是指能够直观

    2024年02月14日
    浏览(22)
  • STM32F103RCT6驱动SG90舵机-完成正反转角度控制

    SG90是一种微型舵机,也被称为伺服电机。它是一种小型、低成本的直流电机,通常用于模型和机器人控制等应用中。SG90舵机可以通过电子信号来控制其精确的位置和速度。它具有体积小、重量轻、响应快等特点,因此在各种小型机械设备上得到了广泛应用。 SG90舵机通常用于

    2024年02月03日
    浏览(35)
  • STM32F103RCT6开发板M3单片机教程06--定时器中断

    除非特别说明,本章节描述的模块应用于整个 STM32F103xx 微控制器系列,因为我们使用是 STM32F103RCT6开发板是mini最小系统板。 本教程使用是( 光明谷SUN_STM32mini开发板 )   首先了解一下是STM32F10X定时器(Timer)   注: 小容量产品是指闪存存储器容量在16K至32K字节之间的STM32F101

    2024年02月04日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包