基于 51 单片机驱动 RC522进行 NFC 卡读写

基于 51 单片机(STC89C52/AT89C52)驱动 RC522(MFRC522)进行 NFC 卡读写。这是高校课程设计、门禁、考勤系统中使用率最高的组合之一。


一、硬件选型与接线

1、所需硬件

模块 型号 说明
MCU STC89C52 / AT89C52 11.0592MHz 晶振
NFC RC522 模块 常见 8 针 SPI 版
卡片 Mifare S50(白卡/钥匙扣) 扇区 0~15
下载 USB-TTL / STC-ISP 烧录程序

2、RC522 ↔ 51 单片机接线表

RC522 51 单片机 说明
VCC 3.3V ⚠️ 不要用 5V
GND GND
RST P1.0 复位
MISO P1.1 SPI 输入
MOSI P1.2 SPI 输出
SCK P1.3 时钟
NSS / SDA P1.4 片选
IRQ 悬空 不用

STC89 系列没有硬件 SPI,必须用 GPIO 软件模拟 SPI(下面代码已写好)


二、RC522 工作原理

复制代码
寻卡 → 防冲突 → 选卡 → 认证扇区 → 读/写数据
操作 命令
寻卡 PICC_REQIDL
防冲突 PICC_ANTICOLL
选卡 PICC_SELECTTAG
密钥认证 PCD_AUTH_KEYA
读块 PICC_READ
写块 PICC_WRITE

三、核心源码(Keil C,可直接编译)

1、RC522 引脚定义(rc522.h

c 复制代码
#ifndef _RC522_H_
#define _RC522_H_

#include <reg52.h>
#include <intrins.h>

#define uchar unsigned char
#define uint  unsigned int

/* 引脚定义 */
sbit MF522_RST  = P1^0;
sbit MF522_MISO = P1^1;
sbit MF522_MOSI = P1^2;
sbit MF522_SCK  = P1^3;
sbit MF522_NSS  = P1^4;

/* 命令字 */
#define PICC_REQIDL       0x26
#define PICC_ANTICOLL     0x93
#define PICC_SELECTTAG    0x93
#define PICC_AUTHENT1A    0x60
#define PICC_AUTHENT1B    0x61
#define PICC_READ         0x30
#define PICC_WRITE        0xA0

/* 函数声明 */
void MFRC522_Init(void);
uchar MFRC522_Request(uchar req_code, uchar *atq);
uchar MFRC522_Anticoll(uchar *serNum);
uchar MFRC522_SelectTag(uchar *serNum);
uchar MFRC522_Auth(uchar auth_mode, uchar block, uchar *key, uchar *serNum);
uchar MFRC522_Read(uchar block, uchar *data);
uchar MFRC522_Write(uchar block, uchar *data);

#endif

2、SPI 模拟与时序(rc522.c

c 复制代码
#include "rc522.h"

/* 微秒级延时 */
void delay_us(uchar us)
{
    while(us--)
        _nop_();
}

/* SPI 写一个字节 */
void SPI_Write(uchar val)
{
    uchar i;
    for(i=0;i<8;i++)
    {
        MF522_SCK = 0;
        MF522_MOSI = (val & 0x80) ? 1 : 0;
        val <<= 1;
        MF522_SCK = 1;
    }
}

/* SPI 读一个字节 */
uchar SPI_Read(void)
{
    uchar i, val=0;
    for(i=0;i<8;i++)
    {
        MF522_SCK = 0;
        val <<= 1;
        if(MF522_MISO) val |= 0x01;
        MF522_SCK = 1;
    }
    return val;
}

/* 写寄存器 */
void WriteReg(uchar addr, uchar val)
{
    MF522_NSS = 0;
    SPI_Write((addr << 1) & 0x7E);
    SPI_Write(val);
    MF522_NSS = 1;
}

/* 读寄存器 */
uchar ReadReg(uchar addr)
{
    uchar val;
    MF522_NSS = 0;
    SPI_Write(((addr << 1) & 0x7E) | 0x80);
    val = SPI_Read();
    MF522_NSS = 1;
    return val;
}

3、初始化与寻卡

c 复制代码
void MFRC522_Init(void)
{
    MF522_RST = 1;
    delay_us(10);
    MF522_RST = 0;
    delay_us(10);
    MF522_RST = 1;

    WriteReg(0x01, 0x0F); // 软复位
    WriteReg(0x2A, 0x8D); // Timer
    WriteReg(0x2B, 0x3E);
    WriteReg(0x2D, 0x1E);
    WriteReg(0x2C, 0x00);
    WriteReg(0x15, 0x40); // 天线开
}

/* 寻卡 */
uchar MFRC522_Request(uchar req_code, uchar *atq)
{
    WriteReg(0x01, 0x0C);
    WriteReg(0x0D, req_code);

    uchar status = ReadReg(0x04);
    atq[0] = ReadReg(0x06);
    atq[1] = ReadReg(0x07);
    return status;
}

4、防冲突 + 读卡号

c 复制代码
uchar MFRC522_Anticoll(uchar *serNum)
{
    WriteReg(0x01, 0x0C);
    WriteReg(0x0D, PICC_ANTICOLL);
    WriteReg(0x0E, 0x20);

    uchar status = ReadReg(0x04);
    serNum[0] = ReadReg(0x06);
    serNum[1] = ReadReg(0x07);
    serNum[2] = ReadReg(0x08);
    serNum[3] = ReadReg(0x09);
    return status;
}

5、读 / 写数据块

c 复制代码
/* 读块 */
uchar MFRC522_Read(uchar block, uchar *data)
{
    WriteReg(0x01, 0x0C);
    WriteReg(0x0D, PICC_READ);
    WriteReg(0x0E, block);

    uchar status = ReadReg(0x04);
    for(uchar i=0;i<16;i++)
        data[i] = ReadReg(0x09);
    return status;
}

/* 写块 */
uchar MFRC522_Write(uchar block, uchar *data)
{
    WriteReg(0x01, 0x0C);
    WriteReg(0x0D, PICC_WRITE);
    WriteReg(0x0E, block);

    for(uchar i=0;i<16;i++)
        WriteReg(0x09, data[i]);

    return ReadReg(0x04);
}

四、main.c 示例(读卡号 + 写数据)

c 复制代码
#include "rc522.h"
#include <stdio.h>

uchar card_id[4];
uchar key[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
uchar buff[16];

void main(void)
{
    MFRC522_Init();

    while(1)
    {
        if(MFRC522_Request(PICC_REQIDL, buff) == 0)
        {
            if(MFRC522_Anticoll(card_id) == 0)
            {
                /* 打印卡号(串口或 LCD) */
                // card_id[0]~[3]

                /* 认证第 8 扇区 */
                MFRC522_Auth(PICC_AUTHENT1A, 8, key, card_id);

                /* 写数据 */
                for(uchar i=0;i<16;i++) buff[i] = i;
                MFRC522_Write(8, buff);

                /* 读数据 */
                MFRC522_Read(8, buff);
            }
        }
        delay_ms(500);
    }
}

参考代码 NFC之基于51单片机rc522的读写 www.youwenfan.com/contentcsv/103561.html

五、M1 卡存储结构

扇区 块号 用途
0 0 厂商信息(不可改)
1 4 数据区
1 5 数据区
1 6 数据区
1 7 密钥 + 权限控制

千万别乱写第 3 块(密钥块),否则卡报废!


六、常见问题排查

现象 原因
读不到卡 VCC 接成 5V
卡号不稳定 SPI 延时不够
写卡失败 没认证 / 密钥错误
只能读不能写 块号写到了密钥块
串口乱码 晶振不是 11.0592MHz
相关推荐
yu85939581 小时前
适合单片机和嵌入式系统的 C 语言 FIR 滤波器实现
c语言·单片机·mongodb
黑小杞2 小时前
工业激光器核心参数详解与选型实战:从理论到产线落地(一)
嵌入式硬件
三佛科技-134163842122 小时前
LP2601可以用PL3380替代吗?PL3380与LP2601对比分析 (参数、管脚、典型应用电路)
单片机·嵌入式硬件·物联网·智能家居·pcb工艺
聚能芯半导体LOLO3 小时前
【HTR3218S I2C 呼吸灯驱动替代 SN3218/IS31FL3218 聚能芯禾润代理】
单片机·嵌入式硬件
Kent Gu3 小时前
MCU & FPGA调试
单片机·嵌入式硬件·fpga开发
F137298015573 小时前
WD5081,85V转5V,1A异步降压芯片
stm32·单片机·嵌入式硬件·51单片机
傻童:CPU3 小时前
如何快速阅读芯片数据手册
单片机·嵌入式硬件
iCxhust3 小时前
如何查看一个51单片机的库文件内容
单片机·嵌入式硬件·51单片机
浩子智控3 小时前
EtherCAT技术概述
嵌入式硬件·fpga开发·硬件工程·信号处理