【摘要】 當前文章介紹如果在Linux系統下編寫MF-RC522模塊驅動,配合應用層,完成IC卡號讀取,扇區讀寫,密碼驗證等等。當前開發板采用友善之臂Tiny4412,芯片是三星的EXYNOS4412,驅動代碼沒有采用SPI子系統,直接控制IO口模擬SPI時序完成與MF-RC522之間通訊。
1. MF-RC522模塊介紹
MFRC522是應用于13.56MHz非接觸式通信中高集成度的讀寫卡芯片,針對“三表”應用推出的一款低電壓、低成本、體積小的非接觸式讀寫卡芯片,是智能儀表和便攜式手持設備研發的較好選擇。便攜式手持設備研發的較好選擇。MFRC522利用了先進的調制和解調概念,集成了在13.56MHz下所有類型的被動非接觸式通信方式和協議。支持14443A兼容應答器信號。數字部分處理ISO14443A幀和錯誤檢測。此外,還支持快速CRYPTO1加密算法,用語驗證MIFARE系列產品。MFRC522支持MI FARE系列更高速的非接觸式通信,雙向數據傳輸速率高達424kbit/s。作為13.56MHz高集成度讀寫卡系列芯片族的新成員,MFRC522與MF RC500和MFRC530有不少相似之處,同時也具備許多特點和差異。它與主機間通信采用SPI模式,有利于減少連線,縮小PCB板體積,降低成本。
淘寶上MFRC522的成品模塊非常多,購買都會送幾張白卡(IC卡),完成讀寫實驗。
淘寶上購買的MF-RC522模塊基本是引出的SPI接口,實際上MF-RC522本身還支持IIC,UART協議,SPI相比來講,協議更加簡單,速度也快。
當前我采用的就是淘寶購買一個封裝好的成品模塊,采用MFRC522原裝芯片設計讀卡電路,使用方便,成本低廉,適用于設備開發、讀卡器開發等高應用的用戶,需要進行射頻卡終端設計/生產的用戶。本模塊可直接裝入各種讀卡器模具。模塊采用電壓為3.3V,通過SPI接口簡單的幾條線就可以直接與用戶任何CPU主板相連接通信,可以保證模塊穩定可靠的工作、讀卡距離遠。


當前文章介紹如果在Linux系統下編寫MF-RC522模塊驅動,配合應用層,完成IC卡號讀取,扇區讀寫,密碼驗證等等。當前開發板采用友善之臂Tiny4412,芯片是三星的EXYNOS4412,驅動代碼沒有采用SPI子系統,直接控制IO口模擬SPI時序完成與MF-RC522之間通訊。
購買模塊時,會送一張IC白卡和一個鑰匙扣,雖然形狀不一樣,內部芯片型號都是屬于S50卡,常用的公交車卡、地鐵卡、超市會員卡等等,都是屬于這種S50卡。這個洗頭還有一個S70類型的卡,空間比S50大4倍。S50卡內部就是一個EEPROM空間,可以存放任何數據,空間一共分為16個扇區,每個扇區由4塊(0、1、2、3)組成。實際操作時,將16個扇區分為64個塊,按絕對地址編號為0-63。
IC卡沒有電源的,它是由IC芯片、感應天線組成,封裝在一個標準的PVC卡片內,芯片及天線無任何外露部分。是世界上最近幾年發展起來的一項新技術,它成功的將射頻識別技術和IC卡技術結合起來,結束了無源(卡中無電源)和免接觸這一難題,是電子器件領域的一大突破。卡片在一定距離范圍(通常為5—10cm)靠近讀寫器表面,通過無線電波的傳遞來完成數據的讀寫操作。
2. 硬件原理連線
3. 驅動代碼示例
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相關操作代碼---------------------------------------------*/
/*
函數功能: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. 注冊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); //時鐘
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);
}
/*
函數功能:SPI時序讀寫一個字節
說 明:SPI底層時序,程序的移植接口
*/
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; //繼續發送下一個數據
gpio_set_value(EXYNOS4_GPB(0), 1);
data_rx<<=1;
if(gpio_get_value(EXYNOS4_GPB(2)))data_rx|=0x01;
}
return data_rx;
}
/*
功能描述:選卡讀取卡存儲器容量
輸入參數: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;
}
/*
延時函數,納秒級
*/
void RC522_Delay(u32 ns)
{
ndelay(ns);
}
/*
函數功能:RC522芯片初始化
*/
void RC522_Init(void)
{
RC522_IO_Init(); //RC522初始化
RC522_PcdReset(); //復位RC522
RC522_PcdAntennaOff(); //關閉天線
msleep(2); //延時2毫秒
RC522_PcdAntennaOn(); //開啟天線
M500PcdConfigISOType('A'); //設置RC632的工作方式
}
/*
函數功能:復位RC522
*/
void RC522_Reset(void)
{
RC522_PcdReset(); //復位RC522
RC522_PcdAntennaOff(); //關閉天線
msleep(2); //延時2毫秒
RC522_PcdAntennaOn(); //開啟天線
}
/*
功 能: 尋卡
參數說明: 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 RC522_PcdRequest(u8 req_code,u8 *pTagType)
{
char status;
u8 unLen;
u8 ucComMF522Buf[MAXRLEN]; // MAXRLEN 18
RC522_ClearBitMask(Status2Reg,0x08); //清RC522寄存器位,/接收數據命令
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;
}
/*
功 能: 防沖撞
參數說明: pSnr[OUT]:卡片序列號,4字節
返 回: 成功返回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 =發送并接收數據
//2:寫入卡里的數據字節長度
//ucComMF522Buf:存放數據的地址
//unLen:從卡里讀出的數據長度
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;
}
/*
功 能:選定卡片
參數說明:pSnr[IN]:卡片序列號,4字節
返 回:成功返回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函數,校驗數據
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;
}
/*
功 能:驗證卡片密碼
參數說明:auth_mode[IN]: 密碼驗證模式
0x60 = 驗證A密鑰
0x61 = 驗證B密鑰
addr[IN]:塊地址
pKey[IN]:扇區密碼
pSnr[IN]:卡片序列號,4字節
返 回:成功返回MI_OK
*/
char RC522_PcdAuthState(u8 auth_mode,u8 addr,u8 *pKey,u8 *pSnr)
{
char status;
u8 unLen;
u8 ucComMF522Buf[MAXRLEN]; //MAXRLEN 18(數組的大小)
//驗證模式+塊地址+扇區密碼+卡序列號
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卡一塊數據
參數說明:
addr:塊地址
p :讀出的塊數據,16字節
返 回:成功返回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;
}
/*
功 能:寫數據到M1卡指定塊
參數說明:addr:塊地址
p :向塊寫入的數據,16字節
返 回:成功返回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數據
{
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;
}
/*
功 能:命令卡片進入休眠狀態
返 回:成功返回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函數
參 數:
*pIn :要讀數CRC的數據
len:-數據長度
*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中寫入數據
for(i=0;i
-
射頻
+關注
關注
106文章
5756瀏覽量
170380 -
RFID
+關注
關注
391文章
6440瀏覽量
242414 -
RC522
+關注
關注
7文章
57瀏覽量
24508
發布評論請先 登錄
飛凌嵌入式ElfBoard ELF 1板卡-Linux驅動模塊之helloworld驅動
SI522A 低功耗尋卡與多款13.56MHZ 兼容開發資料
CI522 NFC刷卡電動車儀表方案
低功耗4G模組:Air780EP開發板RC522實例

評論