14443 TypeA 密耦合射频卡标准广泛应用在门禁、身份识别和电子钱包等领域,而 RC522 作为 Philips 基站芯片产品系列的新成员,不仅兼容 14443A/MIFARF 标准,还具备低电压(3.3V)、低功耗、低成本、小尺寸等优点,适用于智能仪表和手持设备的数据采集和处理。RC522 对外提供多种标准的数字接口(如并行接口、SPI、I2C等),通过对芯片内部的 4 页 64 个寄存器进行读、写来控制。
RC522 芯片在使用前必须复位,除了在复位引脚 NRSTPD 输入从低电平至高电平的跳变沿外,还必须向 RC522 的命令寄存器 CommandReg 写人软复位命令代码 0x0F 进行软复位。
CommandReg: Starts and stops command execution.
MFRC522 Command Set:
/* 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计算
RC522 复位函数:
void PcdReset(void)
{
SET_RC522RST;
delay_ns(10);
CLR_RC522RST;
delay_ns(10);
SET_RC522RST;
delay_ns(10);
WriteRawRC(CommandReg, PCD_RESETPHASE); //复位命令
}
RC522 初始化函数:
void MFRC522_Init(void)
{
PcdReset(); //RC522复位
PcdConfigISOType('A'); //协议配置为ISO14443_A
}
char PcdConfigISOType(unsigned char type)
{
if (type == 'A') //ISO14443_A
{
ClearBitMask(Status2Reg, 0x08); //清MFCrypto1On
WriteRawRC(ModeReg, 0x3D); //CRC初始值0x6363
/* Modulation signal from the internal analog part, default. */
WriteRawRC(RxSelReg,0x86);
WriteRawRC(RFCfgReg,0x7F); //RxGain=48dB
WriteRawRC(TReloadRegL, 30); //定时器重装值
WriteRawRC(TReloadRegH, 0);
WriteRawRC(TModeReg, 0x8D); //TAuto=1,及定时器预分频高4位
WriteRawRC(TPrescalerReg, 0x3E); //定时器预分频低8位
WriteRawRC(TxAutoReg, 0x40); //Force100ASK(必须要)
PcdAntennaOn(); //打开天线
}
else
{
return MI_ERR;
}
return MI_OK;
}
TAuto 位设置为 1,则定时器在数据发送结束时自动启动,如果 RxModeReg
寄存器中的 RxMultiple
位未被设置,则当接收到第一个数据位时,定时器停止。定时器的作用主要是防止通信过程中出错,而设置一个超时时间。上述设置的超时时间为 30 *
0xD3E * 6.78MHz = 15000us = 1.5ms。
RC522 对卡的操作分成五个步骤:寻卡->防冲突->选卡->验证->读/写卡。
/******************************************************************
*功 能:通过 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)
{
unsigned char irqEn = 0x00;
unsigned char waitFor = 0x00;
unsigned char lastBits;
unsigned char n;
unsigned int i;
char status;
switch(Command)
{
case PCD_AUTHENT:
irqEn = 0x12; //使能IdleIEn和ErrIEn
waitFor = 0x10; //等待IdleIRq
break;
case PCD_TRANSCEIVE:
/* 使能TxIEn、RxIEn、IdleIEn、LoAlertIEn、ErrIEn和TimerIEn */
irqEn = 0x77;
waitFor = 0x30; //等待IdleIRq和RxIRq
break;
default:
break;
}
WriteRawRC(CommIEnReg, irqEn|0x80); //使能中断
ClearBitMask(CommIrqReg, 0x80); //清所有的中断标志
WriteRawRC(CommandReg,PCD_IDLE); /*必须要,结束先前的命令*/
SetBitMask(FIFOLevelReg, 0x80); //清FIFO
for (i=0; i {
WriteRawRC(FIFODataReg, pInData[i]);
}
WriteRawRC(CommandReg, Command); //写入命令
if (Command == PCD_TRANSCEIVE)
{
SetBitMask(BitFramingReg, 0x80); //开始传输
}
/* 操作M1卡最大等待时间25ms */
i = 2000; //主要针对“认证卡密”
do
{
status = ReadRawRC(CommIrqReg);
i--;
}
while ((i!=0) && !(status & 0x01) && !(status & waitFor));
ClearBitMask(BitFramingReg, 0x80);
if (i!=0)
{
if(!(ReadRawRC(ErrorReg) & 0x1B)) //判断是否出错
{
if(status & irqEn & 0x01)
{
return 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 {
pOutData[i] = ReadRawRC(FIFODataReg);
}
}
}
else
return MI_ERR;
}
else
{
return MI_ERR;
}
return MI_OK;
}
/******************************************************************
*功 能:寻卡
*参数说明: 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 ret;
unsigned int len;
unsigned char buf[MAXRLEN];
ClearBitMask(Status2Reg, 0x08); //清MFCrypto1On
WriteRawRC(BitFramingReg, 0x07);
buf[0] = req_code;
ret = PcdComMF522(PCD_TRANSCEIVE, buf, 1, buf, &len);
if ((ret == MI_OK) && (len == 0x10))
{
*pTagType = buf[0];
*(pTagType+1) = buf[1];
}
else
{
ret = MI_ERR;
}
return ret ;
}
/******************************************************************
*功 能:防冲突
*参数说明: pSnr[OUT]:卡片序列号,4字节
*返 回: 成功返回MI_OK
******************************************************************/
char PcdAnticoll(unsigned char *pSnr)
{
char ret;
unsigned char i,snr_check=0;
unsigned int len;
unsigned char buf[MAXRLEN];
ClearBitMask(Status2Reg, 0x08); //清MFCrypto1On
WriteRawRC(BitFramingReg, 0x00);
ClearBitMask(CollReg, 0x80);
buf[0] = PICC_ANTICOLL1;
buf[1] = 0x20;
ret = PcdComMF522(PCD_TRANSCEIVE, buf, 2, buf, &len);
if (ret == MI_OK)
{
for (i=0; i<4; i++)
{
*(pSnr+i) = buf[i];
snr_check ^= buf[i];
}
if (snr_check != buf[i])
{
ret = MI_ERR;
}
}
SetBitMask(CollReg, 0x80);
return ret;
}
/******************************************************************
*功 能:选定卡片
*参数说明: pSnr[IN]:卡片序列号,4字节
*返 回: 成功返回MI_OK
******************************************************************/
char PcdSelect(unsigned char *pSnr)
{
char ret;
unsigned char i;
unsigned int len;
unsigned char buf[MAXRLEN];
buf[0] = PICC_ANTICOLL1;
buf[1] = 0x70;
buf[6] = 0;
for (i=0; i<4; i++)
{
buf[i+2] = *(pSnr+i);
buf[6] ^= *(pSnr+i);
}
CalulateCRC(buf, 7, &buf[7]);
ClearBitMask(Status2Reg, 0x08);
ret= PcdComMF522(PCD_TRANSCEIVE, buf, 9, buf, &len);
if ((ret == MI_OK) && (len == 0x18))
return MI_OK;
else
return MI_ERR;
}
/******************************************************************
*功 能:验证卡片密码
*参数说明: auth_mode[IN]: 密码验证模式
* 0x60 = 验证A密钥
* 0x61 = 验证B密钥
* addr[IN]:块地址
* pKey[IN]:密码
* pSnr[IN]:卡片序列号,4字节
*返 回: 成功返回MI_OK
******************************************************************/
char PcdAuthState(unsigned char auth_mode,unsigned char addr,
unsigned char *pKey,unsigned char *pSnr)
{
char ret;
unsigned int len;
unsigned char buf[MAXRLEN];
buf[0] = auth_mode;
buf[1] = addr;
memcpy(&buf[2], pKey, 6);
memcpy(&buf[8], pSnr, 6);
ret = PcdComMF522(PCD_AUTHENT, buf, 12, buf, &len);
if ((ret != MI_OK) || (!(ReadRawRC(Status2Reg) & 0x08)))
{
return MI_ERR;
}
return MI_OK;
}
注意:只有正确验证卡密的情况下 MFCrypto1On 才会被置 1,并且用于后续的读写操作,这也说明成功验证卡密后所有的数据传输都是加密的。在“寻卡”和“选卡”过程中,该位应被软件清零。
/******************************************************************
*功 能:读取M1卡一块数据
*参数说明: addr[IN]:块地址
* pData[OUT]:读出的数据,16字节
*返 回: 成功返回MI_OK
******************************************************************/
char PcdRead(unsigned char addr,unsigned char *pData)
{
char ret;
unsigned int len;
unsigned char buf[MAXRLEN];
buf[0] = PICC_READ;
buf[1] = addr;
CalulateCRC(buf, 2, &buf[2]);
ret = PcdComMF522(PCD_TRANSCEIVE, buf, 4, buf, &len);
if ((ret == MI_OK) && (len == 0x90)) //18个字节,其中有2个是CRC校验
{
memcpy(pData, buf, 16);
}
else
{
return MI_ERR;
}
return MI_OK;
}
/******************************************************************
*功 能:写数据到M1卡一块
*参数说明: addr[IN]:块地址
* pData[IN]:写入的数据,16字节
*返 回: 成功返回MI_OK
******************************************************************/
char PcdWrite(unsigned char addr,unsigned char *pData)
{
char ret;
unsigned int len;
unsigned char buf[MAXRLEN];
buf[0] = PICC_WRITE;
buf[1] = addr;
CalulateCRC(buf, 2, &buf[2]);
ret = PcdComMF522(PCD_TRANSCEIVE, buf, 4, buf, &len);
if ((ret != MI_OK) || (len != 4) || ((buf[0] & 0x0F) != 0x0A))
{
ret = MI_ERR;
}
if (ret == MI_OK)
{
memcpy(buf, pData, 16);
CalulateCRC(buf, 16, &buf[16]);
ret = PcdComMF522(PCD_TRANSCEIVE, buf,18, buf, &len);
if ((ret != MI_OK) || (len != 4) || ((buf[0] & 0x0F) != 0x0A))
{
ret = MI_ERR;
}
}
return ret;
}
例子:门禁系统:读块4处16字节 如果前8个字符为“fourmily”则通过。
相关资料下载:
——Be loyal to dream. Be brave to try! linux_xpj@opencores.org
阅读(4300) | 评论(2) | 转发(2) |