STM32F103+RFID-RC522模块 实现简单读卡写卡demo
目錄
- 前言
- 特別聲明:
- 代碼下載:
- 功能介紹:
- 接線
- STM32
- STM32F1開發指南(精英版)-庫函數版本_V1.2
- STM32中文參考手冊
- RFID-RC522
- RFID射頻模塊電路原理圖
- 使用圖+效果圖
- 測試程序0 RC522_Handle()
- 最終效果
- 一、先用手機軟件NFC Writer讀取空卡看看內容
- 1、打開軟件和NFC(ps:我的手機是小米10)
- 2、將空卡貼于手機背部,彈出提示發現新卡,點擊“好的”
- 3、上面的新卡片左滑到新卡片1,單擊這個卡片
- 4、進入卡片信息詳細頁面
- 鑰匙扣卡
- M1空白卡
- 二、編譯、燒寫程序
- 三、將鑰匙扣卡發在模塊上,打開串口,開始測試
- 測試程序1 RC522_Handle1()
- 核心代碼
- main.c
- rc522.h
- rc522.c
- 額外資料
前言
特別聲明:
-
本倉庫發布的程序,僅用于測試和學習研究,禁止用于商業用途,不能保證其合法性,準確性,完整性和有效性,請根據情況自行判斷。
-
本人對任何腳本問題概不負責,包括但不限于由任何腳本錯誤導致的任何損失或損害。
-
間接使用腳本的任何用戶,包括但不限于建立VPS或在某些行為違反國家/地區法律或相關法規的情況下進行傳播, 本人對于由此引起的任何隱私泄漏或其他后果概不負責。
-
任何以任何方式查看此項目的人或直接或間接使用該項目的任何程序的使用者都應仔細閱讀此聲明。本人保留隨時更改或補充此免責聲明的權利。一旦使用并復制了任何相關腳本或Script項目的規則,則視為您已接受此免責聲明。
本文不含任何廣告性質,僅供學習參考。寫卡需謹慎!!!,不然可能會玩崩了。血的教訓!!!
參考資料:
淺談IC卡數據分析
智能卡 ISO14443 協議 解讀
STM32F103ZET–RFID-RC522使用例程(戰艦版)
M1卡使用說明書
M1卡介紹
STM32-RC522
Mifare1技術說明(M1卡說明文檔)
源碼參考:RFID-RC522,不能使用,我進行了一定的修改。下載參考下方傳送門。
開發板:正點原子 STM32F103 精英版
語言:C語言
開發環境:Keil5
開發板使用了 LED SPI USART RFID-RC522模塊 鑰匙扣卡 M1卡
Win10軟件 SSCOM串口調試 FlyMcu燒錄(ps:電腦安裝驅動CH340)
安卓軟件 NFC Writer (手機需有NFC功能)
代碼下載:
碼云 GitHub
功能介紹:
尋卡-》防沖撞-》選卡-》驗證2扇區密鑰-》讀取2扇區0區塊數據-》寫入數據到2扇區0區塊-》再讀取2扇區0區塊數據。
串口打印卡UID,驗證結果,讀取到的2扇區0區塊數據等信息。
注意:只有驗證成功的扇區,才能對此扇區進行讀寫操作!
另外:3區塊的密鑰A單片機讀取出來是全00,手機是全ff
控制字的默認值是“FF078069”,此時
A密鑰:不可被讀出,有全部權限
B密鑰:可被讀出,沒有任何權限
下圖參考:https://blog.csdn.net/hiwoshixiaoyu/article/details/104048663
接線
1--SDA <----->PA4 2--SCK <----->PA5 3--MOSI <----->PA7 4--MISO <----->PA6 5--懸空 6--GND <----->GND 7--RST <----->PB0 8--VCC <----->VCCSTM32
STM32F1開發指南(精英版)-庫函數版本_V1.2
STM32中文參考手冊
RFID-RC522
參考:https://www.cirmall.com/circuit/2149/
RFID射頻模塊電路原理圖
使用圖+效果圖
測試程序0 RC522_Handle()
最終效果
一、先用手機軟件NFC Writer讀取空卡看看內容
1、打開軟件和NFC(ps:我的手機是小米10)
2、將空卡貼于手機背部,彈出提示發現新卡,點擊“好的”
3、上面的新卡片左滑到新卡片1,單擊這個卡片
4、進入卡片信息詳細頁面
鑰匙扣卡
M1空白卡
可以發現2張卡除了卡號和卡號異或值不同外,其他數據都一樣,之后的例子都以鑰匙扣卡舉例。
下圖參考:https://blog.csdn.net/hiwoshixiaoyu/article/details/104048663
二、編譯、燒寫程序
三、將鑰匙扣卡發在模塊上,打開串口,開始測試
串口打印
注意 原卡 2扇區0區塊數據為
我們放上卡后,進行了數據寫入,之后讀取到的數據都為DATA1的數據0.0
此時數據寫入完畢后,我們再將鑰匙扣卡貼于手機,看看現在手機讀取出來的結果
OK,看樣子寫入成功了,那么到此例程就結束了。
測試程序1 RC522_Handle1()
測試程序1,完成0x0F塊 驗證KEY_A、KEY_B 讀 寫RFID1 驗證KEY_A1、KEY_B1 讀 寫RFID2
// 測試用 3區塊數據 unsigned char RFID1[16]= {0x10,0x20,0x30,0x40,0x50,0x60,0xff,0x07,0x80,0x29,0x01,0x02,0x03,0x04,0x05,0x06}; unsigned char RFID2[16]= {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x80,0x29,0xff,0xff,0xff,0xff,0xff,0xff}; // 測試用 3區塊密鑰 u8 KEY_A1[6]= {0x10,0x20,0x30,0x40,0x50,0x60}; u8 KEY_B1[6]= {0x01,0x02,0x03,0x04,0x05,0x06};核心代碼
main.c
#include "delay.h" #include "sys.h" #include "usart.h" #include "rc522.h" #include "led.h"/** * 連線說明: * 1--SDA <----->PA4 * 2--SCK <----->PA5 * 3--MOSI <----->PA7 * 4--MISO <----->PA6 * 5--懸空 * 6--GND <----->GND * 7--RST <----->PB0 * 8--VCC <----->VCC **/int main(void) {u8 num = 0;delay_init(); //延時函數初始化NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設置中斷優先級分組為組2:2位搶占優先級,2位響應優先級uart_init(115200); //串口初始化為115200LED_Init();RC522_Init(); //初始化射頻卡模塊while(1){// 重要提醒,寫卡操作有風險,請勿隨意嘗試,不能保證程序安全性,本人對任何程序問題概不負責,不限于由任何程序錯誤導致的任何損失或損害// 測試程序0,完成addr讀寫讀RC522_Handle();// 謹慎使用 測試程序1,完成0x0F塊 驗證KEY_A、KEY_B 讀 寫RFID1 驗證KEY_A1、KEY_B1 讀 寫RFID2// RC522_Handle1();if(num % 20 == 0)LED0 = !LED0;num++;} }rc522.h
#ifndef __RC522_H #define __RC522_H #include "sys.h" #include "stm32f10x.h"/ //MF522命令字 / #define PCD_IDLE 0x00 //取消當前命令 #define PCD_AUTHENT 0x0E //驗證密鑰 #define PCD_RECEIVE 0x08 //接收數據 #define PCD_TRANSMIT 0x04 //發送數據 #define PCD_TRANSCEIVE 0x0C //發送并接收數據 #define PCD_RESETPHASE 0x0F //復位 #define PCD_CALCCRC 0x03 //CRC計算/ //Mifare_One卡片命令字 / #define PICC_REQIDL 0x26 //尋天線區內未進入休眠狀態 #define PICC_REQALL 0x52 //尋天線區內全部卡 #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 //調塊數據到緩沖區 #define PICC_TRANSFER 0xB0 //保存緩沖區中數據 #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// //#define spi_cs 1; //sbit spi_ck=P0^6; //sbit spi_mosi=P0^7; //sbit spi_miso=P4^1; //sbit spi_rst=P2^7; #define SPIReadByte() SPIWriteByte(0) u8 SPIWriteByte(u8 byte); void SPI1_Init(void); //void SPI2_Init(void);#define SET_SPI_CS (GPIOF->BSRR=0X01) #define CLR_SPI_CS (GPIOF->BRR=0X01)#define SET_RC522RST GPIOF->BSRR=0X02 #define CLR_RC522RST GPIOF->BRR=0X02/***********************RC522 函數宏定義**********************/ #define RC522_CS_Enable() GPIO_ResetBits ( GPIOA, GPIO_Pin_4 ) #define RC522_CS_Disable() GPIO_SetBits ( GPIOA, GPIO_Pin_4 )#define RC522_Reset_Enable() GPIO_ResetBits( GPIOB, GPIO_Pin_0 ) #define RC522_Reset_Disable() GPIO_SetBits ( GPIOB, GPIO_Pin_0 )#define RC522_SCK_0() GPIO_ResetBits( GPIOA, GPIO_Pin_5 ) #define RC522_SCK_1() GPIO_SetBits ( GPIOA, GPIO_Pin_5 )#define RC522_MOSI_0() GPIO_ResetBits( GPIOA, GPIO_Pin_7 ) #define RC522_MOSI_1() GPIO_SetBits ( GPIOA, GPIO_Pin_7 )#define RC522_MISO_GET() GPIO_ReadInputDataBit ( GPIOA, GPIO_Pin_6 )void RC522_Handle (void); // 測試程序0,完成addr讀寫讀 void RC522_Handle1 (void); // 測試程序1,完成0x0F塊 驗證KEY_A、KEY_B 讀 寫RFID1 驗證KEY_A1、KEY_B1 讀 寫RFID2 void RC522_data_break (void); // 測試用數據爆破程序,僅供學習參考,請勿非法使用 void RC522_Init ( void ); //初始化 void PcdReset ( void ); //復位 void M500PcdConfigISOType ( u8 type ); //工作方式 char PcdRequest ( u8 req_code, u8 * pTagType ); //尋卡 char PcdAnticoll ( u8 * pSnr); //讀卡號char PcdSelect ( u8 * pSnr ); char PcdAuthState ( u8 ucAuth_mode, u8 ucAddr, u8 * pKey, u8 * pSnr ); char PcdWrite ( u8 ucAddr, u8 * pData ); char PcdRead ( u8 ucAddr, u8 * pData ); void ShowID(u8 *p); //顯示卡的卡號,以十六進制顯示extern char* POINT_LNG; extern char* POINT_LAT; extern char* POINT_LNG_ON; extern char* POINT_LAT_ON; extern char* POINT_LNG_OFF; extern char* POINT_LAT_OFF;#endifrc522.c
#include "sys.h" #include "rc522.h" #include "delay.h" #include "usart.h" #include "string.h"// // M1卡分為16個扇區,每個扇區由四個塊(塊0、塊1、塊2、塊3)組成 // 將16個扇區的64個塊按絕對地址編號為:0~63 // 第0個扇區的塊0(即絕對地址0塊),用于存放廠商代碼,已經固化不可更改 // 每個扇區的塊0、塊1、塊2為數據塊,可用于存放數據 // 每個扇區的塊3為控制塊(絕對地址為:塊3、塊7、塊11.....)包括密碼A,存取控制、密碼B等/******************************* *連線說明: *1--SDA <----->PA4 *2--SCK <----->PA5 *3--MOSI <----->PA7 *4--MISO <----->PA6 *5--懸空 *6--GND <----->GND *7--RST <----->PB0 *8--VCC <----->VCC ************************************//*全局變量*/ unsigned char CT[2];//卡類型 unsigned char SN[4]; //卡號 unsigned char DATA[16]; //存放數據 unsigned char RFID[16]; //存放RFID unsigned char card0_bit=0; unsigned char card1_bit=0; unsigned char card2_bit=0; unsigned char card3_bit=0; unsigned char card4_bit=0; unsigned char total=0; // 這UID定義在這不知道干啥用的。。。 替換成自己卡的UID unsigned char card_0[4]= {73,224,5,152}; unsigned char card_1[4]= {105,102,100,152}; unsigned char card_2[4]= {208,121,31,57}; unsigned char card_3[4]= {176,177,143,165}; unsigned char card_4[4]= {5,158,10,136}; u8 KEY_A[6]= {0xff,0xff,0xff,0xff,0xff,0xff}; u8 KEY_B[6]= {0xff,0xff,0xff,0xff,0xff,0xff}; u8 AUDIO_OPEN[6] = {0xAA, 0x07, 0x02, 0x00, 0x09, 0xBC}; // 測試用 3區塊數據 unsigned char RFID1[16]= {0x10,0x20,0x30,0x40,0x50,0x60,0xff,0x07,0x80,0x29,0x01,0x02,0x03,0x04,0x05,0x06}; unsigned char RFID2[16]= {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x80,0x29,0xff,0xff,0xff,0xff,0xff,0xff}; // 測試用 3區塊密鑰 u8 KEY_A1[6]= {0x10,0x20,0x30,0x40,0x50,0x60}; u8 KEY_A2[6]= {0x00,0x00,0x00,0x00,0x00,0x00}; u8 KEY_B1[6]= {0x01,0x02,0x03,0x04,0x05,0x06}; u8 KEY_B2[6]= {0x10,0x20,0x30,0x00,0x00,0x00}; u8 KEY_B3[6]= {0x01,0x02,0x03,0x00,0x00,0x00}; // 置零用 unsigned char DATA0[16]= {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; unsigned char DATA1[16]= {0x12,0x34,0x56,0x78,0x9A,0x00,0xff,0x07,0x80,0x29,0xff,0xff,0xff,0xff,0xff,0xff}; unsigned char status; // 0x08 就是2扇區0區塊(即第9塊) unsigned char addr=0x08; // unsigned char addr=0x08;#define RC522_DELAY() delay_us( 20 )// 測試程序0,完成addr讀寫讀 void RC522_Handle(void) {u8 i = 0;status = PcdRequest(PICC_REQALL,CT);//尋卡// printf("\r\nstatus>>>>>>%d\r\n", status);if(status==MI_OK)// 尋卡成功{status=MI_ERR;status = PcdAnticoll(SN);// 防沖撞 獲得UID 存入SN}if (status==MI_OK)// 防沖撞成功{status = MI_ERR;ShowID(SN); // 串口打印卡的ID號 UID// 難道就是為了做個判斷嗎。。。if((SN[0]==card_0[0])&&(SN[1]==card_0[1])&&(SN[2]==card_0[2])&&(SN[3]==card_0[3])){card0_bit=1;printf("\r\nThe User is:card_0\r\n");}if((SN[0]==card_1[0])&&(SN[1]==card_1[1])&&(SN[2]==card_1[2])&&(SN[3]==card_1[3])){card1_bit=1;printf("\r\nThe User is:card_1\r\n");}if((SN[0]==card_2[0])&&(SN[1]==card_2[1])&&(SN[2]==card_2[2])&&(SN[3]==card_2[3])){card2_bit=1;printf("\r\nThe User is:card_2\r\n");}if((SN[0]==card_3[0])&&(SN[1]==card_3[1])&&(SN[2]==card_3[2])&&(SN[3]==card_3[3])){card3_bit=1;printf("\r\nThe User is:card_3\r\n");}if((SN[0]==card_4[0])&&(SN[1]==card_4[1])&&(SN[2]==card_4[2])&&(SN[3]==card_4[3])){card4_bit=1;printf("\r\nThe User is:card_4\r\n");}//total = card1_bit+card2_bit+card3_bit+card4_bit+card0_bit;status = PcdSelect(SN);}else{}if(status == MI_OK)//選卡成功{status = MI_ERR;// 驗證A密鑰 塊地址 密碼 SN // 注意:此處的塊地址0x0B即2扇區3區塊,可以替換成變量addr ,此塊地址只需要指向某一扇區就可以了,即2扇區為0x08-0x0B這個范圍都有效,且只能對驗證過的扇區進行讀寫操作status = PcdAuthState(0x60, 0x0B, KEY_A, SN);if(status == MI_OK)//驗證成功{printf("PcdAuthState(A) success\r\n");}else{printf("PcdAuthState(A) failed\r\n");}// 驗證B密鑰 塊地址 密碼 SN 塊地址0x0B即2扇區3區塊,可以替換成變量addrstatus = PcdAuthState(0x61, 0x0B, KEY_B, SN);if(status == MI_OK)//驗證成功{printf("PcdAuthState(B) success\r\n");}else{printf("PcdAuthState(B) failed\r\n");}}if(status == MI_OK)//驗證成功{status = MI_ERR;// 讀取M1卡一塊數據 塊地址 讀取的數據 注意:因為上面驗證的扇區是2扇區,所以只能對2扇區的數據進行讀寫,即0x08-0x0B這個范圍,超出范圍讀取失敗。status = PcdRead(addr, DATA);if(status == MI_OK)//讀卡成功{// printf("RFID:%s\r\n", RFID);printf("DATA:");for(i = 0; i < 16; i++){printf("%02x", DATA[i]);}printf("\r\n");}else{printf("PcdRead() failed\r\n");}}if(status == MI_OK)//讀卡成功{status = MI_ERR;printf("Write the card after 1 second. Do not move the card!!!\r\n");delay_ms(1000);// status = PcdWrite(addr, DATA0);// 寫數據到M1卡一塊status = PcdWrite(addr, DATA1);if(status == MI_OK)//寫卡成功{printf("PcdWrite() success\r\n");}else{printf("PcdWrite() failed\r\n");delay_ms(3000);}}if(status == MI_OK)//寫卡成功{status = MI_ERR;// 讀取M1卡一塊數據 塊地址 讀取的數據status = PcdRead(addr, DATA);if(status == MI_OK)//讀卡成功{// printf("DATA:%s\r\n", DATA);printf("DATA:");for(i = 0; i < 16; i++){printf("%02x", DATA[i]);}printf("\r\n");}else{printf("PcdRead() failed\r\n");}}if(status == MI_OK)//讀卡成功{status = MI_ERR;printf("RC522_Handle() run finished after 1 second!\r\n");delay_ms(1000);} }// 測試程序1,完成0x0F塊 驗證KEY_A、KEY_B 讀 寫RFID1 驗證KEY_A1、KEY_B1 讀 寫RFID2 void RC522_Handle1(void) {u8 i = 0;unsigned char test_addr=0x0F;status = PcdRequest(PICC_REQALL,CT);//尋卡// printf("\r\nstatus>>>>>>%d\r\n", status);if(status==MI_OK)// 尋卡成功{status=MI_ERR;status = PcdAnticoll(SN);// 防沖撞 獲得UID 存入SN}if (status==MI_OK)// 防沖撞成功{status = MI_ERR;ShowID(SN); // 串口打印卡的ID號 UID// 難道就是為了做個判斷嗎。。。if((SN[0]==card_0[0])&&(SN[1]==card_0[1])&&(SN[2]==card_0[2])&&(SN[3]==card_0[3])){card0_bit=1;printf("\r\nThe User is:card_0\r\n");}if((SN[0]==card_1[0])&&(SN[1]==card_1[1])&&(SN[2]==card_1[2])&&(SN[3]==card_1[3])){card1_bit=1;printf("\r\nThe User is:card_1\r\n");}status = PcdSelect(SN);}else{}if(status == MI_OK)//選卡成功{status = MI_ERR;// 驗證A密鑰 塊地址 密碼 SN // 注意:此處的塊地址0x0F即3扇區3區塊,此塊地址只需要指向某一扇區就可以了,即3扇區為0x0C-0x0F這個范圍都有效,且只能對驗證過的扇區進行讀寫操作status = PcdAuthState(0x60, test_addr, KEY_A, SN);if(status == MI_OK)//驗證成功{printf("PcdAuthState(A) success\r\n");}else{printf("PcdAuthState(A) failed\r\n");status = MI_OK;goto P1;}// 驗證B密鑰 塊地址 密碼 SN status = PcdAuthState(0x61, test_addr, KEY_B, SN);if(status == MI_OK)//驗證成功{printf("PcdAuthState(B) success\r\n");}else{printf("PcdAuthState(B) failed\r\n");}}if(status == MI_OK)//驗證成功{status = MI_ERR;// 讀取M1卡一塊數據 塊地址 讀取的數據 注意:因為上面驗證的扇區是3扇區,所以只能對2扇區的數據進行讀寫,即0x0C-0x0F這個范圍,超出范圍讀取失敗。status = PcdRead(test_addr, DATA);if(status == MI_OK)//讀卡成功{// printf("RFID:%s\r\n", RFID);printf("DATA:");for(i = 0; i < 16; i++){printf("%02x", DATA[i]);}printf("\r\n");}else{printf("PcdRead() failed\r\n");}}if(status == MI_OK)//讀卡成功{status = MI_ERR;// 寫數據到M1卡一塊status = PcdWrite(test_addr, RFID1);if(status == MI_OK)//寫卡成功{printf("PcdWrite(RFID1) success\r\n");}else{printf("PcdWrite(RFID1) failed\r\n");delay_ms(3000);}}P1: if(status == MI_OK)//寫卡成功{status = MI_ERR;// 驗證A密鑰 塊地址 密碼 SN // 注意:此處的塊地址0x0F即3扇區3區塊,此塊地址只需要指向某一扇區就可以了,即3扇區為0x0C-0x0F這個范圍都有效,且只能對驗證過的扇區進行讀寫操作status = PcdAuthState(0x60, test_addr, KEY_A1, SN);if(status == MI_OK)//驗證成功{printf("PcdAuthState(A1) success\r\n");}else{printf("PcdAuthState(A1) failed\r\n");}// 驗證B密鑰 塊地址 密碼 SN status = PcdAuthState(0x61, test_addr, KEY_B1, SN);if(status == MI_OK)//驗證成功{printf("PcdAuthState(B1) success\r\n");}else{printf("PcdAuthState(B1) failed\r\n");}}if(status == MI_OK)//驗證成功{status = MI_ERR;// 讀取M1卡一塊數據 塊地址 讀取的數據 注意:因為上面驗證的扇區是3扇區,所以只能對2扇區的數據進行讀寫,即0x0C-0x0F這個范圍,超出范圍讀取失敗。status = PcdRead(test_addr, DATA);if(status == MI_OK)//讀卡成功{// printf("RFID:%s\r\n", RFID);printf("DATA:");for(i = 0; i < 16; i++){printf("%02x", DATA[i]);}printf("\r\n");}else{printf("PcdRead() failed\r\n");}}if(status == MI_OK)//讀卡成功{status = MI_ERR;// 寫數據到M1卡一塊status = PcdWrite(test_addr, RFID2);if(status == MI_OK)//寫卡成功{printf("PcdWrite(RFID2) success\r\n");}else{printf("PcdWrite(RFID2) failed\r\n");delay_ms(3000);}}if(status == MI_OK)//寫卡成功{status = MI_ERR;// 讀取M1卡一塊數據 塊地址 讀取的數據status = PcdRead(test_addr, DATA);if(status == MI_OK)//讀卡成功{// printf("DATA:%s\r\n", DATA);printf("DATA:");for(i = 0; i < 16; i++){printf("%02x", DATA[i]);}printf("\r\n");}else{printf("PcdRead() failed\r\n");}}if(status == MI_OK)//讀卡成功{status = MI_ERR;printf("RC522_Handle1() run finished after 1 second!\r\n");delay_ms(1000);} }// 測試用數據爆破程序,僅供學習參考,請勿非法使用 針對card_0進行破解 void RC522_data_break(void) {// 爆破的塊地址unsigned char break_addr = 0x0F;u8 i = 0;/*u8 key_arr[257] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF };*/u8 break_KEY[6]= {0, 0, 0, 0, 0, 0};status = PcdRequest(PICC_REQALL,CT);//尋卡// printf("\r\nstatus>>>>>>%d\r\n", status);if(status==MI_OK)// 尋卡成功{status=MI_ERR;status = PcdAnticoll(SN);// 防沖撞 獲得UID 存入SN}if (status==MI_OK)// 防沖撞成功{status = MI_ERR;ShowID(SN); // 串口打印卡的ID號 UID// 難道就是為了做個判斷嗎。。。if((SN[0]==card_0[0])&&(SN[1]==card_0[1])&&(SN[2]==card_0[2])&&(SN[3]==card_0[3])){card0_bit=1;printf("\r\nThe User is:card_0\r\n");}else{printf("\r\nThe User isn't:card_0\r\n");return;}status = PcdSelect(SN);}else{}if(status == MI_OK)//選卡成功{status = MI_ERR;// 自由發揮 。。。// 驗證A密鑰 塊地址 密碼 SN // 注意:此處的塊地址0x0F即3扇區3區塊,此塊地址只需要指向某一扇區就可以了,即3扇區為0x0C-0x0F這個范圍都有效,且只能對驗證過的扇區進行讀寫操作status = PcdAuthState(0x60, break_addr, break_KEY, SN);if(status == MI_OK)//驗證成功{printf("PcdAuthState(A) success\r\n");}else{printf("PcdAuthState(A) failed\r\n");status = MI_OK;}// 驗證B密鑰 塊地址 密碼 SN status = PcdAuthState(0x61, break_addr, break_KEY, SN);if(status == MI_OK)//驗證成功{printf("PcdAuthState(B) success\r\n");}else{printf("PcdAuthState(B) failed\r\n");}}if(status == MI_OK)//驗證成功{status = MI_ERR;// 讀取M1卡一塊數據 塊地址 讀取的數據 注意:因為上面驗證的扇區是3扇區,所以只能對2扇區的數據進行讀寫,即0x0C-0x0F這個范圍,超出范圍讀取失敗。status = PcdRead(break_addr, DATA);if(status == MI_OK)//讀卡成功{// printf("RFID:%s\r\n", RFID);printf("DATA:");for(i = 0; i < 16; i++){printf("%02x", DATA[i]);}printf("\r\n");}else{printf("PcdRead() failed\r\n");}}delay_ms(3000); }void RC522_Init ( void ) {SPI1_Init();RC522_Reset_Disable();RC522_CS_Disable();PcdReset ();M500PcdConfigISOType ( 'A' );//設置工作方式}void SPI1_Init(void) {GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef SPI_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE );//PORTA、B時鐘使能RCC_APB1PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE ); //SPI1時鐘使能// CSGPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度為50MHzGPIO_Init(GPIOA, &GPIO_InitStructure); //根據設定參數初始化PF0、PF1// SCKGPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度為50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);// MISOGPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //推挽輸出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度為50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);// MOSIGPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度為50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);// RSTGPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度為50MHzGPIO_Init(GPIOB, &GPIO_InitStructure);SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //設置SPI單向或者雙向的數據模式:SPI設置為雙線雙向全雙工SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //設置SPI工作模式:設置為主SPISPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //設置SPI的數據大小:SPI發送接收8位幀結構SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步時鐘的空閑狀態為高電平// SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;// SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //串行同步時鐘的第一個跳變沿(下降)數據被采樣SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步時鐘的第二個跳變沿(上升)數據被采樣SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信號由硬件(NSS管腳)還是軟件(使用SSI位)管理:內部NSS信號有SSI位控制// RC522 SPI通訊時鐘周期最小為100ns 即頻率最大為10MHZ// RC522 數據在下降沿變化SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //定義波特率預分頻的值:波特率預分頻值為256、傳輸速率36M/256=140.625KHzSPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定數據傳輸從MSB位還是LSB位開始:數據傳輸從MSB位開始SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值計算的多項式SPI_Init(SPI1, &SPI_InitStructure); //根據SPI_InitStruct中指定的參數初始化外設SPIx寄存器SPI_Cmd(SPI1, ENABLE); //使能SPI外設 }/** 函數名:SPI_RC522_SendByte* 描述 :向RC522發送1 Byte 數據* 輸入 :byte,要發送的數據* 返回 : RC522返回的數據* 調用 :內部調用*/ void SPI_RC522_SendByte ( u8 byte ) {u8 counter;for(counter=0; counter<8; counter++){if ( byte & 0x80 )RC522_MOSI_1 ();elseRC522_MOSI_0 ();RC522_DELAY();RC522_SCK_0 ();RC522_DELAY();RC522_SCK_1();RC522_DELAY();byte <<= 1;} }/** 函數名:SPI_RC522_ReadByte* 描述 :從RC522發送1 Byte 數據* 輸入 :無* 返回 : RC522返回的數據* 調用 :內部調用*/ u8 SPI_RC522_ReadByte ( void ) {u8 counter;u8 SPI_Data;for(counter=0; counter<8; counter++){SPI_Data <<= 1;RC522_SCK_0 ();RC522_DELAY();if ( RC522_MISO_GET() == 1)SPI_Data |= 0x01;RC522_DELAY();RC522_SCK_1 ();RC522_DELAY();}// printf("****%c****",SPI_Data);return SPI_Data; }/** 函數名:ReadRawRC* 描述 :讀RC522寄存器* 輸入 :ucAddress,寄存器地址* 返回 : 寄存器的當前值* 調用 :內部調用*/ u8 ReadRawRC ( u8 ucAddress ) {u8 ucAddr, ucReturn;ucAddr = ( ( ucAddress << 1 ) & 0x7E ) | 0x80;RC522_CS_Enable();SPI_RC522_SendByte ( ucAddr );ucReturn = SPI_RC522_ReadByte ();RC522_CS_Disable();return ucReturn; }/** 函數名:WriteRawRC* 描述 :寫RC522寄存器* 輸入 :ucAddress,寄存器地址* ucValue,寫入寄存器的值* 返回 : 無* 調用 :內部調用*/ void WriteRawRC ( u8 ucAddress, u8 ucValue ) {u8 ucAddr;ucAddr = ( ucAddress << 1 ) & 0x7E;RC522_CS_Enable();SPI_RC522_SendByte ( ucAddr );SPI_RC522_SendByte ( ucValue );RC522_CS_Disable(); }/** 函數名:SetBitMask* 描述 :對RC522寄存器置位* 輸入 :ucReg,寄存器地址* ucMask,置位值* 返回 : 無* 調用 :內部調用*/ void SetBitMask ( u8 ucReg, u8 ucMask ) {u8 ucTemp;ucTemp = ReadRawRC ( ucReg );WriteRawRC ( ucReg, ucTemp | ucMask ); // set bit mask }/** 函數名:ClearBitMask* 描述 :對RC522寄存器清位* 輸入 :ucReg,寄存器地址* ucMask,清位值* 返回 : 無* 調用 :內部調用*/ void ClearBitMask ( u8 ucReg, u8 ucMask ) {u8 ucTemp;ucTemp = ReadRawRC ( ucReg );WriteRawRC ( ucReg, ucTemp & ( ~ ucMask) ); // clear bit mask }/** 函數名:PcdAntennaOn* 描述 :開啟天線* 輸入 :無* 返回 : 無* 調用 :內部調用*/ void PcdAntennaOn ( void ) {u8 uc;uc = ReadRawRC ( TxControlReg );if ( ! ( uc & 0x03 ) )SetBitMask(TxControlReg, 0x03); }/** 函數名:PcdAntennaOff* 描述 :開啟天線* 輸入 :無* 返回 : 無* 調用 :內部調用*/ void PcdAntennaOff ( void ) {ClearBitMask ( TxControlReg, 0x03 ); }/** 函數名:PcdRese* 描述 :復位RC522* 輸入 :無* 返回 : 無* 調用 :外部調用*/ void PcdReset ( void ) {RC522_Reset_Disable();delay_us ( 1 );RC522_Reset_Enable();delay_us ( 1 );RC522_Reset_Disable();delay_us ( 1 );WriteRawRC ( CommandReg, 0x0f );while ( ReadRawRC ( CommandReg ) & 0x10 );delay_us ( 1 );WriteRawRC ( ModeReg, 0x3D ); //定義發送和接收常用模式 和Mifare卡通訊,CRC初始值0x6363WriteRawRC ( TReloadRegL, 30 ); //16位定時器低位WriteRawRC ( TReloadRegH, 0 ); //16位定時器高位WriteRawRC ( TModeReg, 0x8D ); //定義內部定時器的設置WriteRawRC ( TPrescalerReg, 0x3E ); //設置定時器分頻系數WriteRawRC ( TxAutoReg, 0x40 ); //調制發送信號為100%ASK }/** 函數名:M500PcdConfigISOType* 描述 :設置RC522的工作方式* 輸入 :ucType,工作方式* 返回 : 無* 調用 :外部調用*/ void M500PcdConfigISOType ( u8 ucType ) {if ( ucType == 'A') //ISO14443_A{ClearBitMask ( Status2Reg, 0x08 );WriteRawRC ( ModeReg, 0x3D );//3FWriteRawRC ( RxSelReg, 0x86 );//84WriteRawRC( RFCfgReg, 0x7F ); //4FWriteRawRC( TReloadRegL, 30 );//tmoLength);// TReloadVal = 'h6a =tmoLength(dec)WriteRawRC ( TReloadRegH, 0 );WriteRawRC ( TModeReg, 0x8D );WriteRawRC ( TPrescalerReg, 0x3E );delay_us ( 2 );PcdAntennaOn ();//開天線} }/** 函數名:PcdComMF522* 描述 :通過RC522和ISO14443卡通訊* 輸入 :ucCommand,RC522命令字* pInData,通過RC522發送到卡片的數據* ucInLenByte,發送數據的字節長度* pOutData,接收到的卡片返回數據* pOutLenBit,返回數據的位長度* 返回 : 狀態值* = MI_OK,成功* 調用 :內部調用*/ char PcdComMF522 ( u8 ucCommand, u8 * pInData, u8 ucInLenByte, u8 * pOutData, u32 * pOutLenBit ) {char cStatus = MI_ERR;u8 ucIrqEn = 0x00;u8 ucWaitFor = 0x00;u8 ucLastBits;u8 ucN;u32 ul;switch ( ucCommand ){case PCD_AUTHENT: //Mifare認證ucIrqEn = 0x12; //允許錯誤中斷請求ErrIEn 允許空閑中斷IdleIEnucWaitFor = 0x10; //認證尋卡等待時候 查詢空閑中斷標志位break;case PCD_TRANSCEIVE: //接收發送 發送接收ucIrqEn = 0x77; //允許TxIEn RxIEn IdleIEn LoAlertIEn ErrIEn TimerIEnucWaitFor = 0x30; //尋卡等待時候 查詢接收中斷標志位與 空閑中斷標志位break;default:break;}WriteRawRC ( ComIEnReg, ucIrqEn | 0x80 ); //IRqInv置位管腳IRQ與Status1Reg的IRq位的值相反ClearBitMask ( ComIrqReg, 0x80 ); //Set1該位清零時,CommIRqReg的屏蔽位清零WriteRawRC ( CommandReg, PCD_IDLE ); //寫空閑命令SetBitMask ( FIFOLevelReg, 0x80 ); //置位FlushBuffer清除內部FIFO的讀和寫指針以及ErrReg的BufferOvfl標志位被清除for ( ul = 0; ul < ucInLenByte; ul ++ )WriteRawRC ( FIFODataReg, pInData [ ul ] ); //寫數據進FIFOdataWriteRawRC ( CommandReg, ucCommand ); //寫命令if ( ucCommand == PCD_TRANSCEIVE )SetBitMask(BitFramingReg,0x80); //StartSend置位啟動數據發送 該位與收發命令使用時才有效ul = 1000;//根據時鐘頻率調整,操作M1卡最大等待時間25msdo //認證 與尋卡等待時間{ucN = ReadRawRC ( ComIrqReg ); //查詢事件中斷ul --;} while ( ( ul != 0 ) && ( ! ( ucN & 0x01 ) ) && ( ! ( ucN & ucWaitFor ) ) ); //退出條件i=0,定時器中斷,與寫空閑命令ClearBitMask ( BitFramingReg, 0x80 ); //清理允許StartSend位if ( ul != 0 ){if ( ! (( ReadRawRC ( ErrorReg ) & 0x1B )) ) //讀錯誤標志寄存器BufferOfI CollErr ParityErr ProtocolErr{cStatus = MI_OK;if ( ucN & ucIrqEn & 0x01 ) //是否發生定時器中斷cStatus = MI_NOTAGERR;if ( ucCommand == PCD_TRANSCEIVE ){ucN = ReadRawRC ( FIFOLevelReg ); //讀FIFO中保存的字節數ucLastBits = ReadRawRC ( ControlReg ) & 0x07; //最后接收到得字節的有效位數if ( ucLastBits )* pOutLenBit = ( ucN - 1 ) * 8 + ucLastBits; //N個字節數減去1(最后一個字節)+最后一位的位數 讀取到的數據總位數else* pOutLenBit = ucN * 8; //最后接收到的字節整個字節有效if ( ucN == 0 )ucN = 1;if ( ucN > MAXRLEN )ucN = MAXRLEN;for ( ul = 0; ul < ucN; ul ++ )pOutData [ ul ] = ReadRawRC ( FIFODataReg );}}elsecStatus = MI_ERR; // printf(ErrorReg);}SetBitMask ( ControlReg, 0x80 ); // stop timer nowWriteRawRC ( CommandReg, PCD_IDLE );return cStatus; }/** 函數名:PcdRequest* 描述 :尋卡* 輸入 :ucReq_code,尋卡方式* = 0x52,尋感應區內所有符合14443A標準的卡* = 0x26,尋未進入休眠狀態的卡* pTagType,卡片類型代碼* = 0x4400,Mifare_UltraLight* = 0x0400,Mifare_One(S50)* = 0x0200,Mifare_One(S70)* = 0x0800,Mifare_Pro(X))* = 0x4403,Mifare_DESFire* 返回 : 狀態值* = MI_OK,成功* 調用 :外部調用*/ char PcdRequest ( u8 ucReq_code, u8 * pTagType ) {char cStatus;u8 ucComMF522Buf [ MAXRLEN ];u32 ulLen;ClearBitMask ( Status2Reg, 0x08 ); //清理指示MIFARECyptol單元接通以及所有卡的數據通信被加密的情況WriteRawRC ( BitFramingReg, 0x07 ); // 發送的最后一個字節的 七位SetBitMask ( TxControlReg, 0x03 ); //TX1,TX2管腳的輸出信號傳遞經發送調制的13.56的能量載波信號ucComMF522Buf [ 0 ] = ucReq_code; //存入 卡片命令字cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 1, ucComMF522Buf, & ulLen ); //尋卡if ( ( cStatus == MI_OK ) && ( ulLen == 0x10 ) ) //尋卡成功返回卡類型{* pTagType = ucComMF522Buf [ 0 ];* ( pTagType + 1 ) = ucComMF522Buf [ 1 ];}elsecStatus = MI_ERR;return cStatus; }/** 函數名:PcdAnticoll* 描述 :防沖撞* 輸入 :pSnr,卡片序列號,4字節* 返回 : 狀態值* = MI_OK,成功* 調用 :外部調用*/ char PcdAnticoll ( u8 * pSnr ) {char cStatus;u8 uc, ucSnr_check = 0;u8 ucComMF522Buf [ MAXRLEN ];u32 ulLen;ClearBitMask ( Status2Reg, 0x08 ); //清MFCryptol On位 只有成功執行MFAuthent命令后,該位才能置位WriteRawRC ( BitFramingReg, 0x00); //清理寄存器 停止收發ClearBitMask ( CollReg, 0x80 ); //清ValuesAfterColl所有接收的位在沖突后被清除/*參考ISO14443協議:https://blog.csdn.net/wowocpp/article/details/79910800PCD 發送 SEL = ‘93’,NVB = ‘20’兩個字節迫使所有的在場的PICC發回完整的UID CLn作為應答。*/ucComMF522Buf [ 0 ] = 0x93; //卡片防沖突命令ucComMF522Buf [ 1 ] = 0x20;// 發送并接收數據 接收的數據存儲于ucComMF522BufcStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 2, ucComMF522Buf, & ulLen);//與卡片通信if ( cStatus == MI_OK) //通信成功{// 收到的UID 存入pSnrfor ( uc = 0; uc < 4; uc ++ ){* ( pSnr + uc ) = ucComMF522Buf [ uc ]; //讀出UIDucSnr_check ^= ucComMF522Buf [ uc ];}if ( ucSnr_check != ucComMF522Buf [ uc ] )cStatus = MI_ERR;}SetBitMask ( CollReg, 0x80 );return cStatus; }/** 函數名:CalulateCRC* 描述 :用RC522計算CRC16* 輸入 :pIndata,計算CRC16的數組* ucLen,計算CRC16的數組字節長度* pOutData,存放計算結果存放的首地址* 返回 : 無* 調用 :內部調用*/ void CalulateCRC ( u8 * pIndata, u8 ucLen, u8 * pOutData ) {u8 uc, ucN;ClearBitMask(DivIrqReg, 0x04);WriteRawRC(CommandReg, PCD_IDLE);SetBitMask(FIFOLevelReg, 0x80);for ( uc = 0; uc < ucLen; uc ++)WriteRawRC ( FIFODataReg, * ( pIndata + uc ) );WriteRawRC ( CommandReg, PCD_CALCCRC );uc = 0xFF;do{ucN = ReadRawRC ( DivIrqReg );uc --;} while ( ( uc != 0 ) && ! ( ucN & 0x04 ) );pOutData [ 0 ] = ReadRawRC ( CRCResultRegL );pOutData [ 1 ] = ReadRawRC ( CRCResultRegM ); }/** 函數名:PcdSelect* 描述 :選定卡片* 輸入 :pSnr,卡片序列號,4字節* 返回 : 狀態值* = MI_OK,成功* 調用 :外部調用*/ char PcdSelect ( u8 * pSnr ) {char cStatus;u8 uc;u8 ucComMF522Buf [ MAXRLEN ];u32 ulLen;// 防沖撞 0x93ucComMF522Buf [ 0 ] = PICC_ANTICOLL1;// 假設沒有沖突,PCD 指定NVB為70,此值表示PCD將發送完整的UID CLn,與40位UID CLn 匹配的PICC,以SAK作為應答ucComMF522Buf [ 1 ] = 0x70;ucComMF522Buf [ 6 ] = 0;// 3 4 5 6位存放UID,第7位一直異或。。。for ( uc = 0; uc < 4; uc ++ ){ucComMF522Buf [ uc + 2 ] = * ( pSnr + uc );ucComMF522Buf [ 6 ] ^= * ( pSnr + uc );}// CRC(循環冗余校驗)CalulateCRC ( ucComMF522Buf, 7, & ucComMF522Buf [ 7 ] );ClearBitMask ( Status2Reg, 0x08 );// 發送并接收數據cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 9, ucComMF522Buf, & ulLen );if ( ( cStatus == MI_OK ) && ( ulLen == 0x18 ) )cStatus = MI_OK;elsecStatus = MI_ERR;return cStatus; }/** 函數名:PcdAuthState* 描述 :驗證卡片密碼* 輸入 :ucAuth_mode,密碼驗證模式* = 0x60,驗證A密鑰* = 0x61,驗證B密鑰* u8 ucAddr,塊地址* pKey,密碼* pSnr,卡片序列號,4字節* 返回 : 狀態值* = MI_OK,成功* 調用 :外部調用*/ char PcdAuthState ( u8 ucAuth_mode, u8 ucAddr, u8 * pKey, u8 * pSnr ) {char cStatus;u8 uc, ucComMF522Buf [ MAXRLEN ];u32 ulLen;ucComMF522Buf [ 0 ] = ucAuth_mode;ucComMF522Buf [ 1 ] = ucAddr;for ( uc = 0; uc < 6; uc ++ )ucComMF522Buf [ uc + 2 ] = * ( pKey + uc );for ( uc = 0; uc < 6; uc ++ )ucComMF522Buf [ uc + 8 ] = * ( pSnr + uc );// printf("char PcdAuthState ( u8 ucAuth_mode, u8 ucAddr, u8 * pKey, u8 * pSnr )\r\n");// printf("before PcdComMF522() ucComMF522Buf:%s\r\n", ucComMF522Buf);// 驗證密鑰命令cStatus = PcdComMF522 ( PCD_AUTHENT, ucComMF522Buf, 12, ucComMF522Buf, & ulLen );// printf("after PcdComMF522() ucComMF522Buf:%s\r\n", ucComMF522Buf);if ( ( cStatus != MI_OK ) || ( ! ( ReadRawRC ( Status2Reg ) & 0x08 ) ) ){ // if(cStatus != MI_OK) // printf("666") ; // else // printf("888");cStatus = MI_ERR;}return cStatus; }/** 函數名:PcdWrite* 描述 :寫數據到M1卡一塊* 輸入 :u8 ucAddr,塊地址* pData,寫入的數據,16字節* 返回 : 狀態值* = MI_OK,成功* 調用 :外部調用*/ char PcdWrite ( u8 ucAddr, u8 * pData ) {char cStatus;u8 uc, ucComMF522Buf [ MAXRLEN ];u32 ulLen;ucComMF522Buf [ 0 ] = PICC_WRITE;ucComMF522Buf [ 1 ] = ucAddr;CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );if ( ( cStatus != MI_OK ) || ( ulLen != 4 ) || ( ( ucComMF522Buf [ 0 ] & 0x0F ) != 0x0A ) )cStatus = MI_ERR;if ( cStatus == MI_OK ){memcpy(ucComMF522Buf, pData, 16);for ( uc = 0; uc < 16; uc ++ )ucComMF522Buf [ uc ] = * ( pData + uc );CalulateCRC ( ucComMF522Buf, 16, & ucComMF522Buf [ 16 ] );cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 18, ucComMF522Buf, & ulLen );if ( ( cStatus != MI_OK ) || ( ulLen != 4 ) || ( ( ucComMF522Buf [ 0 ] & 0x0F ) != 0x0A ) )cStatus = MI_ERR;}return cStatus; }/** 函數名:PcdRead* 描述 :讀取M1卡一塊數據* 輸入 :u8 ucAddr,塊地址* pData,讀出的數據,16字節* 返回 : 狀態值* = MI_OK,成功* 調用 :外部調用*/ char PcdRead ( u8 ucAddr, u8 * pData ) {char cStatus;u8 uc, ucComMF522Buf [ MAXRLEN ];u32 ulLen;ucComMF522Buf [ 0 ] = PICC_READ;ucComMF522Buf [ 1 ] = ucAddr;CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );if ( ( cStatus == MI_OK ) && ( ulLen == 0x90 ) ){for ( uc = 0; uc < 16; uc ++ )* ( pData + uc ) = ucComMF522Buf [ uc ];}elsecStatus = MI_ERR;return cStatus; }/** 函數名:PcdHalt* 描述 :命令卡片進入休眠狀態* 輸入 :無* 返回 : 狀態值* = MI_OK,成功* 調用 :外部調用*/ char PcdHalt( void ) {u8 ucComMF522Buf [ MAXRLEN ];u32 ulLen;ucComMF522Buf [ 0 ] = PICC_HALT;ucComMF522Buf [ 1 ] = 0;CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );return MI_OK; }void IC_CMT ( u8 * UID, u8 * KEY, u8 RW, u8 * Dat ) {u8 ucArray_ID [ 4 ] = { 0 };//先后存放IC卡的類型和UID(IC卡序列號)PcdRequest ( 0x52, ucArray_ID );//尋卡PcdAnticoll ( ucArray_ID );//防沖撞PcdSelect ( UID );//選定卡PcdAuthState ( 0x60, 0x10, KEY, UID );//校驗if ( RW )//讀寫選擇,1是讀,0是寫PcdRead ( 0x10, Dat );elsePcdWrite ( 0x10, Dat );PcdHalt (); }// 顯示卡的卡號,以十六進制顯示 void ShowID(u8 *p) {u8 num[9];u8 i;for(i=0; i<4; i++){num[i*2] = p[i] / 16;num[i*2] > 9 ? (num[i*2] += '7') : (num[i*2] += '0');num[i*2+1] = p[i] % 16;num[i*2+1] > 9 ? (num[i*2+1] += '7') : (num[i*2+1] += '0');}num[8] = 0;printf("ID>>>%s\r\n", num); }額外資料
總結
以上是生活随笔為你收集整理的STM32F103+RFID-RC522模块 实现简单读卡写卡demo的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Google Weather API 参
- 下一篇: python不好找工作怎么办信用卡_利用