热度 1||
MF RC522是一款低功耗、低电压3.3V(2.5~3.6)、低成本(比RC500要便宜很多)、小尺寸(只有5mm*5mm)的符合ISO14443A协议的基站芯片,很适用于智能仪表及手持设备的数据采集和处理。
其数据手册可以在网上下载得到。
在水表中的应用如下图所示
VRF为3.6V电池经MCU控制三极管得到的RC522工作电源,VPD为MCU工作电压经MCU控制得到的接口工作电源,本系统中采用2.7V。这两个电源可控带来的好处就是可以极大限度地降低系统功耗,不读写卡时判断其电源即可。采用SPI方式与MCU通信,RC522可以支持高达10Mbit/s的SPI通信速度,相对不用UART方式的好处在于可以以高速度通信、MCU不考虑振荡器精度(用RC振荡器以降低成本)。由于水表是由电池供电,MCU也要求性价比高,所以选用低功耗AVR单片机M88,其WDT工作方式下睡眼工作电流仅10多微安,能够满足系统需要。
对于卡片操作,以S50和S70卡为对象,这些卡片的结构相对简单,所以数据的存储与改写要在软件上做文章。比如数据存在哪个扇区可以不固定,由软件通过一定的方法找到并处理数据,这样有利于实现一卡多用。
其卡片操作的主要过程:
1、初始化RC522
void SetMifareReader(void)
2、检查卡片存在
Request(ISO14443_3_REQALL)
3、选中卡片并激活
AnticollSelect()
4、对卡片进行密码校验及读写操作
一点儿硬件相关的代码
//认证密钥
//auth_mode认证A或B的那一个:MIFARE_AUTHENT_A或MIFARE_AUTHENT_B
//key六字节密钥
//addr BLOCK地址
byte Authentication(byte auth_mode,byte *key,byte addr)
{
byte status;
SendBuffer[0] = auth_mode;
SendBuffer[1] = addr;
memcpy(SendBuffer+2,key,6); //六字节密钥
memcpy(SendBuffer+8,UID,4); //四字节卡号
SetRegister(JREG_TRELOADLO,21); //SetTimeOut(20);
status = PcdCmd(JCMD_AUTHENT,12);
if (status)
{
return status;
};
if (JBIT_CRYPTO1ON != (0x0f & GetRegister(JREG_STATUS2)))
{
return STATUS_AUTHENT_ERROR;
};
return status;
}
//----------------------------------------------------
//向一个块中写16个字节的数据
byte WriteBlock( byte addr, byte *_data)
{
byte status;
SendBuffer[0] = MIFARE_WRITE;
SendBuffer[1] = addr;
SetRegister(JREG_TRELOADLO,100); //SetTimeOut(61);6ms
status = PcdCmd(JCMD_TRANSCEIVE,2);
if (STATUS_IO_TIMEOUT == status)
return STATUS_IO_TIMEOUT;
if (BitsReceived != 4)
return STATUS_BITCOUNT_ERROR;
if ((ReceiveBuffer[0] & 0x0f) != 0x0a)
return STATUS_AUTHENT_ERROR;
SetRegister(JREG_TRELOADLO,61); //SetTimeOut(61);6ms
ReceiveBuffer[0] =0xff;
memcpy(SendBuffer,_data,16);
status = PcdCmd(JCMD_TRANSCEIVE,16); //传16个字节到卡片
if (status & 0x80)
return STATUS_IO_TIMEOUT;
if (BitsReceived != 4)
return STATUS_BITCOUNT_ERROR;
if ((ReceiveBuffer[0] & 0x0f) != 0x0a)
return STATUS_OTHER_ERROR;
//再读出检查是否写入正确
SendBuffer[0] = MIFARE_READ;
SendBuffer[1] = addr;
SetRegister(JREG_TRELOADLO,26); //SetTimeOut(50);
status = PcdCmd(JCMD_TRANSCEIVE,2);
if (status) return status;
if (BytesReceived != 16)
return STATUS_ACCESS_DENIED;
return memcmp(_data,ReceiveBuffer,16);
}
//------------------------------------------------------------
//RC522读写的硬件支持
//------------------------------------------------------------
void SetRegister(byte RegAddr, byte RegVal)
{
SS = 0;
SPDR = RegAddr;
while(!(SPSR & (1<<SPIF)));
SPDR = RegVal;
while(!(SPSR & (1<<SPIF)));
SS = 1;
}
//---------------------
byte GetRegister(byte RegAddr)
{
SS = 0;
SPDR = 0x80|RegAddr;
while(!(SPSR & (1<<SPIF)));
SPDR = 0xff;
while(!(SPSR & (1<<SPIF)));
SS = 1;
return SPDR;
}
//---------------------
void ModifyRegister(byte RegAddr, byte Set, byte Mask)
{
SS = 0;
SPDR = 0x80|RegAddr;
while(!(SPSR & (1<<SPIF)));
SS = 1;
SS = 0;
SPDR = RegAddr;
while(!(SPSR & (1<<SPIF)));
if (Set) {SPDR |= Mask;}
else {SPDR &= (~Mask);};
while(!(SPSR & (1<<SPIF)));
SS = 1;
}