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