說明
更改了網上的源代碼,僅保留了讀取序列號並通過串口回傳的功能。版本號:V1
感謝 https://blog.csdn.net/qq_28877125/article/details/80437095
測試結果
main
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "lcd.h"
#include "RC522.h"
int main(void)
{
unsigned char ID[4],i;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設置系統中斷優先級分組2
delay_init(168); //初始化延時函數
uart_init(115200); //初始化串口波特率為115200
RC522_Init();
while(1)
{
if(RC522_ReadCard(ID))
{
for(i=0;i<4;i++)
{
printf("%x",ID[i]);
}
printf("\r\n");
}
}
}
RC522.h
/******************************************************************************
* @File RC522.h
* @Author Velscode
* @Date 2019/01
* @Email velscode@gmail.com
* @Version 1.0
******************************************************************************/
#ifndef _RC522_H_
#define _RC522_H_
#include "sys.h"
#include "stm32f4xx_it.h"
/*******************************
* 連線說明:
* 1 -- SDA <----->PA4
* 2 -- SCK <----->PA5
* 3 -- MOSI <----->PA7
* 4 -- MISO <----->PA6
* 5 -- 懸空
* 6 -- GND <----->GND
* 7 -- RST <----->PB0
* 8 -- VCC <----->VCC
************************************/
/* IO口宏定義 ----------------------------------------------------------------------- */
#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 )
/* 函數聲明 ---------------------------------------------------- */
u8 RC522_isConnected( void ); //檢查模塊連接
void RC522_Init ( void ); //初始化
void RC522_WriteRawRC ( u8 Address, u8 Value ); //寫寄存器
u8 RC522_ReadRawRC ( u8 Address ); //讀寄存器
u8 RC522_ReadCard( unsigned char *ID ); //讀卡
/* 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計算
/* ifare_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
#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
/* 通信返回碼 ----------------------- */
#define MI_OK 0
#define MI_NOTAGERR 1
#define MI_ERR 2
#endif
/* End of File ------------------------------------------------------------- */
RC522.c
/******************************************************************************
* @File RC522.c
* @Author Velscode
* @Date 2019/01
* @Email velscode@gmail.com
* @Version 1.0
******************************************************************************/
#include "sys.h"
#include "RC522.h"
#include "delay.h"
char PcdAnticoll ( u8 * pSnr );
void PcdAntennaOn ( void );
char PcdComMF522 ( u8 ucCommand, u8 * pInData, u8 ucInLenByte, u8 * pOutData, u32 * pOutLenBit );
void SetBitMask ( u8 Reg, u8 Mask );
void ClearBitMask ( u8 Reg, u8 Mask );
void SPI_RC522_SendByte ( u8 byte );
unsigned char SPI_RC522_ReadByte ( void );
/********************************************
* @Name RC522_ReadCard
* @Brief 讀取射頻卡
* @Para 如果讀取成功,ID中存儲的就是卡序列號
* @Retun 1 - 讀取到ID卡
* 0 - 未讀取到ID卡
********************************************/
u8 RC522_ReadCard( unsigned char *ID )
{
u8 state = 0x00;
u8 ucComMF522Buf [ MAXRLEN ];
u32 ulLen;
ClearBitMask ( Status2Reg, 0x08 ); //清理指示MIFARECyptol單元接通以及所有卡的數據通信被加密的情況
RC522_WriteRawRC ( BitFramingReg, 0x07 ); //發送的最后一個字節的 七位
SetBitMask ( TxControlReg, 0x03 ); //TX1,TX2管腳的輸出信號傳遞經發送調制的13.56的能量載波信號
ucComMF522Buf [ 0 ] = PICC_REQALL; //存入 卡片命令字
state = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 1, ucComMF522Buf, & ulLen ); //尋卡
if(state==MI_OK)//尋卡成功
{
state = MI_ERR;
state = PcdAnticoll(ID);//防沖撞
}
if( state == MI_OK )
{
return 1;
}
else
{
return 0;
}
}
/***********************************
* @Name RC522_isConnected()
* @Brief 檢查RC522模塊是否連接
* @Retun 1 - 連接成功
* 0 - 連接失敗
************************************/
u8 RC522_isConnected(void)
{
if(RC522_ReadRawRC(VersionReg)==0x92)
{
return 1;
}
else
{
return 0;
}
}
/*******************************
* @Name RC522_Init()
* @Brief 初始化RC522
************************************/
void RC522_Init( void )
{
// GPIO初始化 ------------------------------------------------------------------------------
GPIO_InitTypeDef GPIO_InitStructure; //結構體定義
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB , ENABLE );//使能GPIOA\B時鍾
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //輸出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //100MHZ速率
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //不拉
// CS
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_Init(GPIOA, &GPIO_InitStructure); //使用給定參數初始化引腳
// SCK
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// MOSI
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// RST
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// MISO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //MISO引腳配置為輸入模式,其它不變
GPIO_Init(GPIOA, &GPIO_InitStructure);
//其它操作 ----------------------------------
RC522_Reset_Disable();
RC522_CS_Disable();
//復位RC522 ---------------------------------
RC522_Reset_Disable();
delay_us ( 1 );
RC522_Reset_Enable();
delay_us ( 1 );
RC522_Reset_Disable();
delay_us ( 1 );
RC522_WriteRawRC ( CommandReg, 0x0f );
while ( RC522_ReadRawRC ( CommandReg ) & 0x10 );
delay_us ( 1 );
RC522_WriteRawRC ( ModeReg, 0x3D ); //定義發送和接收常用模式 和Mifare卡通訊,CRC初始值0x6363
RC522_WriteRawRC ( TReloadRegL, 30 ); //16位定時器低位
RC522_WriteRawRC ( TReloadRegH, 0 ); //16位定時器高位
RC522_WriteRawRC ( TModeReg, 0x8D ); //定義內部定時器的設置
RC522_WriteRawRC ( TPrescalerReg, 0x3E ); //設置定時器分頻系數
RC522_WriteRawRC ( TxAutoReg, 0x40 ); //調制發送信號為100%ASK
//設置RC522工作方式為ISO14443_A標准 -----------------------------------------------------
ClearBitMask ( Status2Reg, 0x08 );
RC522_WriteRawRC ( ModeReg, 0x3D );//3F
RC522_WriteRawRC ( RxSelReg, 0x86 );//84
RC522_WriteRawRC( RFCfgReg, 0x7F ); //4F
RC522_WriteRawRC( TReloadRegL, 30 );//tmoLength);// TReloadVal = 'h6a =tmoLength(dec)
RC522_WriteRawRC ( TReloadRegH, 0 );
RC522_WriteRawRC ( TModeReg, 0x8D );
RC522_WriteRawRC ( TPrescalerReg, 0x3E );
delay_us ( 20 );
PcdAntennaOn ();//開天線
}
/*********************************************
* @Name SPI_RC522_SendByte
* @brief 向RC522發送1 字節數據
* @input byte,要發送的數據
* @note RC522.c內部函數
*********************************************/
void SPI_RC522_SendByte ( u8 byte )
{
unsigned char i;
for( i = 0; i < 8; i++ )
{
if ( byte & 0x80 )
RC522_MOSI_1();
else
RC522_MOSI_0();
delay_us ( 50 );
RC522_SCK_0 ();
delay_us ( 50 );
RC522_SCK_1();
delay_us ( 50 );
byte <<= 1;
}
}
/*********************************************
* @Name SPI_RC522_ReadByte
* @Brief 讀取RC522 1字節數據
* @Para RC522回傳的數據
* @Note RC522.c內部函數
*********************************************/
u8 SPI_RC522_ReadByte ( void )
{
u8 i;
u8 SPI_Data;
for( i = 0; i < 8; i++ )
{
SPI_Data <<= 1;
RC522_SCK_0();
delay_us ( 50 );
if ( RC522_MISO_GET() == 1)
SPI_Data |= 0x01;
delay_us ( 50 );
RC522_SCK_1();
delay_us ( 50 );
}
return SPI_Data;
}
/*********************************************
* @Name RC522_WriteRawRC
* @Brief 寫RC522寄存器
* @Para Address 寄存器地址
* @Para Value 要寫入的值
*********************************************/
void RC522_WriteRawRC ( u8 Address, u8 Value )
{
u8 Addr;
Addr = ( Address << 1 ) & 0x7E;
RC522_CS_Enable();
SPI_RC522_SendByte ( Addr );
SPI_RC522_SendByte ( Value );
RC522_CS_Disable();
}
/*********************************************
* @Name RC522_ReadRawRC
* @Brief 讀RC522寄存器
* @Para Address 寄存器地址
* @Retun 寄存器中的知
*********************************************/
u8 RC522_ReadRawRC ( u8 Address )
{
u8 Addr, Value;
Addr = ( ( Address << 1 ) & 0x7E ) | 0x80;
RC522_CS_Enable();
SPI_RC522_SendByte ( Addr );
Value = SPI_RC522_ReadByte ();
RC522_CS_Disable();
return Value;
}
/*********************************************
* @Name SetBitMask
* @Brief 設置寄存器指定位
* @Para Reg 寄存器地址
* @Para Mask
*********************************************/
void SetBitMask ( u8 Reg, u8 Mask )
{
u8 Temp;
Temp = RC522_ReadRawRC ( Reg );
RC522_WriteRawRC ( Reg, Temp | Mask ); // set bit mask
}
/*********************************************
* @Name ClearBitMask
* @Brief 清除寄存器指定位
* @Para Reg 寄存器地址
* @Para Mask
*********************************************/
void ClearBitMask ( u8 Reg, u8 Mask )
{
u8 Temp;
Temp = RC522_ReadRawRC ( Reg );
RC522_WriteRawRC ( Reg, Temp & ( ~ Mask) ); // clear bit mask
}
/*********************************************
* @Name PcdAntennaOn
* @Brief 開啟天線
* @Note 有待評估該函數是否必須
*********************************************/
void PcdAntennaOn ( void )
{
u8 uc;
uc = RC522_ReadRawRC ( TxControlReg );
if ( ! ( uc & 0x03 ) )
SetBitMask(TxControlReg, 0x03);
}
/*
* 函數名: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命令后,該位才能置位
RC522_WriteRawRC ( BitFramingReg, 0x00); //清理寄存器 停止收發
ClearBitMask ( CollReg, 0x80 ); //清ValuesAfterColl所有接收的位在沖突后被清除
ucComMF522Buf [ 0 ] = 0x93; //卡片防沖突命令
ucComMF522Buf [ 1 ] = 0x20;
cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 2, ucComMF522Buf, & ulLen);//與卡片通信
if ( cStatus == MI_OK) //通信成功
{
for ( uc = 0; uc < 4; uc ++ )
{
* ( pSnr + uc ) = ucComMF522Buf [ uc ]; //讀出UID
ucSnr_check ^= ucComMF522Buf [ uc ];
}
if ( ucSnr_check != ucComMF522Buf [ uc ] )
cStatus = MI_ERR;
}
SetBitMask ( CollReg, 0x80 );
return cStatus;
}
/*
* 函數名: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 允許空閑中斷IdleIEn
ucWaitFor = 0x10; //認證尋卡等待時候 查詢空閑中斷標志位
break;
case PCD_TRANSCEIVE: //接收發送 發送接收
ucIrqEn = 0x77; //允許TxIEn RxIEn IdleIEn LoAlertIEn ErrIEn TimerIEn
ucWaitFor = 0x30; //尋卡等待時候 查詢接收中斷標志位與 空閑中斷標志位
break;
default:
break;
}
RC522_WriteRawRC ( ComIEnReg, ucIrqEn | 0x80 ); //IRqInv置位管腳IRQ與Status1Reg的IRq位的值相反
ClearBitMask ( ComIrqReg, 0x80 ); //Set1該位清零時,CommIRqReg的屏蔽位清零
RC522_WriteRawRC ( CommandReg, PCD_IDLE ); //寫空閑命令
SetBitMask ( FIFOLevelReg, 0x80 ); //置位FlushBuffer清除內部FIFO的讀和寫指針以及ErrReg的BufferOvfl標志位被清除
for ( ul = 0; ul < ucInLenByte; ul ++ )
RC522_WriteRawRC ( FIFODataReg, pInData [ ul ] ); //寫數據進FIFOdata
RC522_WriteRawRC ( CommandReg, ucCommand ); //寫命令
if ( ucCommand == PCD_TRANSCEIVE )
SetBitMask(BitFramingReg,0x80); //StartSend置位啟動數據發送 該位與收發命令使用時才有效
ul = 1000;//根據時鍾頻率調整,操作M1卡最大等待時間25ms
do //認證 與尋卡等待時間
{
ucN = RC522_ReadRawRC ( ComIrqReg ); //查詢事件中斷
ul --;
} while ( ( ul != 0 ) && ( ! ( ucN & 0x01 ) ) && ( ! ( ucN & ucWaitFor ) ) ); //退出條件i=0,定時器中斷,與寫空閑命令
ClearBitMask ( BitFramingReg, 0x80 ); //清理允許StartSend位
if ( ul != 0 )
{
if ( ! (( RC522_ReadRawRC ( ErrorReg ) & 0x1B )) ) //讀錯誤標志寄存器BufferOfI CollErr ParityErr ProtocolErr
{
cStatus = MI_OK;
if ( ucN & ucIrqEn & 0x01 ) //是否發生定時器中斷
cStatus = MI_NOTAGERR;
if ( ucCommand == PCD_TRANSCEIVE )
{
ucN = RC522_ReadRawRC ( FIFOLevelReg ); //讀FIFO中保存的字節數
ucLastBits = RC522_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 ] = RC522_ReadRawRC ( FIFODataReg );
}
}
else
cStatus = MI_ERR;
}
SetBitMask ( ControlReg, 0x80 ); // stop timer now
RC522_WriteRawRC ( CommandReg, PCD_IDLE );
return cStatus;
}
/* End of File ------------------------------------------------------------- */