最近在研究RFID(射頻識別),我用的是 M1卡(Mifare_One(S50)),是一種常用的非接觸式IC卡
基礎知識不用多講,網上資料一堆,講的很詳細。
現在我們就直入主題,首先介紹一下卡的執行流程圖,如下圖。
中文資料裏的圖,如下:
英文資料裏的圖,如下:
查資料會發現,所有的參考代碼都是按照這個流程圖寫,很容易懂。不管你在寫還是讀的時候一定要選卡,放衝突,驗卡等流程後才能實現讀寫操作。
再看一下他的存儲結構:
////*********引用一個博客文檔 開始
我們可以根據控制字來確定卡的讀寫形式。
M1卡分爲16個扇區,每個扇區由4塊(塊0、塊1、塊2、塊3)組成,前3個塊是數據區,第4塊是密鑰區。每個塊都能存儲16個字節的數據,密鑰區的16個字節數據是有特殊含義的:
6個字節的密碼A + 4個字節密鑰控制位 + 6個字節的密碼B
其中密鑰控制位決定這個扇區的讀寫規則,對於M1卡密鑰控制位及控制規則的說明,這篇文章裏面講述得很清楚了:
https://wenku.baidu.com/view/76afde36312b3169a451a4e6.html
這裏只是給沒有耐心看文章朋友提煉一下,控制字的組合方式雖然多,但實際用得比較多的方案自認爲無外乎四種:
1.默認方式 控制位爲“FF 07 80 69”
這種方式下密鑰A或密鑰B都可以讀寫數據區,密鑰A可寫密鑰區,優點是密鑰控制字無需重新計算,讀寫方便,缺點是安全性能差,密鑰A容易泄露。
2.密鑰B寫方式 控制位爲“7F 07 88 69”
這種方式下密鑰A或密鑰B都可以讀寫數據區,而對於密鑰區只能由密鑰B來寫。優點是密鑰B權限最高,只要知道密鑰B,無論密鑰A寫成什麼都可以改寫,由最高管理員掌握密鑰B,可下發多種密鑰A的一般管理員,一般不會廢卡的。缺點是密鑰B很重要,一旦忘記,卡就不能再改寫密鑰了。
3.A讀B寫方式 控制位爲“08 77 8F 69”
這種方式下由密鑰A讀密鑰B來寫,可以說是上面一種方式的變體,對於密鑰B有更強的保護。
4.只讀不寫方式 控制位爲“FF 00 F0 69”
這種方式下密鑰A或密鑰B都可以讀數據區,但都不能寫數據區(數值可減少,不能增加),密鑰A可以改寫密鑰區。這種方式對於數據是極大的保護,尤其是定額卡,裏面的錢只能減少而不能增加。
以上是常用的幾種控制方式,更多的組合方式可以利用“M1+卡控制字節生成工具.exe”工具來生成
結束 ******////////////
1.完成RFID卡的讀函數代碼:
/* 讀取RFID卡片信息 **/
void Read_RFID_Card_wt(void)
{
char status = MI_ERR;
uint8_t CT[2]; //卡類型
uint8_t SN[4]; //卡號
uint8_t KEY[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; //密鑰 // 密鑰已被我修改 2019.11.19 王艇
uint8_t s = 0x01;
#define DATA_LEN 16 //定義數據字節長度
LED1 = 0;
LED2 = 0;
LED3 = 0;
LED4 = 0;
status = PcdRequest(PICC_REQALL,CT); //尋卡
//Send_ZigbeeData_To_Fifo(CT,2); // wt 2019.10.18
if(status == MI_OK) //尋卡成功
{
status=MI_ERR;
LED1 = 1;
status = PcdAnticoll(SN); //防衝撞
//Send_ZigbeeData_To_Fifo(SN,4); // wt 2019.10.18
if(status == MI_OK)
{
status=MI_ERR;
LED2 = 1;
status =PcdSelect(SN); //選定此卡
if(status == MI_OK) //選定成功
{
status=MI_ERR;
LED3 = 1;
MP_SPK = 1;
status =PcdAuthState(PICC_AUTHENT1A,0x03,KEY,SN); //驗證密鑰
if(status == MI_OK)
{
status = MI_ERR;
status=PcdRead(s,RXRFID); //讀卡
if(status == MI_OK)
{
status = MI_ERR;
LED4 = 1; //讀卡成功
MP_SPK = 0;
//Send_InfoData_To_Fifo(RXRFID,16);
//Send_InfoData_To_Fifo("\n",2);
//Send_ZigbeeData_To_Fifo(RXRFID,16);
}
}
}
}
}
}
這裏我是讀取0扇區第二塊(0X01)的數據,其實讀取其他也很簡單,需要修改0X03(這個是0-15扇區的控制塊,如:0扇區的控制塊是0X03,1扇區的控制塊是0X07 等等)
隨後還要修改,s,這個s就是你要驗證的哪個扇區的數據塊地址還控制塊地址(如:想讀1扇區的0塊數據,這個s的值就是0X04,我們這裏讀取的是0扇區第二塊(0X01)的數據):
注意:一般新卡的默認密鑰都是KEYA或KEYB 0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,但有時候密鑰會被修改,那這時就要填寫正確的key值,才能驗證成功,這樣也很容易理解,只有配上正確的密碼才能激活卡片。
2.完成RFID卡的寫函數代碼:
void Write_RFID_Card_wt(void)
{
char status = MI_ERR;
uint8_t CT[2]; //卡類型
uint8_t SN[4]; //卡號
uint8_t KEY[6]={0xff,0xff,0xff,0xff,0xff,0xff}; //{0x01,0xB2,0xC3,0xD4,0xE5,0xF6}; //密鑰 // 密鑰已被我修改 2019.11.19 王艇
uint8_t s = 0x01;
#define DATA_LEN 16 //定義數據字節長度
LED1 = 0;
LED2 = 0;
LED3 = 0;
LED4 = 0;
status = PcdRequest(PICC_REQALL,CT); //尋卡
//Send_ZigbeeData_To_Fifo(CT,2); // wt 2019.10.18
if(status == MI_OK) //尋卡成功
{
status=MI_ERR;
LED1 = 1;
status = PcdAnticoll(SN); //防衝撞
//Send_ZigbeeData_To_Fifo(SN,4); // wt 2019.10.18
if(status == MI_OK)
{
status=MI_ERR;
LED2 = 1;
status =PcdSelect(SN); //選定此卡
if(status == MI_OK) //選定成功
{
status=MI_ERR;
LED3 = 1;
MP_SPK = 1;
status =PcdAuthState(PICC_AUTHENT1A,0x03,KEY,SN); //驗證密鑰
if(status == MI_OK)
{
status = MI_ERR;
status = PcdWrite(s,TXRFID); //寫卡
if(status == MI_OK)
{
status = MI_ERR;
}
}
}
}
}
}
這裏是給0扇區1數據塊(0X01)寫數據,這個寫函數也是可以給其他扇區中數據塊寫數據的,如現在要給我1扇區,2塊中寫入數據:uint8_t TXRFID[16] = {0x7C,0x32,0x2F,0X30,0X33,0X2D,0X32,0X7C,0X7C,0X33,0X2F,0X30,0X35,0X2D,0X31,0X7C}
這裏選擇的是默認密鑰,全F,驗證A密鑰(PICC_AUTHENT1A)
下面的 0X03需要改成0X07(扇區1 控制塊地址),因爲控制塊中包含密鑰,需要驗證
下面s要修改成0X06(表示1扇區,數據塊2的地址),TXRFID 是所要寫入的數據
這樣就完成了對指定扇區,指定數據塊中寫入指定數據。
3.修改RFID卡的密鑰代碼:
void Write_RFID_Card_wt(void)
{
char status = MI_ERR;
uint8_t CT[2]; //卡類型
uint8_t SN[4]; //卡號
uint8_t KEY[6]={0xff,0xff,0xff,0xff,0xff,0xff}; //{0x01,0xB2,0xC3,0xD4,0xE5,0xF6}; //密鑰 // 密鑰已被我修改 2019.11.19 王艇
uint8_t s = 0x03;
#define DATA_LEN 16 //定義數據字節長度
LED1 = 0;
LED2 = 0;
LED3 = 0;
LED4 = 0;
status = PcdRequest(PICC_REQALL,CT); //尋卡
//Send_ZigbeeData_To_Fifo(CT,2); // wt 2019.10.18
if(status == MI_OK) //尋卡成功
{
status=MI_ERR;
LED1 = 1;
status = PcdAnticoll(SN); //防衝撞
//Send_ZigbeeData_To_Fifo(SN,4); // wt 2019.10.18
if(status == MI_OK)
{
status=MI_ERR;
LED2 = 1;
status =PcdSelect(SN); //選定此卡
if(status == MI_OK) //選定成功
{
status=MI_ERR;
LED3 = 1;
MP_SPK = 1;
status =PcdAuthState(PICC_AUTHENT1A,0x03,KEY,SN); //驗證密鑰
if(status == MI_OK)
{
status = MI_ERR;
status = PcdWrite(s,TXRFID); //寫卡
if(status == MI_OK)
{
status = MI_ERR;
}
}
}
}
}
}
上面的代碼仔細看可以發現和2.完成RFID卡的寫函數代碼,中的代碼基本一致,也就是簡單修改了幾個參數。上面函數的功能是:將扇區0,控制塊的密鑰修改成0x01,0xB2,0xC3,0xD4,0xE5,0xF6,原來的密鑰是0xff,0xff,0xff,0xff,0xff,0xff
當修改完成後,他的密鑰就成了0x01,0xB2,0xC3,0xD4,0xE5,0xF6。
uint8_t TXRFID[16] = {0x01,0xB2,0xC3,0xD4,0xE5,0xF6,0xFF,0x07,0x80,0x69,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
現在假如需要修改扇區1的A密鑰,之前扇區A的密鑰爲0xff,0xff,0xff,0xff,0xff,0xff,修改爲:0x01,0xB2,0xC3,0xD4,0xE5,0xF6
所以需要修改成的地方有:
修改控制塊地址爲0X07,這個地址就是扇區1,控制塊地址
這邊的控制塊地址改成0X07
這個數組爲:TXRFID[16] = {0x01,0xB2,0xC3,0xD4,0xE5,0xF6,0xFF,0x07,0x80,0x69,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
執行成功後,扇區1的密鑰A的密碼就被修改成功了。
這樣就完成了數據的讀取,和密鑰的修改
後期對卡的扣款 充值操作就更容易一點。