版權聲明:轉載請注明出處,謝謝 https://blog.csdn.net/Kevin_8_Lee/article/details/88865556
這兩個平台都是我的個人博客
基於STM32的MFRC522射頻卡模塊使用
本學期感測技術選修課需要做一個作品出來,用到了MFRC522射頻卡模塊,經歷一個星期的調試,終於可以正常使用並尋卡成功了了。 成功的把C51的程序移植到了STM32上面。 現在分享一下調試過程
1、操作環境
我所使用的是STM32F407的開發板,使用STM32CubeMX配置初始代碼。 MFRC522使用軟件模擬SPI通信
2、 關於引腳的配置
淘寶買來的模塊,店家都會送資料 ,也可以點下面連接保存至網盤
鏈接 : https://pan.baidu.com/s/1JlNNIjtvHuRbVMSRZocHLA
提取碼:z119
1、SPI通信引腳
1 NSS(SDA) --------->> 片選信號 2 SCK --------->> 時鍾信號 3 MOSI --------->> 信號輸出端(即單片機引腳設置為輸入,MFRC522該引腳輸出) 4 MISO --------->> 信號輸入端
(上圖截圖於數據手冊,移植別人的程序最好看一下所使用的芯片的數據手冊,很有用,方便自己理解程序。另外,如果數據手冊都不會看的話,基本可以不用談什么開發了)
這里說明一下,在 MFRC522數據手冊里面說了, MFRC522需要工作在從機模式下。 所以MFRC522這個模塊就是從機(Slave),而所使用的單片機就是主機(Master)
這就是為什么上面的MOSI對應的單片機引腳要設置為輸出,(Master Output Slave Input)
MISO信號輸入端是指的輸入給單片機了
2、 通信時序
這是數據手冊里面的,一定要注意時序的正確性
片選信號在數據寫入期間一定要保持低電平,而無數據時(即空閑狀態)必須保持高電平
再次強調:時序很重要
時序出錯,一切都白扯
3、 程序流程
下面我把我用STM32CubeMX的配置貼出來
一定要注意按照這樣配置,因為數據手冊里面的時序要求是NSS(SDA)引腳默認狀態必須是高電平,即1,所以IO口設置必須為High, 且上拉,其他引腳同理,只是不需要上拉了
3、 下面先貼一下尋卡結果
S50的卡是0x04000, 所以打印的就是40了
主函數里面程序如下:
1 int main(void) 2 { 3 /* USER CODE BEGIN 1 */
4 unsigned char status,i; 5 unsigned int temp; 6
7 /* USER CODE END 1 */
8
9 /* MCU Configuration--------------------------------------------------------*/
10
11 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
12 HAL_Init(); 13
14 /* USER CODE BEGIN Init */
15
16 /* USER CODE END Init */
17
18 /* Configure the system clock */
19 SystemClock_Config(); 20
21 /* USER CODE BEGIN SysInit */
22
23 /* USER CODE END SysInit */
24
25 /* Initialize all configured peripherals */
26 MX_GPIO_Init(); 27 MX_USART1_UART_Init(); 28 /* USER CODE BEGIN 2 */
29
30 printf("The USART Is Ok!!!\r\n"); 31
32 // 下面進行的是初始化
33 PcdReset(); 34 PcdAntennaOff(); //關閉天線
35 PcdAntennaOn(); //開啟天線
36 M500PcdConfigISOType('A'); // 選擇工作方式
37
38 printf("開始尋卡... ...\r\n"); 39 /* USER CODE END 2 */
40
41 /* Infinite loop */
42 /* USER CODE BEGIN WHILE */
43 while (1) 44 { 45 /* USER CODE END WHILE */
46
47 /* USER CODE BEGIN 3 */
48
49 status = PcdRequest(PICC_REQALL, g_ucTempbuf);//尋卡
50 if (status == MI_ERR) // 如果尋卡失敗,則重新初始化 然后continue 繼續尋卡
51 { 52 PcdReset(); 53 PcdAntennaOff(); //關閉天線
54 PcdAntennaOn(); //開啟天線
55 M500PcdConfigISOType('A'); 56 continue; 57 } 58
59 // 如果尋卡成功 則LED1閃爍 然后串口打印出來卡的類型
60 HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET); 61 HAL_Delay(10); 62 HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET); 63 HAL_Delay(10); 64 HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET); 65 HAL_Delay(10); 66 HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET); 67 HAL_Delay(10); 68 printf("\r\n卡的類型:"); 69 for (i = 0; i < 2; i++) 70 { 71 temp = g_ucTempbuf[i]; 72 printf("%X", temp); 73 } 74 //PcdHalt();
75 } 76 /* USER CODE END 3 */
77 }
下面是我移植的底層驅動程序, 應該也是大部分人想要的吧,不過最好還是自己好好看看那手冊改一下
我只貼出有關SPI通訊的程序,其他部分跟我上面給出的網盤資料里面的C51例程是差不多的,通用
1 /******************************************************************* 2 @func : ReadRawRC 3 @brief : 讀RC632寄存器 4 @pram : Address[IN]:寄存器地址 5 @retval : 讀出的值 6 @NOTE : MFRC522數據手冊.pdf 10.2是關於SPI的詳細說明 10.2.2 Read data 7 : unsigned char === uint8_t 8 @Call : 內部調用 9 *******************************************************************/
10 unsigned char ReadRawRC(unsigned char Address) 11 { 12 unsigned char i, ucAddr; 13 unsigned char ucResult=0; 14
15 HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_RESET);// MF522_NSS = 0;
16 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);// MF522_SCK = 0; 17
18
19 // 地址左移一位是因為LSB是要保留 即RFU位(Reserved for Future Use) 20 // &0x7E 是把bit1~bit6 的地址(address)寫入 21 // |0x80 是為了使最高位為1 1(Read) 0(Write) 即使能 '讀'
22 ucAddr = ((Address<<1)&0x7E)|0x80; 23
24 for(i=8;i>0;i--) 25 { 26 if((ucAddr&0x80)==0x80) 27 { 28 HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_SET); 29 } 30 else
31 { 32 HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_RESET); 33 } 34 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET); 35 ucAddr <<= 1; 36 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET); 37
38 } 39
40 for(i=8;i>0;i--) 41 { 42 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET); 43 ucResult <<= 1; 44 ucResult |= HAL_GPIO_ReadPin(MISO_GPIO_Port, MISO_Pin); 45 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET); 46 // 有人說對於STM32這里需要加一句延時,這個是沒必要的 這個我經過測試是可以使用的,不用延時
47 } 48
49
50 HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_SET);// MF522_NSS = 1;
51 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);// MF522_SCK = 1;
52
53
54 return ucResult; 55 } 56
57
58
59 /******************************************************************* 60 @func : WriteRawRC 61 @brief : 寫RC632寄存器 62 @pram : Address[IN]:寄存器地址 63 : value[IN]:寫入的值 64 @retval : None 65 @Call : 內部調用 66 *******************************************************************/
67 void WriteRawRC(unsigned char Address, unsigned char value) 68 { 69 unsigned char i, ucAddr; 70
71 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);// MF522_SCK = 0;
72 HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_RESET);// MF522_NSS = 0;
73
74 ucAddr = ((Address << 1) & 0x7E); 75
76 for(i=8;i>0;i--) 77 { 78 if ((ucAddr&0x80)==0x80) 79 { 80 HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_SET); 81 } 82 else
83 { 84 HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_RESET); 85 } 86 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET); 87 ucAddr <<= 1; 88 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET); 89 } 90
91
92 for(i=8;i>0;i--) 93 { 94 // MF522_SI = ((value&0x80)==0x80);
95 if ((value&0x80)==0x80) 96 { 97 HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_SET); 98 } 99 else
100 { 101 HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_RESET); 102 } 103 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET); 104 value <<= 1; 105 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET); 106 } 107
108
109
110
111 HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_SET);// MF522_NSS = 1;
112 HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);// MF522_SCK = 1;
113
114 }
復位函數
1 /******************************************************************* 2 @func : PcdReset 3 @brief : 復位RC522 4 @pram : None 5 @retval : 成功返回MI_OK 6 @NOTE : 外部調用 7 *******************************************************************/
8 char PcdReset(void) 9 { 10 /* MF522_RST=1; */
11 HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_SET); 12 HAL_Delay(10); 13 /* MF522_RST=0; */
14 HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_RESET); 15 HAL_Delay(10); 16 /* MF522_RST=1; */
17 HAL_GPIO_WritePin(NSS_GPIO_Port, NSS_Pin, GPIO_PIN_SET); 18 HAL_Delay(10); 19 WriteRawRC(CommandReg,PCD_RESETPHASE); // 復位
20 HAL_Delay(10); 21
22 WriteRawRC(ModeReg,0x3D); // 和Mifare卡通訊,CRC初始值0x6363
23 WriteRawRC(TReloadRegL,30); // 16位定時器低位
24 WriteRawRC(TReloadRegH,0); // 16位定時器高位
25 WriteRawRC(TModeReg,0x8D); // 定時器內部設置
26 WriteRawRC(TPrescalerReg,0x3E); // 定時器分頻系數設置
27 WriteRawRC(TxAutoReg, 0x40); // 調制發送信號為100%ASK 調試的時候加上這一句試試
28 return MI_OK; 29 }
其他的底層驅動函數就不需要改了,由於總的代碼量比較長,我就只貼出關鍵的,其他不需要改的直接參考資料里面的例程即可
我自己移植過來完整的有很多程序的注注釋,有興趣的可以下載一下,不過自己花時間看看數據手冊打個注釋是最好的
任何你的不足,在你成功地那一刻,都會被別人說成特色!! 加油吧