零知平台上使用PN532进行读写卡操作NFC模块

下面我们使用在零知平台上使用PN532进行读写卡操作。

一、硬件连接:

PN532 零知-标准板
GND GND
VCC 3.3V
TXD 0
RXD 1

二、代码


							
  /**********************************************************
  *    文件: pn532-testing.ino      by 零知实验室([url]www.lingzhilab.com[/url])
  *    -^^- 零知开源,让电子制作变得更简单! -^^-
  *    时间: 2018/11/26 15:15
  *    说明: 
  ************************************************************/
    
  #define SerialNFC Serial1 //使用Serial1接口连接PN532  
    
  //#define DEBUG_PRINT //调试
        
  int8_t nfc_wakeUp();//唤醒操作
  int8_t nfc_scaning(uint8_t []);//寻卡操作
  int8_t nfc_vertify(int block, uint8_t key[], uint8_t uuid[]);//验证
  int8_t nfc_readBlock(int block, uint8_t *data); //读取某一个块 
  int8_t nfc_writeBlock(int block, uint8_t *data);//写入数据到某个块
        
  #define RECV_BUFF_LEN 255
  uint8_t recv_buff[RECV_BUFF_LEN] = {0};//NFC串口返回的数据
    
  void PrintHex(const uint8_t *data, const uint32_t numBytes)
  {
      for (uint8_t i = 0; i < numBytes; i++) {
          if (data[i] < 0x10) {
              Serial.print(" 0");
          } else {
              Serial.print(' ');
          }
          Serial.print(data[i], HEX);
      }
      Serial.println("");
  }
    
  // 复位或上电后运行一次:
  void setup() {
      //在这里加入初始化相关代码,只运行一次:
        
      Serial.begin(9600);
      SerialNFC.begin(115200);
        
      Serial.println("PN532 NFC HSU Mode");
        
      //唤醒
      if(nfc_wakeUp() == 0)
      {
          Serial.println("wake up success...");
      }else{
          Serial.println("wake up failed...");
            
          while(1);
      }
        
      uint8_t uuid[4] = {0};
      //开始寻卡
      Serial.println("scan...");
      if(nfc_scaning(uuid) == 0)
      {
                
          Serial.print("Fond card, UUID:");
          PrintHex(uuid,4);
      }else{
          Serial.println("No card found...");
          while(1);
      }
        
      uint8_t keys[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
      //验证:第7块
      if( nfc_vertify(7, keys, uuid) == 0)
      {
          Serial.println("verify ok");
      }else{
          Serial.println("verify failed");
            
          while(1);
      }
        
      //读取第6块数据
      uint8_t read_data[16] = {0};
      int block = 6;
      int8_t ret = nfc_readBlock(block, read_data);
        
      Serial.print("read  block ");Serial.print(block);
      if(ret == 0)
      {
          Serial.print(",data:");
          PrintHex(read_data,16);
      }
      else
      {
          Serial.println("error...");
      }
        
      //向第6块中写入数据
      uint8_t write_data[16] = {0};
      //写入数据为 0x10 ~ 0x1f
      for(int i=0; i<16;i++)
          write_data[i] = 0x10+i;
        
      ret = nfc_writeBlock(block,write_data);
      Serial.print("write block ");Serial.print(block);
      Serial.print(",data:");
      PrintHex(write_data,16);
        
      if(ret == 0)
      {
          Serial.println("    Write success...");
          memset(read_data,0,16);
          nfc_readBlock(block, read_data);
          Serial.print("read back  :");
          PrintHex(read_data,16);
      }else{
          Serial.println("write failed");
      }
  }
    
  //一直循环执行:
  void loop() {
      // 在这里加入主要程序代码,重复执行:
    
  }			
  
  
  

具体的实现代码如下


							
								
	#ifdef DEBUG_PRINT
	    #define DMSG(args...)       Serial.println(args)
	    #define DMSG_STR(str)       Serial.println(str)
	    #define DMSG_HEX(num)       Serial.println(num, HEX)
	    #define DMSG_INT(num)       Serial.println(num)
	#else
	    #define DMSG(args...)       
	    #define DMSG_STR(str)       
	    #define DMSG_HEX(num)       
	    #define DMSG_INT(num)       
	#endif
	  
	#define PN532_PREAMBLE                (0x00)
	#define PN532_STARTCODE1              (0x00)
	#define PN532_STARTCODE2              (0xFF)
	#define PN532_POSTAMBLE               (0x00)
	  
	#define PN532_HOSTTOPN532             (0xD4)
	#define PN532_PN532TOHOST             (0xD5)
	  
	#define PN532_ACK_WAIT_TIME           (10)  // ms, timeout of waiting for ACK
	  
	#define PN532_INVALID_ACK             (-1)
	#define PN532_TIMEOUT                 (-2)
	#define PN532_INVALID_FRAME           (-3)
	#define PN532_NO_SPACE                (-4)
	  
	uint8_t command;
	  
	int8_t writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen)
	{
	  
	    /** dump serial buffer */
	    if(SerialNFC.available()){
	        DMSG("Dump serial buffer: ");
	    }
	    while(SerialNFC.available()){
	        uint8_t ret = SerialNFC.read();
	        DMSG_HEX(ret);
	    }
	  
	    command = header[0];
	      
	    SerialNFC.write(PN532_PREAMBLE);
	    SerialNFC.write(PN532_STARTCODE1);
	    SerialNFC.write(PN532_STARTCODE2);
	      
	    uint8_t length = hlen + blen + 1;   // length of data field: TFI + DATA
	    SerialNFC.write(length);
	    SerialNFC.write(~length + 1);         // checksum of length
	      
	    SerialNFC.write(PN532_HOSTTOPN532);
	    uint8_t sum = PN532_HOSTTOPN532;    // sum of TFI + DATA
	  
	    DMSG("\nWrite: ");
	      
	    SerialNFC.write(header, hlen);
	    for (uint8_t i = 0; i < hlen; i++) {
	        sum += header[i];
	  
	        DMSG_HEX(header[i]);
	    }
	  
	    SerialNFC.write(body, blen);
	    for (uint8_t i = 0; i < blen; i++) {
	        sum += body[i];
	  
	        DMSG_HEX(body[i]);
	    }
	      
	    uint8_t checksum = ~sum + 1;            // checksum of TFI + DATA
	    SerialNFC.write(checksum);
	    SerialNFC.write(PN532_POSTAMBLE);
	  
	    return readAckFrame();
	}
	  
	int16_t readResponse(uint8_t buf[], uint8_t len, uint16_t timeout)
	{
	    uint8_t tmp[3];
	      
	    delay(100);
	      
	    DMSG("\nRead:  ");
	      
	    /** Frame Preamble and Start Code */
	    if(receive(tmp, 3, timeout)<=0){
	        return PN532_TIMEOUT;
	    }
	    if(0 != tmp[0] || 0!= tmp[1] || 0xFF != tmp[2]){
	        DMSG("Preamble error");
	        return PN532_INVALID_FRAME;
	    }
	      
	    /** receive length and check */
	    uint8_t length[2];
	    if(receive(length, 2, timeout) <= 0){
	        return PN532_TIMEOUT;
	    }
	    if( 0 != (uint8_t)(length[0] + length[1]) ){
	        DMSG("Length error");
	        return PN532_INVALID_FRAME;
	    }
	    length[0] -= 2;
	    if( length[0] > len){
	        return PN532_NO_SPACE;
	    }
	      
	    /** receive command byte */
	    uint8_t cmd = command + 1;               // response command
	    if(receive(tmp, 2, timeout) <= 0){
	        return PN532_TIMEOUT;
	    }
	    if( PN532_PN532TOHOST != tmp[0] || cmd != tmp[1]){
	        DMSG("Command error");
	        return PN532_INVALID_FRAME;
	    }
	      
	    if(receive(buf, length[0], timeout) != length[0]){
	        return PN532_TIMEOUT;
	    }
	    uint8_t sum = PN532_PN532TOHOST + cmd;
	    for(uint8_t i=0; i<length[0]; i++){
	        sum += buf[i];
	    }
	      
	    /** checksum and postamble */
	    if(receive(tmp, 2, timeout) <= 0){
	        return PN532_TIMEOUT;
	    }
	    if( 0 != (uint8_t)(sum + tmp[0]) || 0 != tmp[1] ){
	        DMSG("Checksum error");
	        return PN532_INVALID_FRAME;
	    }
	      
	    return length[0];
	}
	  
	int8_t readAckFrame()
	{
	    const uint8_t PN532_ACK[] = {0, 0, 0xFF, 0, 0xFF, 0};
	    uint8_t ackBuf[sizeof(PN532_ACK)];
	      
	    delay(100);
	      
	    DMSG("\nAck: ");
	      
	    if( receive(ackBuf, sizeof(PN532_ACK), PN532_ACK_WAIT_TIME) <= 0 ){
	        DMSG("Timeout\n");
	        return PN532_TIMEOUT;
	    }
	      
	    if( memcmp(ackBuf, PN532_ACK, sizeof(PN532_ACK)) ){
	        DMSG("Invalid\n");
	        return PN532_INVALID_ACK;
	    }
	    DMSG("OK\n");
	    return 0;
	}
	  
	/**
	    @brief receive data .
	    @param buf --> return value buffer.
	           len --> length expect to receive.
	           timeout --> time of reveiving
	    @retval number of received bytes, 0 means no data received.
	*/
	int8_t receive(uint8_t *buf, int len, uint16_t timeout)
	{
	  int read_bytes = 0;
	  int ret;
	  unsigned long start_millis;
	    
	  while (read_bytes < len) {
	  
	    start_millis = millis();
	    do {
	      ret = SerialNFC.read();
	      if (ret >= 0) {
	        break;
	     }
	     delay(10);
	    } while((timeout == 0) || ((millis()- start_millis ) < timeout));
	      
	    if (ret < 0) {
	        if(read_bytes){
	            return read_bytes;
	        }else{
	            return PN532_TIMEOUT;
	        }
	    }
	  
	    buf[read_bytes] = (uint8_t)ret;
	      
	    read_bytes++;
	      
	  }
	  return read_bytes;
	}
	  
	int8_t nfc_wakeUp()
	{
	    const uint8_t cmd_wake_up[] = {
	    0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xfd, 0xd4, 
	    0x14, 0x01, 0x17, 0x00};
	      
	    const uint8_t wake_up_resp[] = {0x00 ,0x00 ,0xFF ,0x00 ,0xFF ,
	        0x00 ,0x00 ,0x00 ,0xFF ,0x02 ,0xFE ,0xD5 ,0x15 ,0x16 ,0x00};
	      
	    for(int i=0; i<sizeof(cmd_wake_up); i++)
	    {
	        SerialNFC.write(cmd_wake_up[i]);
	    }
	      
	    int getLen = receive(recv_buff,15,1000);
	      
	    for(int i=0; i<getLen; i++)
	    {
	        if(wake_up_resp[i]!=recv_buff[i]){
	            return -1;
	        }
	    }
	      
	    return 0;
	  
	}
	  
	int8_t nfc_scaning(uint8_t uuid[])
	{
	          
	    uint8_t cmd_head[1] = {0x4a};
	    uint8_t cmd_body[2] = {0x02,0x00};
	    if(writeCommand(cmd_head, 1, cmd_body, 2) == 0)
	    {
	//      Serial.println("wr cmd ok");
	    }
	      
	    memset(recv_buff,0,RECV_BUFF_LEN);
	      
	    int8_t ret = 0;
	    if( (ret = readResponse(recv_buff, 13, 6000)) >=0)
	    {
	//      PrintHex(recv_buff,13);
	          
	        for(int i=0; i<4; i++)
	            uuid[i] = recv_buff[i+6];
	          
	        return 0;
	    }else{
	        return -1;
	    }
	}
	int8_t nfc_vertify(int block, uint8_t key[], uint8_t uuid[])
	{
	    //40 01 60 07 FF FF FF FF FF FF 90 1F 2A A4
	    uint8_t cmd_head[3] = {0x40,0x01,0x60};
	    uint8_t cmd_body[1+6+4] = {0};
	    cmd_body[0] = block;
	    for(int i=0; i<6; i++)
	    {
	        cmd_body[i+1] = key[i]; 
	    }
	    for(int i=0; i<4; i++)
	    {
	        cmd_body[i+7] = uuid[i];
	    }
	    if(writeCommand(cmd_head, 3, cmd_body, 11) == 0)
	    {
	//      Serial.println("wr cmd ok");
	    }
	      
	    memset(recv_buff,0,RECV_BUFF_LEN);
	    int8_t ret = readResponse(recv_buff, 1, 1000);
	    if(ret >= 0){
	        if(recv_buff[0] == 0x00)
	            return 0;
	          
	    }
	      
	    return -1;
	}
	int8_t nfc_readBlock(int block, uint8_t *data)
	{
	    uint8_t cmd_head[2] = {0x40,0x01};
	    uint8_t cmd_body[2] = {0x30, block};
	      
	    writeCommand(cmd_head, 2, cmd_body, 2);
	      
	    memset(recv_buff,0,RECV_BUFF_LEN);
	      
	    int ret = readResponse(recv_buff, 17, 1000);
	    if(ret >=0)
	    {
	        for(int i=0; i<ret; i++)
	        {
	            data[i] = recv_buff[i+1];
	        }
	          
	        return 0;
	    }else{
	        return -1;
	    }
	      
	//  Serial.println(ret);
	//  PrintHex(recv_buff, 17);
	}
	int8_t nfc_writeBlock(int block, uint8_t *data)
	{
	    uint8_t cmd_head[4] = {0x40,0x01,0xa0,block};
	    uint8_t cmd_body[16] = {0};
	      
	    for(int i=0; i<16; i++)
	        cmd_body[i] = data[i];
	      
	    writeCommand(cmd_head, 4, cmd_body, 16);
	      
	    memset(recv_buff,0,RECV_BUFF_LEN);
	      
	    int ret = readResponse(recv_buff, 1, 1000);
	    if(ret >=0)
	    {
	        if(recv_buff[0] == 0)
	            return 0;
	    }else{
	        return -1;
	    }
	}							
								
								
						
						

完整工程


pn532-testing.7z(点击下载)