基于STM32的智能门锁安防系统(开源)

目录

项目演示

项目概述

硬件组成:

功能实现

1. 开锁模式

1.1 按键密码开锁

1.2 门禁卡开锁

1.3 指纹开锁

2. 功能备注

3. 硬件模块工作流程

3.1 步进电机控制

3.2 蜂鸣器提示

3.3 OLED显示

3.4 指纹与卡片管理

项目源代码分析

1. 主程序流程 (main.c)

1.1 开机界面

1.2 主界面

1.3 开锁功能

2. 指纹录入与删除

3.门禁卡的录入

4. 数据存储与恢复

完整的main.c文件

总结


项目演示

基于STM32的智能门锁安防系统-CSDN直播

项目概述

智能门锁安防系统是一种集成了多种开锁方式的安全系统,采用STM32单片机作为核心控制器,配备多种硬件设备,如OLED显示器、RC522门禁卡模块、AS608指纹模块、4x4矩阵按键、步进电机、蜂鸣器等,旨在为家庭或企业提供更加安全和便利的门禁系统。该系统支持三种开锁方式:密码锁、门禁卡、指纹识别。

硬件组成:

  • STM32F103C8T6:主控芯片,处理所有的控制任务。
  • OLED显示器:用于显示系统状态、信息、时间等。
  • RC522门禁卡模块:实现RFID卡的读写,支持门禁卡开锁。
  • AS608指纹模块:用于指纹识别,实现指纹开锁。
  • 4x4矩阵按键模块:用于输入密码,实现密码开锁。
  • 步进电机模块:驱动门锁的开关。
  • 蜂鸣器模块:用于提醒用户操作结果,如密码错误、开锁成功等。

功能实现

1. 开锁模式

本系统支持三种开锁方式,每种方式都具有一定的安全性,用户可以根据实际需求选择合适的方式进行解锁:

1.1 按键密码开锁

用户通过按键输入密码进行开锁,密码是可以修改的,用户可以根据需要设置和修改密码。每次输入密码后,系统会对比预设的密码,并决定是否开锁。

1.2 门禁卡开锁

使用RC522门禁卡模块,通过读取门禁卡的信息进行开锁。用户可以录入新的门禁卡,系统会根据用户输入的卡号进行验证,如果匹配成功,则开锁。

1.3 指纹开锁

使用AS608指纹模块,通过指纹识别实现开锁。用户可以录入多个指纹,并通过指纹验证进行开锁。如果验证通过,系统自动解锁。

2. 功能备注

  • 修改密码:用户可以随时修改开锁密码,提供更好的安全性。
  • 添加/删除功能:可以添加新的指纹、门禁卡、密码,支持删除已录入的指纹、门禁卡、密码。
  • 内部Flash存储:系统支持通过内部Flash存储数据,保证即使在掉电情况下,密码、指纹和门禁卡信息仍然能够保留,下次上电时可以继续使用。

3. 硬件模块工作流程

3.1 步进电机控制

步进电机负责锁的物理开关,通过与STM32的GPIO端口连接,可以在接收到开锁命令时,驱动电机打开或关闭锁。

3.2 蜂鸣器提示

蜂鸣器用于提供音响提示,比如开锁成功、密码错误等操作结果。蜂鸣器会根据不同的状态发出不同的声音。

3.3 OLED显示

OLED显示器显示系统的当前状态,包括时间、密码输入界面、开锁提示等信息,增强了用户的交互体验。

3.4 指纹与卡片管理

指纹模块(AS608)与RFID卡模块(RC522)是门锁系统的两大身份验证方式。系统通过这些模块读取指纹和门禁卡信息,并将其与预存的数据库进行比对,判断是否开锁。

项目源代码分析

1. 主程序流程 (main.c)

系统启动后,主程序执行硬件初始化,包括初始化OLED显示器、步进电机、蜂鸣器、按键、指纹模块、门禁卡模块等。然后系统进入主循环,根据用户输入的操作,进行密码验证、指纹识别、门禁卡识别等。

1.1 开机界面
void starting(void)
{OLED_Clear();Show_Str(16,12,128,16,"智能门锁系统",16,0);OLED_Refresh_Gram();delay_ms(2000);
}

在开机时,OLED显示器显示“智能门锁系统”,并延时2秒。

1.2 主界面
			/********************主界面**************************/MENU:OLED_Clear();
MENUNOCLR:OLED_Fill(0,0,20,48,0);//主页菜单显示if(arrow<3){Show_Str(5,arrow*16,128,16,"->",16,0);//显示箭头set=0;}else {Show_Str(5,(arrow-3)*16,128,16,"->",16,0);set=3;}Show_Str(25,0,128,16,setup[set],16,0);Show_Str(25,16,128,16,setup[set+1],16,0);Show_Str(25,32,128,16,setup[set+2],16,0);Show_Str(0,52,128,12,"上    下     确定",12,0);OLED_Refresh_Gram();//更新显示time2=0;while(1){//超时锁屏time2++;if(time2>10000 | key_num==4){  OLED_Clear();DisLock();if(time2>10000)beep_on_mode2();time2 =0;
//								delay_ms(1000);OLED_Clear();goto MAIN;}//手机蓝牙锁定if(memcmp(USART_RX_BUF,"LOCK",4)==0)	{
//							USART_RX_STA=0;
//							memset(USART_RX_BUF,0,USART_REC_LEN);DisLock();goto MAIN;}//功能选项选择key_num=Button4_4_Scan();	if(key_num){if(key_num==13){if(arrow>0)arrow--;goto MENUNOCLR;}if(key_num==15){if(arrow<MaxParaNum-1)arrow++;goto MENUNOCLR;}if(key_num==16){switch(arrow){
#if USE_FINGERPRINTcase 0:Add_FR();		break;//录指case 1:Del_FR();		break;//删指纹case 2:SetPassworld();break;//修改密码case 3:Set_Time(); break;  //设置时间case 4:Add_Rfid(); break;  //录入卡片case 5:Massige(); break;  //显示信息
#elsecase 0:SetPassworld();break;//修改密码case 1:Set_Time(); break;  //设置时间case 2:Add_Rfid(); break;  //录入卡片case 3:Massige(); break;  //显示信息
#endif//									}goto MENU;}		}delay_ms(1);}	}

在主界面,用户可以选择不同的功能选项。界面通过按键的输入切换,显示相应的功能选项,如修改密码、录入指纹、查看信息等。

1.3 开锁功能

系统实现了三种开锁模式,分别是密码开锁、指纹开锁和门禁卡开锁。根据用户输入的方式,系统会调用相应的函数来完成开锁操作。

  • 密码开锁:用户输入密码后,系统会与预设密码进行对比,如果匹配成功,则开锁。
  • 指纹开锁:用户将手指放在指纹模块上,系统通过指纹识别来判断是否开锁。
  • 门禁卡开锁:通过刷卡的方式,系统会验证门禁卡是否匹配,如果匹配成功,则开锁。

蓝牙密码开锁:

						//手机蓝牙解锁密码1Error=usart1_cherk((char*)sys.passwd1);         if(Error==0){ OLED_Clear_NOupdate();Show_Str(12,13,128,20,"蓝牙密码1:正确",12,0); OLED_Refresh_Gram();//更新显示delay_ms(800);DisUnLock();goto MENU;	}else {
//							OLED_Clear_NOupdate();
//							Show_Str(12,13,128,12,"蓝牙密码:错误!",12,0); 
//							OLED_Refresh_Gram();//更新显示
//							delay_ms(800);
//							OLED_Show_Font(56,48,0);//锁}//手机蓝牙解锁密码2Error=usart1_cherk((char*)sys.passwd2);         if(Error==0){sys.errCnt = 0;OLED_Clear_NOupdate();Show_Str(12,13,128,12,"蓝牙密码2:正确",12,0); OLED_Refresh_Gram();//更新显示delay_ms(800);DisUnLock();goto MENU;	}else {//OLED_Show_Font(56,48,0);//锁}

按键密码开锁: 

//密码锁
int password(void)
{int  key_num=0,i=0,satus=0;u16 num=0,num2=0,time3=0,time;u8 pwd[11]="          ";u8 hidepwd[11]="          ";u8 buf[64];OLED_Clear();//清屏if(DisErrCnt())return -1;//错误次数超限OLED_Clear();//清屏Show_Str(5,0,128,16,"密码:",16,0);Show_Str(10,16,128,12," 1   2   3  Bck",12,0);Show_Str(10,28,128,12," 4   5   6  Del",12,0);Show_Str(10,40,128,12," 7   8   9  Dis",12,0);Show_Str(10,52,128,12,"Clr  0  Clr  OK",12,0);OLED_Refresh_Gram();//更新显示
//	Show_Str(102,36,128,12,"显示",12,0);
//	Show_Str(0,52,128,12,"删除 清空   返回 确认",12,0);while(1){key_num=Button4_4_Scan();	if(key_num != -1){	printf("key=[%d]\r\n",key_num);DisFlag = 1;time3=0;if(key_num != -1){	DisFlag = 1;time3=0;switch(key_num){case 1:case 2:case 3:pwd[i]=key_num+0x30; //1-3hidepwd[i]='*';i++;break;case 4://返回OLED_Clear();delay_ms(500);return -1;break;case 5:case 6:case 7:pwd[i]=key_num+0x30-1; //4-6hidepwd[i]='*';i++;break;case 8:if( i > 0){pwd[--i]=' ';  //‘del’键hidepwd[i]=' '; }break;case 9:case 10:case 11:pwd[i]=key_num+0x30-2; //4-6hidepwd[i]='*';i++;break;case 12:satus=!satus; break;//DIScase 13:case 15:while(i--){pwd[i]=' ';  //‘清空’键hidepwd[i]=' '; }i=0;break;case 14:pwd[i]=0x30; //4-6hidepwd[i]='*';i++;break;case 16:goto UNLOCK;break;}}if(DisFlag == 1){if(satus==0)OLED_ShowString(53,0,hidepwd,12);else OLED_ShowString(53,0,pwd,12);OLED_Refresh_Gram();//更新显示}time3++;if(time3%1000==0){OLED_Clear();//清屏return -1;}}}UNLOCK:	for(i=0; i<10; i++){   //验证虚伪密码if(pwd[i]==sys.passwd1[num])num++;else num=0;if(num==6)break;}for(i=0; i<10; i++){   //验证密码if(pwd[i]==sys.passwd2[num2])num2++;else num2=0;if(num2==6)break;}if(num==6 | num2==6){DisUnLock();OLED_Clear();//清屏sys.errCnt = 0;return 0;}else {sys.errCnt++;//错误次数计数if(sys.errCnt>MAXERRTIMES)sys.errTime = 30; //30秒不能再解锁OLED_Clear();//清屏Show_Str(45,48,128,16,"密码错误!",16,0);OLED_Refresh_Gram();//更新显示beep_on_mode1();delay_ms(1500);OLED_Clear();//清屏return -1;}}

指纹开锁:

//刷指纹
int press_FR(void)
{SearchResult seach;u8 ensure;char str[256];if(DisErrCnt())return -1;//错误次数超限ensure=PS_GetImage();OLED_Clear_NOupdate();Show_Str(0,0,128,16,"正在检测指纹",16,0);OLED_Refresh_Gram();//更新显示if(ensure==0x00)//获取图像成功 {	ensure=PS_GenChar(CharBuffer1);if(ensure==0x00) //生成特征成功{		ensure=PS_HighSpeedSearch(CharBuffer1,0,AS608Para.PS_max,&seach);if(ensure==0x00)//搜索成功{				OLED_Clear_NOupdate();Show_Str(20,10,128,24,"解锁中...",24,0);	OLED_Refresh_Gram();//更新显示Walkmotor_ON();Show_Str(20,10,128,24,"已解锁!",24,0);OLED_Refresh_Gram();//更新显示OLED_Show_Font(112,18,1);//开锁				//str=mymalloc(SRAMIN,2000);sprintf(str,"ID:%d     匹配分",seach.pageID);Show_Str(0,52,128,12,(u8*)str,12,0);	sprintf(str,":%d",seach.mathscore);Show_Str(96,52,128,12,(u8*)str,12,0);	//myfree(SRAMIN,str);OLED_Refresh_Gram();//更新显示delay_ms(1800);OLED_Clear();return 0;}else {sys.errCnt++;//错误次数计数if(sys.errCnt>MAXERRTIMES)sys.errTime = 30; //30秒不能再解锁ShowErrMessage(ensure);	OLED_Refresh_Gram();//更新显示beep_on_mode1();OLED_Clear();return -1;}				}elseShowErrMessage(ensure);OLED_Refresh_Gram();//更新显示delay_ms(2000);OLED_Clear();}return -1;	
}

门禁卡开锁:

MFRC522_Initializtion();			
Error=MFRC522_lock();
if(Error==0)
{goto MENU;	
}
else 
{OLED_Show_Font(56,48,0);//锁
}

2. 指纹录入与删除

指纹的录入与删除功能也在系统中得到了实现,用户可以通过界面选择录入或删除指纹,并且在录入时会进行指纹的匹配与验证,确保指纹信息的正确性。

void Add_FR(void)
{// 录入指纹逻辑...
}
//删除指纹
void Del_FR(void)
{//删除指纹逻辑......MENU:	OLED_Clear();
}

3.门禁卡的录入

//录入新卡
u8 Add_Rfid(void)
{//录入卡片逻辑......
}

4. 数据存储与恢复

系统使用STM32的Flash存储用户信息(如指纹、密码和门禁卡信息),确保即使系统掉电,数据不会丢失。系统会在每次开机时检查Flash中的数据,恢复上次的配置。

void SysPartInit(void )
{STMFLASH_Read(SYS_SAVEADDR, (u16*)&sys, sizeof(sys));if(sys.HZCFlag != 980706){// 初始化系统配置}
}

完整的main.c文件

#include "main.h"
#include <string.h>SysTemPat sys;#define USE_FINGERPRINT  1
#define MAXERRTIMES 5
#define usart2_baund  57600//串口2波特率,根据指纹模块波特率更改//要写入到STM32 FLASH的字符串数组
const u8 TEXT_Buffer[]={0x17,0x23,0x6f,0x60,0,0};
#define TEXT_LENTH sizeof(TEXT_Buffer)	 		  	//数组长度	
#define SIZE TEXT_LENTH/4+((TEXT_LENTH%4)?1:0)
#define FLASH_SAVE_ADDR  0X0802C124 	//设置FLASH 保存地址(必须为偶数,且所在扇区,要大于本代码所占用到的扇区.//否则,写操作的时候,可能会导致擦除整个扇区,从而引起部分程序丢失.引起死机.SysPara AS608Para;//指纹模块AS608参数
u16 ValidN;//模块内有效指纹个数
u8** kbd_tbl;void Display_Data(void);//显示时间
void Add_FR(void);	//录指纹
void Del_FR(void);	//删除指纹
int press_FR(void);//刷指纹
void ShowErrMessage(u8 ensure);//显示确认码错误信息
int password(void);//密码锁
void SetPassworld(void);//修改密码
void starting(void);//开机界面信息
u8 MFRC522_lock(void);//刷卡解锁
u8 Add_Rfid(void);		//录入
void Set_Time(void);
void Massige(void);
void SysPartInit(void );   //系统参数初始化 
//u8 Pwd[7]="      ";  //解锁密码1
//u8 Pwd2[7]="      ";  //解锁密码2
//u8 cardid[6]={0,0,0,0,0,0};  //卡号1
int Error;  //密码验证信息u8 DisFlag = 1;//数字的ASCII码
uc8 numberascii[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
//显示缓冲区
u8  dispnumber5buf[6];
u8  dispnumber3buf[4];
u8  dispnumber2buf[3];
//MFRC522数据区
u8  mfrc552pidbuf[18];
u8  card_pydebuf[2];
u8  card_numberbuf[5];
u8  card_key0Abuf[6]={0xff,0xff,0xff,0xff,0xff,0xff};
u8  card_writebuf[16]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
u8  card_readbuf[18];
//SM05-S数据区
u8  sm05cmdbuf[15]={14,128,0,22,5,0,0,0,4,1,157,16,0,0,21};
//extern声明变量已在外部的C文件里定义,可以在主文件中使用
extern u8  sm05receivebuf[16];	//在中断C文件里定义
extern u8  sm05_OK;							//在中断C文件里定义//u8 * week[7]={"Mon","Tue","Wed","Thu","Fri","Sat","Sun"};
u8 * week[7]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};#if USE_FINGERPRINT
#define MaxParaNum 6
u8 * setup[7]={"1、录入指纹","2、删除指纹","3、修改密码","4、修改时间","5、录入卡片","6、查看信息"};
#else
#define MaxParaNum 4
u8 * setup[7]={"1、修改密码","2、修改时间","3、录入卡片","4、查看信息","           ","           "};
#endifvoid DisUnLock(void )
{OLED_Clear();Show_Str(20,10,128,24,"解锁中...",24,0);	OLED_Refresh_Gram();//更新显示Walkmotor_ON();Show_Str(20,10,128,24,"已解锁!",24,0);OLED_Refresh_Gram();//更新显示delay_ms(1500);
}void DisLock(void )
{OLED_Clear();Show_Str(30,20,128,16,"锁定中!",16,0);OLED_Refresh_Gram();//更新显示Walkmotor_OFF();Show_Str(30,20,128,16,"已锁定!",16,0);OLED_Show_Font(56,48,0);//锁OLED_Refresh_Gram();//更新显示delay_ms(1000);
}int main(void)
{			u16 set=0;u8 err=0;int key_num;int time1;int time2;		//锁屏时间char arrow=0;  //箭头位子//SysHSI_Init();delay_init();	    	 //延时函数初始化	  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级uart_init(9600);	 //串口初始化为9600printf("串口功能正常\r\n");Button4_4_Init();          //初始化与按键连接的硬件接口OLED_Init();    			//显示初始化Walkmotor_Init();        //步进电机初始化BEEP_Init();			//蜂鸣器初始化usart2_init(usart2_baund);           //初始化指纹模块PS_StaGPIO_Init();OLED_Clear(); starting();//开机信息  logoerr = RTC_Init();	  			//RTC初始化if(err){OLED_Clear(); Show_Str(12,13,128,20,"RTC CRY ERR!",12,0); OLED_Refresh_Gram();//更新显示delay_ms(3000);}SysPartInit();   //系统参数初始化 while(1){
//锁屏界面
MAIN:OLED_Clear(); OLED_Show_Font(56,48,0);//显示锁图标while(1){time1++;Display_Data();//时间显示:每1000ms更新一次显示数据if(DisFlag == 1){DisFlag = 0;OLED_Fill(0,24,16,63,0);OLED_Refresh_Gram();//更新显示}if((time1%100)==1){//MFRC522解锁time1=0;MFRC522_Initializtion();			Error=MFRC522_lock();if(Error==0){goto MENU;	}else {OLED_Show_Font(56,48,0);//锁}//手机蓝牙解锁密码1Error=usart1_cherk((char*)sys.passwd1);         if(Error==0){ OLED_Clear_NOupdate();Show_Str(12,13,128,20,"蓝牙密码1:正确",12,0); OLED_Refresh_Gram();//更新显示delay_ms(800);DisUnLock();goto MENU;	}else {
//							OLED_Clear_NOupdate();
//							Show_Str(12,13,128,12,"蓝牙密码:错误!",12,0); 
//							OLED_Refresh_Gram();//更新显示
//							delay_ms(800);
//							OLED_Show_Font(56,48,0);//锁}//手机蓝牙解锁密码2Error=usart1_cherk((char*)sys.passwd2);         if(Error==0){sys.errCnt = 0;OLED_Clear_NOupdate();Show_Str(12,13,128,12,"蓝牙密码2:正确",12,0); OLED_Refresh_Gram();//更新显示delay_ms(800);DisUnLock();goto MENU;	}else {//OLED_Show_Font(56,48,0);//锁}}//指纹解锁if(PS_Sta)	 //检测PS_Sta状态,如果有手指按下{while(PS_Sta){Error=press_FR();//刷指纹if(Error==0){//DisUnLock();goto MENU;   //跳到解锁界面}								else {OLED_Show_Font(56,48,0);//锁}}}//密码锁key_num=Button4_4_Scan();	//按键扫描if(key_num!=-1){Error=password();//密码解锁函数if(Error==0){goto MENU;	//跳到解锁界面}else {OLED_Show_Font(56,48,0);//锁}}delay_ms(1);}/********************主界面**************************/MENU:OLED_Clear();
MENUNOCLR:OLED_Fill(0,0,20,48,0);//主页菜单显示if(arrow<3){Show_Str(5,arrow*16,128,16,"->",16,0);//显示箭头set=0;}else {Show_Str(5,(arrow-3)*16,128,16,"->",16,0);set=3;}Show_Str(25,0,128,16,setup[set],16,0);Show_Str(25,16,128,16,setup[set+1],16,0);Show_Str(25,32,128,16,setup[set+2],16,0);Show_Str(0,52,128,12,"上    下     确定",12,0);OLED_Refresh_Gram();//更新显示time2=0;while(1){//超时锁屏time2++;if(time2>10000 | key_num==4){  OLED_Clear();DisLock();if(time2>10000)beep_on_mode2();time2 =0;
//								delay_ms(1000);OLED_Clear();goto MAIN;}//手机蓝牙锁定if(memcmp(USART_RX_BUF,"LOCK",4)==0)	{
//							USART_RX_STA=0;
//							memset(USART_RX_BUF,0,USART_REC_LEN);DisLock();goto MAIN;}//功能选项选择key_num=Button4_4_Scan();	if(key_num){if(key_num==13){if(arrow>0)arrow--;goto MENUNOCLR;}if(key_num==15){if(arrow<MaxParaNum-1)arrow++;goto MENUNOCLR;}if(key_num==16){switch(arrow){
#if USE_FINGERPRINTcase 0:Add_FR();		break;//录指case 1:Del_FR();		break;//删指纹case 2:SetPassworld();break;//修改密码case 3:Set_Time(); break;  //设置时间case 4:Add_Rfid(); break;  //录入卡片case 5:Massige(); break;  //显示信息
#elsecase 0:SetPassworld();break;//修改密码case 1:Set_Time(); break;  //设置时间case 2:Add_Rfid(); break;  //录入卡片case 3:Massige(); break;  //显示信息
#endif//									}goto MENU;}		}delay_ms(1);}	}//while}u8 DisErrCnt(void){int time=0;u8 buf[64];if(sys.errTime>0)//错误次数计数{OLED_Clear();while(1){if(time++ == 1000){time = 0;if(sys.errTime==0){OLED_Clear();break;}Show_Str(0,16,128,16,"密码错误次数过多",16,0);sprintf(buf,"请%02d秒后重试", sys.errTime);Show_Str(20,32,128,16,buf,16,0);OLED_Refresh_Gram();//更新显示}delay_ms(1);if(4 == Button4_4_Scan())//返回{OLED_Clear();return 1;}}}}//获取键盘数值
u16 GET_NUM(void)
{u8  key_num=0;u16 num=0;OLED_ShowNum(78,32,num,3,12);OLED_Refresh_Gram();//更新显示while(1){key_num=Button4_4_Scan();	if(key_num != -1){
//			if(key_num==13)return 0xFFFF;//‘返回’键
//			if(key_num==14)return 0xFF00;//		
//			if(key_num>0&&key_num<10&&num<99)//‘1-9’键(限制输入3位数)
//				num =num*10+key_num;		
//			if(key_num==15)num =num/10;//‘Del’键			
//			if(key_num==10&&num<99)num =num*10;//‘0’键
//			if(key_num==16)return num;  //‘Enter’键switch(key_num){case 1:case 2:case 3:if(key_num>0&&key_num<10&&num<99)//‘1-9’键(限制输入3位数)num =num*10+key_num;		break;case 4://返回return 0xFFFF;return -1;break;case 5:case 6:case 7:if(key_num>0&&key_num<10&&num<99)//‘1-9’键(限制输入3位数)num =num*10+key_num-1;break;case 8:num =num/10;//‘del’键break;case 9:case 10:case 11:if(key_num>0&&key_num<10&&num<99)//‘1-9’键(限制输入3位数)num =num*10+key_num-2;break;case 12: break;//DIScase 13:case 15:return 0xFF00;break;case 14:num =num*10;break;case 16:return num;break;}OLED_ShowNum(78,32,num,3,12);OLED_Refresh_Gram();//更新显示}}	
}
//密码锁
int password(void)
{int  key_num=0,i=0,satus=0;u16 num=0,num2=0,time3=0,time;u8 pwd[11]="          ";u8 hidepwd[11]="          ";u8 buf[64];OLED_Clear();//清屏if(DisErrCnt())return -1;//错误次数超限OLED_Clear();//清屏Show_Str(5,0,128,16,"密码:",16,0);Show_Str(10,16,128,12," 1   2   3  Bck",12,0);Show_Str(10,28,128,12," 4   5   6  Del",12,0);Show_Str(10,40,128,12," 7   8   9  Dis",12,0);Show_Str(10,52,128,12,"Clr  0  Clr  OK",12,0);OLED_Refresh_Gram();//更新显示
//	Show_Str(102,36,128,12,"显示",12,0);
//	Show_Str(0,52,128,12,"删除 清空   返回 确认",12,0);while(1){key_num=Button4_4_Scan();	if(key_num != -1){	printf("key=[%d]\r\n",key_num);DisFlag = 1;time3=0;if(key_num != -1){	DisFlag = 1;time3=0;switch(key_num){case 1:case 2:case 3:pwd[i]=key_num+0x30; //1-3hidepwd[i]='*';i++;break;case 4://返回OLED_Clear();delay_ms(500);return -1;break;case 5:case 6:case 7:pwd[i]=key_num+0x30-1; //4-6hidepwd[i]='*';i++;break;case 8:if( i > 0){pwd[--i]=' ';  //‘del’键hidepwd[i]=' '; }break;case 9:case 10:case 11:pwd[i]=key_num+0x30-2; //4-6hidepwd[i]='*';i++;break;case 12:satus=!satus; break;//DIScase 13:case 15:while(i--){pwd[i]=' ';  //‘清空’键hidepwd[i]=' '; }i=0;break;case 14:pwd[i]=0x30; //4-6hidepwd[i]='*';i++;break;case 16:goto UNLOCK;break;}}if(DisFlag == 1){if(satus==0)OLED_ShowString(53,0,hidepwd,12);else OLED_ShowString(53,0,pwd,12);OLED_Refresh_Gram();//更新显示}time3++;if(time3%1000==0){OLED_Clear();//清屏return -1;}}}UNLOCK:	for(i=0; i<10; i++){   //验证虚伪密码if(pwd[i]==sys.passwd1[num])num++;else num=0;if(num==6)break;}for(i=0; i<10; i++){   //验证密码if(pwd[i]==sys.passwd2[num2])num2++;else num2=0;if(num2==6)break;}if(num==6 | num2==6){DisUnLock();OLED_Clear();//清屏sys.errCnt = 0;return 0;}else {sys.errCnt++;//错误次数计数if(sys.errCnt>MAXERRTIMES)sys.errTime = 30; //30秒不能再解锁OLED_Clear();//清屏Show_Str(45,48,128,16,"密码错误!",16,0);OLED_Refresh_Gram();//更新显示beep_on_mode1();delay_ms(1500);OLED_Clear();//清屏return -1;}}//显示确认码错误信息
void ShowErrMessage(u8 ensure)
{Show_Str(0,48,128,12,(u8*)EnsureMessage(ensure),12,0);	OLED_Refresh_Gram();//更新显示delay_ms(1000);OLED_ShowString(0,48,"                   ",12);	OLED_Refresh_Gram();//更新显示
}
//录指纹
void Add_FR(void)
{u8 i,ensure ,processnum=0;int key_num;u16 ID;OLED_Clear();//清屏while(1){key_num=Button4_4_Scan();	if(key_num==16){OLED_Clear();//清屏return ;}switch (processnum){case 0://OLED_Clear();//清屏i++;Show_Str(0,0,128,16,"=== 录入指纹 ===",16,0);Show_Str(0,24,128,12,"请按指纹!  ",12,0);	Show_Str(104,52,128,12,"返回",12,0);		OLED_Refresh_Gram();//更新显示	ensure=PS_GetImage();if(ensure==0x00) {BEEP=0;ensure=PS_GenChar(CharBuffer1);//生成特征BEEP=1;if(ensure==0x00){Show_Str(0,24,128,12,"指纹正常!    ",12,0);OLED_Refresh_Gram();//更新显示	i=0;processnum=1;//跳到第二步						}else ShowErrMessage(ensure);				}else ShowErrMessage(ensure);//OLED_Clear();//清屏break;case 1:i++;Show_Str(0,24,128,12,"请再按一次指纹",12,0);OLED_Refresh_Gram();//更新显示		ensure=PS_GetImage();if(ensure==0x00) {BEEP=0;ensure=PS_GenChar(CharBuffer2);//生成特征BEEP=1;if(ensure==0x00){Show_Str(0,24,128,12,"指纹正常!",12,0);	OLED_Refresh_Gram();//更新显示i=0;processnum=2;//跳到第三步}else ShowErrMessage(ensure);	}else ShowErrMessage(ensure);		//OLED_Clear();//清屏break;case 2:		Show_Str(0,24,128,12,"对比两次指纹        ",12,0);OLED_Refresh_Gram();//更新显示ensure=PS_Match();if(ensure==0x00) {Show_Str(0,24,128,12,"两次指纹一样       ",12,0);OLED_Refresh_Gram();//更新显示processnum=3;//跳到第四步}else {Show_Str(0,24,128,12,"对比失败 请重录    ",12,0);	OLED_Refresh_Gram();//更新显示ShowErrMessage(ensure);i=0;OLED_Clear();//清屏processnum=0;//跳回第一步		}delay_ms(1200);//OLED_Clear();//清屏break;case 3:Show_Str(0,24,128,12,"生成指纹模板...    ",12,0);OLED_Refresh_Gram();//更新显示	ensure=PS_RegModel();if(ensure==0x00) {
//					Show_Str(0,24,128,12,"生成指纹模板成功!",12,0);OLED_Refresh_Gram();//更新显示processnum=4;//跳到第五步}else {processnum=0;ShowErrMessage(ensure);}delay_ms(1200);break;case 4:	//OLED_Clear();//清屏Show_Str(0,24,128,12,"请输入储存ID:        ",12,0);Show_Str(122,52,128,12," ",12,0);Show_Str(0,52,128,12,"删除 清空      确认",12,0);OLED_Refresh_Gram();//更新显示doID=GET_NUM();while(!(ID<AS608Para.PS_max));//输入ID必须小于模块容量最大的数值ensure=PS_StoreChar(CharBuffer2,ID);//储存模板if(ensure==0x00) {			OLED_Clear_NOupdate();//清屏Show_Str(0,30,128,16,"录指纹成功!",16,0);	PS_ValidTempleteNum(&ValidN);//读库指纹个数Show_Str(66,52,128,12,"剩余",12,0);OLED_ShowNum(90,52,AS608Para.PS_max-ValidN,3,12);OLED_Refresh_Gram();//更新显示delay_ms(1500);OLED_Clear();	return ;}else {processnum=0;ShowErrMessage(ensure);}OLED_Clear();//清屏					break;				}delay_ms(400);if(i==10)//超过5次没有按手指则退出{OLED_Clear();break;}				}
}//刷指纹
int press_FR(void)
{SearchResult seach;u8 ensure;char str[256];if(DisErrCnt())return -1;//错误次数超限ensure=PS_GetImage();OLED_Clear_NOupdate();Show_Str(0,0,128,16,"正在检测指纹",16,0);OLED_Refresh_Gram();//更新显示if(ensure==0x00)//获取图像成功 {	ensure=PS_GenChar(CharBuffer1);if(ensure==0x00) //生成特征成功{		ensure=PS_HighSpeedSearch(CharBuffer1,0,AS608Para.PS_max,&seach);if(ensure==0x00)//搜索成功{				OLED_Clear_NOupdate();Show_Str(20,10,128,24,"解锁中...",24,0);	OLED_Refresh_Gram();//更新显示Walkmotor_ON();Show_Str(20,10,128,24,"已解锁!",24,0);OLED_Refresh_Gram();//更新显示OLED_Show_Font(112,18,1);//开锁				//str=mymalloc(SRAMIN,2000);sprintf(str,"ID:%d     匹配分",seach.pageID);Show_Str(0,52,128,12,(u8*)str,12,0);	sprintf(str,":%d",seach.mathscore);Show_Str(96,52,128,12,(u8*)str,12,0);	//myfree(SRAMIN,str);OLED_Refresh_Gram();//更新显示delay_ms(1800);OLED_Clear();return 0;}else {sys.errCnt++;//错误次数计数if(sys.errCnt>MAXERRTIMES)sys.errTime = 30; //30秒不能再解锁ShowErrMessage(ensure);	OLED_Refresh_Gram();//更新显示beep_on_mode1();OLED_Clear();return -1;}				}elseShowErrMessage(ensure);OLED_Refresh_Gram();//更新显示delay_ms(2000);OLED_Clear();}return -1;	
}//删除指纹
void Del_FR(void)
{u8  ensure;u16 num;OLED_Clear();Show_Str(0,0,128,16,"=== 删除指纹 ===",16,0);	Show_Str(0,16,128,12,"输入指纹ID:",12,0);Show_Str(0,52,128,12,"返回 清空    确认删除",12,0);OLED_Refresh_Gram();//更新显示delay_ms(50);
//	AS608_load_keyboard(0,170,(u8**)kbd_delFR);num=GET_NUM();//获取返回的数值if(num==0xFFFF)goto MENU ; //返回主页面else if(num==0xFF00)ensure=PS_Empty();//清空指纹库else ensure=PS_DeletChar(num,1);//删除单个指纹if(ensure==0){OLED_Clear();Show_Str(0,20,128,12,"删除指纹成功!",12,0);		Show_Str(80,48,128,12,"剩余",12,0);		OLED_Refresh_Gram();//更新显示}elseShowErrMessage(ensure);	OLED_Refresh_Gram();//更新显示PS_ValidTempleteNum(&ValidN);//读库指纹个数OLED_ShowNum(110,48,AS608Para.PS_max-ValidN,3,12);delay_ms(1200);MENU:	OLED_Clear();
}
//修改密码
void SetPassworld(void)
{int pwd_ch=0;int  key_num=0,i=0,satus=0;u16 time4=0;u8 pwd[6]="      ";u8 hidepwd[6]="      ";u8 buf[10];OLED_Clear();//清屏Show_Str(10,16,128,12," 1   2   3  Bck",12,0);Show_Str(10,28,128,12," 4   5   6  Del",12,0);Show_Str(10,40,128,12," 7   8   9  Dis",12,0);Show_Str(10,52,128,12,"Clr  0  Chg  OK",12,0);Show_Str(5,0,128,16,"新密码",16,0);sprintf((char*)buf,"%d:",pwd_ch+1);Show_Str(5,48,128,16,buf,16,0);OLED_Refresh_Gram();//更新显示while(1){key_num=Button4_4_Scan();	if(key_num != -1){	DisFlag = 1;time4=0;switch(key_num){case 1:case 2:case 3:pwd[i]=key_num+0x30; //1-3hidepwd[i]='*';i++;break;case 4://返回OLED_Clear();delay_ms(500);return ;break;case 5:case 6:case 7:pwd[i]=key_num+0x30-1; //4-6hidepwd[i]='*';i++;break;case 8:if( i > 0){pwd[--i]=' ';  //‘del’键hidepwd[i]=' '; }break;case 9:case 10:case 11:pwd[i]=key_num+0x30-2; //4-6hidepwd[i]='*';i++;break;case 12:satus=!satus; break;//DIScase 13:sprintf((char*)buf,"%d:",pwd_ch+1);Show_Str(5,48,128,16,buf,16,0);pwd_ch = !pwd_ch;case 15:while(i--){pwd[i]=' ';  //‘清空’键hidepwd[i]=' '; }i=0;break;case 14:pwd[i]=0x30; //4-6hidepwd[i]='*';i++;break;case 16:goto MODIF;break;}}if(DisFlag == 1)if(satus==0){OLED_ShowString(70,0,hidepwd,12);OLED_Refresh_Gram();//更新显示}else {OLED_ShowString(70,0,pwd,12);OLED_Refresh_Gram();//更新显示}time4++;if(time4%1000==0){OLED_Clear();//清屏DisFlag = 1;return ;}}	MODIF:if(pwd_ch==0){memcpy(sys.passwd1,pwd,7);STMFLASH_Write(SYS_SAVEADDR,(u16*)&sys,sizeof(sys));//保存到内部FLASH//STMFLASH_Read(SYS_SAVEADDR,(u16*)&sys,sizeof(sys)); //读取printf("pwd=%s",sys.passwd1);}else{		memcpy(sys.passwd2,pwd,7);STMFLASH_Write(SYS_SAVEADDR,(u16*)&sys,sizeof(sys));//保存密码到内部FLASH
//		STMFLASH_Write(0X08090004,(u32*)pwd,2);//保存密码到内部eeprom//STMFLASH_Read(SYS_SAVEADDR,(u16*)&sys,sizeof(sys)); //读取密码2printf("pwd2=%s",sys.passwd1);}OLED_Clear();//清屏Show_Str(0,48,128,16,"密码修改成功 !",16,0);OLED_Refresh_Gram();//更新显示delay_ms(1000);
}
//设置时间
void Set_Time(void)
{
//	RTC_TimeTypeDef RTC_TimeStruct;
//	RTC_DateTypeDef calendar;u16 year;u8 mon,dat,wek,hour,min,sec;u16 time5=0;u8 tbuf[40];int key_num;int st=0;//	RTC_GetTime(RTC_Format_BIN,&RTC_TimeStruct);
//	RTC_GetDate(RTC_Format_BIN, &calendar);year=calendar.w_year;mon=calendar.w_month;dat=calendar.w_date;wek=calendar.week;hour=calendar.hour;min=calendar.min;sec=calendar.sec;OLED_Clear();Show_Str(98,38,128,12,"<--",12,0);Show_Str(0,52,128,12,"减  加   切换  确定",12,0);OLED_Refresh_Gram();//更新显示while(1){time5++;key_num=Button4_4_Scan();	if(key_num==12 | time5==3000){OLED_Clear();//清屏return ;}if(key_num==13){switch(st){case 0:if(hour>0)hour--;break;case 1:if(min>0)min--;break;case 2:if(sec>0)sec--;break;case 3:if(wek>0)wek--;break;case 4:if(year>0)year--;break;case 5:if(mon>0)mon--;break;case 6:if(dat>0)dat--;break;}}if(key_num==14){switch(st){case 0:if(hour<23)hour++;break;case 1:if(min<59)min++;break;case 2:if(sec<59)sec++;break;case 3:if(wek<7)wek++;break;case 4:if(year<2099)year++;break;case 5:if(mon<12)mon++;break;case 6:if(dat<31)dat++;break;}}if(key_num==15){if(st<7)st++;if(st==7)st=0;}if(key_num==16){break;}if(time5%250==0){switch(st)			//闪烁{case 0:OLED_ShowString(0,0,"  ",24);break;case 1:OLED_ShowString(36,0,"  ",24);break;case 2:OLED_ShowString(72,0,"  ",24);break;case 3:OLED_ShowString(110,12,"   ",12);break;case 4:OLED_ShowString(68,26,"    ",12);break;case 5:OLED_ShowString(98,26,"  ",12);break;case 6:OLED_ShowString(116,26,"  ",12);break;}OLED_Refresh_Gram();//更新显示}if(time5%500==0){time5=0;sprintf((char*)tbuf,"%02d:%02d:%02d",hour,min,sec); OLED_ShowString(0,0,tbuf,24);	//RTC_GetDate(RTC_Format_BIN, &calendar);sprintf((char*)tbuf,"%04d-%02d-%02d",year,mon,dat); OLED_ShowString(68,26,tbuf,12);		sprintf((char*)tbuf,"%s",week[wek]); OLED_ShowString(110,12,tbuf,12);	OLED_Refresh_Gram();//更新显示}delay_ms(1);}
//	RTC_Set_Time(hour,min,sec,RTC_H12_AM);	//设置时间
//	RTC_Set_Date(year,mon,dat,wek);		//设置日期RTC_Set(year,mon,dat,hour, min,sec);OLED_Clear();Show_Str(20,48,128,16,"设置成功!",16,0);OLED_Refresh_Gram();//更新显示delay_ms(1000);
}//录入新卡
u8 Add_Rfid(void)
{u8 ID;u16 time6=0;u8 i,key_num,status=1,card_size;OLED_Clear();Show_Str(0,0,128,16,"=== 录入卡片 ===",16,0);	Show_Str(0,20,128,12,"请放入新卡片:",12,0);	Show_Str(0,52,128,12,"返回",12,0);OLED_Refresh_Gram();//更新显示MFRC522_Initializtion();			//初始化MFRC522while(1){AntennaOn();status=MFRC522_Request(0x52, card_pydebuf);			//寻卡if(status==0)		//如果读到卡{printf("rc522 ok\r\n");Show_Str(0,38,128,12,"读卡成功!",12,0);OLED_Refresh_Gram();//更新显示status=MFRC522_Anticoll(card_numberbuf);			//防撞处理			card_size=MFRC522_SelectTag(card_numberbuf);	//选卡status=MFRC522_Auth(0x60, 4, card_key0Abuf, card_numberbuf);	//验卡status=MFRC522_Write(4, card_writebuf);				//写卡(写卡要小心,特别是各区的块3)status=MFRC522_Read(4, card_readbuf);					//读卡//printf("卡的类型:%#x %#x",card_pydebuf[0],card_pydebuf[1]);//卡序列号显,最后一字节为卡的校验码printf("卡的序列号:");for(i=0;i<5;i++){printf("%#x ",card_numberbuf[i]);}printf("\r\n");//卡容量显示,单位为Kbits//printf("卡的容量:%dKbits\n",card_size);AntennaOff();OLED_Clear_NOupdate();Show_Str(0,12,128,12,"请输入储存ID(0-9):  ",12,0);Show_Str(122,52,128,12," ",12,0);Show_Str(0,52,128,12,"删除 清空      确认",12,0);OLED_Refresh_Gram();//更新显示doID=GET_NUM();while(!(ID<10));//输入ID必须小于最大容量printf("正在录入卡片:%d\r\n",ID);OLED_Clear_NOupdate();Show_Str(0,38,128,12,"正在录入.",12,0);OLED_Refresh_Gram();//更新显示
//			memcpy(sys.cardid[ID],card_numberbuf,5);for(i=0;i<5;i++){sys.cardid[ID][i] = card_numberbuf[i];}STMFLASH_Write(SYS_SAVEADDR,(u16*)&sys,sizeof(sys));//保存到内部FLASH
//			STMFLASH_Write(0X080f0004,(u32*)card_numberbuf,2);
//			STMFLASH_Read(0X080f0004,(u32*)cardid,1); //读取卡号1for(i=0;i<10;i++)printf("cardid={%X,%X,%X,%X}\r\n",sys.cardid[i][0],sys.cardid[i][1],sys.cardid[i][2],sys.cardid[i][3]);Show_Str(0,38,128,12,"录入成功!",12,0);OLED_Refresh_Gram();//更新显示delay_ms(1000);OLED_Clear();return 0;}key_num=Button4_4_Scan();	time6++;if(time6%5000==0 | key_num==13){OLED_Clear();return 1;}}
}
//rfid卡锁
u8 MFRC522_lock(void)
{u8 i,j,status=1,card_size;u8 count;u8 prtfbuf[64];AntennaOn();status=MFRC522_Request(0x52, card_pydebuf);			//寻卡if(status==0)		//如果读到卡{if(DisErrCnt())return -1;//错误次数超限printf("rc522 ok\r\n");status=MFRC522_Anticoll(card_numberbuf);			//防撞处理			card_size=MFRC522_SelectTag(card_numberbuf);	//选卡status=MFRC522_Auth(0x60, 4, card_key0Abuf, card_numberbuf);	//验卡status=MFRC522_Write(4, card_writebuf);				//写卡(写卡要小心,特别是各区的块3)status=MFRC522_Read(4, card_readbuf);					//读卡//MFRC522_Halt();															//使卡进入休眠状态//卡类型显示//printf("卡的类型:%#x %#x",card_pydebuf[0],card_pydebuf[1]);//卡序列号显,最后一字节为卡的校验码count=0;for(j=0;j<10;j++){printf("\r\n卡%d 的序列号:",j);for(i=0;i<5;i++){printf("%x=%x    ",card_numberbuf[i],sys.cardid[j][i]);if(card_numberbuf[i]==sys.cardid[j][i])count++;}printf("\r\n");if(count>=4){sys.errCnt = 0;OLED_Clear_NOupdate();sprintf(prtfbuf,"RFID:%d匹配成功",j);Show_Str(12,13,128,20,prtfbuf,12,0); OLED_Refresh_Gram();//更新显示delay_ms(500);DisUnLock();return 0;}else count=0;}{sys.errCnt++;//错误次数计数if(sys.errCnt>MAXERRTIMES)sys.errTime = 30; //30秒不能再解锁OLED_Clear(); Show_Str(12,13,128,20,"卡片错误",12,0); OLED_Refresh_Gram();//更新显示beep_on_mode1();OLED_Clear(); OLED_Show_Font(56,48,0);//锁DisFlag = 1;}printf("\n");//卡容量显示,单位为Kbits//printf("卡的容量:%dKbits\n",card_size);//读一个块的数据显示
//		printf("卡数据:\n");
//		for(i=0;i<2;i++)		//分两行显示
//		{
//			for(j=0;j<9;j++)	//每行显示8个
//			{
//				printf("%#x ",card_readbuf[j+i*9]);
//			}
//			printf("\n");
//		}}	AntennaOff();return 1;
}
//显示信息
void Massige(void)
{OLED_Clear();Show_Str(0,0,128,12,"智能能门锁系统",12,0); OLED_Refresh_Gram();//更新显示delay_ms(3000);
}//显示时间
void Display_Data(void)
{static u8 t=1;	u8 tbuf[40];if(t!=calendar.sec){t=calendar.sec;sprintf((char*)tbuf,"%02d:%02d:%02d",calendar.hour,calendar.min,calendar.sec); OLED_ShowString(0,0,tbuf,24);	//printf(tbuf);sprintf((char*)tbuf,"%04d-%02d-%02d",calendar.w_year,calendar.w_month,calendar.w_date); OLED_ShowString(68,26,tbuf,12);		//printf(tbuf);sprintf((char*)tbuf,"%s",week[calendar.week]); //printf(tbuf);OLED_ShowString(110,12,tbuf,12);DisFlag = 1;//更新显示}
}//开机信息
void starting(void)
{u8 cnt = 0;u8 ensure;char str[64];			  u8 key;
//	OLED_Show_Image(0);	//image
//	OLED_Refresh_Gram();//更新显示Show_Str(16,12,128,16,"智能门锁系统",16,0);OLED_Refresh_Gram();//更新显示delay_ms(2000);/*********************************开机信息提示***********************************/
#if USE_FINGERPRINTOLED_Clear();Show_Str(0,0,128,12,"fingerprint system!",12,0); Show_Str(0,12,128,12,"connect to as608",12,0);OLED_Refresh_Gram();//更新显示while(PS_HandShake(&AS608Addr))//与AS608模块握手{cnt++;if(cnt>10)break;delay_ms(400);Show_Str(0,24,128,12,"connect failed! ",12,0);OLED_Refresh_Gram();//更新显示delay_ms(800);Show_Str(0,24,128,12,"connect to as608  ",12,0);	printf("connect to as608..\r\n");OLED_Refresh_Gram();//更新显示}if(cnt>10)Show_Str(0,24,128,12,"connect failed!",12,0);	OLED_Refresh_Gram();//更新显示sprintf(str,"baud:%d  addr:%x",usart2_baund,AS608Addr);Show_Str(0,36,128,12,(u8*)str,12,0);OLED_Refresh_Gram();//更新显示ensure=PS_ValidTempleteNum(&ValidN);//读库指纹个数if(ensure!=0x00)printf("ERR:010\r\n");//ShowErrMessage(ensure);//显示确认码错误信息	ensure=PS_ReadSysPara(&AS608Para);  //读参数 
//	if(ensure==0x00)
//	{sprintf(str,"capacity:%d  Lv: %d",AS608Para.PS_max-ValidN,AS608Para.PS_level);Show_Str(0,48,128,12,(u8*)str,12,0);OLED_Refresh_Gram();//更新显示
//	}
//	else
//		ShowErrMessage(ensure);	//显示确认码错误信息	//	delay_ms(1000);
//
#endifOLED_Clear();
}void SysPartInit(void )   //系统参数初始化 
{STMFLASH_Read(SYS_SAVEADDR,(u16*)&sys,sizeof(sys)); //读取if(sys.HZCFlag != 980706){memset(&sys,0,sizeof(sys));sys.HZCFlag = 980706;strcpy((char *)sys.passwd1, "123456");//密码strcpy((char *)sys.passwd2, "980706");//密码STMFLASH_Write(SYS_SAVEADDR,(u16*)&sys,sizeof(sys));//保存到内部FLASHprintf("初始化配置成功\r\n");}else{printf("欢迎使用智能门锁\r\n");}
}

总结

本项目通过STM32控制多个外设,结合指纹识别、门禁卡与密码开锁三种开锁方式,构建了一个智能门锁系统。系统实现了多种安全措施,如数据存储、指纹验证、密码保护、门禁卡管理等,能够有效地提升安全性和用户体验。需要获取完整资料的,可以私信留言我,记得先点赞关注收藏先喔,完整资料如图所示:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/5304.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AUTOSAR OS模块详解(三) Alarm

AUTOSAR OS模块详解(三) Alarm 本文主要介绍AUTOSAR OS的Alarm&#xff0c;并对基于英飞凌Aurix TC3XX系列芯片的Vector Microsar代码和配置进行部分讲解。 文章目录 AUTOSAR OS模块详解(三) Alarm1 简介2 功能介绍2.1 触发原理2.2 工作类型2.3 Alarm启动方式2.4 Alarm配置2.5…

YOLO目标检测1

一. 参考资料 《YOLO目标检测》 by 杨建华博士 二. 背景 2.1 目标检测发展简史 2014年&#xff0c;RCNN问世&#xff0c;R-CNN的思路是先使用一个搜索算法从图像中提取出若干感兴趣区域(region of interest&#xff0c;RoI)&#xff0c;然后使用一个卷积神经网络(convolutio…

【Qt 常用控件】显示类控件——QLabel

目录 1.QLabel 1.1 textFormat 文本类型 普通文本和富文本 Markdown格式 1.2 alignment 文本对齐方式 1.3 wordWrap 自动换行 1.4 indent 文本缩进 1.5 margin 边距 1.6 buddy&#xff0c;qlabel伙伴 1.7 pixmap图片 和 scaledContents自动填充 1.QLabel 功能&#x…

vif-方差膨胀因子计算

vif-方差膨胀因子 使用statsmodels中的variance_inflation_factor&#xff0c;数据集使用乳腺癌数据集 import pandas as pd import numpy as np from sklearn.datasets import load_breast_cancer from tqdm import notebook from statsmodels.stats.outliers_influence impor…

查看电脑或笔记本CPU的核心数方法及CPU详细信息

一、通过任务管理器查看 1.打开任务管理器 可以按下“Ctrl Shift Esc”组合键&#xff0c;或者按下“Ctrl Alt Delete”组合键后选择“任务管理器”来打开。 2.查看CPU信息 在任务管理器界面中&#xff0c;点击“性能”标签页&#xff0c;找到CPU使用记录区域&#xff0c…

数据恢复常见故障(四)关键信号的耦合电容撞件后导致SATA前端通信异常

数据恢复常见故障&#xff08;四&#xff09;关键信号耦合电容撞件后导致SATA前端通信异常 SATA固态硬盘SATA差分信号上有耦合电容&#xff0c;电容被撞件后&#xff0c;偏移&#xff0c;导致接触不良&#xff0c;引起SATA前端信号通信异常&#xff0c;故障现象表现为不认盘&a…

[HCTF 2018]WarmUp

题目&#xff1a;一上来给了个图片还是很懵的&#xff0c;于是尝试查看一下源代码&#xff1a;发现有提示&#xff1a;于是访问source.php得到了php代码&#xff1a;(这里将代码和代码分析放一块) <?phphighlight_file(__FILE__); class emmm{public static function chec…

MYSQL数据库基础-01.数据库的基本操作

数据库的语法是大小写不敏感的&#xff0c;可以使用大写&#xff0c;也可以使用小写。 每条语句要以&#xff1b;结尾&#xff0c;可以多行输入。 名称不能是关键字,若想用关键字命名,要用反引号 引起来。 目录 一.数据库的基本操作 1.创建数据库&#xff1a; 2.查看数据库…

Decode Global专注金融创新,构建便捷的交易平台

随着金融市场持续进阶&#xff0c;越来越多的年轻正在涌入金融交易的体系中&#xff0c;针对当下年轻人崇尚精简&#xff0c;优中取优的特点&#xff0c;Decode Global紧跟金融市场发展的步伐&#xff0c;不断创新体验&#xff0c;致力于打造一个精简快捷&#xff0c;安全便捷的…

系统思考—转型

我们大多数问题的来源是&#xff1a;人们的思考方式与大自然的运作方式之间的差异。——葛雷果利贝特森&#xff08;人类学家、生物学家及系统思考先驱&#xff09; 在企业转型的过程中&#xff0c;许多企业创始人常常面临一个困境——过去的成功经验和旧有的思维方式&#xf…

Flutter:carousel_slider 横向轮播图、垂直轮播公告栏实现

安装依赖 carousel_slider: ^5.0.01、垂直滚动公告栏 import package:carousel_slider/carousel_options.dart;// 垂直滚动公告栏Widget _buildNotice() {return <Widget>[<Widget>[TDImage(assetUrl: "assets/img/home11.png",width: 60.w,height: 60.w…

【二叉树的深搜】计算布尔二叉树的值 求根节点到叶节点数字之和

文章目录 2331. 计算布尔二叉树的值解题思路&#xff1a;后序遍历129. 求根节点到叶节点数字之和解题思路&#xff1a;深度优先搜索 前序遍历 2331. 计算布尔二叉树的值 2331. 计算布尔二叉树的值 给你一棵 完整二叉树 的根&#xff0c;这棵树有以下特征&#xff1a; 叶子节…

【高阶数据结构】布隆过滤器(BloomFilter)

1. 概念 1.1 背景引入 背景&#xff1a;在计算机软件中&#xff0c;一个常见的需求就是 在一个集合中查找一个元素是否存在 &#xff0c;比如&#xff1a;1. Word 等打字软件需要判断用户键入的单词是否在字典中存在 2. 浏览器等网络爬虫程序需要保存一个列表来记录已经遍历过…

偏序关系.

一、偏序&#xff08;半序&#xff09;关系 偏序关系 自反反对称传递性 二、全序&#xff08;线序、链&#xff09;关系 三、偏序集中的重要元素 1. 极大元与极小元 极大元找所在集合的一个或几个最高点&#xff1b; 极小元找所在集合的一个或几个最低点。 2. 最大元与最小…

国产编辑器EverEdit - 列编辑模式

1 列模式 1.1 应用背景 在编辑CSV格式&#xff0c;或者比较规整的配置文件时&#xff0c;可能会用到一列的内容都要进行修改的情况&#xff0c;在不支持列模式的编辑器中&#xff0c;可能需要用户逐行去编辑&#xff0c;比如有下面一段扯淡文本&#xff1a; ADD NRNFREQ:LOCA…

论文笔记(六十三)Understanding Diffusion Models: A Unified Perspective(一)

Understanding Diffusion Models: A Unified Perspective&#xff08;一&#xff09; 文章概括引言&#xff1a;生成模型背景&#xff1a;ELBO、VAE 和分层 VAE证据下界&#xff08;Evidence Lower Bound&#xff09;变分自编码器 &#xff08;Variational Autoencoders&#x…

【重庆市乡镇界】面图层shp格式arcgis数据乡镇名称和编码wgs84坐标无偏移内容测评

标题中的“最新重庆市乡镇界面图层shp格式arcgis数据乡镇名称和编码wgs84坐标无偏移最新”指的是一个地理信息系统&#xff08;GIS&#xff09;的数据集&#xff0c;特别设计用于ArcGIS软件。这个数据集包含了重庆市所有乡镇的边界信息&#xff0c;以Shapefile&#xff08;.shp…

【0x04】HCI_Connection_Request事件详解

目录 一、事件概述 二、事件格式及参数 2.1. HCI_Connection_Request 事件格式 2.2. BD_ADDR 2.3. Class_Of_Device 2.4. Link_Type 三、主机响应 3.1. ACL链接类型 3.2. SCO或eSCO链接类型 四、应用场景 4.1. 设备配对场景 4.2. 蓝牙文件传输场景 4.3. 蓝牙物联网…

9. 神经网络(一.神经元模型)

首先&#xff0c;先看一个简化的生物神经元结构&#xff1a; 生物神经元有多种类型&#xff0c;内部也有复杂的结构&#xff0c;但是可以把单个神经元简化为3部分组成&#xff1a; 树突&#xff1a;一个神经元往往有多个树突&#xff0c;用于接收传入的信息。轴突&#xff1a;…

CTTSHOW-WEB入门-爆破25-28

web25 题目&#xff1a;解题思路及步骤&#xff1a;分析代码&#xff1a; error_reporting(0); include("flag.php");//包含文件flag.php if(isset($_GET[r])){$r $_GET[r];//获取参数rmt_srand(hexdec(substr(md5($flag), 0,8)));$rand intval($r)-intval(mt_ra…