STM32驱动RFID高频读卡器实现IC卡读取

stm32驱动RFID读卡器读取IC卡

  • 1.介绍RFID
  • 2.RFID控制指令
  • 2.1 读IC卡号
  • 2.2 读IC卡数据块
  • 2.3 写数据到IC卡数据块
  • 2.4 读取RFID读卡器用户数据
  • 2.5 向RFID读卡器写入用户数据
  • 3.代码实例
  • 3.1 rfid.c 源文件
  • 3.2 rfid 头文件
  • 4. 结语
  • 1.介绍RFID

    RFID(Radio-Frequency Identification)高频读卡器是一种设备,用于读取和解析高频(13.56 MHz)频段上的RFID标签信息。这种读卡器通过无线射频技术与标签进行通信,并从标签中获取存储的数据。
    RFID高频读卡器通常包括以下主要组件
    读卡器天线:用于发射和接收射频信号,与标签进行通信。
    处理器:负责解析和处理从标签接收到的数据,以及将数据传输给相应的应用程序。
    电源和接口:提供电力和连接读卡器与其他设备/系统的接口。
    控制单元:用于控制读卡器的操作和配置。
    RFID高频读卡器常用于各种场景,如物流管理、库存跟踪、门禁控制、资产管理等。它们可以与其他设备(如计算机、智能手机、门禁系统)进行通信,以便实现各种应用需求。
    需要注意的是,RFID技术还有其他频段,如低频(LF)和超高频(UHF),每个频段的读卡器具有不同的特点和应用领域。
    我们这里介绍的是RFID高频读卡器。

    2.RFID控制指令

    2.1 读IC卡号


    发送十六进制命令: 01 08 A1 20 00 01 00 76
    成功, 读写器返回十六进制数据: 01 0C A1 20 00 04 00 0A DC EF F9 B7, 其中 04 00 为卡类型, 0A DC
    EF F9 为卡号
    失败, 读写器返回十六进制数据: 01 08 A1 20 01 00 00 76

    2.2 读IC卡数据块


    假如块 2 中的数据为: 78 56 34 12 87 A9 CB ED 78 56 34 12 02 FD 02 FD
    例 1: 验证卡的 KEYA, 读数据块 2 的数据, LED 和蜂鸣器不提示, 命令与返回包如下:
    上位机发送十六进制命令: 01 08 A3 20 02 00 00 77
    成功, 读写器返回十六进制数据: 01 16 A3 20 00 78 56 34 12 87 A9 CB ED 78 56 34 12 02 FD 02 FD 63
    失败, 读写器返回十六进制数据: 01 08 A3 20 01 00 00 74
    例 2: 验证卡的 KEYB, 读数据块 2 的数据, LED 和蜂鸣器不提示, 命令与返回包如下:
    上位机发送十六进制命令: 01 08 5C 20 02 00 00 88
    成功, 读写器返回十六进制数据: 01 16 5C 20 00 78 56 34 12 87 A9 CB ED 78 56 34 12 02 FD 02 FD 9C
    失败, 读写器返回十六进制数据: 01 08 5C 20 01 00 00 8B

    2.3 写数据到IC卡数据块


    写 16 字节数据 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF 到块 2
    例 1: 验证卡的 KEYA, 写数据块 2, LED 与蜂鸣器的状态提示开启, 命令与返回包如下:
    上位机发送十六进制命令: 01 17 A4 20 02 01 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF 6E
    成功, 读写器返回十六进制数据: 01 08 A4 20 00 00 00 72
    失败, 读写器返回十六进制数据: 01 08 A4 20 01 00 00 73
    例 2: 验证卡的 KEYB , 写数据块 2, LED 与蜂鸣器的状态提示开启, 命令与返回包如下:
    上位机发送十六进制命令: 01 17 5B 20 02 01 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF 91
    成功, 读写器返回十六进制数据: 01 08 5B 20 00 00 00 8D
    失败, 读写器返回十六进制数据: 01 08 5B 20 01 00 00 8C

    2.4 读取RFID读卡器用户数据


    例 :用户在从地址 03 开始存储了 6 个字节的数据, 分别是 01 02 03 04 05 06, 查询这个 6 个字节数据, 命令与
    返回包如下:
    上位机发送十六进制命令: 02 08 B5 20 03 06 00 65
    读写器返回十六进制数据: 02 0C B5 20 00 01 02 03 04 05 06 63
    每次读用户内存的字节数不超过 16 字节, 地址空间从 0x00-0x1F,总共 32 字节。

    2.5 向RFID读卡器写入用户数据


    读写器提供 32 字节的内存空间, 地址空间 0-1F, 供用户存储数据, 当内存使用(比如存储用户自己的序列号,
    验证码, 用于跟自己的设备或者上位机管理软件验证, 是否为合法读写设备) ; 用户可以简单的通过命令对读写
    器提供的存储空间进行存取。 可以将数据存储在指定的地址空间。 每次存储数据字节数不能大于 16 字节。
    例 1:如在地址 05 开始处顺序存储 5 个字节:0x12 0x34,0x56,0x78,0x09 , 令与返回包如下:
    上位机发送十六进制命令: 03 0B C5 20 05 12 34 56 78 09 16
    成功, 读写器返回十六进制数据: 03 08 C5 20 00 00 00 11
    失败, 读写器返回十六进制数据: 03 08 C5 20 01 00 00 10

    3.代码实例

    这里我写了以上操作指令代码,这些代码可移植性强,方便调用。你们可以结合自己的需要去使用。
    比如搞一个门禁系统,校园卡等

    3.1 rfid.c 源文件

    这里就是串口代码没提供,代码太多了,贴不下,你们可以用你们自己的串口代码。
    不过我也会提供完成源码。

    #include "stm32f10x.h"
    #include "usart3.h"
    #include "usart.h"
    #include "rfid.h"
    #include "stdio.h"
    
    unsigned char Uart3RxBuf[UART3_RX_BUF_LEN];
    unsigned char Uart3RxDataConut = 0;
    unsigned char Rx3Flag = 0;
    
    unsigned char Cmd_Read_Id[8] = {0x01,0x08,0xa1,0x20,0x00,0x00,0x00,0x00};
    unsigned char Cmd_Read_Block[8]	= {0x01,0x08,0xa3,0x20,0x00,0x00,0x00,0x00};
    unsigned char Cmd_Write_Block[23] = {0x01,0x17,0xa4,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
    
    unsigned char WBlockData[16] = {0x11,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
    //CircularBuffer *Uart2_Circular_Buffer;
    unsigned char Cmd_Write_RFID[0x0B]={0x03, 0x0B, 0xC5, 0x20, 0x05, 0x12, 0x34, 0x56, 0x78, 0x09, 0x16};
     //                          命令类型  包长度  命令  设备地址  起始地址  数据长度   保留  校验和
    unsigned char Cmd_Read_RFID[]={0x02,   0x08,   0xB5,  0x20,    0x03,      0x06,     0x00,  0x65};
    
    //延时,10000000大约为1S
    void Delay(__IO unsigned int nCount)
    {
      for (; nCount != 0; nCount--);
    }
    
    void Uart3_Send_Data(unsigned char *buf,unsigned char num)
    {
    	unsigned char i;
    	for(i=0;i<num;i++)
    	{ 
    	 	USART_SendData(USART3, buf[i]);
    	 	while (USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
    	}	
    }
    
    unsigned char RxCheckSum(unsigned char *ptr,unsigned char len) //计算校验值 
    {
    	unsigned char i;
    	unsigned char checksum;
    	checksum = 0;
    	for(i=0;i<(len-1);i++)
    	{
    		   checksum ^= ptr[i];
    	}
    	checksum = ~checksum;
    	if(ptr[len-1] == checksum)
    		return 	STATUS_OK;
    	else 
    		return 	STATUS_ERR;
    }
    
    void TxCheckSum(unsigned char *ptr,unsigned char len)
    {
    	unsigned char i;
    	unsigned char checksum;
    	checksum = 0;
    	for(i=0;i<(len-1);i++)
    	{
    		   checksum ^= ptr[i];
    	}
    	checksum = ~checksum;
    	ptr[len-1] = checksum;
    }
    //ReadId():读IC卡ID号(卡号)
    //参数:*idout,读取的卡号保存到它所指向的存储空间
    //返回值:0:成功读取卡号,1:读卡号失败
    unsigned char ReadId(void)
    {
    	unsigned char status;
    	unsigned char i;
    	unsigned char idout[6];
    	Cmd_Read_Id[5] = 0x01;//开启蜂鸣器提示
    	//Cmd_Read_Id[5] = 0x00;//关闭蜂鸣器提示
    	TxCheckSum(Cmd_Read_Id,Cmd_Read_Id[1]);		//计算校验和
    	Uart3_Send_Data(Cmd_Read_Id,Cmd_Read_Id[1]);		 //发送读卡号ID命令
    	Delay(2000000);//等待模块返回数据,大于150MS
     	if(Rx3Flag == 1)
     	{	
    		Rx3Flag = 0;
    		status = RxCheckSum(Uart3RxBuf,Uart3RxBuf[1]);//对接收到的数据校验
    		if(status != STATUS_OK)  //判断校验和是否正确
    		{
    			return STATUS_ERR;
    		}
    		status = Uart3RxBuf[4];
    		if(status != STATUS_OK)	//判断是否正确的读到卡
    		{
    		 	return STATUS_ERR;
    		}
    		if((Uart3RxBuf[0] == 0x01)&&(Uart3RxBuf[2] == 0xa1))//判断是否为读卡号返回的数据包
    		{
    			for(i=0;i<6;i++)//获取卡号ID,6字节		 
    			{
    				idout[i] = Uart3RxBuf[i+5];//从数组的第5个字节开始为卡号,长度为6字节
    			}
    			for(i=0;i<6;i++)
    		{
    			while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET); //Ñ­»··¢ËÍ,Ö±µ½·¢ËÍÍê±Ï   
    			USART_SendData(USART1,idout[i]); 
    		}
    			return STATUS_OK;		 //成功返回0
    		}
     	} 
    	return STATUS_ERR;			//失败返回1
    }
    
    
    //ReadId():读IC卡数据块
    //参数:*idout,读取的数据保存到它所指向的存储空间
    //参数:block,块号
    //返回值:0:成功读取,1:读读取失败
    unsigned char ReadDataFromBlock(unsigned char *dataout,unsigned char block)
    {
    	unsigned char status;
    	unsigned char i;
    	Cmd_Read_Block[4] = block;
    	Cmd_Read_Block[5] = 0x01;//开启蜂鸣器提示
    //	Cmd_Read_Block[5] = 0x00;//关闭蜂鸣器提示
    	TxCheckSum(Cmd_Read_Block,Cmd_Read_Block[1]);	//数据校验
    	Uart3_Send_Data(Cmd_Read_Block,Cmd_Read_Block[1]);		 //发送读数据块命令
    	Delay(2000000);//等待模块返回数据,大于150MS
     	if(Rx3Flag == 1)
     	{	
    		Rx3Flag = 0;
    		status = RxCheckSum(Uart3RxBuf,Uart3RxBuf[1]);//对接收到的数据校验
    		if(status != STATUS_OK)		 //判断校验和是否正确
    		{
    			return 	STATUS_ERR;
    		}
    		status = Uart3RxBuf[4];		//获取返回包状态
    		if(status != STATUS_OK)	//判断是否正确的读到卡
    		{
    			return STATUS_ERR;
    		}
    		if((Uart3RxBuf[0] == 0x01)&&(Uart3RxBuf[2] == 0xa3))//判断是否为读块数据返回的数据包
    		{
    			for(i=0;i<16;i++)//获取块数据,16字节	,一个数据块的大小为16字节	 
    			{
    				dataout[i] = Uart3RxBuf[i+5];//从数组的第5个字节开始为数据,长度为16字节
    			}
    			return STATUS_OK;		 //成功返回0
    		}
    	}
    	return STATUS_ERR;			//失败返回1
    }
    //ReadId():写数据到指定的数据块
    //参数:*idout,指向要写入数据的缓冲区
    //参数:block,块号
    //返回值:0:写入成功,1:写入失败
    unsigned char WriteDataToBlock(unsigned char *datain,unsigned char block)
    {
    	unsigned char status;
    	unsigned char i;
    	Cmd_Write_Block[4] = block;
    	for(i=0;i<16;i++)
    	{
    		Cmd_Write_Block[6+i] = datain[i];
    	}
    	TxCheckSum(Cmd_Write_Block,Cmd_Write_Block[1]);	//数据校验
    	Uart3_Send_Data(Cmd_Write_Block,Cmd_Write_Block[1]);		 //发送写命令
    	Delay(2000000);//等待模块返回数据,大于150MS
     	if(Rx3Flag == 1)
     	{	
    		Rx3Flag = 0;
    		status = RxCheckSum(Uart3RxBuf,Uart3RxBuf[1]);//对返回的数据进行校验
    		if(status != STATUS_OK) //判断校验是否通过
    		{
    			return STATUS_ERR;
    		}
    		status = Uart3RxBuf[4];
    		if(status != STATUS_OK) //判断校验是否通过
    		{
    			return STATUS_ERR;
    		}
    		if((Uart3RxBuf[0] == 0x01)&&(Uart3RxBuf[2] == 0xa4))//判断是否为写块数据返回的数据包
    		{
    				return STATUS_OK;		 //成功返回0
    		}
     	} 
    	return STATUS_ERR;			//失败返回1
    }
    //读RFID用户空间
    unsigned char Read_RFID(unsigned char addr,unsigned char len)
    {
      unsigned char status;
      unsigned char i;
        Cmd_Read_RFID[4]=addr;
        Cmd_Read_RFID[5]=len;
    	TxCheckSum(Cmd_Read_RFID,Cmd_Read_RFID[1]);		//计算校验和
    	Uart3_Send_Data(Cmd_Read_RFID,Cmd_Read_RFID[1]);		 //发送读用户数据命令
    	Delay(2000000);//等待模块返回数据,大于150MS
     	if(Rx3Flag == 1)
     	{	
            
    		Rx3Flag = 0;
    		status = RxCheckSum(Uart3RxBuf,Uart3RxBuf[1]);//对接收到的数据校验
    		if(status != STATUS_OK)  //判断校验和是否正确
    		{
    			return STATUS_ERR;
    		}
    		status = Uart3RxBuf[4];
    		if(status != STATUS_OK)	//判断是否正确的读到卡
    		{
    		 	return STATUS_ERR;
    		}
    		if((Uart3RxBuf[0] == 0x02)&&(Uart3RxBuf[2] == 0xB5))//判断是否为读RFID用户信息返回的数据包
    		{
    			
    			for(i=0;i<Cmd_Read_RFID[5];i++)   //将读取的RFID打印到串口
    		{
    			while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET); 
    			USART_SendData(USART1,Uart3RxBuf[i+5]); 
    		}
    			return STATUS_OK;		 //成功返回0
    		}
     	} 
    	return STATUS_ERR;	
    }
    //写RFID 用户空间
    unsigned char Write_RFID(unsigned char addr,unsigned char * data,unsigned char len)
    { 
        unsigned char status;
    	unsigned char i;
        unsigned char cmd[22]={0x03, 0x0B, 0xC5, 0x20};
    	cmd[4] =addr;//地址
        cmd[1]=6+len;//长度
    	for(i=0;i<len;i++)
    	{
    		cmd[5+i] = data[i];
    	}
    	TxCheckSum(cmd,cmd[1]);	//数据校验
    	Uart3_Send_Data(cmd,cmd[1]);	 //发送写命令
    	Delay(2000000);//等待模块返回数据,大于150MS
     	if(Rx3Flag == 1)
     	{	
    		Rx3Flag = 0;
    		status = RxCheckSum(Uart3RxBuf,Uart3RxBuf[1]);//对返回的数据进行校验
    		if(status != STATUS_OK) //判断校验是否通过
    		{
    			return STATUS_ERR;
    		}
    		status = Uart3RxBuf[4];
    		if(status != STATUS_OK) //判断校验是否通过
    		{
    			return STATUS_ERR;
    		}
    		if((Uart3RxBuf[0] == 0x03)&&(Uart3RxBuf[2] == 0xc5))//判断是否为写块数据返回的数据包
    		{        
                 for(i=0;i<len;i++)   //将写入的数据打印到串口
    		{
    			while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET); 
    			USART_SendData(USART1,cmd[i+5]); 
    		}
    				return STATUS_OK;		 //成功返回0
    		}
     	} 
    	return STATUS_ERR;			//失败返回1
    }
    

    3.2 rfid 头文件

    #ifndef _RFID_H
    #define _RFID_H
    
    #define STATUS_OK			0x00
    #define STATUS_ERR    0x01
    
    #define UART3_RX_BUF_LEN 30
    extern unsigned char Uart3RxBuf[];
    extern unsigned char Uart3RxDataConut ;
    extern unsigned char Rx3Flag;
    unsigned char ReadId(void);
    unsigned char Write_RFID(unsigned char addr,unsigned char * data,unsigned char len);
    unsigned char Read_RFID(unsigned char addr,unsigned char len);
    #endif
    
    

    4. 结语

    以上就说指令集以及实现代码了。你们可以拿去使用,改造成你项目中所需要的。
    最后如果想要串口代码或者完整工程的可以评论区或者私信我哦!

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32驱动RFID高频读卡器实现IC卡读取

    发表评论