【摘要】 當(dāng)前文章介紹如果在Linux系統(tǒng)下編寫MF-RC522模塊驅(qū)動(dòng),配合應(yīng)用層,完成IC卡號(hào)讀取,扇區(qū)讀寫,密碼驗(yàn)證等等。當(dāng)前開發(fā)板采用友善之臂Tiny4412,芯片是三星的EXYNOS4412,驅(qū)動(dòng)代碼沒有采用SPI子系統(tǒng),直接控制IO口模擬SPI時(shí)序完成與MF-RC522之間通訊。
1. MF-RC522模塊介紹
MFRC522是應(yīng)用于13.56MHz非接觸式通信中高集成度的讀寫卡芯片,針對(duì)“三表”應(yīng)用推出的一款低電壓、低成本、體積小的非接觸式讀寫卡芯片,是智能儀表和便攜式手持設(shè)備研發(fā)的較好選擇。便攜式手持設(shè)備研發(fā)的較好選擇。MFRC522利用了先進(jìn)的調(diào)制和解調(diào)概念,集成了在13.56MHz下所有類型的被動(dòng)非接觸式通信方式和協(xié)議。支持14443A兼容應(yīng)答器信號(hào)。數(shù)字部分處理ISO14443A幀和錯(cuò)誤檢測(cè)。此外,還支持快速CRYPTO1加密算法,用語(yǔ)驗(yàn)證MIFARE系列產(chǎn)品。MFRC522支持MI FARE系列更高速的非接觸式通信,雙向數(shù)據(jù)傳輸速率高達(dá)424kbit/s。作為13.56MHz高集成度讀寫卡系列芯片族的新成員,MFRC522與MF RC500和MFRC530有不少相似之處,同時(shí)也具備許多特點(diǎn)和差異。它與主機(jī)間通信采用SPI模式,有利于減少連線,縮小PCB板體積,降低成本。
淘寶上MFRC522的成品模塊非常多,購(gòu)買都會(huì)送幾張白卡(IC卡),完成讀寫實(shí)驗(yàn)。
淘寶上購(gòu)買的MF-RC522模塊基本是引出的SPI接口,實(shí)際上MF-RC522本身還支持IIC,UART協(xié)議,SPI相比來(lái)講,協(xié)議更加簡(jiǎn)單,速度也快。
當(dāng)前我采用的就是淘寶購(gòu)買一個(gè)封裝好的成品模塊,采用MFRC522原裝芯片設(shè)計(jì)讀卡電路,使用方便,成本低廉,適用于設(shè)備開發(fā)、讀卡器開發(fā)等高應(yīng)用的用戶,需要進(jìn)行射頻卡終端設(shè)計(jì)/生產(chǎn)的用戶。本模塊可直接裝入各種讀卡器模具。模塊采用電壓為3.3V,通過(guò)SPI接口簡(jiǎn)單的幾條線就可以直接與用戶任何CPU主板相連接通信,可以保證模塊穩(wěn)定可靠的工作、讀卡距離遠(yuǎn)。
當(dāng)前文章介紹如果在Linux系統(tǒng)下編寫MF-RC522模塊驅(qū)動(dòng),配合應(yīng)用層,完成IC卡號(hào)讀取,扇區(qū)讀寫,密碼驗(yàn)證等等。當(dāng)前開發(fā)板采用友善之臂Tiny4412,芯片是三星的EXYNOS4412,驅(qū)動(dòng)代碼沒有采用SPI子系統(tǒng),直接控制IO口模擬SPI時(shí)序完成與MF-RC522之間通訊。
購(gòu)買模塊時(shí),會(huì)送一張IC白卡和一個(gè)鑰匙扣,雖然形狀不一樣,內(nèi)部芯片型號(hào)都是屬于S50卡,常用的公交車卡、地鐵卡、超市會(huì)員卡等等,都是屬于這種S50卡。這個(gè)洗頭還有一個(gè)S70類型的卡,空間比S50大4倍。S50卡內(nèi)部就是一個(gè)EEPROM空間,可以存放任何數(shù)據(jù),空間一共分為16個(gè)扇區(qū),每個(gè)扇區(qū)由4塊(0、1、2、3)組成。實(shí)際操作時(shí),將16個(gè)扇區(qū)分為64個(gè)塊,按絕對(duì)地址編號(hào)為0-63。
IC卡沒有電源的,它是由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)域的一大突破??ㄆ谝欢ň嚯x范圍(通常為5—10cm)靠近讀寫器表面,通過(guò)無(wú)線電波的傳遞來(lái)完成數(shù)據(jù)的讀寫操作。
2. 硬件原理連線
3. 驅(qū)動(dòng)代碼示例
3.1 rc522.c 源代碼
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "rfid_rc522.h"
#include
#include
/*--------------------------------RC522相關(guān)操作代碼---------------------------------------------*/
/*
函數(shù)功能:RC522初始化
Tiny4412硬件連接:
DO--MISO :GPB_2
DI--MOSI :GPB_3
CLK-SCLK :GPB_0
CS--CS :GPB_1
RST-- :GPB_4
*/
void RC522_IO_Init(void)
{
/*1. 注冊(cè)GPIO*/
gpio_request(EXYNOS4_GPB(0), "RC522_CLK-SCLK");
gpio_request(EXYNOS4_GPB(1), "RC522_CS");
gpio_request(EXYNOS4_GPB(2), "MOSI");
gpio_request(EXYNOS4_GPB(3), "RC522_MOSI");
gpio_request(EXYNOS4_GPB(4), "RST");
/*2. 配置GPIO口模式*/
s3c_gpio_cfgpin(EXYNOS4_GPB(0), S3C_GPIO_OUTPUT); //時(shí)鐘
s3c_gpio_cfgpin(EXYNOS4_GPB(1), S3C_GPIO_OUTPUT); //片選
s3c_gpio_cfgpin(EXYNOS4_GPB(2), S3C_GPIO_INPUT); //輸入模式
s3c_gpio_cfgpin(EXYNOS4_GPB(3), S3C_GPIO_OUTPUT); //輸出模式
s3c_gpio_cfgpin(EXYNOS4_GPB(4), S3C_GPIO_OUTPUT); //輸出模式
/*3. 上拉GPIO口*/
gpio_set_value(EXYNOS4_GPB(0), 1);
gpio_set_value(EXYNOS4_GPB(1), 1);
gpio_set_value(EXYNOS4_GPB(3), 1);
gpio_set_value(EXYNOS4_GPB(4), 1);
}
/*
函數(shù)功能:SPI時(shí)序讀寫一個(gè)字節(jié)
說(shuō) 明:SPI底層時(shí)序,程序的移植接口
*/
u8 RC522_SPI_ReadWriteOneByte(u8 data_tx)
{
u8 data_rx=0;
u8 i;
for(i=0;i<8;i++)
{
gpio_set_value(EXYNOS4_GPB(0), 0);
if(data_tx&0x80)gpio_set_value(EXYNOS4_GPB(3), 1);
else gpio_set_value(EXYNOS4_GPB(3), 0);
data_tx<<=1; //繼續(xù)發(fā)送下一個(gè)數(shù)據(jù)
gpio_set_value(EXYNOS4_GPB(0), 1);
data_rx<<=1;
if(gpio_get_value(EXYNOS4_GPB(2)))data_rx|=0x01;
}
return data_rx;
}
/*
功能描述:選卡讀取卡存儲(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)
{
ndelay(ns);
}
/*
函數(shù)功能:RC522芯片初始化
*/
void RC522_Init(void)
{
RC522_IO_Init(); //RC522初始化
RC522_PcdReset(); //復(fù)位RC522
RC522_PcdAntennaOff(); //關(guān)閉天線
msleep(2); //延時(shí)2毫秒
RC522_PcdAntennaOn(); //開啟天線
M500PcdConfigISOType('A'); //設(shè)置RC632的工作方式
}
/*
函數(shù)功能:復(fù)位RC522
*/
void RC522_Reset(void)
{
RC522_PcdReset(); //復(fù)位RC522
RC522_PcdAntennaOff(); //關(guān)閉天線
msleep(2); //延時(shí)2毫秒
RC522_PcdAntennaOn(); //開啟天線
}
/*
功 能: 尋卡
參數(shù)說(shuō)明: req_code[IN]:尋卡方式
0x52 = 尋感應(yīng)區(qū)內(nèi)所有符合14443A標(biāo)準(zhǔn)的卡
0x26 = 尋未進(jìn)入休眠狀態(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); //通過(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); //寫
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:寫入卡里的數(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;
}
/*
功 能:寫數(shù)據(jù)到M1卡指定塊
參數(shù)說(shuō)明: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;
}
/*
功 能:命令卡片進(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中寫入數(shù)據(jù)
for(i=0;i
-
射頻
+關(guān)注
關(guān)注
104文章
5573瀏覽量
167694 -
RFID
+關(guān)注
關(guān)注
388文章
6142瀏覽量
237746 -
RC522
+關(guān)注
關(guān)注
7文章
56瀏覽量
23976
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論