一、環(huán)境介紹
非接觸式讀寫(xiě)卡模塊: MFRC522
完整工程源碼下載:
https://download.csdn.net/download/xiaolong1126626497/18905806
二、功能介紹
使用MFRC522模塊完成對(duì)IC卡卡號(hào)讀取、卡類(lèi)型區(qū)分、IC卡扇區(qū)密碼修改、扇區(qū)數(shù)據(jù)讀寫(xiě)等功能;底層采用SPI模擬時(shí)序,可以很方便的移植到其他設(shè)備,完成項(xiàng)目開(kāi)發(fā)。? 現(xiàn)在很多嵌入式方向的畢業(yè)設(shè)計(jì)經(jīng)常使用到該模塊,比如: 校園一卡通設(shè)計(jì)、水卡充值消費(fèi)設(shè)計(jì)、公交卡充值消費(fèi)設(shè)計(jì)等。
三、MFR522介紹
MF RC522 是應(yīng)用于13.56MHz 非接觸式通信中高集成度讀寫(xiě)卡系列芯片中的一員。是NXP 公司針對(duì)“三表”應(yīng)用推出的一款低電壓、低成本、體積小的非接觸式讀寫(xiě)卡芯片,是智能儀表和便攜式手持設(shè)備研發(fā)的較好選擇。
MF RC522 利用了先進(jìn)的調(diào)制和解調(diào)概念,完全集成了在13.56MHz 下所有類(lèi)型的被動(dòng)非接觸式通信方式和協(xié)議。支持 ISO14443A 的多層應(yīng)用。其內(nèi)部發(fā)送器部分可驅(qū)動(dòng)讀寫(xiě)器天線與ISO 14443A/MIFARE卡和應(yīng)答機(jī)的通信,無(wú)需其它的電路。接收器部分提供一個(gè)堅(jiān)固而有效的解調(diào)和解碼電路,用于處理ISO14443A 兼容的應(yīng)答器信號(hào)。數(shù)字部分處理ISO14443A 幀和錯(cuò)誤檢測(cè)(奇偶 &CRC)。此外,它還支持快速CRYPTO1 加密算法,用于驗(yàn)證MIFARE 系列產(chǎn)品。MFRC522 支持MIFARE?更高速的非接觸式通信,雙向數(shù)據(jù)傳輸速率高達(dá)424kbit/s。
作為13.56MHz 高集成度讀寫(xiě)卡系列芯片家族的新成員,MF RC522 與MF RC500和 MF RC530 有不少相似之處,同時(shí)也具備諸多特點(diǎn)和差異。它與主機(jī)間的通信采用連線較少的串行通信,且可根據(jù)不同的用戶(hù)需求,選取SPI、I2C 或串行UART(類(lèi)似RS232)模式之一,有利于減少連線,縮小PCB 板體積,降低成本。
四、IC卡介紹
非接觸式IC卡又稱(chēng)射頻卡,由IC芯片、感應(yīng)天線組成,封裝在一個(gè)標(biāo)準(zhǔn)的PVC卡片內(nèi),芯片及天線無(wú)任何外露部分。是世界上最近幾年發(fā)展起來(lái)的一項(xiàng)新技術(shù),它成功的將射頻識(shí)別技術(shù)和IC卡技術(shù)結(jié)合起來(lái),結(jié)束了無(wú)源(卡中無(wú)電源)和免接觸這一難題,是電子器件領(lǐng)域的一大突破。卡片在一定距離范圍(通常為5—10cm)靠近讀寫(xiě)器表面,通過(guò)無(wú)線電波的傳遞來(lái)完成數(shù)據(jù)的讀寫(xiě)操作。
射頻讀寫(xiě)器向IC卡發(fā)一組固定頻率的電磁波,卡片內(nèi)有一個(gè)LC串聯(lián)諧振電路,其頻率與讀寫(xiě)器發(fā)射的頻率相同,這樣在電磁波激勵(lì)下,LC諧振電路產(chǎn)生共振,從而使電容內(nèi)有了電荷;在這個(gè)電荷的另一端,接有一個(gè)單向?qū)ǖ碾娮颖茫瑢㈦娙輧?nèi)的電荷送到另一個(gè)電容內(nèi)存儲(chǔ),當(dāng)所積累的電荷達(dá)到2V時(shí),此電容可作為電源為其它電路提供工作電壓,將卡內(nèi)數(shù)據(jù)發(fā)射出去或接受讀寫(xiě)器的數(shù)據(jù)。
非接觸性IC卡與讀卡器之間通過(guò)無(wú)線電波來(lái)完成讀寫(xiě)操作。二者之間的通訊頻率為13.56MHZ。非接觸性IC卡本身是無(wú)源卡,當(dāng)讀寫(xiě)器對(duì)卡進(jìn)行讀寫(xiě)操作時(shí),讀寫(xiě)器發(fā)出的信號(hào)由兩部分疊加組成:一部分是電源信號(hào),該信號(hào)由卡接收后,與本身的L/C產(chǎn)生一個(gè)瞬間能量來(lái)供給芯片工作。另一部分則是指令和數(shù)據(jù)信號(hào),指揮芯片完成數(shù)據(jù)的讀取、修改、儲(chǔ)存等,并返回信號(hào)給讀寫(xiě)器,完成一次讀寫(xiě)操作。讀寫(xiě)器則一般由單片機(jī),專(zhuān)用智能模塊和天線組成,并配有與PC的通訊接口,打印口,I/O口等,以便應(yīng)用于不同的領(lǐng)域。
M1卡詳細(xì)指標(biāo)
M1卡是指M1芯片,是指菲利浦下屬子公司恩智浦出品的芯片縮寫(xiě),全稱(chēng)為NXP Mifare1系列,常用的有S50及S70兩種型號(hào)。
M1(S50)卡詳細(xì)規(guī)格:
- 芯片類(lèi)型:PhilipsMifare1ICS50
- 存儲(chǔ)容量:8Kbit,16個(gè)分區(qū),每分區(qū)兩組密碼;
- 工作頻率:13.56?MHz;
- 通訊速率:106KBoud;
- 讀寫(xiě)距離:2.5~10cm;
- 讀寫(xiě)時(shí)間:1~2ms;
- 工作溫度:-20℃~55℃;
- 擦寫(xiě)壽命:>100,000次;
- 數(shù)據(jù)保存:>10年;
- 外形尺寸:ISO標(biāo)準(zhǔn)卡85.6x54x0.82;
- 封裝材料:PVC、PET、PETG、0.13mm銅線;
Mifare S50和Mifare S70又常被稱(chēng)為Mifare Standard、Mifare Classic、MF1,是遵守ISO14443A標(biāo)準(zhǔn)的卡片中應(yīng)用最為廣、影響力最大的的一員。而Mifare S70的容量是S50的4倍,S50的容量是1K字節(jié),S70的容量為4K字節(jié)。
讀寫(xiě)器對(duì)卡片的操作時(shí)序和操作命令,二者完全一致。??? Mifare S50和Mifare S70的每張卡片都有一個(gè)4字節(jié)的全球唯一序列號(hào),卡上數(shù)據(jù)保存期為10年,可改寫(xiě)10萬(wàn)次,讀無(wú)限次。一般的應(yīng)用中,不用考慮卡片是否會(huì)被讀壞寫(xiě)壞的問(wèn)題,
當(dāng)然暴力硬損壞除外。 Mifare S50和Mifare S70的區(qū)別主要有兩個(gè)方面。一是讀寫(xiě)器對(duì)卡片發(fā)出請(qǐng)求命令,二者應(yīng)答返回的卡類(lèi)型(ATQA)字節(jié)不同。Mifare S50的卡類(lèi)型(ATQA)是0004H,Mifare S70的卡類(lèi)型(ATQA)是0002H。另一個(gè)區(qū)別就是二者的容量和內(nèi)存結(jié)構(gòu)不同。
M1卡分為16個(gè)扇區(qū),每個(gè)扇區(qū)由4塊(0、1、2、3)組成。實(shí)際操作時(shí),將16個(gè)扇區(qū)分為64個(gè)塊,按絕對(duì)地址編號(hào)為0-63。
結(jié)構(gòu)如下:
- 第0個(gè)扇區(qū)用于存放廠商代碼,意見(jiàn)固話,不可更改。
- 每個(gè)扇區(qū)的塊0、塊1、塊2為數(shù)據(jù)塊,可以用于存儲(chǔ)數(shù)據(jù)。數(shù)據(jù)塊可以進(jìn)行讀寫(xiě)操作。
- 每個(gè)扇區(qū)的塊3為控制塊,包括了密碼A、存儲(chǔ)控制、密碼B。具體結(jié)構(gòu)如下:
4. 每個(gè)扇區(qū)的密碼和控制位都是獨(dú)立的,可以根據(jù)實(shí)際需求設(shè)定各自的密碼及存取控制。存取控制為4個(gè)字節(jié),共32位,扇區(qū)中的每個(gè)塊(包括數(shù)據(jù)和控制塊)存取條件是由密碼和存取控制共同決定的,在存取控制中每個(gè)塊都有一個(gè)相應(yīng)的三個(gè)控制位。定義如下:
Mifare 1 S50 白卡讀寫(xiě)時(shí)一般步驟: 尋卡-->下載塊密碼--> 讀寫(xiě)塊數(shù)據(jù)。控制塊也是一樣。
? ? ?數(shù)據(jù)塊的訪問(wèn)權(quán)限設(shè)置表格:(根據(jù)自己需要的權(quán)限,完成上圖字節(jié)6、7、8的填充即可)
控制塊的讀寫(xiě)權(quán)限設(shè)置:(包含了對(duì)密碼A、控制權(quán)限、密碼的讀寫(xiě)權(quán)限)
? ? ? ? ? ?7? 6? 5? 4? 3? 2? 1? 0
字節(jié)6 1? 1? 1? 1? 1? 1? 1? 1
字節(jié)7 0? 0? 0? 0? 1? 1? 1? 1
字節(jié)8 0? 0? 0? 0? 0? 0? 0? 0
字節(jié)9
設(shè)置的控制權(quán)限如下:0xFF 0x0F 0x00 0x00
代表數(shù)據(jù)塊的權(quán)限: 驗(yàn)證密碼A或者密碼B都可以對(duì)數(shù)據(jù)塊進(jìn)行讀寫(xiě)操作或者加值鍵值操作。
2. 代表控制塊的權(quán)限
(1) 驗(yàn)證A密碼之后可以寫(xiě)A/B密碼,不能讀密碼。
可以讀控制字節(jié)(4個(gè)),無(wú)法寫(xiě)控制字節(jié)
可以讀寫(xiě)B(tài)密碼
(2) 驗(yàn)證B密碼之后,可以讀寫(xiě)A/B密碼,也可讀控制字節(jié),但無(wú)法寫(xiě)控制字節(jié)。
五、核心代碼
5.1? rc522.c
#include "sys.h"
#include "RFID_RC522.h"
#include "delay.h"
#include "string.h"
#include "usart.h"
/*
函數(shù)功能:移植接口--SPI時(shí)序讀寫(xiě)一個(gè)字節(jié)
函數(shù)參數(shù):data:要寫(xiě)入的數(shù)據(jù)
返 回 值:讀到的數(shù)據(jù)
*/
u8 RC522_SPI_ReadWriteOneByte(u8 tx_data)
{
u8 rx_data=0;
u8 i;
for(i=0;i<8;i++)
{
RC522_SCLK=0;
if(tx_data&0x80){RC522_OUTPUT=1;}
else {RC522_OUTPUT=0;}
tx_data<<=1;
RC522_SCLK=1;
rx_data<<=1;
if(RC522_INPUT)rx_data|=0x01;
}
return rx_data;
}
/*
函數(shù)功能:初始化RC522的IO口
*/
void RC522_IO_Init(void)
{
RCC->APB2ENR|=1<<2; //PA時(shí)鐘使能
RCC->APB2ENR|=1<<7; //PF時(shí)鐘使能
//PA5 時(shí)鐘 RC522_SCLK
//PA6 輸入 RC522_INPUT
//PA7 輸出 RC522_OUTPUT
GPIOA->CRL&=0x000FFFFF;
GPIOA->CRL|=0x38300000;
GPIOA->ODR|=0x3<<5;
//RC522_RST <----->PF1--復(fù)位腳
//RC522_SDA <----->PF0--片選腳
GPIOF->CRL&=0xFFFFFF00;
GPIOF->CRL|=0x00000033;
GPIOF->ODR|=0x3<<0;
}
/*
功能描述:選卡讀取卡存儲(chǔ)器容量
輸入?yún)?shù):serNum 傳入卡序列號(hào)
返 回 值:成功返回卡容量
*/
u8 RC522_MFRC522_SelectTag(u8 *serNum) //讀取卡存儲(chǔ)器容量
{
u8 i;
u8 status;
u8 size;
u8 recvBits;
u8 buffer[9];
buffer[0]=PICC_ANTICOLL1; //防撞碼1
buffer[1]=0x70;
buffer[6]=0x00;
for(i=0;i<4;i++)
{
buffer[i+2]=*(serNum+i); //buffer[2]-buffer[5]為卡序列號(hào)
buffer[6]^=*(serNum+i); //卡校驗(yàn)碼
}
RC522_CalulateCRC(buffer,7,&buffer[7]); //buffer[7]-buffer[8]為RCR校驗(yàn)碼
RC522_ClearBitMask(Status2Reg,0x08);
status=RC522_PcdComMF522(PCD_TRANSCEIVE,buffer,9,buffer,&recvBits);
if((status==MI_OK)&&(recvBits==0x18))
size=buffer[0];
else
size=0;
return size;
}
/*
延時(shí)函數(shù),納秒級(jí)
*/
void RC522_Delay(u32 ns)
{
u32 i;
for(i=0;i<ns;i++)
{
__nop();
__nop();
__nop();
}
}
/*
函數(shù)功能:RC522芯片初始化
*/
void RC522_Init(void)
{
RC522_IO_Init(); //RC522初始化
RC522_PcdReset(); //復(fù)位RC522
RC522_PcdAntennaOff(); //關(guān)閉天線
DelayMs(2); //延時(shí)2毫秒
RC522_PcdAntennaOn(); //開(kāi)啟天線
M500PcdConfigISOType('A'); //設(shè)置RC632的工作方式
}
/*
函數(shù)功能:復(fù)位RC522
*/
void RC522_Reset(void)
{
RC522_PcdReset(); //復(fù)位RC522
RC522_PcdAntennaOff(); //關(guān)閉天線
DelayMs(2); //延時(shí)2毫秒
RC522_PcdAntennaOn(); //開(kāi)啟天線
}
/*
功 能: 尋卡
參數(shù)說(shuō)明: req_code[IN]:尋卡方式
0x52 = 尋感應(yīng)區(qū)內(nèi)所有符合14443A標(biāo)準(zhǔn)的卡
0x26 = 尋未進(jìn)入休眠狀態(tài)的卡
pTagType[OUT]:卡片類(lèi)型代碼
0x4400 = Mifare_UltraLight
0x0400 = Mifare_One(S50)
0x0200 = Mifare_One(S70)
0x0800 = Mifare_Pro(X)
0x4403 = Mifare_DESFire
返 回 值: 成功返回MI_OK
*/
char RC522_PcdRequest(u8 req_code,u8 *pTagType)
{
char status;
u8 unLen;
u8 ucComMF522Buf[MAXRLEN]; // MAXRLEN 18
RC522_ClearBitMask(Status2Reg,0x08); //清RC522寄存器位,/接收數(shù)據(jù)命令
RC522_WriteRawRC(BitFramingReg,0x07); //寫(xiě)RC632寄存器
RC522_SetBitMask(TxControlReg,0x03); //置RC522寄存器位
ucComMF522Buf[0]=req_code; //尋卡方式
status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen); //通過(guò)RC522和ISO14443卡通訊
if((status==MI_OK)&&(unLen==0x10))
{
*pTagType=ucComMF522Buf[0];
*(pTagType+1)=ucComMF522Buf[1];
}
else
{
status = MI_ERR;
}
return status;
}
/*
功 能: 防沖撞
參數(shù)說(shuō)明: pSnr[OUT]:卡片序列號(hào),4字節(jié)
返 回: 成功返回MI_OK
*/
char RC522_PcdAnticoll(u8 *pSnr)
{
char status;
u8 i,snr_check=0;
u8 unLen;
u8 ucComMF522Buf[MAXRLEN];
RC522_ClearBitMask(Status2Reg,0x08); //清RC522寄存器位
RC522_WriteRawRC(BitFramingReg,0x00); //寫(xiě)
RC522_ClearBitMask(CollReg,0x80); //清
ucComMF522Buf[0]=PICC_ANTICOLL1; //PICC_ANTICOLL1 = 0x93
ucComMF522Buf[1]=0x20;
status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen); //0x0c,通過(guò)RC522和ISO14443卡通訊
//PCD_TRANSCEIVE =發(fā)送并接收數(shù)據(jù)
//2:寫(xiě)入卡里的數(shù)據(jù)字節(jié)長(zhǎng)度
//ucComMF522Buf:存放數(shù)據(jù)的地址
//unLen:從卡里讀出的數(shù)據(jù)長(zhǎng)度
if(status==MI_OK)
{
for(i=0;i<4;i++)
{
*(pSnr+i)=ucComMF522Buf[i]; //把讀到的卡號(hào)賦值給pSnr
snr_check^=ucComMF522Buf[i];
}
if(snr_check!=ucComMF522Buf[i])
{
status = MI_ERR;
}
}
RC522_SetBitMask(CollReg,0x80);
return status;
}
/*
功 能:選定卡片
參數(shù)說(shuō)明:pSnr[IN]:卡片序列號(hào),4字節(jié)
返 回:成功返回MI_OK
*/
char RC522_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);
}
RC522_CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]); //用MF522計(jì)算CRC16函數(shù),校驗(yàn)數(shù)據(jù)
RC522_ClearBitMask(Status2Reg,0x08); //清RC522寄存器位
status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen);
if((status==MI_OK)&&(unLen==0x18))status=MI_OK;
else status=MI_ERR;
return status;
}
/*
功 能:驗(yàn)證卡片密碼
參數(shù)說(shuō)明:auth_mode[IN]: 密碼驗(yàn)證模式
0x60 = 驗(yàn)證A密鑰
0x61 = 驗(yàn)證B密鑰
addr[IN]:塊地址
pKey[IN]:扇區(qū)密碼
pSnr[IN]:卡片序列號(hào),4字節(jié)
返 回:成功返回MI_OK
*/
char RC522_PcdAuthState(u8 auth_mode,u8 addr,u8 *pKey,u8 *pSnr)
{
char status;
u8 unLen;
u8 ucComMF522Buf[MAXRLEN]; //MAXRLEN 18(數(shù)組的大小)
//驗(yàn)證模式+塊地址+扇區(qū)密碼+卡序列號(hào)
ucComMF522Buf[0]=auth_mode;
ucComMF522Buf[1]=addr;
memcpy(&ucComMF522Buf[2],pKey,6); //拷貝,復(fù)制
memcpy(&ucComMF522Buf[8],pSnr,4);
status=RC522_PcdComMF522(PCD_AUTHENT,ucComMF522Buf,12,ucComMF522Buf,&unLen);
if((status!= MI_OK)||(!(RC522_ReadRawRC(Status2Reg)&0x08)))status = MI_ERR;
return status;
}
/*
功 能:讀取M1卡一塊數(shù)據(jù)
參數(shù)說(shuō)明:
addr:塊地址
p :讀出的塊數(shù)據(jù),16字節(jié)
返 回:成功返回MI_OK
*/
char RC522_PcdRead(u8 addr,u8 *p)
{
char status;
u8 unLen;
u8 i,ucComMF522Buf[MAXRLEN]; //18
ucComMF522Buf[0]=PICC_READ;
ucComMF522Buf[1]=addr;
RC522_CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);//通過(guò)RC522和ISO14443卡通訊
if((status==MI_OK&&(unLen==0x90)))
{
for(i=0;i<16;i++)
{
*(p +i)=ucComMF522Buf[i];
}
}
else
{
status=MI_ERR;
}
return status;
}
/*
功 能:寫(xiě)數(shù)據(jù)到M1卡指定塊
參數(shù)說(shuō)明:addr:塊地址
p :向塊寫(xiě)入的數(shù)據(jù),16字節(jié)
返 回:成功返回MI_OK
*/
char RC522_PcdWrite(u8 addr,u8 *p)
{
char status;
u8 unLen;
u8 i,ucComMF522Buf[MAXRLEN];
ucComMF522Buf[0]=PICC_WRITE;// 0xA0 //寫(xiě)塊
ucComMF522Buf[1]=addr; //塊地址
RC522_CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
status=RC522_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++)//向FIFO寫(xiě)16Byte數(shù)據(jù)
{
ucComMF522Buf[i]=*(p +i);
}
RC522_CalulateCRC(ucComMF522Buf,16,&ucComMF522Buf[16]);
status = RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,18,ucComMF522Buf,&unLen);
if((status != MI_OK)||(unLen != 4)||((ucComMF522Buf[0]&0x0F)!=0x0A))
{
status = MI_ERR;
}
}
return status;
}
/*
功 能:命令卡片進(jìn)入休眠狀態(tài)
返 回:成功返回MI_OK
*/
char RC522_PcdHalt(void)
{
u8 status;
u8 unLen;
u8 ucComMF522Buf[MAXRLEN]; //MAXRLEN==18
status=status;
ucComMF522Buf[0]=PICC_HALT;
ucComMF522Buf[1]=0;
RC522_CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
return MI_OK;
}
/*
功 能:用MF522計(jì)算CRC16函數(shù)
參 數(shù):
*pIn :要讀數(shù)CRC的數(shù)據(jù)
len:-數(shù)據(jù)長(zhǎng)度
*pOut:計(jì)算的CRC結(jié)果
*/
void RC522_CalulateCRC(u8 *pIn ,u8 len,u8 *pOut )
{
u8 i,n;
RC522_ClearBitMask(DivIrqReg,0x04); //CRCIrq = 0
RC522_WriteRawRC(CommandReg,PCD_IDLE);
RC522_SetBitMask(FIFOLevelReg,0x80); //清FIFO指針
//向FIFO中寫(xiě)入數(shù)據(jù)
for(i=0;i<len;i++)
{
RC522_WriteRawRC(FIFODataReg,*(pIn +i)); //開(kāi)始RCR計(jì)算
}
RC522_WriteRawRC(CommandReg,PCD_CALCCRC); //等待CRC計(jì)算完成
i=0xFF;
do
{
n=RC522_ReadRawRC(DivIrqReg);
i--;
}
while((i!=0)&&!(n&0x04));//CRCIrq = 1
//讀取CRC計(jì)算結(jié)果
pOut[0]=RC522_ReadRawRC(CRCResultRegL);
pOut[1]=RC522_ReadRawRC(CRCResultRegM);
}
/*
功 能:復(fù)位RC522
返 回:成功返回MI_OK
*/
char RC522_PcdReset(void)
{
RC522_RST=1; //PF1寫(xiě)1
RC522_Delay(10);
RC522_RST=0; //PF1清0
RC522_Delay(10);
RC522_RST=1; //PF1寫(xiě)1
RC522_Delay(10);
RC522_WriteRawRC(CommandReg,PCD_RESETPHASE); //寫(xiě)RC632寄存器,復(fù)位
RC522_WriteRawRC(CommandReg,PCD_RESETPHASE); //寫(xiě)RC632寄存器,復(fù)位
RC522_Delay(10);
RC522_WriteRawRC(ModeReg,0x3D); //和Mifare卡通訊,CRC初始值0x6363
RC522_WriteRawRC(TReloadRegL,30); //寫(xiě)RC632寄存器
RC522_WriteRawRC(TReloadRegH,0);
RC522_WriteRawRC(TModeReg,0x8D);
RC522_WriteRawRC(TPrescalerReg,0x3E);
RC522_WriteRawRC(TxAutoReg,0x40);//必須要
return MI_OK;
}
/*
函數(shù)功能:設(shè)置RC632的工作方式
*/
char M500PcdConfigISOType(u8 type)
{
if(type=='A') //ISO14443_A
{
RC522_ClearBitMask(Status2Reg,0x08); //清RC522寄存器位
RC522_WriteRawRC(ModeReg,0x3D); //3F//CRC初始值0x6363
RC522_WriteRawRC(RxSelReg,0x86); //84
RC522_WriteRawRC(RFCfgReg,0x7F); //4F //調(diào)整卡的感應(yīng)距離//RxGain = 48dB調(diào)節(jié)卡感應(yīng)距離
RC522_WriteRawRC(TReloadRegL,30); //tmoLength);// TReloadVal = 'h6a =tmoLength(dec)
RC522_WriteRawRC(TReloadRegH,0);
RC522_WriteRawRC(TModeReg,0x8D);
RC522_WriteRawRC(TPrescalerReg,0x3E);
RC522_Delay(1000);
RC522_PcdAntennaOn(); //開(kāi)啟天線
}
else return 1; //失敗,返回1
return MI_OK; //成功返回0
}
/*
功 能:讀RC632寄存器
參數(shù)說(shuō)明:Address[IN]:寄存器地址
返 回:讀出的值
*/
u8 RC522_ReadRawRC(u8 Address)
{
u8 ucAddr;
u8 ucResult=0;
RC522_CS=0; //片選選中RC522
ucAddr=((Address<<1)&0x7E)|0x80;
RC522_SPI_ReadWriteOneByte(ucAddr); //發(fā)送命令
ucResult=RC522_SPI_ReadWriteOneByte(0); //讀取RC522返回的數(shù)據(jù)
RC522_CS=1; //釋放片選線(PF0)
return ucResult; //返回讀到的數(shù)據(jù)
}
/*
功 能:寫(xiě)RC632寄存器
參數(shù)說(shuō)明:Address[IN]:寄存器地址
value[IN] :寫(xiě)入的值
*/
void RC522_WriteRawRC(u8 Address,u8 value)
{
u8 ucAddr;
RC522_CS=0; //PF0寫(xiě) 0 (SDA)(SPI1片選線,低電平有效)
ucAddr=((Address<<1)&0x7E);
RC522_SPI_ReadWriteOneByte(ucAddr); //SPI1發(fā)送一個(gè)字節(jié)
RC522_SPI_ReadWriteOneByte(value); //SPI1發(fā)送一個(gè)字節(jié)
RC522_CS=1; //PF1寫(xiě)1(SDA)(SPI1片選線)
}
/*
功 能:置RC522寄存器位
參數(shù)說(shuō)明:reg[IN]:寄存器地址
mask[IN]:置位值
*/
void RC522_SetBitMask(u8 reg,u8 mask)
{
char tmp=0x0;
tmp=RC522_ReadRawRC(reg); //讀RC632寄存器
RC522_WriteRawRC(reg,tmp|mask); //寫(xiě)RC632寄存器
}
/*
功 能:清RC522寄存器位
參數(shù)說(shuō)明:reg[IN]:寄存器地址
mask[IN]:清位值
*/
void RC522_ClearBitMask(u8 reg,u8 mask)
{
char tmp=0x0;
tmp=RC522_ReadRawRC(reg); //讀RC632寄存器
RC522_WriteRawRC(reg,tmp&~mask); // clear bit mask
}
/*
功 能:通過(guò)RC522和ISO14443卡通訊
參數(shù)說(shuō)明:Command[IN]:RC522命令字
pIn [IN]:通過(guò)RC522發(fā)送到卡片的數(shù)據(jù)
InLenByte[IN]:發(fā)送數(shù)據(jù)的字節(jié)長(zhǎng)度
pOut [OUT]:接收到的卡片返回?cái)?shù)據(jù)
*pOutLenBit[OUT]:返回?cái)?shù)據(jù)的位長(zhǎng)度
*/
char RC522_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: //驗(yàn)證密鑰
irqEn=0x12;
waitFor=0x10;
break;
case PCD_TRANSCEIVE: //發(fā)送并接收數(shù)據(jù)
irqEn=0x77;
waitFor=0x30;
break;
default:
break;
}
RC522_WriteRawRC(ComIEnReg,irqEn|0x80);
RC522_ClearBitMask(ComIrqReg,0x80); //清所有中斷位
RC522_WriteRawRC(CommandReg,PCD_IDLE);
RC522_SetBitMask(FIFOLevelReg,0x80); //清FIFO緩存
for(i=0;i<InLenByte;i++)
{
RC522_WriteRawRC(FIFODataReg,pIn[i]);
}
RC522_WriteRawRC(CommandReg,Command);
if(Command==PCD_TRANSCEIVE)
{
RC522_SetBitMask(BitFramingReg,0x80); //開(kāi)始傳送
}
//有問(wèn)題,下面的循環(huán)
//i = 600;//根據(jù)時(shí)鐘頻率調(diào)整,操作M1卡最大等待時(shí)間25ms
i=2000;
do
{
n=RC522_ReadRawRC(ComIrqReg);
i--;
}
while((i!=0)&&!(n&0x01)&&!(n&waitFor));
RC522_ClearBitMask(BitFramingReg,0x80);
if(i!=0)
{
if(!(RC522_ReadRawRC(ErrorReg)&0x1B))
{
status=MI_OK;
if(n&irqEn&0x01)
{
status=MI_NOTAGERR;
}
if(Command==PCD_TRANSCEIVE)
{
n=RC522_ReadRawRC(FIFOLevelReg);
lastBits=RC522_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]=RC522_ReadRawRC(FIFODataReg);
}
}
}
else
{
status=MI_ERR;
}
}
RC522_SetBitMask(ControlReg,0x80);// stop timer now
RC522_WriteRawRC(CommandReg,PCD_IDLE);
return status;
}
/*
函數(shù)功能:開(kāi)啟天線
參 數(shù):每次啟動(dòng)或關(guān)閉天險(xiǎn)發(fā)射之間應(yīng)至少有1ms的間隔
*/
void RC522_PcdAntennaOn(void)
{
u8 i;
i=RC522_ReadRawRC(TxControlReg);
if(!(i&0x03))
{
RC522_SetBitMask(TxControlReg,0x03);
}
}
/*
函數(shù)功能:關(guān)閉天線
參 數(shù):每次啟動(dòng)或關(guān)閉天險(xiǎn)發(fā)射之間應(yīng)至少有1ms的間隔
*/
void RC522_PcdAntennaOff(void)
{
RC522_ClearBitMask(TxControlReg,0x03); //清RC522寄存器位
}
5.2 rc522.h
#ifndef RFID_RC522_H
#define RFID_RC522_H
#include "sys.h"
/*
RC522射頻模塊外部的接口:
*1--SDA <----->PF0--片選腳
*2--SCK <----->PA5--時(shí)鐘線
*3--MOSI<----->PA7--輸出
*4--MISO<----->PA6--輸入
*5--懸空
*6--GND <----->GND
*7--RST <----->PF1--復(fù)位腳
*8--VCC <----->VCC
*/
#define RC522_OUTPUT PAout(7)
#define RC522_INPUT PAin(6)
#define RC522_SCLK PAout(5)
#define RC522_CS PFout(0)
#define RC522_RST PFout(1)
//MF522命令字
#define PCD_IDLE 0x00 //取消當(dāng)前命令
#define PCD_AUTHENT 0x0E //驗(yàn)證密鑰
#define PCD_RECEIVE 0x08 //接收數(shù)據(jù)
#define PCD_TRANSMIT 0x04 //發(fā)送數(shù)據(jù)
#define PCD_TRANSCEIVE 0x0C //發(fā)送并接收數(shù)據(jù)
#define PCD_RESETPHASE 0x0F //復(fù)位
#define PCD_CALCCRC 0x03 //CRC計(jì)算
//Mifare_One卡片命令字
#define PICC_REQIDL 0x26 //尋天線區(qū)內(nèi)未進(jìn)入休眠狀態(tài),返回的是卡的類(lèi)型
#define PICC_REQALL 0x52 //尋天線區(qū)內(nèi)全部卡,返回的是卡的類(lèi)型
#define PICC_ANTICOLL1 0x93 //防沖撞
#define PICC_ANTICOLL2 0x95 //防沖撞
#define PICC_AUTHENT1A 0x60 //驗(yàn)證A密鑰
#define PICC_AUTHENT1B 0x61 //驗(yàn)證B密鑰 命令認(rèn)證代碼
#define PICC_READ 0x30 //讀塊
#define PICC_WRITE 0xA0 //寫(xiě)塊
#define PICC_DECREMENT 0xC0 //扣款
#define PICC_INCREMENT 0xC1 //充值
#define PICC_RESTORE 0xC2 //調(diào)塊數(shù)據(jù)到緩沖區(qū)
#define PICC_TRANSFER 0xB0 //保存緩沖區(qū)中數(shù)據(jù)
#define PICC_HALT 0x50 //休眠
//MF522 FIFO長(zhǎng)度定義
#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通訊時(shí)返回的錯(cuò)誤代碼
#define MI_OK 0
#define MI_NOTAGERR 1
#define MI_ERR 2
#define SHAQU1 0X01
#define KUAI4 0X04
#define KUAI7 0X07
#define REGCARD 0xa1
#define CONSUME 0xa2
#define READCARD 0xa3
#define ADDMONEY 0xa4
/*
RC522各種驅(qū)動(dòng)函數(shù)
*/
u8 RC522_SPI_ReadWriteOneByte(u8 tx_data);
void RC522_IO_Init(void);
u8 RC522_MFRC522_SelectTag(u8 *serNum);
void RC522_Delay(u32 ns);
void RC522_Init(void);
void RC522_Reset(void);
char RC522_PcdRequest(u8 req_code,u8 *pTagType);
char RC522_PcdAnticoll(u8 *pSnr);
char RC522_PcdSelect(u8 *pSnr);
char RC522_PcdAuthState(u8 auth_mode,u8 addr,u8 *pKey,u8 *pSnr);
char RC522_PcdRead(u8 addr,u8 *p);
char RC522_PcdWrite(u8 addr,u8 *p);
char RC522_PcdHalt(void);
void RC522_CalulateCRC(u8 *pIn ,u8 len,u8 *pOut );
char RC522_PcdReset(void);
char M500PcdConfigISOType(u8 type);
char M500PcdConfigISOType(u8 type);
u8 RC522_ReadRawRC(u8 Address);
void RC522_WriteRawRC(u8 Address,u8 value);
void RC522_SetBitMask(u8 reg,u8 mask) ;
void RC522_ClearBitMask(u8 reg,u8 mask);
char RC522_PcdComMF522(u8 Command,u8 *pIn,u8 InLenByte,u8 *pOut,u8 *pOutLenBit);
void RC522_PcdAntennaOn(void);
void RC522_PcdAntennaOff(void);
#endif