RC522射频卡读写模块驱动(仅读取)
说明
更改了网上的源代码,仅保留了读取序列号并通过串口回传的功能。版本号: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 ------------------------------------------------------------- */
如果你对本博客有任何的疑问或者建议,欢迎联系作者:QQ944273070