crystal1987的个人空间 https://bbs.21ic.com/?1370010 [收藏] [复制] [RSS]

日志

STM32驱动射频卡(RC522)以及人体红外感应器

热度 1已有 1501 次阅读2016-9-20 10:22 |个人分类:单片机驱动相关模块|系统分类:单片机| 射频卡RC522, 人体红外感应

    最近做射频卡控制实验,参考的是野火的代码,代码研读了一遍,但是和文档“RFID智能卡RC522+USART+TIM3实验”的内容由出入,尤其是使用的PIN口差别较大;而且和射频卡的接口对应不上,这里没有指责野火的意思,毕竟是做服务的,就是提点建议,当然这也不是本文的重点(野火的工作人员,尤其工程师看见别生气,对不住啊)。
     试验的方法是参考野火的,使用串口给单片机发送命令,控制射频卡执行相关动作。本来是想使用红外遥控让单片机执行相关动作,由于现有的单片机功能比较单一,所以还是选择串口啦。试验的方法:使用串口发送命令控制射频卡执行读写卡功能,并在OLED屏上对相关动作进行显示,同时读取的数据在OLED屏或串口中进行显示。具体的命令可以参考文档“RFID智能卡RC522+USART+TIM3实验”的内容;对于射频卡充值和消费数据记录由以下两条命令完成,
消费命令:1A A4 FF FF FF FF FF FF 04 C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 64 
充值命令:1A A4 FF FF FF FF FF FF 04 C1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 64 
对于以上两条命令的功能,在后面进行说明。
    试验中人体红外感应功能比较简单,就是相当于按键采集功能。还有就是OLED和串口通信功能也比较简单,这里不再敖述。先看看试验效果。


RC522.H文件

#ifndef __rc522_H_F
#define __rc522_H_F
#include "stm32f10x_spi.h"
       
/////////////////////////////////////////////////////////////////////
//MF522命令字
/////////////////////////////////////////////////////////////////////
#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_REQIDL           0x26               //寻天线区内未进入休眠状态
#define PICC_REQALL           0x52               //寻天线区内全部卡
#define PICC_ANTICOLL1        0x93               //防冲撞
#define PICC_ANTICOLL2        0x95               //防冲撞
#define PICC_AUTHENT1A        0x60               //验证A密钥
#define PICC_AUTHENT1B        0x61               //验证B密钥
#define PICC_READ             0x30               //读块
#define PICC_WRITE            0xA0               //写块
#define PICC_DECREMENT        0xC0               //扣款
#define PICC_INCREMENT        0xC1               //充值
#define PICC_RESTORE          0xC2               //调块数据到缓冲区
#define PICC_TRANSFER         0xB0               //保存缓冲区中数据
#define PICC_HALT             0x50               //休眠

/////////////////////////////////////////////////////////////////////
//MF522 FIFO长度定义
/////////////////////////////////////////////////////////////////////
#define DEF_FIFO_LENGTH       64                 //FIFO size=64byte
#define MAXRLEN  18

/////////////////////////////////////////////////////////////////////
//MF522寄存器定义
/////////////////////////////////////////////////////////////////////
// PAGE 0
#define     RFU00                 0x00    
#define     CommandReg            0x01    
#define     ComIEnReg             0x02    
#define     DivlEnReg             0x03    
#define     ComIrqReg             0x04    
#define     DivIrqReg             0x05
#define     ErrorReg              0x06    
#define     Status1Reg            0x07    
#define     Status2Reg            0x08    
#define     FIFODataReg           0x09
#define     FIFOLevelReg          0x0A
#define     WaterLevelReg         0x0B
#define     ControlReg            0x0C
#define     BitFramingReg         0x0D
#define     CollReg               0x0E
#define     RFU0F                 0x0F
// PAGE 1     
#define     RFU10                 0x10
#define     ModeReg               0x11
#define     TxModeReg             0x12
#define     RxModeReg             0x13
#define     TxControlReg          0x14
#define     TxAutoReg             0x15
#define     TxSelReg              0x16
#define     RxSelReg              0x17
#define     RxThresholdReg        0x18
#define     DemodReg              0x19
#define     RFU1A                 0x1A
#define     RFU1B                 0x1B
#define     MifareReg             0x1C
#define     RFU1D                 0x1D
#define     RFU1E                 0x1E
#define     SerialSpeedReg        0x1F
// PAGE 2    
#define     RFU20                 0x20  
#define     CRCResultRegM         0x21
#define     CRCResultRegL         0x22
#define     RFU23                 0x23
#define     ModWidthReg           0x24
#define     RFU25                 0x25
#define     RFCfgReg              0x26
#define     GsNReg                0x27
#define     CWGsCfgReg            0x28
#define     ModGsCfgReg           0x29
#define     TModeReg              0x2A
#define     TPrescalerReg         0x2B
#define     TReloadRegH           0x2C
#define     TReloadRegL           0x2D
#define     TCounterValueRegH     0x2E
#define     TCounterValueRegL     0x2F
// PAGE 3      
#define     RFU30                 0x30
#define     TestSel1Reg           0x31
#define     TestSel2Reg           0x32
#define     TestPinEnReg          0x33
#define     TestPinValueReg       0x34
#define     TestBusReg            0x35
#define     AutoTestReg           0x36
#define     VersionReg            0x37
#define     AnalogTestReg         0x38
#define     TestDAC1Reg           0x39  
#define     TestDAC2Reg           0x3A   
#define     TestADCReg            0x3B   
#define     RFU3C                 0x3C   
#define     RFU3D                 0x3D   
#define     RFU3E                 0x3E   
#define     RFU3F                                  0x3F

/////////////////////////////////////////////////////////////////////
//和MF522通讯时返回的错误代码
/////////////////////////////////////////////////////////////////////
#define         MI_OK                 0
#define         MI_NOTAGERR           (1)
#define         MI_ERR                (2)


#define  SENDID     0xA0
#define  READCARD   0xA1
#define  WRITECARD  0xA2
#define  KEYCARD    0xA3
#define  VALUECARD  0xA4
//#define  SETTIME    0xA4

#define SPIReadByte()        SPIWriteByte(0)
u8 SPIWriteByte(u8 byte);
void SPI2_Init(void);

#define SET_SPI_CS  (GPIOB->BSRR=0X01)
#define CLR_SPI_CS  (GPIOB->BRR=0X01)

#define SET_RC522RST  GPIOB->BSRR=0X02
#define CLR_RC522RST  GPIOB->BRR=0X02
void InitRc522(void);
void ClearBitMask(u8 reg,u8 mask);
void WriteRawRC(u8 Address, u8 value);
void SetBitMask(u8 reg,u8 mask);
char PcdComMF522(u8 Command,u8 *pIn,u8 InLenByte,u8 *pOut,u8 *pOutLenBit);
void CalulateCRC(u8 *pIn ,u8 len,u8 *pOut);
u8 ReadRawRC(u8 Address);
void PcdAntennaOn(void);

char PcdReset(void);
char PcdRequest(unsigned char req_code,unsigned char *pTagType);
void PcdAntennaOn(void);
void PcdAntennaOff(void);
char M500PcdConfigISOType(unsigned char type);
char PcdAnticoll(unsigned char *pSnr);
char PcdSelect(unsigned char *pSnr);
char PcdAuthState(unsigned char auth_mode,unsigned char addr,unsigned char *pKey,unsigned char *pSnr);
char PcdWrite(unsigned char addr,unsigned char *pData);
char PcdRead(unsigned char addr,unsigned char *pData);
char PcdHalt(void);
void Reset_RC522(void);
void RC522_Test_Func(void);
char PcdValue(u8 dd_mode,u8 addr,u8 *pValue);
char PcdBakValue(u8 sourceaddr, u8 goaladdr);
#endif

RC522.C文件

#include "delay.h"
#include "rc522.h"
#include <string.h>
#include "main.h"
#include "oled.h"

void delay_ns(u32 ns)
{
                u32 i;
                for(i=0;i<ns;i++)
                {
                        __nop();
                        __nop();
                        __nop();
                }
}

u8 SPIWriteByte(u8 Byte)
{
                while((SPI2->SR&0X02)==0);                //等待发送区空         
                SPI2->DR=Byte;                //发送一个byte   
                while((SPI2->SR&0X01)==0);//等待接收完一个byte  
                return SPI2->DR;                      //返回收到的数据                       
}
void SPI2_Init(void)       
{
                GPIO_InitTypeDef GPIO_InitStructure;
                 
                //配置SPI2管脚
                RCC->APB2ENR|=1<<0;
                RCC->APB2ENR|=1<<3;
               
                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
                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_13 | GPIO_Pin_15;
                GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
                GPIO_Init(GPIOB, &GPIO_InitStructure);

                GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_14;    
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 
                GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
                GPIO_Init(GPIOB, &GPIO_InitStructure);  

                RCC->APB1ENR|=1<<14;

                SPI2->CR1|=0<<10;//全双工模式       
                SPI2->CR1|=1<<9; //软件nss管理
                SPI2->CR1|=1<<8;  
               
                SPI2->CR1|=1<<2; //SPI主机
                SPI2->CR1|=0<<11;//8bit数据格式       
                SPI2->CR1&=~0x02; //空闲模式下SCK为0 CPOL=0
                SPI2->CR1&=~0x01; //数据采样从第一个时间边沿开始,CPHA=0  
                SPI2->CR1|=7<<3; //Fsck=Fcpu/4
                SPI2->CR1|=0<<7; //MSBfirst   
                SPI2->CR1|=1<<6; //SPI设备使能
                //SPIx_ReadWriteByte(0xff);//启动传输   
}

void InitRc522(void)
{
                SPI2_Init();
                PcdReset();
                PcdAntennaOff();  
                PcdAntennaOn();
                M500PcdConfigISOType( 'A' );
}
void Reset_RC522(void)
{
                PcdReset();
                PcdAntennaOff();  
                PcdAntennaOn();
}                         
/////////////////////////////////////////////////////////////////////
//功    能:寻卡
//参数说明: 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(u8 req_code,u8 *pTagType)
{
                char status;  
                u8   unLen;
                u8   ucComMF522Buf[MAXRLEN]; 

                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(u8 *pSnr)
{
    char status;
    u8   i,snr_check=0;
    u8   unLen;
    u8   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;
}

/////////////////////////////////////////////////////////////////////
//功    能:选定卡片
//参数说明: pSnr[IN]:卡片序列号,4字节
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdSelect(u8 *pSnr)
{
    char   status;
    u8   i;
    u8   unLen;
    u8   ucComMF522Buf[MAXRLEN]; 
    
    ucComMF522Buf[0] = PICC_ANTICOLL1;
    ucComMF522Buf[1] = 0x70;
    ucComMF522Buf[6] = 0;
    for (i=0; i<4; i++)
    {
                                ucComMF522Buf[i+2] = *(pSnr+i);
                                ucComMF522Buf[6]  ^= *(pSnr+i);
    }
    CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]);
  
    ClearBitMask(Status2Reg,0x08);

    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen);
    
    if((status == MI_OK) && (unLen == 0x18))
    {
                                status = MI_OK;  
                }
    else
    {   
                                status = MI_ERR;    
                }

    return status;
}

/////////////////////////////////////////////////////////////////////
//功    能:验证卡片密码
//参数说明: auth_mode[IN]: 密码验证模式
//                 0x60 = 验证A密钥
//                 0x61 = 验证B密钥 
//          addr[IN]:块地址
//          pKey[IN]:密码
//          pSnr[IN]:卡片序列号,4字节
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////               
char PcdAuthState(u8  auth_mode,u8   addr,u8 *pKey,u8 *pSnr)
{
    char   status;
    u8   unLen;
    u8   ucComMF522Buf[MAXRLEN]; 

    ucComMF522Buf[0] = auth_mode;
    ucComMF522Buf[1] = addr;
    memcpy(&ucComMF522Buf[2], pKey, 6); 
    memcpy(&ucComMF522Buf[8], pSnr, 4);    
    status = PcdComMF522(PCD_AUTHENT,ucComMF522Buf,12,ucComMF522Buf,&unLen);
    if ((status != MI_OK) || (!(ReadRawRC(Status2Reg) & 0x08)))
    {
                                status = MI_ERR;   
                }
    return status;
}

/////////////////////////////////////////////////////////////////////
//功    能:读取M1卡一块数据
//参数说明: addr[IN]:块地址
//          p [OUT]:读出的数据,16字节
//返    回: 成功返回MI_OK
///////////////////////////////////////////////////////////////////// 
char PcdRead(u8   addr,u8 *p )
{
    char status;
    u8   unLen;
    u8   i,ucComMF522Buf[MAXRLEN]; 

    ucComMF522Buf[0] = PICC_READ;
    ucComMF522Buf[1] = addr;
    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
   
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
    if ((status == MI_OK) && (unLen == 0x90))
    {
        for (i=0; i<16; i++)
        { 
                                                *(p +i) = ucComMF522Buf[i];   
                                }
    }
    else
    {
                                status = MI_ERR;   
                }
    return status;
}

/////////////////////////////////////////////////////////////////////
//功    能:写数据到M1卡一块
//参数说明: addr[IN]:块地址
//          p [IN]:写入的数据,16字节
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////                  
char PcdWrite(u8   addr,u8 *p )
{
    char   status;
    u8   unLen;
    u8   i,ucComMF522Buf[MAXRLEN]; 
    
    ucComMF522Buf[0] = PICC_WRITE;
    ucComMF522Buf[1] = addr;
    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
    if((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
    {   status = MI_ERR;   }
        
    if (status == MI_OK)
    {
        for (i=0; i<16; i++)
        {    
                ucComMF522Buf[i] = *(p +i);   
        }
        CalulateCRC(ucComMF522Buf,16,&ucComMF522Buf[16]);

        status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,18,ucComMF522Buf,&unLen);
        if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
        {   status = MI_ERR;   }
    }   
    return status;
}

/////////////////////////////////////////////////////////////////////
//功    能:命令卡片进入休眠状态
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdHalt(void)
{
    u8   status;
    u8   unLen;
    u8   ucComMF522Buf[MAXRLEN]; 

    ucComMF522Buf[0] = PICC_HALT;
    ucComMF522Buf[1] = 0;
    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
    return MI_OK;
}

/////////////////////////////////////////////////////////////////////
//用MF522计算CRC16函数
/////////////////////////////////////////////////////////////////////
void CalulateCRC(u8 *pIn ,u8   len,u8 *pOut )
{
    u8   i,n;
    ClearBitMask(DivIrqReg,0x04);
    WriteRawRC(CommandReg,PCD_IDLE);
    SetBitMask(FIFOLevelReg,0x80);
    for (i=0; i<len; i++)
    {   WriteRawRC(FIFODataReg, *(pIn +i));   }
    WriteRawRC(CommandReg, PCD_CALCCRC);
    i = 0xFF;
    do 
    {
        n = ReadRawRC(DivIrqReg);
        i--;
    }
    while ((i!=0) && !(n&0x04));
    pOut [0] = ReadRawRC(CRCResultRegL);
    pOut [1] = ReadRawRC(CRCResultRegM);
}

/////////////////////////////////////////////////////////////////////
//功    能:复位RC522
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdReset(void)
{
       
                SET_RC522RST;
                delay_ns(10);
                CLR_RC522RST;
                delay_ns(10);               
                SET_RC522RST;
    delay_ns(10);
       
    WriteRawRC(CommandReg,PCD_RESETPHASE);
                WriteRawRC(CommandReg,PCD_RESETPHASE);
    delay_ns(10);
    
    WriteRawRC(ModeReg,0x3D);            //和Mifare卡通讯,CRC初始值0x6363
    WriteRawRC(TReloadRegL,30);           
    WriteRawRC(TReloadRegH,0);
    WriteRawRC(TModeReg,0x8D);
    WriteRawRC(TPrescalerReg,0x3E);
                WriteRawRC(TxAutoReg,0x40);//必须要
  
    return MI_OK;
}
//////////////////////////////////////////////////////////////////////
//设置RC632的工作方式 
//////////////////////////////////////////////////////////////////////
char M500PcdConfigISOType(u8   type)
{
   if(type == 'A')                     //ISO14443_A
   { 
       ClearBitMask(Status2Reg,0x08);
       WriteRawRC(ModeReg,0x3D);//3F
       WriteRawRC(RxSelReg,0x86);//84
       WriteRawRC(RFCfgReg,0x7F);   //4F
             WriteRawRC(TReloadRegL,30);//tmoLength);// TReloadVal = 'h6a =tmoLength(dec) 
                        WriteRawRC(TReloadRegH,0);
       WriteRawRC(TModeReg,0x8D);
            WriteRawRC(TPrescalerReg,0x3E);
                        delay_ns(1000);
       PcdAntennaOn();
   }
   else
       
                        return 1; 
        }
   return MI_OK;
}
/////////////////////////////////////////////////////////////////////
//功    能:读RC632寄存器
//参数说明:Address[IN]:寄存器地址
//返    回:读出的值
/////////////////////////////////////////////////////////////////////
u8 ReadRawRC(u8   Address)
{
    u8   ucAddr;
    u8   ucResult=0;
         CLR_SPI_CS;
    ucAddr = ((Address<<1)&0x7E)|0x80;
       
                SPIWriteByte(ucAddr);
                ucResult=SPIReadByte();
                SET_SPI_CS;
    return ucResult;
}

/////////////////////////////////////////////////////////////////////
//功    能:写RC632寄存器
//参数说明:Address[IN]:寄存器地址
//          value[IN]:写入的值
/////////////////////////////////////////////////////////////////////
void WriteRawRC(u8   Address, u8   value)
{  
    u8   ucAddr;

                CLR_SPI_CS;
                ucAddr = ((Address<<1)&0x7E);
                SPIWriteByte(ucAddr);
                SPIWriteByte(value);
                SET_SPI_CS;
}
/////////////////////////////////////////////////////////////////////
//功    能:置RC522寄存器位
//参数说明:reg[IN]:寄存器地址
//          mask[IN]:置位值
/////////////////////////////////////////////////////////////////////
void SetBitMask(u8   reg,u8   mask)  
{
    char   tmp = 0x0;
    tmp = ReadRawRC(reg);
    WriteRawRC(reg,tmp | mask);  // set bit mask
}

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

/////////////////////////////////////////////////////////////////////
//功    能:通过RC522和ISO14443卡通讯
//参数说明:Command[IN]:RC522命令字
//          pIn [IN]:通过RC522发送到卡片的数据
//          InLenByte[IN]:发送数据的字节长度
//          pOut [OUT]:接收到的卡片返回数据
//          *pOutLenBit[OUT]:返回数据的位长度
/////////////////////////////////////////////////////////////////////
char PcdComMF522(u8   Command, 
                 u8 *pIn , 
                 u8   InLenByte,
                 u8 *pOut , 
                 u8 *pOutLenBit)
{
    char   status = MI_ERR;
    u8   irqEn   = 0x00;
    u8   waitFor = 0x00;
    u8   lastBits;
    u8   n;
    u16   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, pIn [i]);    }
    WriteRawRC(CommandReg, Command);         
    
    if (Command == PCD_TRANSCEIVE)
    {    SetBitMask(BitFramingReg,0x80);  }        //开始传送
                                                                                     
    //i = 600;//根据时钟频率调整,操作M1卡最大等待时间25ms
                i = 700;
    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++)
                {   pOut [i] = ReadRawRC(FIFODataReg);    }
            }
        }
        else
        {   status = MI_ERR;   }
        
    }
    SetBitMask(ControlReg,0x80);           // stop timer now
    WriteRawRC(CommandReg,PCD_IDLE); 
    return status;
}

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


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



/*******************************************************************************
* 描  述  :  对寻卡、防冲撞、选卡、发送卡号、读卡、写卡、修改密码进行操作
             成功则LED1灯亮
* 输  入  :  无
* 输  出  :  无
* 返  回  :  无
*******************************************************************************/
unsigned char Card_Id_Arr[4] = {0};
void ctrlprocess(void)
{
  unsigned char ii;
  char status;
        unsigned char NumtoStr[6];
  
  PcdReset();
  status=PcdRequest(PICC_REQIDL,&uart_R_Buff[0]);//寻天线区内未进入休眠状态的卡,返回卡片类型 2字节
  if(status!=MI_OK) return;
 
  status=PcdAnticoll(&Card_Id_Arr[0]);//防冲撞,返回卡的序列号 4字节
  if(status!=MI_OK)
  {
    uart_R_Len=0;
                return;
  }
  memcpy(MLastSelectedSnr,&Card_Id_Arr[0],4); 
  status=PcdSelect(MLastSelectedSnr);//选卡
  if(status!=MI_OK)
        {
                uart_R_Len=0;
                return;       
        }
  
        if(oprationcard==SENDID)//发送卡号 A0
  {
    oprationcard=0;
    for(ii=0;ii<4;ii++)
    {
                 cardID[ii] = MLastSelectedSnr[ii];
    }
                uart_Send(&MLastSelectedSnr[0],4);
               
               
                LCD_P8x16Str(10,0,"Card ID is :");
                for(ii = 0; ii < 4;ii++)
                {
                                itoafunc(MLastSelectedSnr[ii],&NumtoStr[0]);
                                LCD_P8x16Str((ii*30+6),3,&NumtoStr[1]);       
                }
         uart_R_Len=0;
//         CLR_BEEP;
  } 
  else if(oprationcard==READCARD)//读卡 A1
  {
    oprationcard=0;
    status=PcdAuthState(PICC_AUTHENT1A,KuaiN,PassWd,MLastSelectedSnr);        //验证A密匙
    if(status!=MI_OK)  return;
    
    status=PcdRead(KuaiN,Read_Data);
    if(status!=MI_OK)  return;
    
    uart_Send(&Read_Data[0],16);          
    PcdHalt();
                uart_R_Len=0;       
               
                LCD_P8x16Str(20,2,"Read Card !");
               
//        CLR_BEEP;
  }
  else if(oprationcard==WRITECARD)//写卡 A2
  {
    oprationcard=0;
    status=PcdAuthState(PICC_AUTHENT1A,KuaiN,PassWd,MLastSelectedSnr);//
    if(status!=MI_OK)
    {
      return;
    }
    status=PcdWrite(KuaiN,&WriteData[0]);
    if(status!=MI_OK)
    {
      return;
    }       
    PcdHalt();
    uart_R_Len=0;       
               
                LCD_P8x16Str(15,2,"Write Card !");
//   CLR_BEEP;       
  } 
        else if(oprationcard == KEYCARD)//修改密码  A3
  {
    oprationcard=0;    
    status=PcdAuthState(PICC_AUTHENT1A,KuaiN,PassWd,MLastSelectedSnr);
    if(status!=MI_OK)  return;
    status=PcdWrite(KuaiN,&NewKey[0]);
    if(status!=MI_OK)
      return;                           
    PcdHalt();
         uart_R_Len=0;
//        CLR_BEEP;修改密码 
                LCD_P8x16Str(0,2,"Modify password!");   //   扣款 Debit    Recharge 充值

  }
        else if(oprationcard == VALUECARD) //消费和充值  A4
        {
                 unsigned int Source_Num = 0;
                 unsigned int Write_Num  = 0;
                 unsigned int Lost_Num   = 0;
                 unsigned char Lost_Flag = 0;
                        oprationcard=0; 
                        //读取块中原始数据
                        if((Add_Subtract_** == 0xC0) || (Add_Subtract_** == 0xC1))   //先读出块中的数据
                        {
                                        status=PcdAuthState(PICC_AUTHENT1A,KuaiN,PassWd,MLastSelectedSnr);        //验证A密匙
                                        if(status!=MI_OK)  return;
                                       
                                        status=PcdRead(KuaiN,Read_Data);
                                        if(status!=MI_OK)  return;
                                       
                                        uart_Send(&Read_Data[0],16);          

                                       
                                        Source_Num = (Read_Data[14]<<8) + Read_Data[15];
                                        LCD_P8x16Str(6,2,"$ 1:");
                                        itoafunc(Source_Num,&NumtoStr[0]);
                                 LCD_P8x16Str(50,2,&NumtoStr[1]);       
                        }
                        else 
                        {       
                                        uart_R_Len=0;
                                        return;       
                        }
               
                        //修改数据
                        Write_Num = (WriteData[14]<<8) + WriteData[15];
                 if(Add_Subtract_** == 0xC0)  //消费
                        {
                                 LCD_P8x16Str(20,0,"Consume!");
                                 if(Source_Num >= Write_Num)
                                        {
                                                        Lost_Num = Source_Num - Write_Num;
                                                        Lost_Flag = 0;
                                       
                                        else
                                        {
                                                 Lost_Flag = 5;
                                        }
                                       
                        }
                        else if(Add_Subtract_** == 0xC1) //充值
                        {
                                 LCD_P8x16Str(20,0,"Recharge!");
                                        Lost_Num = Source_Num + Write_Num;
                        }
                       
                        if(Lost_Num > 65536)
                        {
                                        LCD_P8x16Str(6,4,"$ 2:");
                                        LCD_P8x16Str(40,4,"enough");
                        }
                        else if(Lost_Flag == 5)
                        {
                                 LCD_P8x16Str(6,4,"$ 2:");
                                        LCD_P8x16Str(50,4,"shortage");
                        }
                        else
                        {
                                        LCD_P8x16Str(6,4,"$ 2:");
                                        itoafunc(Write_Num,&NumtoStr[0]);
                                        LCD_P8x16Str(50,4,&NumtoStr[1]);       
                                        //写入块中修改后数据
                                        {
                                                        status=PcdAuthState(PICC_AUTHENT1A,KuaiN,PassWd,MLastSelectedSnr);//
                                                        if(status!=MI_OK)
                                                        {
                                                                uart_R_Len=0;
                                                                return;
                                                        }
                                                       
                                                        WriteData[14] = Lost_Num >> 8;
                                                        WriteData[15] = Lost_Num & 0xFF;
                                                        status=PcdWrite(KuaiN,&WriteData[0]);
                                                        if(status!=MI_OK)
                                                        {
                                                                uart_R_Len=0;
                                                                return;
                                                        }       
                                                        PcdHalt();
                                                        LCD_P8x16Str(6,6,"$ 3:");
                                                        itoafunc(Lost_Num,&NumtoStr[0]);
                                                        LCD_P8x16Str(50,6,&NumtoStr[1]);
                                        }
                        }
                        uart_R_Len=0;
        }
  else
        {
                        uart_R_Len=0;
        }               
                                            
}
 /*******************************************************************************
* 描  述  : 判断操作类型(发送卡号、读卡、写卡、修改密码 )
* 输  入  :  无
* 输  出  :  无
* 返  回  :  无
*******************************************************************************/
void ctrl_uart(void)
{
  u8 ii;
  switch(uart_R_Buff[1])
  {
    case 0xa0:        //发送卡号
      oprationcard=SENDID;
      break;
    case 0xa1://读数据
      oprationcard=READCARD;
      for(ii=0;ii<6;ii++)
      {
        PassWd[ii]=uart_R_Buff[ii+2];
      } 
      KuaiN=uart_R_Buff[8];
      break;
    case 0xa2://写数据
      oprationcard=WRITECARD;
      for(ii=0;ii<6;ii++)
      {
        PassWd[ii]=uart_R_Buff[ii+2];
      } 
      KuaiN=uart_R_Buff[8];
      for(ii=0;ii<16;ii++)
      {
        WriteData[ii]=uart_R_Buff[ii+9];
      }
      break;  
    case 0xa3: //修改密码
      oprationcard=KEYCARD; 
      for(ii=0;ii<6;ii++)
      {
        PassWd[ii]=uart_R_Buff[ii+2];
      } 
      KuaiN=uart_R_Buff[8];
      for(ii=0;ii<6;ii++)
      {
        NewKey[ii]=uart_R_Buff[ii+9];
        NewKey[ii+10]=uart_R_Buff[ii+9];
      }
      break;
                case 0xa4: //充值或扣款
      oprationcard = VALUECARD; 
      for(ii=0;ii<6;ii++)
      {
        PassWd[ii]=uart_R_Buff[ii+2];
      } 
      KuaiN=uart_R_Buff[8];
                        Add_Subtract_** = uart_R_Buff[9];
      for(ii=0;ii<16;ii++)
      {
         WriteData[ii]=uart_R_Buff[ii+10];
      }
      break;
    default:  break;                     
  }
}
/////////////////////////////////////////////////////////////////////
//功    能:扣款和充值
//参数说明: dd_mode[IN]:命令字
//               0xC0 = 扣款
//               0xC1 = 充值
//          addr[IN]:钱包地址
//          pValue[IN]:4字节增(减)值,低位在前
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////                 
char PcdValue(u8 dd_mode,u8 addr,u8 *pValue)
{
    char status;
    u8  unLen;
    u8 ucComMF522Buf[MAXRLEN]; 
    //u8 i;
       
    ucComMF522Buf[0] = dd_mode;
    ucComMF522Buf[1] = addr;
    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
 
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);

    if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
    {   status = MI_ERR;   }
        
    if (status == MI_OK)
    {
        memcpy(ucComMF522Buf, pValue, 4);
        //for (i=0; i<16; i++)
        //{    ucComMF522Buf[i] = *(pValue+i);   }
        CalulateCRC(ucComMF522Buf,4,&ucComMF522Buf[4]);
        unLen = 0;
        status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,6,ucComMF522Buf,&unLen);
                if (status != MI_ERR)
        {    status = MI_OK;    }
    }
    
    if (status == MI_OK)
    {
        ucComMF522Buf[0] = PICC_TRANSFER;
        ucComMF522Buf[1] = addr;
        CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]); 
   
        status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);

        if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
        {   status = MI_ERR;   }
    }
    return status;
}

/////////////////////////////////////////////////////////////////////
//功    能:备份钱包
//参数说明: sourceaddr[IN]:源地址
//          goaladdr[IN]:目标地址
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdBakValue(u8 sourceaddr, u8 goaladdr)
{
    char status;
    u8  unLen;
    u8 ucComMF522Buf[MAXRLEN]; 

    ucComMF522Buf[0] = PICC_RESTORE;
    ucComMF522Buf[1] = sourceaddr;
    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
 
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);

    if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
    {   status = MI_ERR;   }
    
    if (status == MI_OK)
    {
        ucComMF522Buf[0] = 0;
        ucComMF522Buf[1] = 0;
        ucComMF522Buf[2] = 0;
        ucComMF522Buf[3] = 0;
        CalulateCRC(ucComMF522Buf,4,&ucComMF522Buf[4]);
 
        status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,6,ucComMF522Buf,&unLen);
                if (status != MI_ERR)
        {    status = MI_OK;    }
    }
    
    if (status != MI_OK)
    {    return MI_ERR;   }
    
    ucComMF522Buf[0] = PICC_TRANSFER;
    ucComMF522Buf[1] = goaladdr;

    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
 
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);

    if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
    {   status = MI_ERR;   }

    return status;
}
/////////////////////////////////////////////////////////////////////
//功    能:测试RC522功能
//参数说明: sourceaddr[IN]:源地址
//           goaladdr[IN]:目标地址
//返    回: 
/////////////////////////////////////////////////////////////////////
//unsigned char status;

void RC522_Test_Func(void)
{
                if(uart_comp == 5)         //配置读卡,写卡,修改密码
    {
                                ctrl_uart(); 
                                uart_comp = 10;                       
    }
    else if(uart_comp == 10)         
    {
                         LCD_CLS();
                                delay_ms(10);
                                uart_comp = 0;
                                ctrlprocess();   
    } 
}

MAIN.C文件

#include "main.h"
#include "stm32f10x.h"
#include "rc522.h"
#include "oled.h"
#include "delay.h"

unsigned char uart_R_Buff[256] = {0};
unsigned char uart_R_Len = 0;

unsigned char uart_len = 4;
unsigned char *uart_buf;


u8 G_un8TestFlag=0;
unsigned long G_un32TestCont=0;

u16  KuaiN;
u8   Add_Subtract_** = 0;  //1-扣款  2-充值
u8 SysTime, oprationcard,bSendID;
u8  Read_Data[16],PassWd[6],WriteData[16],RevBuffer[30], MLastSelectedSnr[4],NewKey[16];               
char cardID[4];
u8 uart_comp = 0;       

/*******************************************************************************
* Function Name  : main
* Description    : 程序入口函数
* Input          : None
* Output         : None
* Return         : None
* Attention      : 
*******************************************************************************/
/*******************************
*射频卡连线说明:
*1--SS  <----->PB0
*2--SCK <----->PB13
*3--MOSI<----->PB15
*4--MISO<----->PB14
*5--悬空
*6--GND <----->GND
*7--RST <----->PB1
*8--VCC <----->VCC
************************************/
/*******************************
*人体红外感应连线说明:
*1--GND <----->GND
*2--RST <----->PB4
*3--VCC <----->VCC
************************************/
int main(void)
{
                /* System Clocks Configuration */
       
                delay_init(24);                                                 //延时初始化函数         
                RCC_Configuration();       

                SPI1_GPIO_Config();
                 ALL_GPIO_Config();       
                OLED_Initial();
                USART_Configuration1();
                TIM_InitConfigFunc();
                NVIC_Configuration();
       
                InitRc522();                                //初始化射频卡模块
                LED_ON;
                while(1)
                {                                                               
                                sleep(100);
                                RC522_Test_Func();        //智能卡功能测试函数
                                sleep(10);
                                Body_Infrared_Sensor();   //人体红外感应函数
                }
}

/***************************************************************************************
** 函数名称: sleep
** 功能描述: 简单的延时函数
** 参    数: None
** 返 回 值: None       
** 作   者: 
** 日   期: 2012年10月28日
****************************************************************************************/
void sleep(u32 cnt)
{
        u32 i = 0;
        u32 j = 0;
        for(i = 0; i < cnt; i++)
                for(j = 10000; j > 0 ; j--);
}
/***************************************************************************************
** 函数名称: Body_Infrared_Sensor
** 功能描述: 人体红外感应采集函数
** 参    数: None
** 返 回 值: None       
** 作   者: 
** 日   期: 2016年09月20日
****************************************************************************************/
unsigned char Led_Count = 0;
unsigned char Key_Down_** = 0;
void Body_Infrared_Sensor(void)
{
                 unsigned char KeyValue1 = 0;
                unsigned char KeyValue2 = 0;
         
                KeyValue1= GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4);
                delay_ms(10);       
                KeyValue2= GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4);
               
                if(KeyValue1 == KeyValue2)
                {
                         if(KeyValue2 == 1)
                                {
                                                Key_Down_** = 0x05;
                                }
                                else 
                                {
                                                Key_Down_** = 0x00;
                                }
                }
               
                if(Key_Down_** == 0x05)
                {       
                                LED_ON;
                }
                else 
                {
                                LED_OFF;
                }
}
通信命令帧:
02 A0

09 A1 FF FF FF FF FF FF 04
09 A1 22 22 22 22 22 22 04

19 A2 FF FF FF FF FF FF 04 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

0F A3 FF FF FF FF FF FF 04 22 22 22 22 22 22

1A A4 FF FF FF FF FF FF 04 C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 64 
1A A4 FF FF FF FF FF FF 04 C1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 64


路过

鸡蛋

鲜花

握手

雷人

发表评论 评论 (1 个评论)

回复 18529092183 2019-5-5 14:58
13.56MHz芯片:SI522(直接PIN2PIN 兼容RC522,与FM17550/FM17520/RM522)

中科微推出SI522(超低功耗13.56M芯片)
以目前测试结果来看,
Si522   主要优势点:
1. 直接PIN2PIN 兼容RC522,软硬件兼容,与FM17550/FM17520/RM522
2. 完全替换RC522,接收功耗下降10mA,相比新增了自动寻卡和定时唤醒,自动寻卡功耗为4.5uA,业界最低。
3.首创全新寻卡方式,读卡模组不再死机。

有兴趣可以找我(2355239057周先生)了解,我们是中科微的全国总代理,跟其他几家国产对比,这颗芯片性价比挺高的。
绝对价优,大力支持!