1 //本头文件是以51为蓝本 2 #ifndef __rc522_h__ 3 #define __rc522_h__ 4 5 #include <string.h> 6 #include <wiringPi.h> 7 #include <unistd.h> 8 #include "Library.h" 9 #include "51initrc522.h" 10 11 12 / 13 //MF522命令字 14 / 15 #define PCD_IDLE 0x00 //取消当前命令 16 #define PCD_AUTHENT 0x0E //验证密钥 17 #define PCD_RECEIVE 0x08 //接收数据 18 #define PCD_TRANSMIT 0x04 //发送数据 19 #define PCD_TRANSCEIVE 0x0C //发送并接收数据 20 #define PCD_RESETPHASE 0x0F //复位 21 #define PCD_CALCCRC 0x03 //CRC计算 22 23 / 24 //Mifare_One卡片命令字 25 #define PICC_REQIDL 0x26 //寻天线区内未进入休眠状态 26 #define PICC_REQALL 0x52 //寻天线区内全部卡 27 / 28 #define PICC_ANTICOLL1 0x93 //防冲撞 29 #define PICC_ANTICOLL2 0x95 //防冲撞 30 #define PICC_AUTHENT1A 0x60 //验证A密钥 31 #define PICC_AUTHENT1B 0x61 //验证B密钥 32 #define PICC_READ 0x30 //读块 33 #define PICC_WRITE 0xA0 //写块 34 #define PICC_DECREMENT 0xC0 //扣款 35 #define PICC_INCREMENT 0xC1 //充值 36 #define PICC_RESTORE 0xC2 //调块数据到缓冲区 37 #define PICC_TRANSFER 0xB0 //保存缓冲区中数据 38 #define PICC_HALT 0x50 //休眠 39 40 / 41 //MF522 FIFO长度定义 42 / 43 #define DEF_FIFO_LENGTH 64 //FIFO size=64byte 44 #define MAXRLEN 18 45 46 / 47 //MF522寄存器定义 48 / 49 // PAGE 0 50 #define RFU00 0x00 51 #define CommandReg 0x01 52 #define ComIEnReg 0x02 53 #define DivlEnReg 0x03 54 #define ComIrqReg 0x04 55 #define DivIrqReg 0x05 56 #define ErrorReg 0x06 57 #define Status1Reg 0x07 58 #define Status2Reg 0x08 59 #define FIFODataReg 0x09 60 #define FIFOLevelReg 0x0A 61 #define WaterLevelReg 0x0B 62 #define ControlReg 0x0C 63 #define BitFramingReg 0x0D 64 #define CollReg 0x0E 65 #define RFU0F 0x0F 66 // PAGE 1 67 #define RFU10 0x10 68 #define ModeReg 0x11 69 #define TxModeReg 0x12 70 #define RxModeReg 0x13 71 #define TxControlReg 0x14 72 #define TxAutoReg 0x15 73 #define TxSelReg 0x16 74 #define RxSelReg 0x17 75 #define RxThresholdReg 0x18 76 #define DemodReg 0x19 77 #define RFU1A 0x1A 78 #define RFU1B 0x1B 79 #define MifareReg 0x1C 80 #define RFU1D 0x1D 81 #define RFU1E 0x1E 82 #define SerialSpeedReg 0x1F 83 // PAGE 2 84 #define RFU20 0x20 85 #define CRCResultRegM 0x21 86 #define CRCResultRegL 0x22 87 #define RFU23 0x23 88 #define ModWidthReg 0x24 89 #define RFU25 0x25 90 #define RFCfgReg 0x26 91 #define GsNReg 0x27 92 #define CWGsCfgReg 0x28 93 #define ModGsCfgReg 0x29 94 #define TModeReg 0x2A 95 #define TPrescalerReg 0x2B 96 #define TReloadRegH 0x2C 97 #define TReloadRegL 0x2D 98 #define TCounterValueRegH 0x2E 99 #define TCounterValueRegL 0x2F 100 // PAGE 3 101 #define RFU30 0x30 102 #define TestSel1Reg 0x31 103 #define TestSel2Reg 0x32 104 #define TestPinEnReg 0x33 105 #define TestPinValueReg 0x34 106 #define TestBusReg 0x35 107 #define AutoTestReg 0x36 108 #define VersionReg 0x37 109 #define AnalogTestReg 0x38 110 #define TestDAC1Reg 0x39 111 #define TestDAC2Reg 0x3A 112 #define TestADCReg 0x3B 113 #define RFU3C 0x3C 114 #define RFU3D 0x3D 115 #define RFU3E 0x3E 116 #define RFU3F 0x3F 117 118 119 / 120 //和MF522通讯时返回的错误代码 121 / 122 #define MI_OK 0 123 #define MI_NOTAGERR (-1) 124 #define MI_ERR (-2) 125 126 #define BOOLEAN unsigned char 127 #define INT8U unsigned char 128 #define INT8S signed char 129 #define INT16U unsigned short int 130 #define INT16S signed short int 131 #define INT32U unsigned int 132 #define INT32S signed int 133 134 void delay_ns(INT16U ns); //延时ns级别 135 INT8U SPIReadByte(void); // 读SPI数据 136 void SPIWriteByte(INT8U SPIData); // 写SPI数据 137 INT8U ReadRawRC(INT8U Address); //读RC632寄存器 138 void WriteRawRC(INT8U Address, INT8U value); //写RC632寄存器 139 void ClearBitMask(INT8U reg,INT8U mask); //清RC522寄存器位 140 void SetBitMask(INT8U reg,INT8U mask); //置RC522寄存器位 141 void CalulateCRC(INT8U *pIndata,INT8U len,INT8U *pOutData); //用MF522计算CRC16函数 142 char PcdComMF522(INT8U Command, 143 INT8U *pInData, 144 INT8U InLenByte, 145 INT8U *pOutData, 146 INT16U *pOutLenBit); //通过RC522和ISO14443卡通讯 147 148 char PcdReset(void); //复位RC522 149 char PcdRequest(INT8U req_code,INT8U *pTagType); //寻卡 150 void PcdAntennaOn(void); //开启天线 151 void PcdAntennaOff(void); //关闭天线 152 char M500PcdConfigISOType(INT8U type); //设置RC632的工作方式 153 char PcdAnticoll(INT8U *pSnr); //防冲撞 154 char PcdSelect(INT8U *pSnr); //选定卡片 155 char PcdAuthState(INT8U auth_mode,INT8U addr,INT8U *pKey,INT8U *pSnr); //验证卡片密码 156 char PcdWrite(INT8U addr,INT8U *pData); //写数据到M1卡一块 157 char PcdRead(INT8U addr,INT8U *pData); //读取M1卡一块数据 158 char PcdHalt(void); //命令卡片进入休眠状态 159 void init_rc522(void); //初始化rc522 160 161 162 void delay_ns(INT16U ns) //延时ns级别 163 { 164 usleep(ns); 165 } 166 167 168 //------------------------------------------ 169 // 读SPI数据 170 //------------------------------------------ 171 INT8U SPIReadByte(void) 172 { 173 INT8U SPICount; //用于时钟输出数据的计数器 174 INT8U SPIData; 175 SPIData = 0; 176 for (SPICount = 0; SPICount < 8; SPICount++) //准备在要读取的数据时钟 177 { 178 SPIData <<=1; //旋转数据 179 CLR_SPI_CK; //nop();//nop(); //提高时钟时钟数据从MAX7456 180 if(STU_SPI_MISO) 181 { 182 SPIData|=0x01; 183 } 184 SET_SPI_CK; //nop();//nop(); // 放下时钟准备下一位 185 } // 和环回 186 return (SPIData); // 最后返回读取数据 187 } 188 //------------------------------------------ 189 // 写SPI数据 190 //------------------------------------------ 191 void SPIWriteByte(INT8U SPIData) 192 { 193 INT8U SPICount; //用于时钟输出数据的计数器 194 for (SPICount = 0; SPICount < 8; SPICount++) 195 { 196 if (SPIData & 0x80) 197 { 198 SET_SPI_MOSI; 199 } 200 else 201 { 202 CLR_SPI_MOSI; 203 } 204 delay_ns(1); 205 CLR_SPI_CK;delay_ns(1); 206 SET_SPI_CK;delay_ns(1); 207 SPIData <<= 1; 208 } 209 } 210 / 211 //功 能:读RC632寄存器 212 //参数说明:Address[IN]:寄存器地址 213 //返 回:读出的值 214 / 215 INT8U ReadRawRC(INT8U Address) 216 { 217 INT8U ucAddr; 218 INT8U ucResult=0; 219 CLR_SPI_CS; 220 ucAddr = ((Address<<1)&0x7E)|0x80; 221 SPIWriteByte(ucAddr); // 写SPI数据 222 ucResult=SPIReadByte(); // 读SPI数据 223 SET_SPI_CS; 224 return ucResult; 225 } 226 227 / 228 //功 能:写RC632寄存器 229 //参数说明:Address[IN]:寄存器地址 230 // value[IN]:写入的值 231 / 232 void WriteRawRC(INT8U Address, INT8U value) 233 { 234 INT8U ucAddr; 235 CLR_SPI_CS; 236 ucAddr = ((Address<<1)&0x7E); 237 SPIWriteByte(ucAddr); //选定寄存器 238 SPIWriteByte(value); //写入数据 239 SET_SPI_CS; 240 } 241 242 / 243 //功 能:清RC522寄存器位 244 //参数说明:reg[IN]:寄存器地址 245 // mask[IN]:清位值 246 / 247 void ClearBitMask(INT8U reg,INT8U mask) 248 { 249 char tmp = 0x00; 250 tmp = ReadRawRC(reg); //读出要清除的清除位掩码数据 251 WriteRawRC(reg, tmp & ~mask); //要清除的清除位掩码 252 } 253 / 254 //功 能:置RC522寄存器位 255 //参数说明:reg[IN]:寄存器地址 256 // mask[IN]:置位值 257 / 258 void SetBitMask(INT8U reg,INT8U mask) 259 { 260 char tmp = 0x00; 261 tmp = ReadRawRC(reg); //读出要清除的清除位掩码数据 262 WriteRawRC(reg,tmp | mask); //写入的清除位掩码 263 } 264 265 / 266 //用MF522计算CRC16函数 267 / 268 void CalulateCRC(INT8U *pIndata,INT8U len,INT8U *pOutData) 269 { 270 INT8U i,n; 271 ClearBitMask(DivIrqReg,0x04); //清RC522寄存器位 272 WriteRawRC(CommandReg,PCD_IDLE); //写RC632寄存器 273 SetBitMask(FIFOLevelReg,0x80); 274 for (i=0; i<len; i++) 275 {WriteRawRC(FIFODataReg, *(pIndata+i));} 276 WriteRawRC(CommandReg, PCD_CALCCRC); 277 i = 0xFF; 278 do 279 { 280 n = ReadRawRC(DivIrqReg); 281 i--; 282 } 283 while ((i!=0) && !(n&0x04)); 284 pOutData[0] = ReadRawRC(CRCResultRegL); 285 pOutData[1] = ReadRawRC(CRCResultRegM); 286 } 287 288 / 289 //功 能:通过RC522和ISO14443卡通讯 290 //参数说明:Command[IN]:RC522命令字 291 // pInData[IN]:通过RC522发送到卡片的数据 292 // InLenByte[IN]:发送数据的字节长度 293 // pOutData[OUT]:接收到的卡片返回数据 294 // *pOutLenBit[OUT]:返回数据的位长度 295 / 296 char PcdComMF522(INT8U Command, 297 INT8U *pInData, 298 INT8U InLenByte, 299 INT8U *pOutData, 300 INT16U *pOutLenBit) 301 { 302 char status = MI_ERR; 303 INT8U irqEn = 0x00; 304 INT8U waitFor = 0x00; 305 INT8U lastBits; 306 INT8U n; 307 INT16U i; 308 switch (Command) 309 { 310 case PCD_AUTHENT: 311 irqEn = 0x12; 312 waitFor = 0x10; 313 break; 314 case PCD_TRANSCEIVE: 315 irqEn = 0x77; 316 waitFor = 0x30; 317 break; 318 default: 319 break; 320 } 321 322 WriteRawRC(ComIEnReg,irqEn|0x80); 323 ClearBitMask(ComIrqReg,0x80); 324 WriteRawRC(CommandReg,PCD_IDLE); 325 SetBitMask(FIFOLevelReg,0x80); 326 327 for (i=0; i<InLenByte; i++) 328 { 329 WriteRawRC(FIFODataReg, pInData[i]); 330 } 331 WriteRawRC(CommandReg, Command); 332 333 if (Command == PCD_TRANSCEIVE) 334 { 335 SetBitMask(BitFramingReg,0x80); 336 } 337 338 //i = 600;//根据时钟频率调整,操作M1卡最大等待时间25ms 339 i = 2000; 340 do 341 { 342 n = ReadRawRC(ComIrqReg); 343 i--; 344 } 345 while ((i!=0) && !(n&0x01) && !(n&waitFor)); 346 ClearBitMask(BitFramingReg,0x80); 347 348 if (i!=0) 349 { 350 if(!(ReadRawRC(ErrorReg)&0x1B)) 351 { 352 status = MI_OK; 353 if (n & irqEn & 0x01) 354 { status = MI_NOTAGERR; } 355 if (Command == PCD_TRANSCEIVE) 356 { 357 n = ReadRawRC(FIFOLevelReg); 358 lastBits = ReadRawRC(ControlReg) & 0x07; 359 if (lastBits) 360 { 361 *pOutLenBit = (n-1)*8 + lastBits; 362 } 363 else 364 { 365 *pOutLenBit = n*8; 366 } 367 if (n == 0) 368 { 369 n = 1; 370 } 371 if (n > MAXRLEN) 372 { 373 n = MAXRLEN; 374 } 375 for (i=0; i<n; i++) 376 { 377 pOutData[i] = ReadRawRC(FIFODataReg); 378 } 379 } 380 } 381 else 382 { 383 status = MI_ERR; 384 } 385 386 } 387 388 SetBitMask(ControlReg,0x80); // stop timer now 389 WriteRawRC(CommandReg,PCD_IDLE); 390 return status; 391 } 392 393 / 394 //功 能:寻卡 395 //参数说明: req_code[IN]:寻卡方式 396 // 0x52 = 寻感应区内所有符合14443A标准的卡 397 // 0x26 = 寻未进入休眠状态的卡 398 // pTagType[OUT]:卡片类型代码 399 // 0x4400 = Mifare_UltraLight 400 // 0x0400 = Mifare_One(S50) 401 // 0x0200 = Mifare_One(S70) 402 // 0x0800 = Mifare_Pro(X) 403 // 0x4403 = Mifare_DESFire 404 //返 回: 成功返回MI_OK 405 / 406 char PcdRequest(INT8U req_code,INT8U *pTagType) 407 { 408 char status; 409 INT16U unLen; 410 INT8U ucComMF522Buf[MAXRLEN]; 411 412 ClearBitMask(Status2Reg,0x08); //清RC522寄存器位 413 WriteRawRC(BitFramingReg,0x07); //写RC632寄存器 414 SetBitMask(TxControlReg,0x03); //置RC522寄存器位 415 416 ucComMF522Buf[0] = req_code; 417 418 status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen); 419 420 if ((status == MI_OK) && (unLen == 0x10)) 421 { 422 *pTagType = ucComMF522Buf[0]; 423 *(pTagType+1) = ucComMF522Buf[1]; 424 } 425 else 426 { 427 status = MI_ERR; 428 } 429 return status; 430 } 431 432 433 / 434 //功 能:防冲撞 435 //参数说明: pSnr[OUT]:卡片序列号,4字节 436 //返 回: 成功返回MI_OK 437 / 438 char PcdAnticoll(INT8U *pSnr) 439 { 440 char status; 441 INT8U i,snr_check=0; 442 INT16U unLen; 443 INT8U ucComMF522Buf[MAXRLEN]; 444 445 446 ClearBitMask(Status2Reg,0x08); 447 WriteRawRC(BitFramingReg,0x00); 448 ClearBitMask(CollReg,0x80); 449 450 ucComMF522Buf[0] = PICC_ANTICOLL1; 451 ucComMF522Buf[1] = 0x20; 452 453 status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen); 454 455 if (status == MI_OK) 456 { 457 for (i=0; i<4; i++) 458 { 459 *(pSnr+i) = ucComMF522Buf[i]; 460 snr_check ^= ucComMF522Buf[i]; 461 } 462 if (snr_check != ucComMF522Buf[i]) 463 { 464 status = MI_ERR; 465 } 466 } 467 468 SetBitMask(CollReg,0x80); 469 return status; 470 } 471 472 / 473 //功 能:选定卡片 474 //参数说明: pSnr[IN]:卡片序列号,4字节 475 //返 回: 成功返回MI_OK 476 / 477 char PcdSelect(INT8U *pSnr) 478 { 479 char status; 480 INT8U i; 481 INT16U unLen; 482 INT8U ucComMF522Buf[MAXRLEN]; 483 484 ucComMF522Buf[0] = PICC_ANTICOLL1; 485 ucComMF522Buf[1] = 0x70; 486 ucComMF522Buf[6] = 0; 487 for (i=0; i<4; i++) 488 { 489 ucComMF522Buf[i+2] = *(pSnr+i); 490 ucComMF522Buf[6] ^= *(pSnr+i); 491 } 492 CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]); 493 494 ClearBitMask(Status2Reg,0x08); 495 496 status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen); 497 498 if ((status == MI_OK) && (unLen == 0x18)) 499 { 500 status = MI_OK; 501 } 502 else 503 { 504 status = MI_ERR; 505 } 506 507 return status; 508 } 509 / 510 //功 能:验证卡片密码 511 //参数说明: auth_mode[IN]: 密码验证模式 512 // 0x60 = 验证A密钥 513 // 0x61 = 验证B密钥 514 // addr[IN]:块地址 515 // pKey[IN]:密码 516 // pSnr[IN]:卡片序列号,4字节 517 //返 回: 成功返回MI_OK 518 / 519 char PcdAuthState(INT8U auth_mode,INT8U addr,INT8U *pKey,INT8U *pSnr) 520 { 521 char status; 522 INT16U unLen; 523 INT8U ucComMF522Buf[MAXRLEN]; 524 525 ucComMF522Buf[0] = auth_mode; 526 ucComMF522Buf[1] = addr; 527 memcpy(&ucComMF522Buf[2], pKey, 6); 528 memcpy(&ucComMF522Buf[8], pSnr, 6); 529 530 status = PcdComMF522(PCD_AUTHENT,ucComMF522Buf,12,ucComMF522Buf,&unLen); 531 if ((status != MI_OK) || (!(ReadRawRC(Status2Reg) & 0x08))) 532 { 533 status = MI_ERR; 534 } 535 536 return status; 537 } 538 539 / 540 //功 能:读取M1卡一块数据 541 //参数说明: addr[IN]:块地址 542 // pData[OUT]:读出的数据,16字节 543 //返 回: 成功返回MI_OK 544 / 545 char PcdRead(INT8U addr,INT8U *pData) 546 { 547 char status; 548 INT16U unLen; 549 INT8U ucComMF522Buf[MAXRLEN]; 550 551 ucComMF522Buf[0] = PICC_READ; 552 ucComMF522Buf[1] = addr; 553 CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]); 554 555 status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen); 556 if ((status == MI_OK) && (unLen == 0x90)) 557 { 558 memcpy(pData, ucComMF522Buf, 16); 559 } 560 else 561 { 562 status = MI_ERR; 563 } 564 565 return status; 566 } 567 568 / 569 //功 能:命令卡片进入休眠状态 570 //返 回: 成功返回MI_OK 571 / 572 char PcdHalt(void) 573 { 574 char status; 575 INT16U unLen; 576 INT8U ucComMF522Buf[MAXRLEN]; 577 578 ucComMF522Buf[0] = PICC_HALT; 579 ucComMF522Buf[1] = 0; 580 CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]); 581 582 status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen); 583 584 return MI_OK; 585 } 586 / 587 //功 能:复位RC522 588 //返 回: 成功返回MI_OK 589 / 590 char PcdReset(void) 591 { 592 SET_RC522RST; //rst 高电平 593 delay_ns(10); //10ns 594 CLR_RC522RST; //rst 低电平 595 delay_ns(10); //10ns 596 SET_RC522RST; //rst 高电平 597 delay_ns(10); //10ns 598 WriteRawRC(CommandReg,PCD_RESETPHASE); //复位 599 delay_ns(10); //10ns 600 601 WriteRawRC(ModeReg,0x3D); //和Mifare卡通讯,CRC初始值0x6363,SIGIN为低电平有效,无线模式 602 WriteRawRC(TReloadRegL,30); //高装入定时器 603 WriteRawRC(TReloadRegH,0); //低装入定时器 604 WriteRawRC(TModeReg,0x8D); //开启522,设置分频 605 WriteRawRC(TPrescalerReg,0x3E); //定时器当前值 606 607 WriteRawRC(TxAutoReg,0x40); //必须要(控制天线设置) 608 609 return MI_OK; 610 } 611 // 612 //设置RC632的工作方式 613 // 614 char M500PcdConfigISOType(INT8U type) 615 { 616 if (type == 'A') //ISO14443_A 617 { 618 ClearBitMask(Status2Reg,0x08); //接收器,发射器和数据模式检测器的状态位 619 WriteRawRC(ModeReg,0x3D); //定义发送和接受的常用模式 620 WriteRawRC(RxSelReg,0x86); //非接触方式,引脚保护为6个时钟 621 WriteRawRC(RFCfgReg,0x7F); //非接触的48dB的增益 622 WriteRawRC(TReloadRegL,30); //tmoLength);// TReloadVal = 'h6a =tmoLength(dec) 623 WriteRawRC(TReloadRegH,0); //定时器重装值 624 WriteRawRC(TModeReg,0x8D); //16位定时器重装值 625 WriteRawRC(TPrescalerReg,0x3E); //定义内部定时器重装值 626 delay_ns(1000); 627 PcdAntennaOn(); //设置天线开启设置(间隔1ms) 628 } 629 else{ return -1; } 630 631 return MI_OK; 632 } 633 / 634 //开启天线 635 //每次启动或关闭天险发射之间应至少有1ms的间隔 636 / 637 void PcdAntennaOn(void) 638 { 639 INT8U i; 640 i = ReadRawRC(TxControlReg); 641 if (!(i & 0x03)) 642 { 643 SetBitMask(TxControlReg, 0x03); 644 } 645 } 646 / 647 //关闭天线 648 / 649 void PcdAntennaOff(void) 650 { 651 ClearBitMask(TxControlReg, 0x03); 652 } 653 654 //// 655 //初始化gpio 656 //int spi_cs =0; //片选 657 //int spi_ck =1; // 时钟信号,由主器件产生 658 //int spi_mosi =2; //主器件数据输出,从器件数据输入 659 //int spi_miso =3; //主器件数据输入,从器件数据输出 660 //int spi_rst =4; //复位低电平有效(1开始) 661 //// 662 /**/ 663 void init_gpio_rc522(void) 664 { 665 wiringPi(0,0); //初始化wiringPi库 666 GPIO_init(spi_cs,1,2,0); //输出,下拉,无调试 667 GPIO_init(spi_ck,1,2,0); //输出,下拉,无调试 668 GPIO_init(spi_mosi,1,2,0); //输出,下拉,无调试 669 GPIO_init(spi_miso,0,2,0); //输入,下拉,无调试 670 GPIO_init(spi_rst,1,2,0); //输出,下拉,无调试 671 } 672 673 void init_rc522(void) 674 { 675 init_gpio_rc522(); //树莓派gpio应用初始化 676 PcdReset(); //复位RC522 677 PcdAntennaOff(); //关闭天线 678 PcdAntennaOn(); //开启天线 679 M500PcdConfigISOType( 'A' ); //设置RC632的工作方式 680 } 681 682 #endif