小项目-----小型门禁开源
当初在学校的时候,看到学校老旧的钥匙开门方式,突然想做个小型门禁,然后就。。。
好吧,言归正传,门禁主要包括的外设如下:
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。
比如后来才发现一个重要功能没添加,那就是应该根据用户的输入来修改内部密码,当时这个没有考虑到,是一个问题;
由于在下水平有限,望各位海涵,有问题可以在评论区提出,我们可以一起研究研究。