[STM32F0] 基于STM32F030实现RFID射频识别

[复制链接]
4977|110
 楼主| 个百zz分点个 发表于 2022-9-29 15:43 | 显示全部楼层
int8_t Card_Find(uint8_t Findway, uint8_t *Cardtype)
{
RC522_ClearReg(Status2Reg, 0x08); // 该位表示MIFARE®Crypto1单元已打开,因此与该卡的所有数据通信都已加密
          RC522_WriteData(BitFramingReg, 0x07); // 不启动数据发送
          RC522_SetReg(TxControlReg, 0x03);// TX1、TX2输出信号将传递经发送数据调制的13.56MHz的能量载波信号。

          uint32_t OutLen;
          uint8_t RC522_DataBuffer[MAXRLEN] = {Findway}; // 将寻卡命令填入到数组
       
          int8_t status = RC522_CardCom(PCD_TRANSCEIVE, RC522_DataBuffer, 1, RC522_DataBuffer, &OutLen); // 发送命令并获取返回数据
       
          if((status == MI_OK) && (OutLen == 0x10)) // 状态正确,并且返回16位数据
          {   
         Cardtype[0] = RC522_DataBuffer[0]; // 获取卡类型
         Cardtype[1] = RC522_DataBuffer[1];
          }
        else
          {  
         status = MI_ERR;  
          }
          return status;
}
 楼主| 个百zz分点个 发表于 2022-9-29 15:43 | 显示全部楼层
在sensor_rfid.c文件中添加Card_Anticoll()函数,这个函数用于防冲突操作。防冲突操作就是将防冲突命令通过PcdComMF522()函数与PICC卡进行交互。防冲突命令是两个字节,其中第一字节为Mifare_One卡的防冲突命令字PICC_ANTICOLL1 (0x93),第二个字节为0x20。对于多个卡片同时进入有效区域的防冲突操作:由于是非接触式的,同一时间天线作用范围内可能不只一张卡时,即有多于一张的IC卡发回了卡序列号应答,则发生了冲突。函数如下
 楼主| 个百zz分点个 发表于 2022-9-29 15:44 | 显示全部楼层
  1. // 防冲撞       
  2. int8_t Card_Anticoll(uint8_t *card_sn)
  3. {
  4. // 该位表示MIFARE®Crypto1单元已打开,因此与该卡的所有数据通信都已加密
  5.     RC522_ClearReg(Status2Reg, 0x08);
  6. // 不启动数据发送,接收的LSB位存放在位0,接收到的第二位放在位1,定义发送的最后一个字节的位数为8
  7.     RC522_WriteData(BitFramingReg, 0x00);
  8. // 所有接收的位在冲突后将被清除。106kbit/s 有效。其他速率应该置1
  9.     RC522_ClearReg(CollReg, 0x80);
  10.     uint32_t OutLen;
  11.     uint8_t RC522_DataBuffer[MAXRLEN] = {0};

  12.     RC522_DataBuffer[0] = PICC_ANTICOLL1;        // 0x93表明串联级别1
  13.     RC522_DataBuffer[1] = 0x20; // 表明PCD发送字节数为整两个字节

  14.     int8_t status = RC522_CardCom(PCD_TRANSCEIVE, RC522_DataBuffer, 2, RC522_DataBuffer, &OutLen);

  15.     if(status == MI_OK)
  16.     {
  17. uint8_t sn_check = 0;
  18.        for(uint8_t i=0; i<4; i++)
  19.        {  
  20.           card_sn[i]  = RC522_DataBuffer[i];
  21.           sn_check ^= RC522_DataBuffer[i];
  22.        }
  23.        if(sn_check != RC522_DataBuffer[4]) // 返回四个字节,最后一个字节为校验位
  24.        {  
  25.           status = MI_ERR;
  26.        }
  27.     }
  28.     RC522_SetReg(CollReg, 0x80); // 关闭冲撞检测
  29.     return status;
  30. }
 楼主| 个百zz分点个 发表于 2022-9-29 15:45 | 显示全部楼层
在sensor_rfid.c文件中添加CalulateCRC()函数,实现用MF522计算CRC16
 楼主| 个百zz分点个 发表于 2022-9-29 15:45 | 显示全部楼层
  1. // 用MF522计算CRC16函数
  2. void CalulateCRC(uint8_t *Indata, uint8_t len, uint8_t *OutData)
  3. {
  4.     RC522_ClearReg(DivIrqReg, 0x04); // 清除CRC中断
  5.     RC522_WriteData(CommandReg, PCD_IDLE); // 进入IDLE模式
  6. RC522_SetReg(FIFOLevelReg, 0x80); // 清楚缓冲区
  7.                                
  8.     for (uint8_t i=0; i<len; i++)
  9.     {
  10.             RC522_WriteData(FIFODataReg, Indata[i]); // 写入FIFO
  11.         }
  12.         RC522_WriteData(CommandReg, PCD_CALCCRC); // 计算CRC模式
  13.        
  14.         for(uint8_t i = 0xFF; i>0; i--)
  15.         {
  16.             if(RC522_ReadData(DivIrqReg) & 0x04) // 等待CRC计算完成中断
  17.             {
  18.                 break;
  19.             }
  20.         }
  21.     OutData[0] = RC522_ReadData(CRCResultRegL); // 读CRC计算结果
  22.     OutData[1] = RC522_ReadData(CRCResultRegM);
  23. }
 楼主| 个百zz分点个 发表于 2022-9-29 15:46 | 显示全部楼层
在sensor_rfid.c文件中添加Card_Select()函数,实现选定卡片功能,函数实现方法与寻卡、防冲撞类似,向RF522寄存器发送数据并等待应答
  1. int8_t Card_Select(uint8_t *card_sn)
  2. {
  3.     uint8_t RC522_DataBuffer[MAXRLEN] = {0};
  4.    
  5.     RC522_DataBuffer[0] = PICC_ANTICOLL1; // 选卡命令
  6.     RC522_DataBuffer[1] = 0x70; // 表明PCD发送字节数为整7个字节
  7.                
  8.     for(uint8_t i=0; i<4; i++) // 卡ID(4字节)及校验位(1字节)
  9.     {
  10.                 RC522_DataBuffer[i+2] = card_sn[i];
  11.             RC522_DataBuffer[6] ^= card_sn[i];
  12.     }
  13.                
  14.     CalulateCRC(RC522_DataBuffer, 7, &RC522_DataBuffer[7]); // 计算CRC16
  15.   
  16.     RC522_ClearReg(Status2Reg, 0x08); // 该位表示MIFARE®Crypto1单元已打开,因此与该卡的所有数据通信都已加密
  17.                
  18.     uint32_t OutLen;
  19.     int8_t status = RC522_CardCom(PCD_TRANSCEIVE, RC522_DataBuffer, 9, RC522_DataBuffer, &OutLen); // 返回值共24位, 0x08 0xB6 0xDD
  20.    
  21.     if((status == MI_OK)&&(OutLen == 0x18))
  22.         {
  23.             status = MI_OK;
  24.         }
  25.     else
  26.         {
  27.             status = MI_ERR;
  28.         }               
  29.     return status;
  30. }
 楼主| 个百zz分点个 发表于 2022-9-29 15:47 | 显示全部楼层
在sensor_rfid.c文件中添加Card_Validation()函数,实现验证卡的密钥
 楼主| 个百zz分点个 发表于 2022-9-29 15:48 | 显示全部楼层
  1. int8_t Card_Validation(const uint8_t verifymode, const uint8_t address, const uint8_t *key, const uint8_t *cardseries)
  2. {
  3.     uint8_t RC522_DataBuffer[MAXRLEN] = {0};

  4.     RC522_DataBuffer[0] = verifymode; // 密码验证模式
  5.     RC522_DataBuffer[1] = address; //
  6.                
  7.     for (uint8_t i=0; i<6; i++)
  8.     {
  9.             RC522_DataBuffer[i+2] = key[i]; // 填入密码
  10.         }
  11.     for (uint8_t i=0; i<4; i++)
  12.     {
  13.             RC522_DataBuffer[i+8] = cardseries[i]; // 填入卡片序列号
  14.         }
  15.         uint32_t  OutLen;
  16.     int8_t status = RC522_CardCom(PCD_AUTHENT, RC522_DataBuffer, 12, RC522_DataBuffer, &OutLen);
  17.     if((status != MI_OK) || (!(RC522_ReadData(Status2Reg) & 0x08))) // 该位表示MIFARE®Crypto1单元已打开,因此与该卡的所有数据通信都已加密
  18.     {
  19.             status = MI_ERR;
  20.         }
  21.     return status;
  22. }
 楼主| 个百zz分点个 发表于 2022-9-29 15:48 | 显示全部楼层
在sensor_rfid.c文件中添加Card_Read()函数,实现读取卡中的数据
 楼主| 个百zz分点个 发表于 2022-9-29 15:49 | 显示全部楼层
  1. int8_t Card_Read(uint8_t address, uint8_t *Data)
  2. {
  3.     uint8_t RC522_DataBuffer[MAXRLEN] = {0};

  4.     RC522_DataBuffer[0] = PICC_READ;
  5.     RC522_DataBuffer[1] = address;
  6.     CalulateCRC(RC522_DataBuffer, 2, &RC522_DataBuffer[2]);
  7.    
  8.         uint32_t OutLen;
  9.     int8_t status = RC522_CardCom(PCD_TRANSCEIVE, RC522_DataBuffer, 4, RC522_DataBuffer, &OutLen);
  10.     if((status == MI_OK) && (OutLen == 0x90))
  11.     {
  12.         for (uint8_t i=0; i<16; i++)
  13.         {
  14.                 Data[i] = RC522_DataBuffer[i];
  15.             }
  16.     }
  17.     else
  18.     {
  19.             status = MI_ERR;
  20.         }   
  21.     return status;
  22. }
 楼主| 个百zz分点个 发表于 2022-9-29 15:50 | 显示全部楼层
在sensor_rfid.c文件中添加Card_Write()函数,实现写数据到IC卡

 楼主| 个百zz分点个 发表于 2022-9-29 15:51 | 显示全部楼层
int8_t Card_Write(uint8_t address, const uint8_t *Data)
{
        uint32_t OutLen;
        uint8_t RC522_DataBuffer[MAXRLEN] = {0};
       
        RC522_DataBuffer[0] = PICC_WRITE;
        RC522_DataBuffer[1] = address;
       
        CalulateCRC(RC522_DataBuffer, 2, &RC522_DataBuffer[2]);

        int8_t status = RC522_CardCom(PCD_TRANSCEIVE, RC522_DataBuffer, 4, RC522_DataBuffer, &OutLen);

        if((status != MI_OK) || (OutLen != 4) || ((RC522_DataBuffer[0] & 0x0F) != 0x0A))
        {   
            status = MI_ERR;
        }
                       
        if(status == MI_OK)
        {
            for(uint8_t i=0; i<16; i++)
            {
                RC522_DataBuffer[i] = Data[i];
            }
               
            CalulateCRC(RC522_DataBuffer, 16, &RC522_DataBuffer[16]);

            status = RC522_CardCom(PCD_TRANSCEIVE, RC522_DataBuffer, 18, RC522_DataBuffer, &OutLen);
            if((status != MI_OK) || (OutLen != 4) || ((RC522_DataBuffer[0] & 0x0F) != 0x0A))
            {   
                status = MI_ERR;
            }
        }
        return status;
}
 楼主| 个百zz分点个 发表于 2022-9-29 15:52 | 显示全部楼层
在sensor_rfid.c文件中添加RC522_Read_ID()函数,这个函数用于识别IC卡的ID。函数中首先调用PcdRequest()实现寻卡操作,然后调用PcdAnticoll()函数进行防冲撞并将卡ID存储到Card_ID,最后返回状态

 楼主| 个百zz分点个 发表于 2022-9-29 15:53 | 显示全部楼层
  1. // 读ID函数
  2. int8_t RC522_Read_ID(uint8_t *Card_ID)
  3. {
  4.         int8_t status = 0;
  5.         uint8_t count = CARD_INIT_RETRY_COUNT;
  6.         while(Card_Find(PICC_REQALL, Card_ID) != MI_OK && --count);
  7.         if(count==0) status = MI_FIND_ERR;
  8.         count = CARD_INIT_RETRY_COUNT;
  9.         while(Card_Anticoll(Card_ID) != MI_OK && --count);
  10.         if(count==0) status = MI_ANTICOLL_ERR;
  11.         return status;
  12. }
 楼主| 个百zz分点个 发表于 2022-9-29 15:53 | 显示全部楼层
在sensor_rfid.c文件中添加Card_Adjust()函数,实现数据块的自增自减功能
 楼主| 个百zz分点个 发表于 2022-9-29 15:54 | 显示全部楼层
int8_t Card_Adjust(uint8_t Command, uint8_t block_num, uint32_t value)
{
uint32_t OutLen;
          uint8_t RC522_DataBuffer[MAXRLEN] = {0};
  
          RC522_DataBuffer[0] = Command;
          RC522_DataBuffer[1] = block_num;
          CalulateCRC(RC522_DataBuffer, 2, &RC522_DataBuffer[2]);

        // 写入命令和地址
          int8_t status = RC522_CardCom(PCD_TRANSCEIVE, RC522_DataBuffer, 4, RC522_DataBuffer, &OutLen);

          if((status != MI_OK) || (OutLen != 4) || ((RC522_DataBuffer[0] & 0x0F) != 0x0A))
          {
            status = MI_ERR;
          }
      
          if(status == MI_OK)
          {
            RC522_DataBuffer[0] = ((uint8_t*)&value)[0];
            RC522_DataBuffer[1] = ((uint8_t*)&value)[1];
            RC522_DataBuffer[2] = ((uint8_t*)&value)[2];
            RC522_DataBuffer[3] = ((uint8_t*)&value)[3];
            CalulateCRC(RC522_DataBuffer, 4, &RC522_DataBuffer[4]);
            OutLen = 0;
            status = RC522_CardCom(PCD_TRANSCEIVE, RC522_DataBuffer, 6, RC522_DataBuffer, &OutLen);
            if(status != MI_ERR)
            {
                status = MI_OK;   
            }
                       
            if(status == MI_OK)
            {
                RC522_DataBuffer[0] = PICC_TRANSFER; // 保存缓冲区数据
                RC522_DataBuffer[1] = block_num;
                CalulateCRC(RC522_DataBuffer, 2, &RC522_DataBuffer[2]);
               
                status = RC522_CardCom(PCD_TRANSCEIVE, RC522_DataBuffer, 4, RC522_DataBuffer, &OutLen);
       
                if ((status != MI_OK) || (OutLen != 4) ||((RC522_DataBuffer[0] & 0x0F) != 0x0A))
                {  
                    status = MI_ERR;
                }
            }
  }
     return status;
}
 楼主| 个百zz分点个 发表于 2022-9-29 15:55 | 显示全部楼层
在sensor_rfid.c文件中添加Card_Init()函数,实现寻卡、防冲撞、选卡以及验证密钥

 楼主| 个百zz分点个 发表于 2022-9-29 15:57 | 显示全部楼层
// 寻卡 防冲撞  选卡 验证密钥
static int8_t Card_Init(const uint8_t block_num, const uint8_t* passwd)
{       
        uint8_t Data_Buffer[4] = {0};
        uint8_t count = CARD_INIT_RETRY_COUNT;
        while(Card_Find(PICC_REQALL, Data_Buffer) != MI_OK && --count);
        if(count==0) return MI_FIND_ERR;
        count = CARD_INIT_RETRY_COUNT;
        while(Card_Anticoll(Data_Buffer) != MI_OK && --count);
        if(count==0) return MI_ANTICOLL_ERR;
        count = CARD_INIT_RETRY_COUNT;
        while(Card_Select(Data_Buffer) != MI_OK && --count);
        if(count==0) return MI_SELECT_ERR;
        count = CARD_INIT_RETRY_COUNT;
        while(Card_Validation(PICC_AUTHENT1A, block_num / 4 * 4 + 3, passwd, Data_Buffer) != MI_OK && --count);
        if(count==0) return MI_VALIDATION_ERR;
        return MI_OK;
}
 楼主| 个百zz分点个 发表于 2022-9-29 15:59 | 显示全部楼层
在sensor_rfid.c文件中添加RFID_Write()函数,实现向卡中写入数据。函数首先调用Card_Init()实现寻卡、防冲撞、选卡以及验证密钥,然后调用RFID_Write()函数实现写数据功能
 楼主| 个百zz分点个 发表于 2022-9-29 16:02 | 显示全部楼层
int8_t RFID_Write(const uint8_t block_num, const uint8_t* passwd, const uint8_t* buffer)
{       
        if(block_num < 1 || block_num > 63 || block_num % 4 == 3)
        {
            return MI_PARAM_ERR;
        }
        int8_t state = Card_Init(block_num, passwd);
        if(state != MI_OK)
        {
            return state;
        }
        return Card_Write(block_num, buffer);
}
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部