基于STM32C8T6门禁系统(AS608、RFID、ESP8266、继电器)

        最近写了一个关于智能门禁的小项目,功能实现包括指纹AS608、RFID、ESP8266、MP3-TF-16P控制门禁开关。然后我本次写文章的目的是提供一个思路参考和对自己进行一个总结,而不是给你现成的代码,代码的部分我会给出来,具体框架和源码涉及到毕业设计,所以到6月份之后再考虑发出来。

       废话不多说开始进入设计环节,作为一个门禁系统,需要开门是肯定的,这里没有用舵机来模拟,我这里选择的是用继电器来模拟开门,所以首先做的是把继电器拿出来进行一个寄存器配置和写好开关,这些比较基础就不用很多说。

void JDQ_Init(void)   //继电器初始化/采用PB1
{
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeDef   GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;  //推挽输出
	GPIO_InitStructure.GPIO_Pin= GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	
    GPIO_Init(GPIOB,&GPIO_InitStructure);

} 
void Delay_EXT(u16 time)  //延迟函数设计,程序延迟
{    
   u16 i=0;  
   while(time--)
   {
      i=12000;  //自己定义
      while(i--) ;    
   }
}
void JDQ_ON(void)      //继电器开
{
  GPIO_SetBits(GPIOB,GPIO_Pin_1);

}

void JDQ_OFF(void)    //继电器关
{
  GPIO_ResetBits(GPIOB,GPIO_Pin_1);
}
void JDQ_GUAN(void)   //继电器延迟一会儿关闭
{
  Delay_EXT(1000);
  JDQ_OFF();
}

        这个是关于继电器模拟开门的设计,主要实现三个功能,开门、关门、自动关门。后面会调用这三个函数。然后设计关于AS608的代码,这个AS608代码我是拿别的配好的寄存器和函数,自己进行一个改造,然后收为自己使用。 

     

        AS608模块有六个引脚引出来了,(这张图出自某宝)第一根线(红线)接3.3v电源,第二个和第三个线是串口线,这里用串口3,黄线TX接PB10白线PB11,黑线是GND,接地就行,蓝线是判断线(有没有手指放在指纹模块,触发电容)接任意IO口,绿线也是电源线,接3.3V,这里尤其要注意,不能接5V电,会很烫,接久了百分百烧掉。

         接线是这样设计的,我预留串口1不动,串口2接ESP8266,串口3接指纹模块。这里的指纹源码我看了一下,攻略给的源码都是一个模板出来的,无法是删减问题。这里因为不是我写的,我只是基于源码进行一个串口更改,从串口2转成串口3,我就发部分源码。(不是自己亲手写的,不好意思发出来)都是一个源码出来的,所以可以去找指纹商家和b站上拿一下。

        

void USART3_init(u32 bound)
{  

	NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	// GPIOA时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); //串口2时钟使能

 	USART_DeInit(USART3);  //复位串口2
		 //USART3_TX   PA2
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PA2
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
  GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PA2
   
    //USART3_RX	  PA3
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOB, &GPIO_InitStructure);  //初始化PA3
	
	USART_InitStructure.USART_BaudRate = bound;//波特率设置
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式
  
	USART_Init(USART3, &USART_InitStructure); //初始化串口2
  

	USART_Cmd(USART3, ENABLE);                    //使能串口 
	
	//使能接收中断
  USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断   
	
	//设置中断优先级
	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
	
	TIM4_Int_Init(99,7199);		//10ms中断
	USART3_RX_STA=0;		//清零
	TIM_Cmd(TIM4,DISABLE);			//关闭定时器4

}

//串口2,printf 函数
//确保一次发送数据不超过USART3_MAX_SEND_LEN字节
void u2_printf(char* fmt,...)  
{  
	u16 i,j; 
	va_list ap; 
	va_start(ap,fmt);
	vsprintf((char*)USART3_TX_BUF,fmt,ap);
	va_end(ap);
	i=strlen((const char*)USART3_TX_BUF);		//此次发送数据的长度
	for(j=0;j<i;j++)							//循环发送数据
	{
	  while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET); //循环发送,直到发送完毕   
		USART_SendData(USART3,USART3_TX_BUF[j]); 
	} 
}
--------------------------------------------------------------------------------------
//这里因为模块化编程,一个是USART3一个是TIMER,所以要注意分开
void TIM4_Int_Init(u16 arr,u16 psc)
{	
	NVIC_InitTypeDef NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//TIM4时钟使能    
	
	//定时器TIM4初始化
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE ); //使能指定的TIM7中断,允许更新中断
	
	TIM_Cmd(TIM4,ENABLE);//开启定时器4
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;		//子优先级2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
}

     这里写的是串口3的初始化和定时器初始化,寄存器配置是这样的,不用很细究,能用就行,注意中断通道不冲突即可。然后还有一个蓝线的IO配置,这个就是自己选择一个IO口进行使用就行,当按键使用。

void PS_StaGPIO_Init(void)
{   
  GPIO_InitTypeDef  GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能GPIOA时钟
  //初始化读状态引脚GPIOA
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//输入下拉模式
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO	
}

这里使用的是PA1,主要的作用就是判断是不是有手指放上去,所以说当按键使用。(很好理解)

然后我提供一个头文件和定义函数,可以对比一下名字一样就是我用的那套源码。


#define PS_Sta   PAin(1)//读指纹模块状态引脚
#define CharBuffer1 0x01
#define CharBuffer2 0x02

extern u32 AS608Addr;//模块地址

typedef struct  
{
	u16 pageID;//指纹ID
	u16 mathscore;//匹配得分
}SearchResult;

typedef struct
{
	u16 PS_max;//指纹最大容量
	u8  PS_level;//安全等级
	u32 PS_addr;
	u8  PS_size;//通讯数据包大小
	u8  PS_N;//波特率基数N
}SysPara;

void PS_StaGPIO_Init(void);//初始化PA6读状态引脚
	
u8 PS_GetImage(void); //录入图像 
 
u8 PS_GenChar(u8 BufferID);//生成特征 

u8 PS_Match(void);//精确比对两枚指纹特征 

u8 PS_Search(u8 BufferID,u16 StartPage,u16 PageNum,SearchResult *p);//搜索指纹 
 
u8 PS_RegModel(void);//合并特征(生成模板) 
 
u8 PS_StoreChar(u8 BufferID,u16 PageID);//储存模板 

u8 PS_DeletChar(u16 PageID,u16 N);//删除模板 

u8 PS_Empty(void);//清空指纹库 

u8 PS_WriteReg(u8 RegNum,u8 DATA);//写系统寄存器 
 
u8 PS_ReadSysPara(SysPara *p); //读系统基本参数 

u8 PS_SetAddr(u32 addr);  //设置模块地址 

u8 PS_WriteNotepad(u8 NotePageNum,u8 *content);//写记事本 

u8 PS_ReadNotepad(u8 NotePageNum,u8 *note);//读记事 

u8 PS_HighSpeedSearch(u8 BufferID,u16 StartPage,u16 PageNum,SearchResult *p);//高速搜索 
  
u8 PS_ValidTempleteNum(u16 *ValidN);//读有效模板个数 

u8 PS_HandShake(u32 *PS_Addr); //与AS608模块握手

const char *EnsureMessage(u8 ensure);//确认码错误信息解析

我是看了好几套代码都是基于一套修改的,所以说不用很怕没有源码的,直接找网上的就行,因为都好懒,不乐意写一套新的,大家都是用旧的。(能用就行)实在需要源码六月之后在评论区我发一下就行。

然后是基于AS608的刷指纹、添加指纹、删除指纹的设计,这里是在别人的代码里面进行一个稍微修改,这个代码是我发刷指纹的函数,剩下的添加和删除我没修改。

void ShowErrMessage(u8 ensure)
{
	printf("\r\n错误信息:%s \r\n",(u8*)EnsureMessage(ensure));

    AS_BZW=0;
}

//刷指纹
void press_FR(void)
{
	SearchResult seach;
	u8 ensure;
	ensure=PS_GetImage();
	if(ensure==0x00)//获取图像成功 
	{	

		ensure=PS_GenChar(CharBuffer1);
		if(ensure==0x00) //生成特征成功
		{		
			ensure=PS_HighSpeedSearch(CharBuffer1,0,AS608Para.PS_max,&seach);
			if(ensure==0x00)//搜索成功
			{				
				printf("刷指纹成功\r\n");             //设置开门阈 值
				printf("确有此人,ID:%d  匹配得分:%d",seach.pageID,seach.mathscore);
				JDQ_ON();
				JDQ_BZW=1;
				AS_BZW=1;
				ACK(4);
				ACK(2);
				delay_ms(300);
				OLED_Clear();
				OLED_ShowString(1,3,"close ");
	            OLED_ShowString(2,1,"JDQ:");
               	OLED_ShowString(3,1,"RFID:");
	            OLED_ShowString(4,1,"AS608:");
             	OLED_ShowNum(2,5,JDQ_BZW,1);
	            OLED_ShowNum(3,6,RFID_BZW,1);
				OLED_ShowNum(4,7,AS_BZW,1);
             
			if(JDQ_BZW==1)
			{ 
				ACK(3);
			   JDQ_GUAN();
               JDQ_BZW=0;
                AS_BZW=0;		
			   OLED_ShowNum(4,7,AS_BZW,1);				
			}
			}
			else 
				ShowErrMessage(ensure);
			        LED_ON();
					FMQ_ON();
			       	ACK(2);
	        		delay_ms(300);
			        LED_OFF();
					FMQ_OFF();
//			        ACK(3);

			
			
			
	  }
		else
			ShowErrMessage(ensure);
			        
	}
		
}

           可能你们拿的代码会是不一样的,没有写参数的刷指纹和删除指纹,这个是一个人修改的,目的是可以指定存入位置,指纹存储是从1-300中挑一个数字,写入ADD_FR()中,很方便就能存储,指纹模块自带存储芯片,取得的指纹模型会存入芯片中,然后用数字1-300去代表。这样就不用记下复杂的进制地址。它是掉电不丢失数据的,存下就一直会有。

       然后就是设计如何用按键控制指纹添加和删除,源码是用串口控制添加,这就显得比较鸡肋,门禁还要接个电脑才能用,我就设计了用按键来控制指纹添加和删除。用OLED来显示状态。

     设计了6个按键来控制,分别是添加、删除和返回、确定还有加减。

  加减的按键设计:

uint8_t KeyNum;
uint8_t Key_Getnum_1(void)
{
   
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4)==0)
	{   
		delay_ms(20);
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4)==0)
		{
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4)==0);
		}
		delay_ms(20);   
		KeyNum++;
	}	
    return KeyNum;
}
uint8_t Key_Getnum_2(void)
{
   
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)==0)
	{   
		delay_ms(20);
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)==0)
		{
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)==0);
		}
		delay_ms(20);   
		KeyNum--;
	}

    return KeyNum;
}

 添加、删除、返回的设计:


uint8_t ABC;
uint8_t KEY_GetABC_1(void)
{
   if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)==0)
	{   
		delay_ms(20);
		if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)==0)
		{
		while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)==0);
		}
		delay_ms(20);   
		ABC=1;
	}
    return ABC;
}
uint8_t KEY_GetABC_2(void)
{
   if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_12)==0)
	{   
		delay_ms(20);
		if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_12)==0)
		{
		while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_12)==0);
		}
		delay_ms(20);   
		ABC=2;
	}
    return ABC;
}
uint8_t KEY_GetABC_3(void)
{
   if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)==0)
	{   
		delay_ms(20);
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)==0)
		{
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)==0);
		}
		delay_ms(20);   
		ABC=0;
		ADD=0;
	    OLED_Clear();
	}
    return ABC;
}

确认的设计(实际上用了两个IO口,但是只需要一个按键按下就行):

uint8_t ADD;
uint8_t Key_Z_1(void)
{
   
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)==0)
	{   
		delay_ms(20);
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)==0)
		{
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)==0);
		}
		delay_ms(20);   
		ADD=0;
	}

    return ADD;
}
uint8_t Key_Z_2(void)
{
   
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)==0)
	{   
		delay_ms(20);
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)==0)
		{
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)==0);
		}
		delay_ms(20);   
		ADD=1;
		KeyNum=0;
		
	}

    return ADD;
}

这里可能有人不理解,这里我来解释一下,就是看变量的改变,首先加减的keynum、添加删除返回的ABC,确认的ADD。这里的想法是这样的,用switch来达到判断的目的,首先是返回0添加1删除2,然后进入添加或者删除就是进入到ADD0的状态,在添加或者删除的里面通过死循环对keynum选择的目的,选择完成就跳出循环,也就是确定。确定按下就是ADD变成1,跳出循环进入到等待返回变量,返回按下就变成正常。配合代码对这段话进行理解就能看懂

 void Key_and_AS(void)
{
    switch(AC) 
	{
	case 0:	
	      break;
	case 1:		
		 switch(BCC)
	   {        
		 case 0:  
             printf("请选择录入指纹:");
		     OLED_Clear();
			 while(BCC==0)
			  {
			   key_num=Key_Getnum_1();
               key_num=Key_Getnum_2(); 
			   BCC=Key_Z_1();
	           BCC=Key_Z_2();
               OLED_AS_1();
 	           printf("num:%d sum %d AC:%d BCC:%d\r\n",key_num,key_Sum,AC,BCC);			  
			  }  
			  printf("确认录入指纹");
			  OLED_Clear();
			  OLED_ShowString(1,1,"querenluru");
			  OLED_ShowString(2,1,"luruweizhi");
			  OLED_ShowNum(3,1,key_num,3);
			  Add_FR(key_num);
			  if(ABC_ZW==0){ABC_ZW=key_num;}
              else if(ABD_ZW==0){ABD_ZW=key_num;}	  
              break;    
		 case 1:		   	
		        while(AC==1)
					{ 
					AC=KEY_GetABC_3();
                    BCC=Key_Z_1();
	                BCC=Key_Z_2();					 
				    printf("请按返回\r\n");
					OLED_Clear();
					OLED_ShowString(2,1,"qinganxiafanhui");	
					}
				OLED_Clear();	
                break;	      	 
        }
        break;	   
	case 2:
		
			 switch(BCC)
	   {        
		 case 0:  
             printf("请选择?埃指纹:");
		     OLED_Clear();
			 while(BCC==0)
			  {
			   key_num=Key_Getnum_1();
               key_num=Key_Getnum_2(); 
			   BCC=Key_Z_1();
	           BCC=Key_Z_2();
               OLED_AS_2();
	           printf("num:%d sum %d AC:%d BCC:%d\r\n",key_num,key_Sum,AC,BCC);				  
			  }  
			  OLED_Clear();
			  OLED_ShowString(1,1,"querenshanchu");
			  OLED_ShowString(2,1,"shanchuweizhi");
			  OLED_ShowNum(3,1,key_num,3);
			  printf("指纹");
		      Del_FR(key_num);
              if(ABC_ZW==key_num){ABC_ZW=0;}
			  else if(ABD_ZW==key_num){ABD_ZW=0;}
              break;    
		 case 1:		   	
                while(AC==2)
					{ 
					AC=KEY_GetABC_3();
                    BCC=Key_Z_1();
	                BCC=Key_Z_2();						
				    printf("请按返回\r\n");
					OLED_ShowString(2,1,"qinganxiafanhui");
					OLED_Clear();	
					} 
				OLED_Clear();
                break;	      	 
        }
        break;	   
     }
        
} 

多看框架就能明白,剩下的自己修改就行。这里就是设计完成了指纹的添加删除。

---------------------------------------------------------------------------------------------------------------------------------

剩下的部分我过两天写一个下册或者沿着这个继续写。

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值