小项目-----小型门禁

本文分享小型门禁开源项目,介绍门禁包含的外设,如4*4按键、继电器、语音芯片等。硬件主控采用stm32f103c8系列单片机,展示了各部分电路及成品PCB。还给出代码部分,包括头文件、主程序等,承认代码有未优化和功能缺失问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

                                      小项目-----小型门禁开源

当初在学校的时候,看到学校老旧的钥匙开门方式,突然想做个小型门禁,然后就。。。

好吧,言归正传,门禁主要包括的外设如下:

1./*4*4按键,按键密码开锁*/

2./*继电器,电磁阀断电*/

3./*语音芯片,提示音,人工语音播报*/

4./*蓝牙模块,手机APP控制开锁*/

5./*RC522射频卡,刷卡开锁*/

6./*按钮,触摸开关,内部开门*/

硬件部分:

1.主控采用的是stm32f103c8系列单片机

MCU部分电路:

语音芯片部分:

 

RC522(RFID CARD)部分:

蓝牙部分:

矩阵按键部分:

继电器,触摸按键部分:

还有一部分旁路电路在此就不截图了

最后成品PCB:

这是外壳尺寸(淘宝买的,嘿嘿嘿),由于买的外壳,导致外壳和板子并不匹配,

废了九牛二虎之力才塞进去的。。。

本来是拍了一段视频的,可惜现在换手机没了,而成品也扔学校去了;

下面代码部分:

代码量不大,但文件比较多,

头文件部分:

射频卡对应类型,扇区,蓝牙密码,卡密码设置:

各部分密码初始化:

数据验证:

这谁看得懂?

还是直接复制粘贴程序吧,基本都注释了:

主程序:

#include "Uart.h"
#include "SPI.h"
#include "rc522.h"
#include "delay.h"
#include "Config.h"
#include "Sound.h"
#include "Key.h"

#define KEY GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)

/**参数设置区域**/
unsigned char CT[20];//卡类型
unsigned char SN[4]; //卡号
unsigned char DefaultKey[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 
unsigned char RevData[20];
unsigned char Card_Data[16] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};//块2数据
unsigned char Blue_Rev_Data[6];
unsigned char Blue_Password[1] = {49};
unsigned char Key_Password[6] = {1,5,9,13,14,15};
u8 Rev_Key_Password[6];
int Key_Pass_Num = 0;

/*
    将数据初始化
    完成返回MI_OK
*/
u8 Data_Clear(void)
{
	int i;
	for(i=0;i<16;i++)
	{
		RevData[i] = 0;
	}
	for(i=0;i<6;i++)
	{
		Rev_Key_Password[i] = 255;
	}
	return MI_OK;
}

/*
    比较按键输入的密码是否正确
    成功返回MI_OK
    失败返回MI_ERR
*/
u8 KeyBoard_Compare(void)
{
	
	u8 KeyValue;
	
	KeyValue = ReadKeyValue();
	
	if(KeyValue != 255) 
	{
		
		Rev_Key_Password[Key_Pass_Num] = KeyValue;  
//		printf("%d",Rev_Key_Password[i]);
		Key_Pass_Num++;
	

	if(Key_Pass_Num>5)
	{
		
		Key_Pass_Num = 0;
		for(Key_Pass_Num = 0;Key_Pass_Num<6;Key_Pass_Num++)
		{	
//			printf("Rev_Key_Password =%d,Key_Password = %d\r\n",Rev_Key_Password[Key_Pass_Num],Key_Password[Key_Pass_Num]);	
			if(Rev_Key_Password[Key_Pass_Num] != Key_Password[Key_Pass_Num]) 
			{
				Key_Error_Music();
				Data_Clear();
			 	return MI_ERR;
			}
			
		} 
		return MI_OK;
	 }
	}
	return MI_ERR;
}

/*
    接收数据和MCU里设置的密码对比,
    其实这里用传参的方式更好,
    当时想省事就全局变量解决了;
    成功返回MI_OK
    失败返回MI_ERR
*/
u8 Data_Compare(void)
{
	int i;
//	int temp;
	for(i=0;i<16;i++)
	{
		if(RevData[i] != Card_Data[i]) return MI_ERR;
		//printf("%X",temp);
		//printf("\r\n");									
	}
	return MI_OK;
}



/*
    蓝牙接收数据和MCU里设置的密码对比,
    其实这里用传参的方式更好,
    当时想省事就全局变量解决了;
    成功返回MI_OK
    失败返回MI_ERR
*/											
u8 Blue_Data_Compar(void)
{
//   int i;
//   for(i = 0;i<2;i++)
//   { 
//    printf("%d",Blue_Rev_Data[i]); printf("\r\n");
//	if(Blue_Rev_Data[i] != Blue_Password[i]) return MI_ERR;
//	
//   }
   if(Blue_Rev_Data[0] != Blue_Password[0]) return MI_ERR;
   return MI_OK;

}

/*
    主函数就是不断扫描卡片,按键,蓝牙接口,和内部按键,然后进行密码匹配;
    成功返回MI_OK
    失败返回MI_ERR
*/	
int main(void)
{
//	unsigned char status = 0;
//	unsigned char i;
//    unsigned int temp;
	unsigned int BlueValue,KeyBoardValue;

	delay_init();	    	 //延时函数初始化	  
	NVIC_Configuration(); 	 //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	Uart1_Init_Config();
	Spi_Init_Config();
	InitRc522();				//初始化射频卡模块
	Config_Other_Init();//其他外设初始化
	Key_Init();


	printf("RFID_Debug!");
	
	while(1) 
	{	 
		 //Write_Card_Data(2,Card_Data);//写密码到卡中
		 Read_Card_Data(2,Card_Data);
//		 printf("%d",Blue_Data_Compar());
		 BlueValue = Blue_Data_Compar();
		 KeyBoardValue = KeyBoard_Compare();

		 if((Data_Compare() == MI_OK) || (BlueValue == MI_OK) || (KEY == MI_OK) || (KeyBoardValue == MI_OK)) 
		 {
		 	printf("Open");
			Blue_Rev_Data[0] = 0xff ;
			GPIO_ResetBits(GPIOA,GPIO_Pin_11);
			Open_Door_Music();
			Reset_RC522();
			Data_Clear();
			delay_ms(1000);
			delay_ms(1000);
			delay_ms(1000);
			GPIO_SetBits(GPIOA,GPIO_Pin_11);
			printf("Close");
			
			
		 }
		 
		//printf("Card_Pass = %d \t\n",Data_Compare());

	}
	
}








串口部分:

#include "Uart.h"

void Uart1_Init_Config(void)
{
	Sys_Init();	   //系统时钟的初始化
	Gpio_Init();	   // 端口的初始化
	Uart1_Init();   // 串口的配置及其初始化
	Nvid_Init();		// 中断模式的初始化
}

void Sys_Init(void)
{
	//SystemInit();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
}

void Gpio_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_2 ;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP ;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_3 ;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void Uart1_Init(void)
{
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate = 9600;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	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_Tx | USART_Mode_Rx;
	USART_Init(USART1, &USART_InitStructure);

	USART_InitStructure.USART_BaudRate = 9600;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	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_Tx | USART_Mode_Rx;
	USART_Init(USART2, &USART_InitStructure);

	USART_Cmd(USART1, ENABLE);
	USART_Cmd(USART2, ENABLE);
	USART_ITConfig(USART1, USART_IT_RXNE,ENABLE);
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//使能或者失能指定的USART中断 接收中断
	USART_ClearFlag(USART1,USART_FLAG_RXNE|USART_FLAG_TC|USART_FLAG_TXE);
	USART_ClearFlag(USART2,USART_FLAG_RXNE|USART_FLAG_TC|USART_FLAG_TXE);
}

void Nvid_Init(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;	
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; 
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
	NVIC_Init(&NVIC_InitStructure);

}

int fputc(int ch, FILE *f)
{
		/* 发送一个字节数据到USART1 */
		USART_SendData(USART1, (uint8_t) ch);
		/* 等待发送完毕 */
		while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
		return (ch);
}

/// 重定向c库函数scanf到USART1
int fgetc(FILE *f)
{
		/* 等待串口1输入数据 */
		while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
		return (int)USART_ReceiveData(USART1);
}

void USART1_IRQHandler(void)
{
	if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)//检查指定的USART中断发生与否
	{

		USART_SendData(USART2,USART_ReceiveData(USART1));//通过外设USARTx发送单个数据
		//USART_ReceiveData(USART1)返回USARTx最近接收到的数据
	
		while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);
	}
}

void USART2_IRQHandler(void)
{
	unsigned int i=0,j;
	if(USART_GetITStatus(USART2,USART_IT_RXNE)!=RESET)//检查指定的USART中断发生与否
	{	
		//printf("%d\n",USART_ReceiveData(USART2));
		
		Blue_Rev_Data[i] = USART_ReceiveData(USART2);
		i++;
		//while(1);
//		USART_SendData(USART1,USART_ReceiveData(USART2));//通过外设USARTx发送单个数据
//		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	}
}







SPI部分用于和射频卡通讯:

#include "SPI.h"


void Spi_Init_Config(void)
{
	 Spi_Rcc_Init();
	 Spi_Gpio_Init();
	 SPI1_Config();
}
void Spi_Rcc_Init(void)
{
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能GPIOA时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能GPIOB时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);//使能spi1

}

void Spi_Gpio_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;//sck miso/ mosi
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
		
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;//cs  PA4
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);

	GPIO_SetBits(GPIOA,GPIO_Pin_4); 
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;//RST PA3
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	GPIO_ResetBits(GPIOA,GPIO_Pin_8);
	


	 
}


void SPI1_Config(void)
{
	SPI_InitTypeDef SPI_InitStructure;
	SPI_Cmd(SPI1, DISABLE);
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//SPI_FirstBit_MSB;
	SPI_InitStructure.SPI_CRCPolynomial = 7;
	SPI_Init(SPI1, &SPI_InitStructure);
	 /*Enable SPI1.NSS as a GPIO*/
	SPI_SSOutputCmd(SPI1, ENABLE);
	SPI_Cmd(SPI1, ENABLE);
	//spi1_cs_low;
}
void SPI2_Config(void)
{
	SPI_InitTypeDef SPI_InitStructure;
	SPI_Cmd(SPI2, DISABLE);
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//SPI_FirstBit_MSB;
	SPI_InitStructure.SPI_CRCPolynomial = 7;
	SPI_Init(SPI2, &SPI_InitStructure);
	SPI_Cmd(SPI2, ENABLE);

//	SPI_NSSInternalSoftwareConfig(SPI2, SPI_NSSInternalSoft_Set);
//	SPI_SSOutputCmd(SPI2, ENABLE);


}














语音部分:

#include "Sound.h"


void Open_Door_Music(void)
{
	USART_SendData(USART1, 0x7E);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	USART_SendData(USART1, 0x04);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	USART_SendData(USART1, 0x03);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	USART_SendData(USART1, 0x00);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	USART_SendData(USART1, 0x01);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	USART_SendData(USART1, 0xEF);
}

void Key_Error_Music(void)
{
	USART_SendData(USART1, 0x7E);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	USART_SendData(USART1, 0x04);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	USART_SendData(USART1, 0x03);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	USART_SendData(USART1, 0x00);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	USART_SendData(USART1, 0x02);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	USART_SendData(USART1, 0xEF);
}


















键盘按键扫描部分,行列扫描:

#include "Key.h"

void Key_Init(void)
{
	
	GPIO_InitTypeDef GPIO_InitStructure;	
	/**列**/
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //输入
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD ; //输出 
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	GPIO_SetBits(GPIOB,GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11);
	GPIO_ResetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
	
}

u8 ReadKeyValue(void)
{
	u8 KeyValue = 255;

	if((GPIO_ReadInputData(GPIOB)&0xff00)!=0x0f00)
	{
		delay_ms(10);
		if((GPIO_ReadInputData(GPIOB)&0xff00)!=0x0f00)
		{
			GPIO_SetBits(GPIOB,GPIO_Pin_8);
			GPIO_ResetBits(GPIOB,GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11);
			switch(GPIO_ReadInputData(GPIOB)&0xff00)
			{
				case 0x1100:KeyValue = 3;break;
				case 0x2100:KeyValue = 7;break;
				case 0x4100:KeyValue = 11;break;
				case 0x8100:KeyValue = 15;break;

			
			}
			GPIO_SetBits(GPIOB,GPIO_Pin_9);
			GPIO_ResetBits(GPIOB,GPIO_Pin_8|GPIO_Pin_10|GPIO_Pin_11);
			switch(GPIO_ReadInputData(GPIOB)&0xff00)
			{
				case 0x1200:KeyValue = 2;break;
				case 0x2200:KeyValue = 6;break;
				case 0x4200:KeyValue = 10;break;
				case 0x8200:KeyValue = 14;break;
			
			}
			GPIO_SetBits(GPIOB,GPIO_Pin_10);
			GPIO_ResetBits(GPIOB,GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_11);
			switch(GPIO_ReadInputData(GPIOB)&0xff00)
			{
				case 0x1400:KeyValue = 1;break;
				case 0x2400:KeyValue = 5;break;
				case 0x4400:KeyValue = 9;break;
				case 0x8400:KeyValue = 13;break;
			
			}

			GPIO_SetBits(GPIOB,GPIO_Pin_11);
			GPIO_ResetBits(GPIOB,GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10);
			switch(GPIO_ReadInputData(GPIOB)&0xff00)
			{
				case 0x1800:KeyValue = 0;break;
				case 0x2800:KeyValue = 4;break;
				case 0x4800:KeyValue = 8;break;
				case 0x8800:KeyValue = 12;break;
			
			}		
			GPIO_SetBits(GPIOB,GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11);
			GPIO_ResetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
			
			while((GPIO_ReadInputData(GPIOB)&0xff00)!= 0x0f00);
			
			}
	
	}
	return KeyValue;
   
}


其余IO口配置:

#include "Config.h"


void Config_Other_Init(void)
{
	Rcc_Other_Init();
	Gpio_Other_Init();

}

void Rcc_Other_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);	
}

void Gpio_Other_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;//PA11 Relay
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);

	GPIO_SetBits(GPIOA,GPIO_Pin_11);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//PA0 Key
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);

	GPIO_SetBits(GPIOA,GPIO_Pin_0);




}





嗯,里面的里面的重点就这些,当时弄完就没有继续去代码优化了,里面肯定还有许多的BUG。

比如后来才发现一个重要功能没添加,那就是应该根据用户的输入来修改内部密码,当时这个没有考虑到,是一个问题;

由于在下水平有限,望各位海涵,有问题可以在评论区提出,我们可以一起研究研究。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值