WriteRawRC(reg,tmp | mask); // set bit mask }
/********************************************************************* * 功 能:清RC522寄存器位 * 参数说明:reg[IN]:寄存器地址 * mask[IN]:清位值
*********************************************************************/ void ClearBitMask(unsigned char reg,unsigned char mask) {
char tmp = 0x0;
tmp = ReadRawRC(reg);
WriteRawRC(reg, tmp & ~mask); // clear bit mask }
/********************************************************************* * 功 能:通过RC522和ISO14443卡通讯 * 参数说明:Command[IN]:RC522命令字
* pInData[IN]:通过RC522发送到卡片的数据 * InLenByte[IN]:发送数据的字节长度 * pOutData[OUT]:接收到的卡片返回数据 * *pOutLenBit[OUT]:返回数据的位长度
*********************************************************************/ char PcdComMF522(unsigned char Command, unsigned char *pInData, unsigned char InLenByte, unsigned char *pOutData, unsigned int *pOutLenBit) {
char status = MI_ERR;
unsigned char irqEn = 0x00; unsigned char waitFor = 0x00; unsigned char lastBits; unsigned char n; unsigned int i; switch (Command) {
case PCD_AUTHENT: // 验证密钥 irqEn = 0x12; waitFor = 0x10; break;
case PCD_TRANSCEIVE: // 发送并接收数据 irqEn = 0x77; waitFor = 0x30;
break; default: break; }
WriteRawRC(ComIEnReg,irqEn|0x80); // ComIEnReg:中断请求的使能位。验证密钥:(10010010)位7:管脚IRQ与Status1Reg的IRq反相。位4:允许空闲中断请求(IdleIRq位)传递到IRQ管脚上。位1:允许错误中断请求(ErrIRq位)传递到IRQ管脚上。
// 发送并接收数据:(11110111)除高位中断请求外,其他都能传到IRQ管脚上
ClearBitMask(ComIrqReg,0x80); // ComIrqReg的屏蔽位清零
WriteRawRC(CommandReg,PCD_IDLE); // CommandReg低4位写0000B,处于空闲模式 SetBitMask(FIFOLevelReg,0x80); // FIFOLevelReg中FlushBuffer位置1,表示缓冲区读和写指针清除,即缓冲区无数据,用来存放一下批数据,ErrReg的BufferOvfl清除
for (i=0; i WriteRawRC(FIFODataReg, pInData[i]); // 将pInData数组的数据写进FIFO缓冲区 } WriteRawRC(CommandReg, Command); // 验证密钥 or 发送并接收数据 if (Command == PCD_TRANSCEIVE) { SetBitMask(BitFramingReg,0x80); } // 启动数据的发送 // i = 600;//根据时钟频率调整,操作M1卡最大等待时间25ms i = 2000; do { n = ReadRawRC(ComIrqReg); i--; } while ((i!=0) && !(n&0x01) && !(n&waitFor)); //如果i不为0,并且定时器没减到0,并且没有未知命令和自身终止命令和接收器没有检测到有效数据流,就继续循环,退出循环则表示接收完成 ClearBitMask(BitFramingReg,0x80); // StartSend位清零 if (i!=0) { if(!(ReadRawRC(ErrorReg)&0x1B)) // FIFO没有溢出、接收器启动并完成接收之后:(没冲突)、(CRC没出错)、(没有SOF错误)、(验证时接受字节数没错) { status = MI_OK; if (n & irqEn & 0x01) // 发送并接收数据、定时器减到0 { status = MI_NOTAGERR; } // 没有找到目标错误 if (Command == PCD_TRANSCEIVE) { n = ReadRawRC(FIFOLevelReg); // 读FIFO保存的字节数 lastBits = ReadRawRC(ControlReg) & 0x07; // 最后一个接收的字节的有效位数(0则表示8位都有效) if (lastBits) { *pOutLenBit = (n-1)*8 + lastBits; } else { *pOutLenBit = n*8; } if (n == 0) { n = 1; } if (n > MAXRLEN) { n = MAXRLEN; } for (i=0; i { pOutData[i] = ReadRawRC(FIFODataReg); } // 将缓冲区的数据读出 } } else { status = MI_ERR; } // 验证错误 } SetBitMask(ControlReg,0x80); // stop timer now WriteRawRC(CommandReg,PCD_IDLE); // 空闲 return status; } /******************************************************************** * 开启天线 * 每次启动或关闭天险发射之间应至少有1ms的间隔 ********************************************************************/ void PcdAntennaOn() { unsigned char i; i = ReadRawRC(TxControlReg); if (!(i & 0x03)) { SetBitMask(TxControlReg, 0x03); // Tx1和Tx2管脚的输出信号调制到13.56MHz的载波上 } } /******************************************************************** * 关闭天线 ********************************************************************/ void PcdAntennaOff() { ClearBitMask(TxControlReg, 0x03); } /********************************************************************* * 功 能:扣款和充值 * 参数说明: dd_mode[IN]:命令字 * 0xC0 = 扣款 * 0xC1 = 充值 * addr[IN]:钱包地址 * pValue[IN]:4字节增(减)值,低位在前 * 返 回: 成功返回MI_OK *********************************************************************/ char PcdValue(unsigned char dd_mode,unsigned char addr,unsigned char *pValue) { char status; unsigned int unLen; unsigned char ucComMF522Buf[MAXRLEN]; ucComMF522Buf[0] = dd_mode; // 充值还是扣款(加还是减) ucComMF522Buf[1] = addr; // 钱包地址(写卡的地址) CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]); // 计算CRC status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen); // 发送数据并接收数据 if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A)) // 卡片返回1010 { status = MI_ERR; } if (status == MI_OK) { //(ucComMF522Buf, pValue, 4); for (i=0; i<4; i++) //16 { ucComMF522Buf[i] = *(pValue+i); } CalulateCRC(ucComMF522Buf,4,&ucComMF522Buf[4]); unLen = 0; status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,6,ucComMF522Buf,&unLen); // 发送充或者扣的数据 if (status != MI_ERR) { status = MI_OK; } } if (status == MI_OK) { ucComMF522Buf[0] = PICC_TRANSFER; // 保存缓冲区中的数据 ucComMF522Buf[1] = addr; // 地址 CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]); // 计算crc status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen); // 发送保存缓冲区数据的命令 if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A)) // 卡片返回1010B { status = MI_ERR; } } return status; } /********************************************************************** * 功 能:备份钱包 * 参数说明: sourceaddr[IN]:源地址 * goaladdr[IN]:目标地址 * 返 回: 成功返回MI_OK **********************************************************************/ char PcdBakValue(unsigned char sourceaddr, unsigned char goaladdr) { char status; unsigned int unLen; unsigned char ucComMF522Buf[MAXRLEN]; ucComMF522Buf[0] = PICC_RESTORE; // 0xC2,调块数据到缓冲区 ucComMF522Buf[1] = sourceaddr; // 源地址 CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]); // 计算CRC status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen); // 发送命令:将源地址的数据调到缓冲区 if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))