1. MF-RC522模块介绍
MFRC522是应用于13.56MHz对于三表应用推出的低电压、低成本、体积小的非接触式读写卡芯片,是智能仪表和便携式手持设备研发的较好选择。研发便携式手持设备的更好选择。MFRC522采用先进的调制和解调概念,集成在13.56MHz所有类型的被动非接触式通信方式和协议。支持14443A与应答器信号兼容。数字部分处理ISO14443A帧和错误检测。还支持快速CRYPTO1.用语验证加密算法MIFARE系列产品。MFRC522支持MI FARE双向数据传输速率高达424kbit/s。作为13.56MHz高集成读写卡系列芯片族的新成员,MFRC522与MF RC500和MFRC530有很多相似之处,也有很多特点和差异。它与主机间通信SPI模式有利于减少连接和缩小PCB板体积,降低成本。
淘宝上MFRC522成品模块很多,买的时候会送几张白卡(IC完成读写实验的卡)。
淘宝上买的MF-RC522模块基本引出SPI实际上,接口MF-RC522本身还支持IIC,UART协议,SPI协议更简单、更快。
目前,我使用淘宝购买包装成品模块MFRC522原芯片设计读卡电路,使用方便,成本低。适用于需要射频卡终端设计/生产的设备开发、读卡器开发等高应用用用户。各种读卡器模具可直接安装在本模块中。电压为3.3V,通过SPI几条接口简单的线可以直接与用户使用CPU主板连接通信,可保证模块工作稳定可靠,读卡距离长。
如果是当前文章的介绍Linux系统下编写MF-RC522模块驱动,配合应用层完成IC卡号读取、扇区读写、密码验证等。目前开发板采用友好臂Tiny芯片是三星EXYNOS4412没有使用驱动代码SPI直接控制子系统IO口模拟SPI时序完成与MF-RC522之间通讯。
购买模块时,会发送一个模块IC白卡和钥匙扣虽然形状不同,但内部芯片型号属于S50卡、常用的公交卡、地铁卡、超市会员卡等都属于这一类S50卡。还有一个洗发水S70类卡,空间比S50大4倍。S50卡内部是一张EEPROM任何数据都可以存储在空间中,空间分为16个扇区,每个扇区由4个(0、1、2、3)组成。在实际操作中,将16扇分成64块,按绝对地址编号为0-63。
IC卡没有电源,它是由IC芯片、感应天线组成,封装在一个标准的PVC芯片和天线在卡片中没有暴露部分。这是近年来世界上发展起来的一项新技术。它成功地将射频识别技术和IC结合卡技术,结束了无源(卡中无电源)和免接触问题,是电子设备领域的一大突破。卡在一定距离内(通常是5-10)cm)靠近读写器表面,通过无线电波传输完成数据读写操作。
2. 连接硬件原理
3. 驱动代码示例
3.1 rc522.c 源代码
#include <linux/init.h> #include <linux/module.h> #include <linux/ioctl.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/err.h> #include <linux/list.h> #include <linux/errno.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/compat.h> #include <linux/spi/spi.h> #include <linux/spi/spidev.h> #include <asm/uaccess.h> #include <linux/gpio.h> #include <mach/gpio.h> #include <plat/gpio-cfg.h> #include <linux/delay.h> #include "rfid_rc522.h" #include &l;linux/miscdevice.h> #include <linux/fs.h> /*--------------------------------RC522相关操作代码---------------------------------------------*/ /* 函数功能:RC522初始化 Tiny4412硬件连接: DO--MISO :GPB_2 DI--MOSI :GPB_3 CLK-SCLK :GPB_0 CS--CS :GPB_1 RST-- :GPB_4 */ void RC522_IO_Init(void) { /*1. 注册GPIO*/ gpio_request(EXYNOS4_GPB(0), "RC522_CLK-SCLK"); gpio_request(EXYNOS4_GPB(1), "RC522_CS"); gpio_request(EXYNOS4_GPB(2), "MOSI"); gpio_request(EXYNOS4_GPB(3), "RC522_MOSI"); gpio_request(EXYNOS4_GPB(4), "RST"); /*2. 配置GPIO口模式*/ s3c_gpio_cfgpin(EXYNOS4_GPB(0), S3C_GPIO_OUTPUT); //时钟 s3c_gpio_cfgpin(EXYNOS4_GPB(1), S3C_GPIO_OUTPUT); //片选 s3c_gpio_cfgpin(EXYNOS4_GPB(2), S3C_GPIO_INPUT); //输入模式 s3c_gpio_cfgpin(EXYNOS4_GPB(3), S3C_GPIO_OUTPUT); //输出模式 s3c_gpio_cfgpin(EXYNOS4_GPB(4), S3C_GPIO_OUTPUT); //输出模式 /*3. 上拉GPIO口*/ gpio_set_value(EXYNOS4_GPB(0), 1); gpio_set_value(EXYNOS4_GPB(1), 1); gpio_set_value(EXYNOS4_GPB(3), 1); gpio_set_value(EXYNOS4_GPB(4), 1); } /* 函数功能:SPI时序读写一个字节 说 明:SPI底层时序,程序的移植接口 */ u8 RC522_SPI_ReadWriteOneByte(u8 data_tx) { u8 data_rx=0; u8 i; for(i=0;i<8;i++) { gpio_set_value(EXYNOS4_GPB(0), 0); if(data_tx&0x80)gpio_set_value(EXYNOS4_GPB(3), 1); else gpio_set_value(EXYNOS4_GPB(3), 0); data_tx<<=1; //继续发送下一个数据 gpio_set_value(EXYNOS4_GPB(0), 1); data_rx<<=1; if(gpio_get_value(EXYNOS4_GPB(2)))data_rx|=0x01; } return data_rx; } /* 功能描述:选卡读取卡存储器容量 输入参数:serNum 传入卡序列号 返 回 值:成功返回卡容量 */ u8 RC522_MFRC522_SelectTag(u8 *serNum) //读取卡存储器容量 { u8 i; u8 status; u8 size; u8 recvBits; u8 buffer[9]; buffer[0]=PICC_ANTICOLL1; //防撞码1 buffer[1]=0x70; buffer[6]=0x00; for(i=0;i<4;i++) { buffer[i+2]=*(serNum+i); //buffer[2]-buffer[5]为卡序列号 buffer[6]^=*(serNum+i); //卡校验码 } RC522_CalulateCRC(buffer,7,&buffer[7]); //buffer[7]-buffer[8]为RCR校验码 RC522_ClearBitMask(Status2Reg,0x08); status=RC522_PcdComMF522(PCD_TRANSCEIVE,buffer,9,buffer,&recvBits); if((status==MI_OK)&&(recvBits==0x18)) size=buffer[0]; else size=0; return size; } /* 延时函数,纳秒级 */ void RC522_Delay(u32 ns) { ndelay(ns); } /* 函数功能:RC522芯片初始化 */ void RC522_Init(void) { RC522_IO_Init(); //RC522初始化 RC522_PcdReset(); //复位RC522 RC522_PcdAntennaOff(); //关闭天线 msleep(2); //延时2毫秒 RC522_PcdAntennaOn(); //开启天线 M500PcdConfigISOType('A'); //设置RC632的工作方式 } /* 函数功能:复位RC522 */ void RC522_Reset(void) { RC522_PcdReset(); //复位RC522 RC522_PcdAntennaOff(); //关闭天线 msleep(2); //延时2毫秒 RC522_PcdAntennaOn(); //开启天线 } /* 功 能: 寻卡 参数说明: req_code[IN]:寻卡方式 0x52 = 寻感应区内所有符合14443A标准的卡 0x26 = 寻未进入休眠状态的卡 pTagType[OUT]:卡片类型代码 0x4400 = Mifare_UltraLight 0x0400 = Mifare_One(S50) 0x0200 = Mifare_One(S70) 0x0800 = Mifare_Pro(X) 0x4403 = Mifare_DESFire 返 回 值: 成功返回MI_OK */ char RC522_PcdRequest(u8 req_code,u8 *pTagType) { char status; u8 unLen; u8 ucComMF522Buf[MAXRLEN]; // MAXRLEN 18 RC522_ClearBitMask(Status2Reg,0x08); //清RC522寄存器位,/接收数据命令 RC522_WriteRawRC(BitFramingReg,0x07); //写RC632寄存器 RC522_SetBitMask(TxControlReg,0x03); //置RC522寄存器位 ucComMF522Buf[0]=req_code; //寻卡方式 status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen); //通过RC522和ISO14443卡通讯 if((status==MI_OK)&&(unLen==0x10)) { *pTagType=ucComMF522Buf[0]; *(pTagType+1)=ucComMF522Buf[1]; } else { status = MI_ERR; } return status; } /* 功 能: 防冲撞 参数说明: pSnr[OUT]:卡片序列号,4字节 返 回: 成功返回MI_OK */ char RC522_PcdAnticoll(u8 *pSnr) { char status; u8 i,snr_check=0; u8 unLen; u8 ucComMF522Buf[MAXRLEN]; RC522_ClearBitMask(Status2Reg,0x08); //清RC522寄存器位 RC522_WriteRawRC(BitFramingReg,0x00); //写 RC522_ClearBitMask(CollReg,0x80); //清 ucComMF522Buf[0]=PICC_ANTICOLL1; //PICC_ANTICOLL1 = 0x93 ucComMF522Buf[1]=0x20; status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen); //0x0c,通过RC522和ISO14443卡通讯 //PCD_TRANSCEIVE =发送并接收数据 //2:写入卡里的数据字节长度 //ucComMF522Buf:存放数据的地址 //unLen:从卡里读出的数据长度 if(status==MI_OK) { for(i=0;i<4;i++) { *(pSnr+i)=ucComMF522Buf[i]; //把读到的卡号赋值给pSnr snr_check^=ucComMF522Buf[i]; } if(snr_check!=ucComMF522Buf[i]) { status = MI_ERR; } } RC522_SetBitMask(CollReg,0x80); return status; } /* 功 能:选定卡片 参数说明:pSnr[IN]:卡片序列号,4字节 返 回:成功返回MI_OK */ char RC522_PcdSelect(u8 *pSnr) { char status; u8 i; u8 unLen; u8 ucComMF522Buf[MAXRLEN]; ucComMF522Buf[0]=PICC_ANTICOLL1; ucComMF522Buf[1]=0x70; ucComMF522Buf[6]=0; for(i=0;i<4;i++) { ucComMF522Buf[i+2]=*(pSnr+i); ucComMF522Buf[6]^=*(pSnr+i); } RC522_CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]); //用MF522计算CRC16函数,校验数据 RC522_ClearBitMask(Status2Reg,0x08); //清RC522寄存器位 status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen); if((status==MI_OK)&&(unLen==0x18))status=MI_OK; else status=MI_ERR; return status; } /* 功 能:验证卡片密码 参数说明:auth_mode[IN]: 密码验证模式 0x60 = 验证A密钥 0x61 = 验证B密钥 addr[IN]:块地址 pKey[IN]:扇区密码 pSnr[IN]:卡片序列号,4字节 返 回:成功返回MI_OK */ char RC522_PcdAuthState(u8 auth_mode,u8 addr,u8 *pKey,u8 *pSnr) { char status; u8 unLen; u8 ucComMF522Buf[MAXRLEN]; //MAXRLEN 18(数组的大小) //验证模式+块地址+扇区密码+卡序列号 ucComMF522Buf[0]=auth_mode; ucComMF522Buf[1]=addr; memcpy(&ucComMF522Buf[2],pKey,6); //拷贝,复制 memcpy(&ucComMF522Buf[8],pSnr,4); status=RC522_PcdComMF522(PCD_AUTHENT,ucComMF522Buf,12,ucComMF522Buf,&unLen); if((status!= MI_OK)||(!(RC522_ReadRawRC(Status2Reg)&0x08)))status = MI_ERR; return status; } /* 功 能:读取M1卡一块数据 参数说明: addr:块地址 p :读出的块数据,16字节 返 回:成功返回MI_OK */ char RC522_PcdRead(u8 addr,u8 *p) { char status; u8 unLen; u8 i,ucComMF522Buf[MAXRLEN]; //18 ucComMF522Buf[0]=PICC_READ; ucComMF522Buf[1]=addr; RC522_CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]); status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);//通过RC522和ISO14443卡通讯 if((status==MI_OK&&(unLen==0x90))) { for(i=0;i<16;i++) { *(p +i)=ucComMF522Buf[i]; } } else { status=MI_ERR; } return status; } /* 功 能:写数据到M1卡指定块 参数说明:addr:块地址 p :向块写入的数据,16字节 返 回:成功返回MI_OK */ char RC522_PcdWrite(u8 addr,u8 *p) { char status; u8 unLen; u8 i,ucComMF522Buf[MAXRLEN]; ucComMF522Buf[0]=PICC_WRITE;// 0xA0 //写块 ucComMF522Buf[1]=addr; //块地址 RC522_CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]); status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen); if((status!= MI_OK)||(unLen != 4)||((ucComMF522Buf[0]&0x0F)!=0x0A)) { status = MI_ERR; } if(status==MI_OK) { for(i=0;i<16;i++)//向FIFO写16Byte数据 { ucComMF522Buf[i]=*(p +i); } RC522_CalulateCRC(ucComMF522Buf,16,&ucComMF522Buf[16]); status = RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,18,ucComMF522Buf,&unLen); if((status != MI_OK)||(unLen != 4)||((ucComMF522Buf[0]&0x0F)!=0x0A)) { status = MI_ERR; } } return status; } /* 功 能:命令卡片进入休眠状态 返 回:成功返回MI_OK */ char RC522_PcdHalt(void) { u8 status; u8 unLen; u8 ucComMF522Buf[MAXRLEN]; //MAXRLEN==18 status=status; ucComMF522Buf[0]=PICC_HALT; ucComMF522Buf[1]=0; RC522_CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]); status=RC522_PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen); return MI_OK; } /* 功 能:用MF522计算CRC16函数 参 数: *pIn :要读数CRC的数据 len:-数据长度 *pOut:计算的CRC结果 */ void RC522_CalulateCRC(u8 *pIn ,u8 len,u8 *pOut ) { u8 i,n; RC522_ClearBitMask(DivIrqReg,0x04); //CRCIrq = 0 RC522_WriteRawRC(CommandReg,PCD_IDLE); RC522_SetBitMask(FIFOLevelReg,0x80); //清FIFO指针 //向FIFO中写入数据 for(i=0;i<len;i++) { RC522_WriteRawRC(FIFODataReg,*(pIn +i)); //开始RCR计算 } RC522_WriteRawRC(CommandReg,PCD_CALCCRC); //等待CRC计算完成 i=0xFF; do { n=RC522_ReadRawRC(DivIrqReg); i--; } while((i!=0)&&!(n&0x04));//CRCIrq = 1 //读取CRC计算结果 pOut[0]=RC522_ReadRawRC(CRCResultRegL); pOut[1]=RC522_ReadRawRC(CRCResultRegM); } /* 功 能:复位RC522 返 回:成功返回MI_OK */ char RC522_PcdReset(void) { gpio_set_value(EXYNOS4_GPB(4), 1); //PF1写1 RC522_Delay(10); gpio_set_value(EXYNOS4_GPB(4), 0); //PF1清0 RC522_Delay 标签:
m射频连接器板线连接器s3b存储器连接器智能卡