🎀 文章作者:二土电子
🌸 关注公众号获取完整程序工程!
🐸 期待大家一起学习交流!
文章目录
一、项目简介
本项目基于STM32F103C8T6核心板,利用MF RC522射频模块、IC卡以及按键模块实现一个门禁系统设计,能够实现卡片添加、删除和识别,使用串口输出全部信息。
🔧软件工具:Keil5、串口助手
二、硬件简介
- 主控:STM32F103C8T6核心板
- 射频模块:MF RC522,使用软件模拟的SPI通信
- 两张IC卡
- 三个独立按键,一端接地
- USB-TTL,用于输出信息
引脚分配
引脚 | 对应IO |
---|---|
模式切换按键 | PA1 |
添加卡片按键 | PA2 |
删除卡片按键 | PA3 |
RC522_CS | PA4 |
RC522_SCK | PA5 |
RC522_MISO | PA6 |
RC522_MOSI | PA7 |
RC522_RST | PB0 |
三、软件设计思路
该项目除了一些驱动和功能程序设计外,主要有两个业务,一个是卡片ID库管理业务,用来管理卡片ID库,实现卡片的添加和删除,另一个是卡识别测业务,用来检测卡片是否已经入库,开机默认在卡片识别模式,通过模式切换按键实现两种模式的切换。
3.1 卡片ID库管理业务
3.1.1 添加卡片
每一个IC卡都会有一个四字节的ID号作为唯一标识,我们添加或者删除卡片时只需要存储或者删除这个ID号即可。程序设计时定义了四个四字节长度的数组用来存储卡片ID号,当然也可以根据自己的需求添加更多的卡片。
只有在该业务中添加按键和删除按键才可以生效,利用switch实现不同功能之间的切换。
当按下进入添加卡片模式时,会首先等待寻卡结果,也就是有没有检测到有IC卡被放到了感应区。如果在一段时间内没有检测到IC卡,会自动退出添加卡片模式并输出提示信息。如果检测到了IC卡,首先会检测一下ID库是否已经存储满了,如果存储满了会输出存满提示,如果仍有空位,会将新的ID按照顺序存储到空位并输出提示信息,最后退出添加卡片模式。
3.1.2 删除卡片
删除卡片与添加卡片大同小异,当按下删除卡片按键时会进入删除卡片功能,如果在一段时间内没有检测到IC卡,会自动退出删除卡片模式并输出提示信息。如果检测到了IC卡,会将卡片ID与库内已经存储的ID进行比较,如果有该卡片,将会清除并输出提示信息,如果没有找到对应ID,则退出删除卡片模式并输出提示信息。
3.2 卡片识别业务
该业务只有一个功能,检测卡片是否已经在库内,在或不在都会输出提示信息。
四、程序设计
关于MF RC522的驱动函数和功能函数的实现已经在外设系列专栏中呈现,这里就不再赘述。
4.1 卡片库管理业务函数
/*
*==============================================================================
*函数名称:App_Rc522_CardIdLib_Manage
*函数功能:卡片ID库管理
*输入参数:无
*返回值:无
*备 注:无
*==============================================================================
*/
void App_Rc522_CardIdLib_Manage (void)
{
u8 keyValue = 0; // 存储按键键值
u8 cardId[4] = {0,0,0,0}; // 存储读取到的卡片ID
u8 cardSaveIndex = 0; // 卡片存储位置索引
u32 timeOutCunt = 0; // 超时计数变量
u8 findFlag = 0; // 寻卡成功标志位
u8 modeRunFlg = 1; // 模式运行标志位,1:运行中;0:退出
printf ("Enter card library manage mode!\r\n");
while (modeRunFlg)
{
keyValue = Med_KeyScan(); // 按键扫描
switch (keyValue)
{
case 0xAD: // 添加卡片
printf ("Add card!\r\n");
// 等待读取到卡片ID
while (1)
{
findFlag = Med_Rc522_GetId(cardId);
timeOutCunt ++;
if (timeOutCunt >= 65530)
{
timeOutCunt = 0;
break;
}
else if (findFlag == 1)
break;
}
if (findFlag == 1)
{
// 查看当前卡片库是否已经存储满
if (gCardId1[0] == 0x00 && gCardId1[1] == 0x00 && gCardId1[2] == 0x00 && gCardId1[3] == 0x00)
cardSaveIndex = 1;
else if (gCardId2[0] == 0x00 && gCardId2[1] == 0x00 && gCardId2[2] == 0x00 && gCardId2[3] == 0x00)
cardSaveIndex = 2;
else if (gCardId3[0] == 0x00 && gCardId3[1] == 0x00 && gCardId3[2] == 0x00 && gCardId3[3] == 0x00)
cardSaveIndex = 3;
else if (gCardId4[0] == 0x00 && gCardId4[1] == 0x00 && gCardId4[2] == 0x00 && gCardId4[3] == 0x00)
cardSaveIndex = 4;
else
cardSaveIndex = LIB_FULL;
// 判断新卡是否已经在库内
if (cardId[0] == gCardId1[0] && cardId[1] == gCardId1[1] && cardId[2] == gCardId1[2] && cardId[3] == gCardId1[3])
cardSaveIndex = CARD_EXIST;
else if (cardId[0] == gCardId2[0] && cardId[1] == gCardId2[1] && cardId[2] == gCardId2[2] && cardId[3] == gCardId2[3])
cardSaveIndex = CARD_EXIST;
else if (cardId[0] == gCardId3[0] && cardId[1] == gCardId3[1] && cardId[2] == gCardId3[2] && cardId[3] == gCardId3[3])
cardSaveIndex = CARD_EXIST;
else if (cardId[0] == gCardId4[0] && cardId[1] == gCardId4[1] && cardId[2] == gCardId4[2] && cardId[3] == gCardId4[3])
cardSaveIndex = CARD_EXIST;
switch (cardSaveIndex)
{
case 1:
gCardId1[0] = cardId[0];
gCardId1[1] = cardId[1];
gCardId1[2] = cardId[2];
gCardId1[3] = cardId[3];
printf ("Add card1 is successful!\r\n");
break;
case 2:
gCardId2[0] = cardId[0];
gCardId2[1] = cardId[1];
gCardId2[2] = cardId[2];
gCardId2[3] = cardId[3];
printf ("Add card2 is successful!\r\n");
break;
case 3:
gCardId3[0] = cardId[0];
gCardId3[1] = cardId[1];
gCardId3[2] = cardId[2];
gCardId3[3] = cardId[3];
printf ("Add card3 is successful!\r\n");
break;
case 4:
gCardId4[0] = cardId[0];
gCardId4[1] = cardId[1];
gCardId4[2] = cardId[2];
gCardId4[3] = cardId[3];
printf ("Add card4 is successful!\r\n");
break;
case LIB_FULL:
printf ("Card library is full!\r\n");
break;
case CARD_EXIST:
printf ("Card already exists!\r\n");
break;
default:
break;
}
findFlag = 0;
}
else
printf ("No card found!\r\n");
break;
case 0xDE: // 删除卡片
printf ("Delete card!\r\n");
// 等待读取到卡片ID
while (1)
{
findFlag = Med_Rc522_GetId(cardId);
timeOutCunt ++;
if (timeOutCunt >= 65530)
{
timeOutCunt = 0;
break;
}
else if (findFlag == 1)
break;
}
if (findFlag == 1)
{
// 判断卡片是否已经在库内
if (cardId[0] == gCardId1[0] && cardId[1] == gCardId1[1] && cardId[2] == gCardId1[2] && cardId[3] == gCardId1[3])
{
gCardId1[0] = 0x00;
gCardId1[1] = 0x00;
gCardId1[2] = 0x00;
gCardId1[3] = 0x00;
printf ("Delete card1 is successful!\r\n");
}
else if (cardId[0] == gCardId2[0] && cardId[1] == gCardId2[1] && cardId[2] == gCardId2[2] && cardId[3] == gCardId2[3])
{
gCardId2[0] = 0x00;
gCardId2[1] = 0x00;
gCardId2[2] = 0x00;
gCardId2[3] = 0x00;
printf ("Delete card2 is successful!\r\n");
}
else if (cardId[0] == gCardId3[0] && cardId[1] == gCardId3[1] && cardId[2] == gCardId3[2] && cardId[3] == gCardId3[3])
{
gCardId3[0] = 0x00;
gCardId3[1] = 0x00;
gCardId3[2] = 0x00;
gCardId3[3] = 0x00;
printf ("Delete card3 is successful!\r\n");
}
else if (cardId[0] == gCardId4[0] && cardId[1] == gCardId4[1] && cardId[2] == gCardId4[2] && cardId[3] == gCardId4[3])
{
gCardId4[0] = 0x00;
gCardId4[1] = 0x00;
gCardId4[2] = 0x00;
gCardId4[3] = 0x00;
printf ("Delete card4 is successful!\r\n");
}
else
printf ("Not found this card!\r\n");
findFlag = 0;
}
else
printf ("No card found!\r\n");
break;
case 0x55:
printf ("Quit card library manage mode!\r\n");
modeRunFlg = 0;
break;
default:
break;
}
}
}
4.2 卡片识别业务函数
/*
*==============================================================================
*函数名称:App_Rc522_IdentifyCard
*函数功能:卡片识别
*输入参数:无
*返回值:无
*备 注:无
*==============================================================================
*/
void App_Rc522_IdentifyCard (void)
{
u8 keyValue = 0; // 存储按键键值
u8 cardId[4] = {0,0,0,0}; // 存储读取到的卡片ID
u32 timeOutCunt = 0; // 超时计数变量
u8 findFlag = 0; // 寻卡成功标志位
u8 modeRunFlg = 1; // 模式运行标志位,1:运行中;0:退出
printf ("Enter card identify mode!\r\n");
while (modeRunFlg)
{
keyValue = Med_KeyScan(); // 按键扫描
switch (keyValue)
{
case 0x55:
printf ("Quit card identify mode!\r\n");
modeRunFlg = 0;
break;
default:
// 等待读取到卡片ID
while (1)
{
keyValue = Med_KeyScan(); // 按键扫描
findFlag = Med_Rc522_GetId(cardId);
timeOutCunt ++;
if (timeOutCunt >= 65530)
{
timeOutCunt = 0;
break;
}
else if (findFlag == 1)
break;
else if (keyValue == 0x55)
{
printf ("Quit card identify mode!\r\n");
modeRunFlg = 0;
break;
}
}
if (findFlag == 1)
{
// 逐一对比卡片库ID
if (cardId[0] == gCardId1[0] && cardId[1] == gCardId1[1] && cardId[2] == gCardId1[2] && cardId[3] == gCardId1[3])
printf ("The cards are in the library!\r\n");
else if (cardId[0] == gCardId2[0] && cardId[1] == gCardId2[1] && cardId[2] == gCardId2[2] && cardId[3] == gCardId2[3])
printf ("The cards are in the library!\r\n");
else if (cardId[0] == gCardId3[0] && cardId[1] == gCardId3[1] && cardId[2] == gCardId3[2] && cardId[3] == gCardId3[3])
printf ("The cards are in the library!\r\n");
else if (cardId[0] == gCardId4[0] && cardId[1] == gCardId4[1] && cardId[2] == gCardId4[2] && cardId[3] == gCardId4[3])
printf ("The cards are in the library!\r\n");
else
printf ("The card is not in the library!\r\n");
findFlag = 0;
}
break;
}
}
}
五、总结与展望
本项目基于STM32,利用RFID技术实现了门禁系统设计,但是仍有一些地方可以进行优化
- 可以增加OLED用来显示提示信息
- 可以增加舵机模拟开关门
- 可以利用Flash实现卡片ID库的掉电存储
虽然上面列出来的这些内容本文并没有实现,但是别慌!
- OLED模块指路:“STM32开发笔记—外设系列”专栏
- SG90舵机指路:“STM32开发笔记—外设系列”专栏
- FLASH指路:“STM32速成笔记”专栏
另外在学习SG90舵机时会涉及到定时器和PWM相关知识,也可以到“STM32速成笔记”专栏查看!