简介

基于RFID视频技术的汽车车位锁系统,由STM32F103C8T6单片机核心板电路、LCD1602液晶显示电路、RFID模块电路、按键电路和继电器电路组成。通过继电器模拟车位入口锁开关,正常情况下闭合不允许其他车辆驶入,如果刷卡成功继电器断开,车辆驶入。

学习主要学习使用RC552,RFID射频模块, 主要学习使用RC552,RFID射频模块,主要学习使用RC552,RFID射频模块

设计背景及其意义

射频识别,RFID(Radio Frequency Identification)技术,又称无线射频识别,是一种通信技术,可通过无线电讯号识别特定目标并读写相关数据,而无需识别系统与特定目标之间建立机械或光学接触。RFID技术具有防水、防磁、耐高温、使用寿命长、读取距离大、标签上数据可以加密、存储数据容量更大、存储信息更改自如等优点,应用在各领域;经济水平的高速发展让人们越来越关心建筑内部的安全性。为了适应信息时代的需要,保证建筑内部的安全性,智能门禁系统由此而研发。门禁系统集电脑技术、电子技术、机械技术、磁电技术和射频识别技术于一体,以智能卡的方式来控制门锁的开启,它不仅给管理者提供了更安全、更快捷、更自动化的管理模式,而且也给使用者带来了极大的方便。

方案的设计与论证

控制方案的确定

STM32F103C8T6单片机核心板电路+LCD1602液晶显示电路+RFID模块电路+按键电路+继电器电路组成。

控制方式的选择

选择STM32单片机,STM32系列处理器是意法半导体ST公司生产的一种基于ARM 7架构的32位、支持实时仿真和跟踪的微控制器。使用ARM最新的、先进架构的Cortex-M3内核,具有优异的实时性能、杰出的功耗控制、出众及创新的外设,并且最大程度的集成整合,十分易于开发,可使产品快速将进入市场。

硬件电路的设计

系统的功能分析及体系结构设计

系统功能分析

  • 继电器模拟车位入口锁开关(类似车位前车桩),正常情况下闭合不允许其他车辆驶入,如果刷卡成功继电器断开,车辆驶入。
  • 车辆驶入后,通过按键再次打开继电器,打开车桩,即将车锁在车位处。

系统总体结构

本系统具体框图如下图所示:

STM32单片机核心电路设计

STM32系列处理器是意法半导体ST公司生产的一种基于ARM 7架构的32位、支持实时仿真和跟踪的微控制器。选择此款控制芯片是因为本系统设计并非追求成本的最低或更小的功耗,而是在实现本设计功能的前提下能够提供更丰富的接口和功能以便于设计实验系统各实验项目所需的外围扩展电路。此款控制芯片在完成单片机课程的学习后上手较为容易,在医疗器械中应用广泛,具有很好的学习、实验研究价值。

STM32的主要优点

  • (1)使用ARM最新的、先进架构的Cortex-M3内核
  • (2) 优异的实时性能
  • (3) 功耗相当低
  • (4) 出众及创新的外设
  • (5) 最大程度的集成整合
  • (6) 易于开发,可使产品快速将进入市场

对于使用同一平台进行多个项目开发而言,STM32是最佳的选择:

  • (1) 从仅需少量的存储空间和管脚应用到需要更多的存储空间和管脚的应用
  • (2) 从苛求性能的应用到电池供电的应用
  • (3) 从简单而成本敏感的应用到高端应用
  • (4) 全系列脚对脚、外设及软件的高度兼容性,给您带来全方位的灵活性。您可以在不必修改您原始框架及软件的条件下,将您的应用升级到需要更多存储空间或精简到使用更少存储空间/ 或改用不同的封装的规格。

STM32F103C8T6单片机核心板接口电路图如下图所示。

STM32单片机核心板内部电路图如下图所示。

按键电路(含上拉电阻)设计

轻触按键是按键产品下属的一款分类产品,它其实相当于是一种电子开关,只要轻轻的按下按键就可以是开关接通,松开时是开关就断开连接,实现原理主要是通过轻触按键内部的金属弹片受力弹动来实现接通和断开的。按键作为系统的输入,起到了人机交互的枢纽作用。按键的单片机控制引脚默认为高电平,当按键按下后,单片机的相关引脚则变成低电平。进而实现对系统的手动输入。其电路原理图如下图所示。电路中电阻作用为上拉电阻,保证按键信号的稳定输出。

MFRC-522RFID射频模块电路设计

选择MFRC-522射频模块进行刷卡操作。MF RC522是应用于13.56MHz非接触式通信中高集成度的读写卡芯片,是NXP公司针对“三表”应用推出的一款低电压、低成本、体积小的非接触式读写卡芯片,是智能仪表和便携式手持设备研发的较好选择。MF RC522利用了先进的调制和解调概念,完全集成了在13.56MHz下所有类型的被动非接触式通信方式和协议。支持14443A兼容应答器信号。数字部分处理ISO14443A帧和错误检测。此外,还支持快速CRYPTO1加密算法,用语验证MIFARE系列产品。MFRC522支持MIFARE系列更高速的非接触式通信,双向数据传输速率高达424kbit/s。作为13.56MHz高集成度读写卡系列芯片家族的新成员,MF RC522与MF RC500和MF RC530有不少相似之处,同时也具备许多特点和差异。它与主机间通信采用SPI模式,有利于减少连线,缩小PCB板体积,降低成本。MF522-AN模块采用Philips MFRC522原装芯片设计读卡电路,使用方便,成本低廉,适用于设备开发、读卡器开发等高级应用的用户、需要进行射频卡终端设计/生产的用户。本模块可直接装入各种读卡器模具。模块采用电压为3.3V,通过SPI接口简单的几条线就可以直接与用户任何CPU主板相连接通信,可以保证模块稳定可靠的工作、读卡距离远;

电气参数简介

  • (1)工作电流:13—26mA/直流3.3V
  • (2)空闲电流:10-13mA/直流3.3V
  • (3)休眠电流:<80uA
  • (4)峰值电流:<30mA
  • (5)工作频率:13.56MHz
  • (6)支持的卡类型:mifare1 S50、mifare1 S70、mifare UltraLight、mifare Pro、mifare Desfire
  • (7)环境工作温度:摄氏-20—80度
  • (8)环境储存温度:摄氏-40—85度
  • (9)环境相对湿度:
  • (10)相对湿度5%—95%

模块接口SPI参数

  • 数据传输速率:最大10Mbit/s

模块主要指标

  • 容量为8K位EEPROM
  • 分为16个扇区,每个扇区为4块,每块16个字节,以块为存取单位
  • 每个扇区有独立的一组密码及访问控制
  • 每张卡有唯一序列号,为32位
  • 具有防冲突机制,支持多卡操作
  • 无电源,自带天线,内含加密控制逻辑和通讯逻辑电路
  • 数据保存期为10年,可改写10万次,读无限次
  • 工作温度:-20℃~50℃(湿度为90%)
  • 工作频率:13.56MHZ
  • 通信速率:106 KBPS
  • 读写距离:10 cm以内(与读写器有关)

模块接口原理图

模块实物图

5V继电器控制电路

继电器是一种电控制器件,是当输入量(激励量)的变化达到规定要求时,在电气输出电路中使被控量发生预定的阶跃变化的一种电器。它具有控制系统(又称输入回路)和被控制系统(又称输出回路)之间的互动关系。通常应用于自动化的控制电路中,它实际上是用小电流去控制大电流运作的一种“自动开关”。继电器是具有隔离功能的自动开关元件,广泛应用于遥控、遥测、

通讯、自动控制、机电一体化及电力电子设备中,是最重要的控制元件之一故在电路中起着自动调节、安全保护、转换电路等作用。继电器一般由铁芯、线圈、衔铁、触点簧片等组成的。只要在线圈两端加上一定的电压,线圈中就会流过一定的电流,从而产生电磁效应,衔铁就会在电磁力吸引的作用下克服返回弹簧的拉力吸向铁芯,从而带动衔铁的动触点与静触点(常开触点)吸合。当线圈断电后,电磁的吸力也随之消失,衔铁就会在弹簧的反作用力返回原来的位置,使动触点与原来的静触点(常闭触点)释放。这样吸合、释放,从而达到了在电路中的导通、切断的目的。在本系统中,通过三极管驱动继电器,当单片机的控制引脚为高电平时,三极管导通,此时继电器供电闭合,同时指示灯LED亮,与LED灯串联的电阻为限流作用保护LED灯,与三极管基集相连的电阻也是限流作用,保护三极管。继电器控制电路的原理图如下图所示。

软件设计

程序流程图

本系统设计主要采用Keil uVision5软件编写与调试程序,代码C语言编写。

Code

main.c

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "lcd.h"
#include <stdio.h>
#include "timer.h"
#include "lcd1602.h"
#include "key.h"
#include "rc522.h"

/**************/
unsigned char idCard[4]={0x87,0x15,0xc9,0x73};        //有效卡号
/**************/

u8 rekey = 0;//按键防止重复
u8 i;
unsigned char UID[5];            //读取到的卡号
unsigned char Temp[4] ;

int main(void)
{      
    delay_init();             //延时函数初始化      
    uart_init(9600);         //串口初始化为9600
  TIM3_Int_Init(499,7199);//50ms       
    LED_Init();                  //初始化与LED连接的硬件接口
    KEY_Init();            //初始化按键

    relay1 = 0;  
    delay_ms(200);
    relay1 =1;

  Rc522IoInit();
  PcdReset();//复位RC522
  PcdAntennaOn();//开启天线发射 

     while(1)
    {
        if(key1==0)         //检测到按键按下
        {
            delay_ms(10);   //小抖动

                if(key1==0)    //检测是否按下
                {
                    relay1 =1;    //打开继电器
            }
        }
    if(PcdRequest(0x52,Temp)==MI_OK)//读取到卡
    {
      if(PcdAnticoll(UID)==MI_OK)//卡号获取成功
      { 
                if((UID[0]==idCard[0])&&(UID[2]==idCard[2])&&(UID[3]==idCard[3]))//匹配卡号
                {
                    relay1 =0;        //关闭继电器
                }        
                delay_ms(10);
      }
    }

    }                                                
}

lcd1602.h

#include "lcd1602.h"

/************************端口初始化*******************************/
void Lcd_GPIO_init(void)
{
     GPIO_InitTypeDef GPIO_InitStructure;   //声明结构体

    /********Data端口设置*************/
     RCC_APB2PeriphClockCmd(RCC_GPIO_DATA, ENABLE);  //打开端口B时钟 
     GPIO_InitStructure.GPIO_Pin  = GPIO_DATA_0_PIN|GPIO_DATA_1_PIN|GPIO_DATA_2_PIN|GPIO_DATA_3_PIN|GPIO_DATA_4_PIN|GPIO_DATA_5_PIN|GPIO_DATA_6_PIN|GPIO_DATA_7_PIN; //  DB8~DB15
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //标准输出模式
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度
     GPIO_Init(GPIO_DATA_0, &GPIO_InitStructure);      //初始化端口

     /********使能端口设置**********/
     RCC_APB2PeriphClockCmd(RCC_GPIO_EN, ENABLE);        //打开端口时钟 
     GPIO_InitStructure.GPIO_Pin =  GPIO_EN_PIN;         // 使能端口
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //标准输出模式
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度
     GPIO_Init(GPIO_EN, &GPIO_InitStructure);

     /********读/写端口设置**********/
     RCC_APB2PeriphClockCmd(RCC_GPIO_RW, ENABLE);    //打开端口时钟 
     GPIO_InitStructure.GPIO_Pin =  GPIO_RW_PIN;     // 使能端口
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //标准输出模式
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度
     GPIO_Init(GPIO_RW, &GPIO_InitStructure);

     /********指令/数据端口设置**********/
     RCC_APB2PeriphClockCmd(RCC_GPIO_RS, ENABLE);    //打开端口时钟 
     GPIO_InitStructure.GPIO_Pin =  GPIO_RS_PIN;     // 使能端口
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽复用输出
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度
     GPIO_Init(GPIO_RS, &GPIO_InitStructure);


}
/******************************************************************/



void Lcd_Init( void )  //初始化
{  
     Lcd_GPIO_init();
    delay_us(1500);                     //延时15ms
    Lcd_Write_Command( 0x38,0);       // 写指令38H 不检测忙信号
    delay_us(500);                      //延时5ms
    Lcd_Write_Command( 0x38,0);       // 写指令38H 不检测忙信号
    delay_us(500);                      //延时5ms
    Lcd_Write_Command( 0x38,0);       // 写指令38H 不检测忙信号
                                         //以后每次写指令、读/写数据操作之前需检测忙信号
    Lcd_Write_Command( 0x38,1);       //显示模式设置 
    Lcd_Write_Command( 0x08,1);          //显示关闭
    Lcd_Write_Command( 0x01,1);       //显示清屏
    Lcd_Write_Command( 0x06,1);       //显示光标移动设置 
    Lcd_Write_Command( 0x0C,1);       //显示开、光标不显示
} 
/******************************************************/

void Lcd_En_Toggle(void) //发使能脉冲
{
    SET_EN;        //使能1
    delay_us(5);   //延时160us
    CLE_EN;
}


void Lcd_Busy(void)//判断忙
{
     unsigned int later0=0;
     GPIO_InitTypeDef GPIO_InitStructure;
     RCC_APB2PeriphClockCmd(RCC_GPIO_DATA, ENABLE);    //打开DATA端口时钟 

     GPIO_InitStructure.GPIO_Pin  = GPIO_DATA_0_PIN|GPIO_DATA_1_PIN|GPIO_DATA_2_PIN|GPIO_DATA_3_PIN|GPIO_DATA_4_PIN|GPIO_DATA_5_PIN|GPIO_DATA_6_PIN|GPIO_DATA_7_PIN; //  DB8~DB15
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //输入模式 = 上拉输入
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度
     GPIO_Init(GPIO_DATA_7, &GPIO_InitStructure);      //打开忙检测端口

      CLE_RS; //RS = 0
     //delay_us(1);   //延时10us
     SET_RW; //RW = 1
     //delay_us(1);   //延时10us
     SET_EN; //EN = 1
     //delay_us(2);   //延时20us
     while ((GPIO_ReadInputDataBit(GPIO_DATA_7,GPIO_DATA_7_PIN))&&(later0<20000)) //循环等待忙检测端口 = 0
     {
         delay_us(5);
        later0++;    
     }
     CLE_EN; //EN = 0

     //恢复端口为输出状态 
        RCC_APB2PeriphClockCmd(RCC_GPIO_DATA, ENABLE);    //打开DATA端口时钟 
     GPIO_InitStructure.GPIO_Pin  = GPIO_DATA_0_PIN|GPIO_DATA_1_PIN|GPIO_DATA_2_PIN|GPIO_DATA_3_PIN|GPIO_DATA_4_PIN|GPIO_DATA_5_PIN|GPIO_DATA_6_PIN|GPIO_DATA_7_PIN; //  DB8~DB15
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度
     GPIO_Init(GPIO_DATA_7, &GPIO_InitStructure);

} 

void Gpio_data(unsigned char x)  //端口置入数据
{  
GPIO_ResetBits(GPIO_DATA_0, GPIO_DATA_0_PIN);  //DB0
GPIO_ResetBits(GPIO_DATA_0, GPIO_DATA_1_PIN);  //DB1
GPIO_ResetBits(GPIO_DATA_0, GPIO_DATA_2_PIN);  //DB2
GPIO_ResetBits(GPIO_DATA_0, GPIO_DATA_3_PIN);  //DB3
GPIO_ResetBits(GPIO_DATA_0, GPIO_DATA_4_PIN);  //DB4
GPIO_ResetBits(GPIO_DATA_0, GPIO_DATA_5_PIN);  //DB5
GPIO_ResetBits(GPIO_DATA_0, GPIO_DATA_6_PIN);  //DB6
GPIO_ResetBits(GPIO_DATA_0, GPIO_DATA_7_PIN);  //DB7
if(x&0X01)GPIO_SetBits(GPIO_DATA_0, GPIO_DATA_0_PIN);//DB0
if(x&0X02)GPIO_SetBits(GPIO_DATA_0, GPIO_DATA_1_PIN);//DB1
if(x&0X04)GPIO_SetBits(GPIO_DATA_0, GPIO_DATA_2_PIN);//DB2
if(x&0X08)GPIO_SetBits(GPIO_DATA_0, GPIO_DATA_3_PIN);//DB3
if(x&0X10)GPIO_SetBits(GPIO_DATA_0, GPIO_DATA_4_PIN);//DB4
if(x&0X20)GPIO_SetBits(GPIO_DATA_0, GPIO_DATA_5_PIN);//DB5
if(x&0X40)GPIO_SetBits(GPIO_DATA_0, GPIO_DATA_6_PIN);//DB6
if(x&0X80)GPIO_SetBits(GPIO_DATA_0, GPIO_DATA_7_PIN);//DB7
}


//向液晶里面写入指令  时序:RS=L,RW=L,Data0-Data7=指令码,E=高脉冲
void Lcd_Write_Command(unsigned char x,char Busy) 
{ 
    if(Busy) Lcd_Busy();
    //delay_us(1);   //延时10us
    CLE_RS;  //RS = 0 
    //delay_us(1);   //延时10us
    CLE_RW;  //RW = 0 
    //delay_us(4);   //延时40us
    Gpio_data(x);  //端口置入数据
    //delay_us(4);   //延时40us
    Lcd_En_Toggle();  //发使能脉冲
    //delay_us(1);   //延时100us
    Lcd_Busy(); //测忙

}
//向液晶里面写入数据  时序:RS=H,RW=L,Data0-Data7=指令码,E=高脉冲
void Lcd_Write_Data( unsigned char x) //向液晶里面写入数据 
{ 
    Lcd_Busy(); //测忙
    //delay_us(1);   //延时10us
    SET_RS;   //RS = 1 
    //delay_us(1);   //延时10us
    CLE_RW;   //RW = 0
    //delay_us(4);   //延时40us
    Gpio_data(x);
    //delay_us(4);   //延时40us
    Lcd_En_Toggle();  //发使能脉冲
    //delay_us(1);   //延时100us
    Lcd_Busy(); //测忙

} 

void Lcd_SetXY(unsigned char x,unsigned char y)   //字符初始位置设定,x表示列,y表示行 
{ 
     unsigned char addr; 
     if(y==0) 
          addr=0x80+x; 
     else if(y==1)
          addr=0xC0+x; 
     Lcd_Write_Command(addr,1) ; 
} 
/******************************************************/

void Lcd_Puts(unsigned char x,unsigned char y, unsigned char *string) //向1602写一个字符串 
{ 
   //unsigned char i=0;
   Lcd_SetXY(x,y); 
    while(*string) 
      { 
       Lcd_Write_Data(*string); 
       string++; 
      } 
}

void Lcd_1Put(unsigned char x,unsigned char y, unsigned char Data0)
{
       Lcd_SetXY(x,y); 
    Lcd_Write_Data(Data0); 
}

lcd1602.h

#ifndef __lcd1602_H
#define __lcd1602_H     

#include "stm32f10x.h"
#include "delay.h"

/********************各端口定义*********************************/
#define GPIO_EN       GPIOB                 //  使能端口组
#define GPIO_EN_PIN   GPIO_Pin_7            //  使能端口号
#define RCC_GPIO_EN   RCC_APB2Periph_GPIOB  //  使能时钟组

#define GPIO_RW       GPIOB                 //  读/写选择端口组
#define GPIO_RW_PIN   GPIO_Pin_6            //  读/写选择端口号
#define RCC_GPIO_RW   RCC_APB2Periph_GPIOB  //  读/写时钟组

#define GPIO_RS       GPIOB                 //  数据/命令端口组
#define GPIO_RS_PIN   GPIO_Pin_5            //  数据/命令端口号
#define RCC_GPIO_RS   RCC_APB2Periph_GPIOB  //  数据/命令时钟组

#define GPIO_DATA_0       GPIOB         //  数据线0_端口组
#define GPIO_DATA_0_PIN   GPIO_Pin_8    //  数据线0_端口号
#define GPIO_DATA_1       GPIOB         //  数据线1_端口组0
#define GPIO_DATA_1_PIN   GPIO_Pin_9    //  数据线1_端口号
#define GPIO_DATA_2       GPIOB         //  数据线2_端口组
#define GPIO_DATA_2_PIN   GPIO_Pin_10   //  数据线2_端口号
#define GPIO_DATA_3       GPIOB         //  数据线3_端口组
#define GPIO_DATA_3_PIN   GPIO_Pin_11   //  数据线3_端口号
#define GPIO_DATA_4       GPIOB         //  数据线4_端口组
#define GPIO_DATA_4_PIN   GPIO_Pin_12   //  数据线4_端口号
#define GPIO_DATA_5       GPIOB         //  数据线5_端口组
#define GPIO_DATA_5_PIN   GPIO_Pin_13   //  数据线5_端口号
#define GPIO_DATA_6       GPIOB         //  数据线6_端口组
#define GPIO_DATA_6_PIN   GPIO_Pin_14   //  数据线6_端口号
#define GPIO_DATA_7       GPIOB         //  数据线7_端口组
#define GPIO_DATA_7_PIN   GPIO_Pin_15   //  数据线7_端口号
#define RCC_GPIO_DATA   RCC_APB2Periph_GPIOB  //  数据线时钟组


/******************************************************************/


/***********************基本指令***********************************/
#define SET_EN  GPIO_SetBits(GPIO_EN, GPIO_EN_PIN)        //EN 使能  输出1
#define CLE_EN  GPIO_ResetBits(GPIO_EN, GPIO_EN_PIN)    //      输出0 
#define SET_RW  GPIO_SetBits(GPIO_RW, GPIO_RW_PIN)      //RW 读写  输出1
#define CLE_RW  GPIO_ResetBits(GPIO_RW, GPIO_RW_PIN)    //      输出0
#define SET_RS  GPIO_SetBits(GPIO_RS, GPIO_RS_PIN)        //RS 指令  输出1
#define CLE_RS  GPIO_ResetBits(GPIO_RS, GPIO_RS_PIN)    //      输出0
/******************************************************************/

void Lcd_GPIO_init(void);
void Lcd_Init( void ) ;
void Lcd_En_Toggle(void);
void Lcd_Busy(void);
void Gpio_data(unsigned char x);
void Lcd_Write_Command(unsigned char x,char Busy);
void Lcd_Write_Data( unsigned char x); 
void Lcd_SetXY(unsigned char x,unsigned char y);
void Lcd_Puts(unsigned char x,unsigned char y, unsigned char *string);
void Lcd_1Put(unsigned char x,unsigned char y, unsigned char Data0);


#endif

rc552.c

#include "rc522.h"

void Rc522IoInit(void)
{
//  P4DIR |= BIT7+BIT6+BIT5+BIT3;     //读卡接口
//  P4DIR &=~BIT4;

 GPIO_InitTypeDef  GPIO_InitStructure;

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);     //使能PA,PD端口时钟

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;                 // 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;          //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;         //IO口速度为50MHz
 GPIO_Init(GPIOA, &GPIO_InitStructure);                     //根据设定参数初始化

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能PORTA,PORTC时钟

    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_1;//PA1
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA15

}

//******************************************************************/
//功    能:读RC522寄存器
//参数说明:Address[IN]:寄存器地址
//返    回:读出的值
//******************************************************************/
unsigned char ReadRawRC(unsigned char Address)
{
  unsigned char i, ucAddr             ;
  unsigned char ucResult=0            ;
  NSS522_0                            ;
  SCK522_0                            ;
  ucAddr = ((Address<<1)&0x7E)|0x80   ;
  for(i=8;i>0;i--)
  {
    if((ucAddr&0x80)==0x80)
      SI522_1                         ;
    else
      SI522_0                         ;
    SCK522_1                          ;
    ucAddr <<= 1                      ;
    SCK522_0                          ;
  }
  for(i=8;i>0;i--)
  {
    SCK522_1                          ;
    ucResult <<=1                     ;
    ucResult |= SO522                 ;
    SCK522_0                          ;
  }
  SCK522_0                            ;
  NSS522_1                            ;
  return ucResult                     ;
}

//******************************************************************/
//功    能:写RC522寄存器
//参数说明:Address[IN]:寄存器地址
//          value 要写入的值
//******************************************************************/

void WriteRawRC(unsigned char Address, unsigned char value)
{  
    unsigned char  ucAddr        ;

    NSS522_0                     ;
    SCK522_0                     ;
    ucAddr = ((Address<<1)&0x7E) ;
    {
      if(ucAddr&0x80)
        SI522_1                  ;
      else
        SI522_0                  ; 
      SCK522_1                   ;
      ucAddr <<= 1               ;
      SCK522_0                   ;

      if(ucAddr&0x80)
        SI522_1                  ;
      else
        SI522_0                  ; 
      SCK522_1                   ;
      ucAddr <<= 1               ;
      SCK522_0                   ;

      if(ucAddr&0x80)
        SI522_1                  ;
      else
        SI522_0                  ; 
      SCK522_1                   ;
      ucAddr <<= 1               ;
      SCK522_0                   ;

      if(ucAddr&0x80)
        SI522_1                  ;
      else
        SI522_0                  ; 
      SCK522_1                   ;
      ucAddr <<= 1               ;
      SCK522_0                   ;

      if(ucAddr&0x80)
        SI522_1                  ;
      else
        SI522_0                  ; 
      SCK522_1                   ;
      ucAddr <<= 1               ;
      SCK522_0                   ;

      if(ucAddr&0x80)
        SI522_1                  ;
      else
        SI522_0                  ; 
      SCK522_1                   ;
      ucAddr <<= 1               ;
      SCK522_0                   ;

      if(ucAddr&0x80)
        SI522_1                  ;
      else
        SI522_0                  ; 
      SCK522_1                   ;
      ucAddr <<= 1               ;
      SCK522_0                   ;

      if(ucAddr&0x80)
        SI522_1                  ;
      else
        SI522_0                  ; 
      SCK522_1                   ;
      ucAddr <<= 1               ;
      SCK522_0                   ;                  
    }
    {
      if(value&0x80)
        SI522_1                  ;
      else
        SI522_0                  ;
      SCK522_1                   ;
      value <<= 1                ;
      SCK522_0                   ;

      if(value&0x80)
        SI522_1                  ;
      else
        SI522_0                  ;
      SCK522_1                   ;
      value <<= 1                ;
      SCK522_0                   ;

      if(value&0x80)
        SI522_1                  ;
      else
        SI522_0                  ;
      SCK522_1                   ;
      value <<= 1                ;
      SCK522_0                   ;

      if(value&0x80)
        SI522_1                  ;
      else
        SI522_0                  ;
      SCK522_1                   ;
      value <<= 1                ;
      SCK522_0                   ;

      if(value&0x80)
        SI522_1                  ;
      else
        SI522_0                  ;
      SCK522_1                   ;
      value <<= 1                ;
      SCK522_0                   ;

      if(value&0x80)
        SI522_1                  ;
      else
        SI522_0                  ;
      SCK522_1                   ;
      value <<= 1                ;
      SCK522_0                   ;

      if(value&0x80)
        SI522_1                  ;
      else
        SI522_0                  ;
      SCK522_1                   ;
      value <<= 1                ;
      SCK522_0                   ;

      if(value&0x80)
        SI522_1                  ;
      else
        SI522_0                  ;
      SCK522_1                   ;
      value <<= 1                ;
      SCK522_0                   ;      
    }
    SCK522_0;
    NSS522_1;
}

//******************************************************************/
//功    能:置RC522寄存器位
//参数说明:reg[IN]:寄存器地址
//          mask[IN]:置位值
//******************************************************************/
void SetBitMask(unsigned char reg,unsigned char mask)  
{
  char tmp = 0x0            ;
  tmp = ReadRawRC(reg)| mask;
  WriteRawRC(reg,tmp | mask);  // set bit mask
}

//******************************************************************/
//功    能:清RC522寄存器位
//参数说明:reg[IN]:寄存器地址
//          mask[IN]:清位值
//******************************************************************/
void ClearBitMask(unsigned char reg,unsigned char mask)  
{
  char tmp = 0x0              ;
  tmp = ReadRawRC(reg)&(~mask);
  WriteRawRC(reg, tmp)        ;  // clear bit mask
} 

//******************************************************************/
//功    能:复位RC522
//返    回: 成功返回MI_OK
//******************************************************************/
#define DELAYNUM 200
char PcdReset()
{
  RF_POWER_ON                          ;
  RST522_1                             ;
  delay_us(DELAYNUM)                             ;
  RST522_0                             ;
  delay_us(DELAYNUM)                             ;
  RST522_1                             ;
  delay_us(DELAYNUM)                             ;
  WriteRawRC(CommandReg,PCD_RESETPHASE);
  delay_us(DELAYNUM)                             ;
  WriteRawRC(ModeReg,0x3D)             ;
  WriteRawRC(TReloadRegL,30)           ;
  WriteRawRC(TReloadRegH,0)            ;
  WriteRawRC(TModeReg,0x8D)            ;
  WriteRawRC(TPrescalerReg,0x3E)       ;   
//  WriteRawRC(TxASKReg,0x40)            ; // FOR DEBUG AND TEST
  return MI_OK                         ; 
}

//******************************************************************/
//开启天线发射  
//每次启动或关闭天险发射之间应至少有1ms的间隔
//******************************************************************/
void PcdAntennaOn()
{
  unsigned char i;
  WriteRawRC(TxASKReg,0x40)       ;
  delay_us(800);//delay_ms(1)                       ;
  i = ReadRawRC(TxControlReg)     ;
  if(!(i&0x03))
    SetBitMask(TxControlReg, 0x03);
  i=ReadRawRC(TxASKReg)       ;
}

//******************************************************************/
//关闭天线发射
//******************************************************************/
//void PcdAntennaOff()
//{
//  ClearBitMask(TxControlReg, 0x03);
//}

//******************************************************************/
//功    能:通过RC522和ISO14443卡通讯
//参数说明:Command[IN]:RC522命令字
//          pInData[IN]:通过RC522发送到卡片的数据
//          InLenByte[IN]:发送数据的字节长度
//          pOutData[OUT]:接收到的卡片返回数据
//          *pOutLenBit[OUT]:返回数据的位长度
//******************************************************************/
char PcdComMF522(unsigned char Command  ,unsigned char *pInData , 
                 unsigned char InLenByte,unsigned char *pOutData, 
                 unsigned int  *pOutLenBit                       )
{
  char status = MI_ERR                          ;
  unsigned char irqEn   = 0x00                  ;
  unsigned char waitFor = 0x00                  ;
  unsigned char lastBits                        ;
  unsigned char n                               ;
  unsigned int  i                               ;
  switch (Command)
  {
    case PCD_AUTHENT:
      irqEn   = 0x12                            ;
      waitFor = 0x10                            ;
      break                                     ;
    case PCD_TRANSCEIVE:
      irqEn   = 0x77                            ;
      waitFor = 0x30                            ;
      break                                     ;
    default:
      break                                     ;
  }
  WriteRawRC(ComIEnReg,irqEn|0x80)              ; //
  ClearBitMask(ComIrqReg,0x80)                  ;
  WriteRawRC(CommandReg,PCD_IDLE)               ;
  SetBitMask(FIFOLevelReg,0x80)                 ; // 清空FIFO 
  for(i=0; i<InLenByte; i++)
    WriteRawRC(FIFODataReg,pInData[i])          ; // 数据写入FIFO 
  WriteRawRC(CommandReg, Command)               ; // 命令写入命令寄存器
  if(Command == PCD_TRANSCEIVE)
    SetBitMask(BitFramingReg,0x80)              ; // 开始发送     
  i = 6000                                      ; //根据时钟频率调整,操作M1卡最大等待时间25ms
  do 
  {
    n = ReadRawRC(ComIrqReg)                    ;
    i--                                         ;
  }
  while((i!=0)&&!(n&0x01)&&!(n&waitFor))        ;
  ClearBitMask(BitFramingReg,0x80)              ;
  if(i!=0)
  {
    if(!(ReadRawRC(ErrorReg)&0x1B))
    {
      status = MI_OK                            ;
      if (n&irqEn&0x01)
        status = MI_NOTAGERR                    ;
      if(Command==PCD_TRANSCEIVE)
      {
        n = ReadRawRC(FIFOLevelReg)             ;
        lastBits = ReadRawRC(ControlReg)&0x07   ;
        if(lastBits)
          *pOutLenBit = (n-1)*8 + lastBits      ;
        else
          *pOutLenBit = n*8                     ;
        if(n==0)
          n = 1                                 ;
        if(n>MAXRLEN)
          n = MAXRLEN                           ;
        for (i=0; i<n; i++)
          pOutData[i] = ReadRawRC(FIFODataReg)  ; 
      }
    }
    else
      status = MI_ERR                           ;        
  }
  SetBitMask(ControlReg,0x80)                   ;// stop timer now
  WriteRawRC(CommandReg,PCD_IDLE)               ; 
  return status;
}

//******************************************************************/
//功    能:寻卡                                                    /
//参数说明: req_code[IN]:寻卡方式                                   /
//                0x52 = 寻感应区内所有符合14443A标准的卡           /
//                0x26 = 寻未进入休眠状态的卡                       /
//          pTagType[OUT]:卡片类型代码                             /
//                0x4400 = Mifare_UltraLight                        /
//                0x0400 = Mifare_One(S50)                          /
//                0x0200 = Mifare_One(S70)                          /
//                0x0800 = Mifare_Pro(X)                            /
//                0x4403 = Mifare_DESFire                           /
//返    回: 成功返回MI_OK                                           /
//******************************************************************/
char PcdRequest(unsigned char req_code,unsigned char *pTagType)
{
  char status                                        ;  
  unsigned int  unLen                                ;
  unsigned char ucComMF522Buf[MAXRLEN]               ; 

    PcdReset();//复位RC522
  PcdAntennaOn();//开启天线发射 
    delay_ms(1);

  ClearBitMask(Status2Reg,0x08)                      ;
  WriteRawRC(BitFramingReg,0x07)                     ;
  SetBitMask(TxControlReg,0x03)                      ;

  ucComMF522Buf[0] = req_code                        ;

  status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,
                       1,ucComMF522Buf,&unLen       );
  if ((status == MI_OK) && (unLen == 0x10))
  {    
    *pTagType     = ucComMF522Buf[0]                 ;
    *(pTagType+1) = ucComMF522Buf[1]                 ;
  }
  else
    status = MI_ERR                                  ;
  return status                                      ;
}

//******************************************************************/
//功    能:防冲撞                                                  /
//参数说明: pSnr[OUT]:卡片序列号,4字节                             /
//返    回: 成功返回MI_OK                                           /
//******************************************************************/
char PcdAnticoll(unsigned char *pSnr)
{
    char status;
    unsigned char i,snr_check=0;
    unsigned int  unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 

    ClearBitMask(Status2Reg,0x08);
    WriteRawRC(BitFramingReg,0x00);
    ClearBitMask(CollReg,0x80);

    ucComMF522Buf[0] = PICC_ANTICOLL1;
    ucComMF522Buf[1] = 0x20;

    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen);

    if (status == MI_OK)
    {
         for (i=0; i<4; i++)
         {   
             *(pSnr+i)  = ucComMF522Buf[i];
             snr_check ^= ucComMF522Buf[i];
         }
         if (snr_check != ucComMF522Buf[i])
         {   status = MI_ERR;    }
    }

    SetBitMask(CollReg,0x80);
    return status;
}

rc552.h

#include "stm32f10x.h"
#include "delay.h"

#define RF_SS                  PAout(4)  // p4.7 射频卡从机选择(SS)---SDA
#define RF_SCLK                PAout(3)  // p4.6 射频卡数据时钟输出(SCLK)
#define RF_DATA_OUT            PAout(2)  // p4.5 射频卡数据输出(MOSI)
#define RF_DATA_IN             PAin(1)  // p4.4 射频模块输入(MISO) 
#define RF_LPCTL               PAout(0)  // P4.3 射频卡休眠控制 ------RST   



#define    NSS522_1                RF_SS=1                        // 从机选择无效       
#define    NSS522_0                RF_SS=0                        // 从机选择有效
#define    SCK522_1                RF_SCLK=1                      // 数据时钟置高
#define    SCK522_0                RF_SCLK=0                      // 数据时钟置低
#define    SI522_1                 RF_DATA_OUT=1                  // 数据置高        
#define    SI522_0                 RF_DATA_OUT=0                  // 数据置低 

#define    SO522                 RF_DATA_IN                // 数据输入

#define    RST522_1                RF_LPCTL=1
#define    RST522_0                RF_LPCTL=0

//------------------------------- RC522操作宏 ------------------------------//
#define    RF_POWER_ON             delay_us(10)                                // 射频模块上电
#define    RF_POWER_OFF            delay_us(10)                                // 射频模块下电



#define MAXRLEN        18

//*******************RC522 FIFO长度定义***************************/
//#define DEF_FIFO_LENGTH             64           //FIFO size=64byte

//***********************RC522命令字*****************************/
#define PCD_IDLE                  0x00           //取消当前命令
#define PCD_AUTHENT               0x0E           //验证密钥
//#define PCD_RECEIVE               0x08           //接收数据
//#define PCD_TRANSMIT              0x04           //发送数据
#define PCD_TRANSCEIVE            0x0C           //发送并接收数据
#define PCD_RESETPHASE            0x0F           //复位
#define PCD_CALCCRC               0x03           //CRC计算

//*******************Mifare_One卡片命令字****************************/
#define PICC_ANTICOLL1            0x93           //防冲撞

//************************MF522寄存器定义**************************/
// PAGE 0    
#define     CommandReg            0x01    
#define     ComIEnReg             0x02     
#define     ComIrqReg             0x04    
#define     DivIrqReg             0x05
#define     ErrorReg              0x06      
#define     Status2Reg            0x08    
#define     FIFODataReg           0x09
#define     FIFOLevelReg          0x0A
#define     ControlReg            0x0C
#define     BitFramingReg         0x0D
#define     CollReg               0x0E
// PAGE 1     
#define     ModeReg               0x11
#define     TxControlReg          0x14
#define     TxASKReg              0x15
// PAGE 2    
#define     CRCResultRegM         0x21
#define     CRCResultRegL         0x22
#define     TModeReg              0x2A
#define     TPrescalerReg         0x2B
#define     TReloadRegH           0x2C
#define     TReloadRegL           0x2D

//*******************RC522通讯返回错误代码*********************/
#define MI_ERR                      0xFE 
#define MI_OK                          0 
#define MI_NOTAGERR                 0xFF 

//***********************函数定义***************************/
void Rc522IoInit(void);
char PcdReset(void)                                                          ;
void PcdAntennaOn(void)                                                      ;
//void PcdAntennaOff(void)                                                     ;
char PcdRequest(unsigned char req_code,unsigned char *pTagType)              ;   
char PcdAnticoll(unsigned char *pSnr)                                        ;                               
char PcdComMF522(unsigned char Command, unsigned char *pInData, 
                 unsigned char InLenByte,unsigned char *pOutData, 
                 unsigned int  *pOutLenBit                       )           ;
void WriteRawRC(unsigned char Address,unsigned char value)                   ;
unsigned char ReadRawRC(unsigned char Address)                               ; 
void SetBitMask(unsigned char reg,unsigned char mask)                        ; 
void ClearBitMask(unsigned char reg,unsigned char mask)                      ;

//void CalulateCRC(unsigned char *pIndata,unsigned char len,
//                 unsigned char *pOutData                  )                  ;