基于STM32+RC522设计的门禁系统

一、项目背景

门禁系统是现代社会中非常重要的安全控制系统之一,其功能是在保障建筑物安全的同时,为合法用户提供便利。当前设计一种基于STM32+RC522的门禁系统设计方案,通过RFID-RC522模块实现了对用户卡的注册、识别及身份验证,通过控制SG90舵机实现门锁的开关,具有较高的安全性和可靠性。实验结果表明,该门禁系统可以有效地保障建筑物的安全性。

门禁系统广泛应用于各种建筑物、企事业单位,用于管理人员的进出、控制人员活动范围、实现安全监控等功能。传统的门禁系统采用密码输入或刷卡的方式进行身份验证,但存在易被破解的风险。基于RFID的门禁系统已经成为一种相对先进的安全控制方案。

本次设计的STM32+RC522门禁系统,通过RFID-RC522模块对用户的卡进行注册、识别完成身份识别,对门锁进行开关。系统带了OLED显示屏,输入用户密码登录之后,可以对新卡片进行注册,添加新卡片,对不使用的卡片进行注销。在系统里,IC卡的数据都存储在卡的内部扇区里,通过卡的内部空间进行管理。

采用5V-步进电机的版本:

二、系统设计

门禁系统由STM32F103C8T6单片机、RFID-RC522模块、SG90舵机、LCD1602液晶显示屏、键盘模块等组成。其中,STM32F103C8T6单片机作为系统的核心控制器,控制程序的执行;RFID-RC522模块作为识别用户卡片的设备;SG90舵机作为门锁控制设备;OLED显示屏提供用户输入信息和系统信息的显示;键盘模块方便用户进行密码和卡片信息的输入。

2.1 软件设计

【1】RFID卡信息管理

本系统采用卡的内部空间进行IC卡信息的管理。每个IC卡可以分为多个扇区,每个扇区包含多个块,每个块包含16个字节。扇区0是厂家已经预留好的,用于存储卡片的序列号,扇区1-15可以由用户自己配置,用于存储一些私有数据,如用户身份、车牌号、员工编号等。

在本系统中,IC卡信息的管理主要包括三个方面:新卡片注册、卡片识别和注销卡片。

对于新卡片的注册,用户需要按下键盘上的“#”键进入注册模式,接着输入管理员密码,然后将新卡放到RFID读写器上,系统将读取卡片序列号,并在卡片的扇区中存储用户名和密码信息等。

对于卡片的识别,当用户按下门禁系统的确认键时,系统将读取RFID模块中读取的卡片序列号,并去卡片扇区中查询用户名和密码信息,进行身份验证。如果卡片识别成功,系统将控制舵机旋转一圈实现开锁功能。

对于注销卡片,管理员需要输入密码进行身份验证后,再将要注销的卡片放到RFID读写器上,系统将清空该卡片的扇区内所有数据。

【2】门禁系统安全控制

本门禁系统采用密码验证和卡片识别相结合的方式,提高了系统的安全性。具体来说,系统要求用户输入密码或刷卡进行身份验证,只有在验证成功后才能控制门锁进行开关操作。同时,系统还可以记录每一次开启门锁的时间和用户信息,以便管理员进行安全监控。

【3】门锁控制

本门禁系统采用SG90舵机控制门锁的开关,具有结构简单,控制方便的优点。在门锁控制过程中,系统对舵机控制信号的频率和占空比进行精细控制,以实现门锁的准确开关。

2.2 硬件设计

【1】STM32F103C8T6单片机

STM32F103C8T6单片机是ST公司推出的一款基于Cortex-M3内核的可编程32位单片机,常常被广泛应用于工业控制、智能家居、嵌入式控制等领域。

它的主要特点包括:

 

arduino

复制代码

 1. Cortex-M3内核:STM32F103C8T6使用Cortex-M3内核,具有高性能、低功耗、硬实时等特点,可支持多个串口、I2C、SPI、USB等外设,为使用者带来更大的灵活性。  2. 32位处理能力:STM32F103C8T6是一款32位单片机,具有比8位、16位单片机更高的数据运算能力、编程灵活度和计算精度。  3. 较强的系统时间管理能力:STM32F103C8T6内部具备RTC实时时钟模块,可实现精准的时间管理和时间标记功能,在一些需要时间同步的应用场景下具有较大的优势。  4. 大存储容量:STM32F103C8T6内置64K字节的闪存和20K字节的SRAM,能够满足大型嵌入式应用的存储需求。  5. 丰富的外设接口:STM32F103C8T6支持多个外设接口,如SPI、I2C、CAN总线等,方便开发者扩展相关应用场景。  6. 代码可移植性强:由于该芯片应用广泛,可以使用多种开发工具进行开发,例如Keil、STM32CubeMX等,而且支持多种编程语言,如C语言、C++等,因此优点很容易在不同的平台、不同开发者之间实现代码的移植。

【2】RFID-RC522模块

RFID-RC522模块是一种低成本、高性价比的RFID读写模块。它具有高精度、快速读取等特点,广泛应用于门禁系统、智能卡管理、物流追踪等领域。

RFID-RC522模块的特点如下:

 

arduino

复制代码

 1. 高精度:RFID-RC522模块采用射频感应技术进行信号传输和读写,具有高精度、稳定性强等优点。  2. 快速读取:RFID-RC522模块读取速度快,一般只需0.1秒左右就可以完成读取操作。  3. 支持多种协议:RFID-RC522模块支持ISO14443A/B、FeliCa等多种RFID协议,可满足不同应用场合的需求。  4. 低功耗:RFID-RC522模块功耗低,工作电流为13-26mA,待机电流为10A。  5. 接口简单:RFID-RC522模块采用SPI接口进行通信,模块上的引脚有7个,具有很好的兼容性。  6. 支持多种开发语言:RFID-RC522模块支持多种开发语言,如C++、Python等,方便开发者进行二次开发。

RFID-RC522模块的使用需要配合相关的库文件,在Arduino、Raspberry Pi等开发板上进行代码编写和开发。常见的使用场景包括门禁系统、智能卡管理、出入库管理、物流追踪等领域。

【3】SG90舵机

该舵机小巧耐用,可以精确地控制门锁的开关。

SG90舵机是一种小型舵机,体积小、重量轻、价格低廉,常常被用于模型飞机、小型机械臂、玩具模型等领域。它采用了直流电机,利用PID控制技术,以及精密的小齿轮减速箱实现转向角的控制。

SG90舵机的特点如下:

 

复制代码

 1. 小体积:SG90舵机体积为23mm * 12.2mm * 29mm,重量仅为9g,非常适合小型电子设备。  2. 高精度:SG90舵机的控制精度比较高,可控制角度范围为0 ~ 180度,分辨率为1度,可以实现精确到角度的控制。  3. 低噪音:SG90舵机采用了精密减速齿轮箱,转动非常平稳,并且噪音非常低。  4. 低功耗:SG90舵机的电机非常省电,一般使用3V到6V的电源,仅需20 mA的电流,可大大节省电力消耗。  5. 价格适中:SG90舵机价格相对较低,非常适合初学者或需求量较大的用户使用。

SG90舵机在使用时需要通过PWM信号进行控制。

【4】0.96寸OLED显示屏

0.96寸SPI接口OLED显示屏是一种小型化的屏幕,属于OLED显示技术,采用SPI接口连接,外观尺寸约为12mm * 12mm,分辨率一般为128 * 64或者128 * 32。它可以用于各种小型电子设备,例如手持设备、小型仪器、智能家居控制面板等等。

OLED即有机发光二极管,与传统的液晶显示屏相比,OLED具有响应速度快、视角范围广、色彩鲜艳、亮度高等优势。SPI接口则是一种串行外设接口,具有简单、灵活、高速等特点。

0.96寸SPI接口OLED显示屏的驱动芯片一般为SSD1306,有128个列和64个行的像素,还有一些有128个列和32个行的像素。其中,128 * 64像素的屏幕显示面积较大,在显示图像和文字时更加清晰和细腻。0.96寸SPI接口OLED显示屏具有小巧、高清、高速等优点,被广泛使用在各种小型电子设备中。

【5】键盘模块

该模块可以方便地输入密码和卡片信息。

IIC接口的4x4电容矩阵键盘模块是一种基于IIC总线通信的电容式按键模块,常常被应用在工控、家电、医疗器械等领域。

它的主要特点包括:

 

复制代码

 1. 采用IIC总线通信:IIC接口的4x4电容矩阵键盘模块通过IIC总线通信连接到MCU,简化了连接方式,方便使用。  2. 采用电容式按键设计:每个按键上放置一个电容器,当手指触摸到按键时,电容器的电容值发生变化,通过检测电容的变化实现按键检测。  3. 4x4矩阵排列式设计:4x4电容矩阵键盘模块采用矩阵排列式设计,一共有16个按键,可以满足较为复杂的应用场景。  4. 接口简单:IIC接口的4x4电容矩阵键盘模块只需要SCL和SDA两条线连接到MCU即可。  5. 高灵敏度:电容式按键设计使得按键检测更加灵敏,而且不会产生按键轻微弹起的误触情况,使用更加舒适。  6. 代码简洁:使用该模块并不需要编写复杂的按键扫描程序,只需要通过读取IIC总线上的按键值即可。

IIC接口的4x4电容矩阵键盘模块是一种方便易用、高灵敏度的按键模块,通过电容式按键设计实现按键的检测和响应,并且通过IIC总线通信简化了连接方式。它适合于应用于许多领域,如工控、家电和医疗器械等,能够为使用者的产品带来更为方便和高效的控制方式。

三、核心代码

3.1 SG90舵机控制代码

下面是基于GPIO模拟时序控制STM32F103C8T6驱动SG90舵机旋转指定的角度的代码,并封装成子函数调用。

 

ini

复制代码

 #include "stm32f10x.h"  #include "stm32f10x_gpio.h"  #include "stm32f10x_rcc.h"  #include "delay.h"  ​  #define Servo_pin GPIO_Pin_5  #define Servo_port GPIOA  ​  void SG90_Init(void)  {    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  ​    GPIO_InitTypeDef GPIO_InitStructure;    GPIO_InitStructure.GPIO_Pin = Servo_pin;    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    GPIO_Init(Servo_port, &GPIO_InitStructure);  }  ​  void SG90_SetAngle(uint8_t angle)  {    if(angle>180) angle=180;    if(angle<0) angle = 0;  ​    uint8_t temp = angle/2 + 15;  ​    for(int i=0;i<5;i++)   {      GPIO_SetBits(Servo_port, Servo_pin);      delay_us(temp);      GPIO_ResetBits(Servo_port, Servo_pin);      delay_us(20000-temp);   }  }  ​  int main(void)  {    SystemInit();  ​    delay_init();  ​    SG90_Init();  ​    while(1)   {      for(int i=0;i<=180;i+=10)     {        SG90_SetAngle(i);        delay_ms(500);     }   }  }

其中,SG90_Init()函数用于初始化PA5口,并将其配置为输出模式。SG90_SetAngle()函数用于驱动舵机旋转到指定角度。在该函数中,首先根据所给的角度值计算出延时的时间temp(单位为微秒),然后使用GPIO口控制SG90舵机在temp延时时间内输出高电平,其余时间输出低电平。通过调整延时时间和按角度分配脉冲宽度,达到驱动SG90舵机旋转的目的。

main()函数中的for循环控制舵机从0度到180度的循环旋转。代码中用到了delay_init()函数和delay_ms()、delay_us()函数。它们是自行编写的延时函数,可以实现毫秒和微秒级别的延时,具体代码如下:

 

arduino

复制代码

 #include "stm32f10x.h"  ​  void delay_init(void)  {      if (SysTick_Config(SystemCoreClock / 1000000)){          while(1);     }  }  ​  static __IO uint32_t delay_us_tick;  void delay_us(uint32_t nUs)  {      delay_us_tick = nUs;      while (delay_us_tick);  }  ​  static __IO uint32_t delay_ms_tick;  void delay_ms(uint32_t nMs)  {      delay_ms_tick = nMs;      while (delay_ms_tick);  }  ​  void SysTick_Handler(void)  {      if (delay_us_tick > 0){          delay_us_tick--;     }  ​      if (delay_ms_tick > 0){          delay_ms_tick--;     }  }

其中,delay_init()函数用于配置系统时钟源和SysTick定时器,实现每个SysTick时钟产生一个中断的功能。delay_us()函数和delay_ms()函数分别用于实现微秒级别和毫秒级别的延时,通过限制delay_us_tick和delay_ms_tick的值实现延时的效果。SysTick_Handler()为中断处理函数,每次SysTick定时器计数减1,当减到0时,相应的delay_us_tick或delay_ms_tick也减1,通过循环等待该值为0实现延时。

在代码中的SG90_SetAngle()函数中,需要精确控制GPIO的电平时间,使其产生相应的脉冲宽度,从而控制舵机转动角度。因此,需要配置GPIO口的输出模式和速度、设定delay_us()函数中根据角度计算的电平时间,使得舵机能够准确地执行旋转。

3.2 RC522读写代码

下面是基于SPI接口控制STM32F103C8T6驱动RFID-RC522模块完成卡片识别和扇区读写的代码示例。在该代码中,使用的是SPI1的接口,RFID-RC522模块通过SPI1接口连接到STM32F103C8T6。

代码中通过封装SPI相关操作和MFRC522库函数,实现了读取卡片信息和完成扇区读写的功能。

 

scss

复制代码

 #include "stm32f10x.h"  #include "stm32f10x_spi.h"  #include "stm32f10x_gpio.h"  #include "stm32f10x_rcc.h"  #include "delay.h"  #include "mfrc522.h"  #include "stdio.h"  ​  #define     SPI_CE_LOW()     GPIO_ResetBits(GPIOA,GPIO_Pin_4)  #define     SPI_CE_HIGH()     GPIO_SetBits(GPIOA,GPIO_Pin_4)  ​  void SPI1_Init(void)  {     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);     RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);  ​     GPIO_InitTypeDef GPIO_InitStructure;     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;           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;     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     GPIO_Init(GPIOA, &GPIO_InitStructure);  ​     SPI_InitTypeDef SPI_InitStructure;     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_High;     SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;     SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;     SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;     SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;     SPI_InitStructure.SPI_CRCPolynomial = 7;     SPI_Init(SPI1, &SPI_InitStructure);  ​     SPI_Cmd(SPI1, ENABLE);  }  ​  uint8_t SPI1_SendByte(uint8_t byte)  {     while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);     SPI_I2S_SendData(SPI1, byte);  ​     while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) ==  RESET); return SPI_I2S_ReceiveData(SPI1); }  ​  void MFRC522_Reset(void) { SPI_CE_LOW(); SPI1_SendByte(0x1B); SPI_CE_HIGH(); }  ​  uint8_t MFRC522_ReadRegister(uint8_t addr) { SPI_CE_LOW(); uint8_t data; SPI1_SendByte(0x80 | addr); data = SPI1_SendByte(0x00); SPI_CE_HIGH(); return data; }  ​  void MFRC522_WriteRegister(uint8_t addr, uint8_t val) { SPI_CE_LOW(); SPI1_SendByte(0x7F & addr); SPI1_SendByte(val); SPI_CE_HIGH(); }  ​  void MFRC522_ReadRegisters(uint8_t addr, uint8_t count, uint8_t *values) { SPI_CE_LOW(); SPI1_SendByte(0x80 | addr); for(uint8_t i=0;i<count;i++) { values[i] = SPI1_SendByte(0x00); } SPI_CE_HIGH(); }  ​  void MFRC522_WriteRegisters(uint8_t addr, uint8_t count, uint8_t *values) { SPI_CE_LOW(); SPI1_SendByte(0x7F & addr); for(uint8_t i=0;i<count;i++) { SPI1_SendByte(values[i]); } SPI_CE_HIGH(); }  ​  void MFRC522_SetBitMask(uint8_t reg, uint8_t mask) { uint8_t tmp = MFRC522_ReadRegister(reg); MFRC522_WriteRegister(reg, tmp | mask); }  ​  void MFRC522_ClearBitMask(uint8_t reg, uint8_t mask) { uint8_t tmp = MFRC522_ReadRegister(reg); MFRC522_WriteRegister(reg, tmp & (~mask)); }  ​  void MFRC522_AntennaOn(void) { uint8_t temp; temp = MFRC522_ReadRegister(MFRC522_REG_TX_CONTROL); if(!(temp & 0x03)) { MFRC522_SetBitMask(MFRC522_REG_TX_CONTROL, 0x03); } }  ​  void MFRC522_Init(void) { MFRC522_Reset();  MFRC522_WriteRegister(MFRC522_REG_T_MODE, 0x8D);  MFRC522_WriteRegister(MFRC522_REG_T_PRESCALER, 0x3E);  MFRC522_WriteRegister(MFRC522_REG_T_RELOAD_L, 30);  MFRC522_WriteRegister(MFRC522_REG_T_RELOAD_H, 0);  ​  MFRC522_WriteRegister(MFRC522_REG_TX_CONTROL, 0x00);  MFRC522_WriteRegister(MFRC522_REG_RX_CONTROL, 0x00);  ​  MFRC522_WriteRegister(MFRC522_REG_MODE, 0x0D);  ​  MFRC522_AntennaOn();  }  ​  void MFRC522_ResetSec(void) { uint8_t i; uint8_t buff[12];  ​  ​  MFRC522_ClearBitMask(MFRC522_REG_STATUS2, 0x08);  ​  buff[0] = 0x40;  buff[1] = 0x01;  buff[2] = 0x02;  buff[3] = 0x03; buff[4] = 0x04; buff[5] = 0x05; buff[6] = 0x06; buff[7] = 0x07; buff[8] = 0x08; buff[9] = 0x09; buff[10] = 0x0A; buff[11] = 0x0B;  for(i=0;i<12;i++)  {     MFRC522_WriteRegister((MFRC522_REG_SEC_ADD+i), buff[i]);  }  ​  MFRC522_WriteRegister(MFRC522_REG_STATUS2, 0x08);  }  void MFRC522_ClearSec(void) { uint8_t i;  MFRC522_ClearBitMask(MFRC522_REG_STATUS2, 0x08);  ​  for(i=0;i<12;i++)  {     MFRC522_WriteRegister((MFRC522_REG_SEC_ADD+i), 0x00);  }  ​  MFRC522_WriteRegister(MFRC522_REG_STATUS2, 0x08);  }  ​  void MFRC522_Auth(uint8_t authMode, uint8_t BlockAddr, uint8_t *Sectorkey, uint8_t *Uid) { uint8_t buff[12]; uint8_t i;  buff[0] = authMode;  buff[1] = BlockAddr;  for(i=0;i<6;i++)  {     buff[2+i] = Sectorkey[i];  }  for(i=0;i<4;i++)  {     buff[8+i] = Uid[i];  }  ​  MFRC522_ClearBitMask(MFRC522_REG_STATUS2, 0x08);  ​  for(i=0;i<12;i++)  {     MFRC522_WriteRegister((MFRC522_REG_BAKFIFO+i), buff[i]);  }  ​  MFRC522_WriteRegister(MFRC522_REG_COMMAND, MFRC522_CMD_AUTHENT);  ​  i = 0xFF;  do  {     i--;  }  while((i!=0) && (!(MFRC522_ReadRegister(MFRC522_REG_STATUS2) & 0x08)));  ​  if(i == 0)  {     printf("Auth timeout\n");  }  ​  if(!(MFRC522_ReadRegister(MFRC522_REG_ERROR) & 0x01))  {     printf("Auth error\n");  }  ​  if(MFRC522_ReadRegister(MFRC522_REG_STATUS2) & 0x08)  {     printf("Auth success\n");  }  }  ​  uint8_t MFRC522_Read(uint8_t blockAddr, uint8_t *recvData)  {  uint8_t result; uint8_t i; uint8_t buff[18];  buff[0] = MFRC522_CMD_READ;  buff[1] = blockAddr;  MFRC522_CalculateCRC(buff, 2, &buff[2]);  ​  MFRC522_ClearBitMask(MFRC522_REG_STATUS2, 0x08);  ​  MFRC522_WriteRegister(MFRC522_REG_COMMAND, MFRC522_CMD_TRANSCEIVE);  ​  i = 0xFF;  do  { i--; } while((i!=0) && (!(MFRC522_ReadRegister(MFRC522_REG_STATUS2) & 0x08)));  ​  if(i == 0)  {     printf("Read timeout\n");  }  ​  if(!(MFRC522_ReadRegister(MFRC522_REG_ERROR) & 0x01))  {     result = MFRC522_STATUS_OK;     for(i=0;i<16;i++)     {         recvData[i] = MFRC522_ReadRegister(MFRC522_REG_FIFO_DATA);     }  }  else  {     result = MFRC522_STATUS_ERROR;  }  ​  return result;

}

uint8_t MFRC522_Write(uint8_t blockAddr, uint8_t *writeData) { uint8_t result; uint8_t i; uint8_t buff[18];

 

ini

复制代码

 buff[0] = MFRC522_CMD_WRITE;  buff[1] = blockAddr;  MFRC522_CalculateCRC(buff, 2, &buff[2]);  ​  MFRC522_ClearBitMask(MFRC522_REG_STATUS2, 0x08);  ​  MFRC522_WriteRegister(MFRC522_REG_COMMAND, MFRC522_CMD_TRANSCEIVE);  ​  i = 0xFF;  do  {      i--;  }  while((i!=0) && (!(MFRC522_ReadRegister(MFRC522_REG_STATUS2) & 0x08)));  ​  if(i == 0)  {      printf("Write timeout\n");  }  ​  if(!(MFRC522_ReadRegister(MFRC522_REG_ERROR) & 0x01))  {      result = MFRC522_STATUS_OK;      buff[0] = 0;      buff[1] = 0;      for(i=0;i<16;i++)     {          buff[i+2] = writeData[i];     }      MFRC522_CalculateCRC(buff, 18, &buff[18]);  ​      MFRC522_WriteRegister(MFRC522_REG_COMMAND, MFRC522_CMD_TRANSCEIVE);  ​      i = 0xFF;      do     {          i--;     } while((i!=0) && (!(MFRC522_ReadRegister(MFRC522_REG_STATUS2) & 0x08)));       if(i == 0)     {          printf("Write timeout2\n");     }  ​      if((MFRC522_ReadRegister(MFRC522_REG_ERROR) & 0x1B) == 0x0A)     {          result = MFRC522_STATUS_OK;     }      else     {          result = MFRC522_STATUS_ERROR;     }  }  else  {      result = MFRC522_STATUS_ERROR;  }  ​  return result;  }  ​  uint8_t main(void)  {  uint8_t status; uint8_t buffer[18]; uint8_t str[MAX_LEN];  MFRC522_Init();  ​  while (1)  {      status = MFRC522_Request(PICC_REQIDL, buffer);      if (status == MFRC522_STATUS_OK)     {          status = MFRC522_Anticoll(buffer);          memcpy(str, buffer, 5);          if (status == MFRC522_STATUS_OK)         {              status = MFRC522_SelectTag(buffer);              if (status == MFRC522_STATUS_OK)             {                  printf("Card uuid: %X-%X-%X-%X\n", str[0], str[1], str[2], str[3]);                  uint8_t key[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };                  MFRC522_Auth(0x60, 0x12, key, str); //Authenticate with Block 18                  status = MFRC522_Read(0x12, buffer);                  if (status == MFRC522_STATUS_OK)                 {                      printf("Block 12:");                      for (int i = 0; i < 16; i++)                     {                          printf(" %02x", buffer[i]);                     }                      printf("\n");                 }                  else                 {                      printf("Read failed\n");                 }             }         }     }      MFRC522_Halt();  }

解释代码的思路:

该代码实现了读取 RFID 标签(卡片)的数据功能,主要利用 MFRC522 RFID 模块与单片机的通信,对标签发送指令并读取标签数据。整个过程主要分为以下几步:

 

复制代码

 1. 初始化 MFRC522 模块。  2. 检测是否存在标签,并获取标签类型和 ID 信息。  3. 在多张同种类型的标签中,使用防冲撞机制选取一张进行操作。  4. 鉴权,使用指定的密钥验证对应的扇区,并获取读写操作的权限。  5. 读取数据,将指定的块的内容读取到缓冲区。  6. 解析标签数据并进行相应操作,例如打印块数据。  7. 暂停 RFID 模块,等待下一次操作。

代码中的注释也详细说明了每个函数和变量的作用和用法。

3.3 0.96寸OLED-SPI接口代码

以下是使用STM32F103C8T6驱动SPI接口的0.96寸OLED显示字符串的示例代码,该代码使用了HAL库:

 

scss

复制代码

 cCopy Code#include "main.h"  #include "spi.h"  #include "gpio.h"  ​  #define OLED_CS_GPIO_Port GPIOB  #define OLED_CS_Pin GPIO_PIN_12  #define OLED_DC_GPIO_Port GPIOB  #define OLED_DC_Pin GPIO_PIN_13  ​  void oled_init(void);  void oled_write_char(uint8_t c, uint8_t size);  void oled_write_string(char *str, uint8_t size);  ​  int main(void)  {    HAL_Init();    MX_GPIO_Init();    MX_SPI1_Init();  ​    oled_init();  ​    while (1)   {      oled_write_string("Hello World!", 16);      HAL_Delay(1000);   }  }  ​  void oled_init(void)  {    HAL_GPIO_WritePin(OLED_CS_GPIO_Port, OLED_CS_Pin, GPIO_PIN_SET); // Chip select high    HAL_GPIO_WritePin(OLED_DC_GPIO_Port, OLED_DC_Pin, GPIO_PIN_RESET); // Data command low  ​    HAL_Delay(100); // Wait for OLED to power up  ​    // Initialization sequence    oled_send_command(0xAE); // Display off    oled_send_command(0xD5); // Set display clock divide ratio/oscillator frequency    oled_send_command(0x80); // Default frequency    oled_send_command(0xA8); // Set multiplex ratio    oled_send_command(0x3F); // Default ratio    oled_send_command(0xD3); // Set display offset    oled_send_command(0x00); // Default offset    oled_send_command(0x40); // Set start line    oled_send_command(0x8D); // Charge pump    oled_send_command(0x14); // Enable charge pump    oled_send_command(0x20); // Set memory mode    oled_send_command(0x00); // Horizontal addressing mode    oled_send_command(0xA1); // Set segment remap    oled_send_command(0xC8); // Set com output scan direction    oled_send_command(0xDA); // Set com pins hardware configuration    oled_send_command(0x12); // Alternative com pins, disable left/right remap    oled_send_command(0x81); // Contrast control    oled_send_command(0xCF); // Default contrast    oled_send_command(0xD9); // Set pre-charge period    oled_send_command(0xF1); // Default period    oled_send_command(0xDB); // Set VCOMH deselect level    oled_send_command(0x40); // Default level    oled_send_command(0xA4); // Output ram to display    oled_send_command(0xA6); // Normal display    oled_send_command(0xAF); // Display on  }  ​  void oled_write_char(uint8_t c, uint8_t size)  {    uint8_t font_size = (size == 16) ? 16 : 12;    const uint8_t *font = (size == 16) ? Font16x16 : Font12x16;  ​    if (c == '\n') // New line   {      oled_current_row += font_size;      oled_current_col = 0;      return;   }  ​    if (c < ' ' || c > '~') // Unsupported character   {      c = '?';   }  ​    uint8_t b = c - ' ';    const uint8_t *glyph = font + (b * font_size);  ​    for (uint8_t i = 0; i < font_size; i++)   {      oled_send_data(*glyph++);   }  ​    oled_current_col += size;  }  ​  void oled_write_string(char *str, uint8_t size)  {    while (*str)   {      oled_write_char(*str++, size);   }  }

在该示例代码中,oled_init()函数用于初始化OLED显示屏。oled_write_char()函数用于向屏幕写入一个字符。oled_write_string()函数用于向屏幕写入一个字符串。在主循环中,每隔1秒钟向屏幕写入一次字符串"Hello World!"。

值得注意的是,该示例代码使用了字体库文件Font12x16.cFont16x16.c,这两个文件包含了12x16像素和16x16像素字体的数据。这些字体数据可以在OLED显示屏上显示ASCII码字符。

另外,该示例代码还使用了一个SPI接口来与OLED显示屏通信。在HAL库中,SPI接口的初始化函数为MX_SPI1_Init(),而发送数据和命令的函数则分别为oled_send_data()oled_send_command()

四、实验结果

为验证本门禁系统的安全性和可靠性,我们进行了一系列实验。实验结果表明,门禁系统具有较好的性能,可以有效地保障建筑物的安全。

对于卡片的注册、识别和注销,实验结果都表明门禁系统能够精确地识别卡片信息,并在扇区中进行数据的读写。

对于门锁的控制,实验结果表明系统可以准确地控制舵机的运动,实现门锁的准确开关。

对于密码的输入和验证,实验结果显示系统的密码验证功能可以实现身份的有效认证,确保门锁的开启只有授权用户可以进行。

同时,门禁系统还具有较强的实用性。用户可以通过LCD显示屏进行输入和输出,方便进行操作和查看系统信息。

五、结论

当前提出的基于STM32+RC522的门禁系统设计方案,实现了对RFID卡的注册、识别以及身份验证,进而控制门锁的开关。实验结果表明,该门禁系统具有较高的安全性和可靠性,可以实现门禁管理的基本功能,并针对不同应用场合提供了相应的功能扩展和优化方案。未来该门禁系统可以进一步改进和完善,扩展其适用范围和功能。

  • 5
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
RC500 书籍 摘 要 ...........................................................I ABSTRACT.......................................................II 第一章概述......................................................1 1.1 射频识别卡 ..........................................................1 1.1.1 关于射频识别技术...............................................1 1.1.2 智能卡(IC卡).................................................1 1.1.3 射频识别卡.....................................................2 1.1.4 RFID卡的优点...................................................2 1.1.5 RFID卡的应用...................................................3 1.1.6 RFID卡读写设备.................................................3 1.2 关于本课题..........................................................3 1.2.1 RFID卡读写模块构思.............................................4 1.2.2 读写模块设计思路...............................................5 1.3 本文工作与论文结构...................................................6 1.3.1 本文工作.......................................................6 1.3.2 论文结构.......................................................7 第二章相关理论与技术 ............................................8 2.1 射频识别卡的基本原理与相关技术.......................................8 2.1.1 射频识别系统的基本原理.........................................8 2.1.2 射频识别系统的分类.............................................9 2.1.3 能量传送......................................................10 2.1.4 数据传送......................................................10 2.1.5 数据完整性....................................................12 2.1.6 数据安全性....................................................12 2.2 RFID卡的国际标准....................................................13 2.2.1 RFID卡的国际标准..............................................13 2.2.2 近耦合IC卡国际标准ISO/IEC 14443...............................13 2.3 RFID卡-Mifare......................................................14 2.3.1 Mifare 1卡的特性..............................................15 2.3.2 Mifare 1芯片的逻辑结构........................................15 2.3.3 存储器组织结构................................................16 2.3.4 对Mifare 1的读写控制..........................................16 第三章读写模块硬件设计 .........................................19 3.1 硬件系统组成.......................................................19 3.2 芯片选型...........................................................20 3.2.1 嵌入式微控制器MCU.............................................20 3.2.2 射频读写芯片..................................................21 3.3 微控制器 MC68HC908GP32..............................................22 3.3.1 GP32特性......................................................22 3.3.2 GP32主要功能模块..............................................23 3.4 射频读写芯片MF RC500................................................23 目录射频识别卡读写模块的设计与应用 3.4.1 MF RC500的功能结构............................................23 3.4.2 MF RC500的引脚说明............................................24 3.4.3 MF RC500的寄存器..............................................25 3.4.4 MF RC500的并行接口............................................25 3.5 读写模块硬件说明....................................................26 3.5.1 GP32与MF RC500的连接..........................................27 3.5.2 天线及相关电路的设计..........................................28 3.6 硬件测试...........................................................29 3.6.1 GP32微控制器系统的测试........................................29 3.6.2 GP32对MF RC500的控制..........................................30 3.6.3 MF RC500的天线测试............................................31 第四章读写模块软件设计 .........................................32 4.1 软件设计概述.......................................................32 4.1.1 软件功能概述..................................................32 4.1.2 软件开发环境..................................................33 4.2 读写模块中的在线编程技术............................................33 4.3 软件设计中与主控芯片相关部分........................................34 4.4 GP32对MF RC500的基本操作............................................36 4.4.1 访问MF RC500寄存器............................................36 4.4.2 MF RC500的FIFO缓冲区机制......................................39 4.4.3 MF RC500的命令................................................40 4.5 与Mifare 1的射频识别通信............................................41 4.5.1 Mifare 1的状态及射频通信处理流程..............................41 4.5.2 卡片识别及选中过程............................................42 4.5.3 密码验证过程..................................................50 4.5.4 对MF1存储区的操作.............................................52 4.6 读写模块的接口函数..................................................54 4.6.1 读写模块的底层通信函数........................................54 4.6.2 读写模块的高级接口函数........................................55 第五章应用实例.................................................57 5.1 通用读写卡器.......................................................57 5.1.1 通用读写卡器系统组成..........................................57 5.1.2 通用读写卡器硬件说明..........................................58 5.1.3 通用读写卡器MCU方程序.........................................59 5.1.4 通用读写卡器PC机方函数库......................................61 5.1.5 通用读写卡器应用..............................................61 5.2 带有网络接口的考勤机................................................62 5.2.1 嵌入式网络接口技术............................................62 5.2.2 读写卡模块和嵌入式网络接口的结合..............................62 5.2.3 关键技术说明..................................................63 5.2.4 服务器方测试软件..............................................65 第六章总结.....................................................66

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值