wenbo2005.online

学习记录 / STM32

关于 RFID

STM322024-09-17

关于RFID

说明:

1、16个扇区(015),64个块(063),其中每个扇区有4个块(块0~块3),所以16x4=64块。

2、每个扇区的第0块至第2块为数据块(其中第0扇区的第0块为无效块(卡片生产的时候已固定),第3块为密钥地址。

3、根据扇区与块地址关系表得到块地址与密钥地址的计算:

4、例如:求第12扇区第1块的块地址和密钥地址:

块地址为:(4x12)+1=49

密钥地址为:(4x12)+3=51

非加密卡和加密卡的区别就是,非加密卡中所有扇区的KEYA和KEYB数值都是默认值FFFFFFFFFFFF;而加密卡中,其中有扇区的KEYA和KEYB不等于FFFFFFFFFFFF,部分扇区加密的卡称半加密卡,所有扇区都加密的卡称全加密卡

//=================================================================================

#include <stdio.h>
#include <string.h>
#include "RC522.h"

uint8_t readUid[5];                     //卡号
uint8_t CT[3];                         //卡类型
uint8_t DATA[16];                    //存放数据

uint8_t KEY_A[6]= {0xff,0xff,0xff,0xff,0xff,0xff};
uint8_t KEY_B[6]= {0xff,0xff,0xff,0xff,0xff,0xff};//非加密卡密钥

uint8_t NUM = 1;
uint8_t num = 0;
uint8_t status;
uint8_t addr ;                             // (4 * NUM ) + num       NUM: 扇区(0~15)  num: 块(0~3)

uint8_t myDATA[16];

MFRC_Init();
PCD_Reset();

uint32_t rfid_time=0;
void Cardcompare()
{
    if(uwTick - rfid_time<200) return;
    rfid_time = uwTick;

    uint8_t i;
    addr =  (4 * NUM) + num ;//

    status = PCD_Request(0x52, CT);                        //找到卡返回0
    if(!status)  //寻卡成功
    {
            status = PCD_ERR;
            status = PCD_Anticoll(readUid);//防冲撞
    }
    if(!status) //防冲撞成功
    {
        status = PCD_ERR;
        printf("卡的类型为:%x%x%x\r\n",CT[0],CT[1],CT[2]); //读取卡的类型 //读取卡的类型
        printf("卡号:%x-%x-%x-%x\r\n",readUid[0],readUid[1],readUid[2],readUid[3]);
        HAL_Delay(800);
        status=PCD_Select(readUid);
    }
    if(!status) //选卡成功
    {
        status = PCD_ERR;
        // 验证A密钥 块地址 密码 SN
        status = PCD_AuthState(0x60, addr, KEY_A, readUid);
        if(status == PCD_OK)//验证A成功
            printf("A密钥验证成功\r\n");
        else
            printf("A密钥验证失败\r\n");
        HAL_Delay(500);  
        // 验证B密钥 块地址 密码 SN  
        status = PCD_AuthState(0x61, addr, KEY_B, readUid);
        if(status == PCD_OK)//验证B成功
            printf("B密钥验证成功\r\n");
        else
            printf("B密钥验证失败\r\n");  
    }
    HAL_Delay(500);
    if(status == PCD_OK)//验证密码成功,接着读取0块
    {
        status = PCD_ERR;
        status = PCD_ReadBlock(addr, DATA);
        //PCD_WriteBlock(addr,myDATA);//写
        if(status == PCD_OK)//读卡成功
        {
             printf("%d扇区%d块DATA:",NUM,num);

             for(i = 0; i < 16; i++)
             {
                printf("%02x", DATA[i]);
             }
             printf("\r\n");  
        }
        else
         printf("读卡失败\r\n");
    }
    HAL_Delay(500);
}

//=================================================== 改进读写函数===============================================

//My_ReadBlock 函数用于读取某扇区的某块数据
/*
* BlockAddr : 地址 (4 * NUM ) + num       NUM: 扇区(0~15)  num: 块(0~3)
* *Data:储存数组
* num:需要读取几位数据,等于数组大小
* return: 返回1表示成功,2表示失败
*/
uint8_t My_ReadBlock(uint8_t BlockAddr, uint8_t *Data,uint8_t num)
{
    uint16_t unLen;
    uint8_t i, CmdFrameBuf[num+2];

    CmdFrameBuf[0] = PICC_READ;
    CmdFrameBuf[1] = BlockAddr;
    MFRC_CalulateCRC(CmdFrameBuf, 2, &CmdFrameBuf[2]);

    status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 4, CmdFrameBuf, &unLen);
    if((status == PCD_OK) && (unLen == 0x90))
    {
        for(i = 0; i < num; i++)
        {
            *(Data + i) = CmdFrameBuf[i];
        }
    }
    else
    {
        return 2;
    }
    return 1;
}

//My_ReadBlock 函数用于写入某扇区的某块数据
/*
* BlockAddr : 地址 (4 * NUM ) + num       NUM: 扇区(0~15)  num: 块(0~3)
* *Data:写入的数组
* num:需要写入几位数据,等于数组大小
*/
void My_WriteBlock(uint8_t BlockAddr, uint8_t *pData,uint8_t num)
{
    uint16_t unLen;
    uint8_t i, CmdFrameBuf[MFRC_MAXRLEN];

    CmdFrameBuf[0] = PICC_WRITE;
    CmdFrameBuf[1] = BlockAddr;
    MFRC_CalulateCRC(CmdFrameBuf, 2, &CmdFrameBuf[2]);
    status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 4, CmdFrameBuf, &unLen);
    if((status != PCD_OK) || (unLen != 4) || ((CmdFrameBuf[0] & 0x0F) != 0x0A))
    {
        status = PCD_ERR;
    }

    if(status == PCD_OK)
    {
        for(i = 0; i < num; i++)
        {
            CmdFrameBuf[i] = *(pData + i);
        }
        MFRC_CalulateCRC(CmdFrameBuf, 16, &CmdFrameBuf[16]);

        status = MFRC_CmdFrame(MFRC_TRANSCEIVE, CmdFrameBuf, 18, CmdFrameBuf, &unLen);

        if((status != PCD_OK) || (unLen != 4) || ((CmdFrameBuf[0] & 0x0F) != 0x0A))
        {
            status = PCD_ERR;
        }
    }
}