NFC 学习笔记 5 MFRC522读写器2 NDEF

news2024/12/24 3:00:29

NDEF简介

NDEF(NFC Data Exchange Format)是一种标准化的数据格式,用于将数据存储在NFC标签或智能手机中。该格式是NFC论坛定义的,目的是在不同的NFC设备之间交换信息。 NDEF格式可以存储各种类型的数据,例如URL、文本、电话号码和地理位置等。 NFC设备可以读取和写入NDEF格式的数据,这使得NFC成为了在无线场景中实现简单、快捷数据传输的理想选择。 除了标准的NDEF格式外,还有其他类似的格式,例如NFC Forum Type 1-5格式和MIFARE格式,它们也可以用于存储和交换数据。NDEF标准的出现,使得不同类型的NFC设备之间的数据交换更加简单,也为应用开发者提供了更加简单、可靠的NFC数据传输方式。

NFC Forum Type 1-5格式是由NFC Forum组织定义的一组标准化的标签数据格式。与NDEF格式相似,这些格式可以用于存储各种类型的数据,并可以在不同类型的NFC设备之间交换信息。不同的NFC Forum Type格式具有不同的存储容量和数据传输速度,但它们都采用了类似的数据格式和协议。

MIFARE格式是一种由NXP Semiconductors公司开发的标签数据格式。与NFC Forum Type和NDEF格式不同,MIFARE格式通常用于存储和传输经过安全加密的数据,例如支付信息和门禁认证信息等。MIFARE标签还具备访问控制和安全管理功能,能够保护存储在标签中的敏感信息不被未经授权的第三方访问和篡改。

arduino平台源码

源码:https://github.com/461911662/NDEF

模块关系梳理

mindmaster

demo学习

1.CleanTag

描述:清除标签到工厂模式。
主要流程:

1.初始化串口、SPI、MFRC522、NFC适配器
2.循坏查找,寻选卡片后,清除标签到工厂模式

关键函数:

NfcAdapter nfc = NfcAdapter(&mfrc522)
// 使用MFRC522构造一个nfc适配器,因为NFC功能是基于MFRC522模块实现的。
// nfc适配器的内部函数如下:
NfcAdapter::NfcAdapter(MFRC522 *interface)
{
// NFC适配器最终使用shield去访问NFC卡片
    shield = interface;
}
nfc.tagPresent()
// tagPresent 是对寻卡和选卡的封装
bool NfcAdapter::tagPresent()
{
    // If tag has already been authenticated nothing else will work until we stop crypto (shouldn't hurt)
    shield->PCD_StopCrypto1();

    if(!(shield->PICC_IsNewCardPresent() && shield->PICC_ReadCardSerial()))
    {
        return false;
    }

    MFRC522::PICC_Type piccType = shield->PICC_GetType(shield->uid.sak);
    return ((piccType == MFRC522::PICC_TYPE_MIFARE_1K) || (piccType == MFRC522::PICC_TYPE_MIFARE_UL));
}
bool success = nfc.clean()
// clean原理是构造一个MifareClassic实例,分别将数据块和控制块格式化成指定格式
byte emptyBlock[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
byte authBlock[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
2.EraseTag

描述:擦除tag就是写一个空的NDEF消息。
主要流程:

1.初始化串口、SPI、MFRC522、NFC适配器
2.循坏查找,寻选卡片后,对卡片进行擦除

关键函数:

bool success = nfc.erase()
// 该函数实现了对nfc卡片信息的擦除功能。
// 主要有以下流程:
// 1.构造NdefMessage实例
// 2.向NdefMessage实例中添加一个空的NdefRecord
// 3.写NdefMessage打开卡片
bool NfcAdapter::erase()
{
    NdefMessage message = NdefMessage();
    message.addEmptyRecord();
    return write(message);
}
// write函数最终会构造MifareClassic实例去写NDEF消息
MifareClassic mifareClassic = MifareClassic(shield);
return mifareClassic.write(ndefMessage);
// 1.MifareClassic实例首先会将NDEF消息进行编码成字节流
// 2.NDEF消息实例会遍历自己的record,然后调用NdefRecord::encode去编码字节流
// 3.然后以TLV+0xFE数据封装
// 4.最后将封装的数据依次写道卡片的数据块中
3.FormatTag

描述:将一个Mifare卡格式化成一个NDEF卡。
主要流程:

1.初始化串口、SPI、MFRC522、NFC适配器
2.循坏查找,寻选卡片后,对卡片进行格式化

关键函数:

bool success = nfc.format()
// 格式化的实现也是构造MifareClassic实例,通过MifareClassic来对卡进行格式化
MifareClassic mifareClassic = MifareClassic(shield)
mifareClassic.formatNDEF()
// 1.将第一个扇区的block1、block2、block3设置成如下数据
byte blockbuffer1[16] = {0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
byte blockbuffer2[16] = {0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
byte blockbuffer3[16] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
// 2.其他扇区控制块设置为如下数据
byte blockbuffer4[16] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
// 3.数据块设置成空 empty NDEF TLV 03 00 FE
byte emptyNdefMesg[16] = {0x03, 0x03, 0xD0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
4.ReadTag

描述:展示将 Mifare Classic 标签格式化为 NDEF 标签后的内容。
主要流程:

1.初始化串口、SPI、MFRC522、NFC适配器
2.循坏查找,寻选卡片后,读取卡片内容,然后使用串口打印出来

关键函数:

NfcTag tag = nfc.read()
// 读卡的实现也是构造MifareClassic实例,通过MifareClassic来读取卡标签的
// 读取卡片的过程就是对NDEF数据进行解码的过程
// 1.首先需要找到TLV的开始字节0x3,然后获取message的大小
// 2.然后循环从数据块中读取NDEF数据
// 3.最后构造NfcTag实例,准备对NDEF进行操作
tag.print()
// NfcTag调用自己的方法打印NDEF信息
// 接着会调用NdefMessage::print
// 最终调用NdefRecord::print打印record信息
5.ReadTagExtended

描述:这个例子是对ReadTag的扩展。
主要流程:

1.初始化串口、SPI、MFRC522、NFC适配器
2.循坏查找,寻选卡片后,读取卡片内容
3.判断当前卡片有NDEF消息
4.遍历打印NDEF消息的record内容

关键函数:

tag.hasNdefMessage()
boolean NfcTag::hasNdefMessage()
{
    return (_ndefMessage != NULL);
}
NdefMessage message = tag.getNdefMessage()
NdefMessage NfcTag::getNdefMessage()
{
    return *_ndefMessage;
}
int recordCount = message.getRecordCount()
uint8_t NdefMessage::getRecordCount()
{
    return _recordCount;
}
6.WriteTag

描述:这个例子是对ReadTag的扩展。
主要流程:

1.初始化串口、SPI、MFRC522、NFC适配器
2.循坏查找,寻选卡片
3.构造NdefMessage实例
4.在NdefMessage实例中添加一个URL的record
5.将NdefMessage内容写到M卡片中

关键函数:

message.addUriRecord("https://arduino.cc")
void NdefMessage::addUriRecord(const char *uri)
{
    NdefRecord r;
    r.setTnf(NdefRecord::TNF_WELL_KNOWN);

    uint8_t RTD_URI[] = { NdefRecord::RTD_URI };
    r.setType(RTD_URI, sizeof(RTD_URI));

    size_t uriLength = strlen(uri);

    byte header[] = {0x00};

    r.setPayload(header, sizeof(header), (byte *)uri, uriLength);

    addRecord(r);
}
bool NdefMessage::addRecord(NdefRecord &record)
{

    if (_recordCount < MAX_NDEF_RECORDS)
    {
        _records[_recordCount] = new NdefRecord(record);
        _recordCount++;
        return true;
    }
    ...
}
7.WriteTagMultipleRecords

描述:这个例子是对ReadTag的扩展。
主要流程:

1.初始化串口、SPI、MFRC522、NFC适配器
2.循坏查找,寻选卡片
3.构造NdefMessage实例
4.在NdefMessage实例中添加一个URL的record
5.将NdefMessage内容写到M卡片中

关键函数:

void loop() {
    if (nfc.tagPresent()) {
        Serial.println("Writing multiple records to NFC tag");
        NdefMessage message = NdefMessage();
        message.addTextRecord("Hello, Arduino!");
        message.addUriRecord("https://arduino.cc");
        message.addTextRecord("Goodbye, Arduino!");
        boolean success = nfc.write(message);
        if (success) {
            Serial.println("\tSuccess. Try reading this tag with your phone.");
            delay(10000);
        } else {
            Serial.println("\tWrite failed");
        }
    }
    delay(5000);
}

NFC协议

NDEF message包含多个record。一个record由record header+record payload组成。如下是1个record数据:
data
其中第一个字节最重要 包含 MB ME CF SR IL TNF:
2.1 MB(message begin)消息开始的地方 一般用于开头 且置1
2.2 ME(message end)消息结束的地方 一般用于结尾 且置1
2.3 CF(chunk flag)是否分块
2.4 SR(short record)如果设置该值,则上图的 pay length 只需要1个, 表示payload数据长度被限制在255个字节之内。
2.5 IL(id_length标志)表示 header 是否含有 id 和 id length 这两个字段
2.6 TNF(type name format )用于指明 payload 的类型 具体可见图
NFC资料打包

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/455207.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

面对市场内卷,不同品牌应该如何做客户增长?

后疫情时代&#xff0c;我国新生人口减少、人口老龄化加剧&#xff0c;chatgpt火爆和AI替代论盛行&#xff0c;市场上&#xff0c;口红效应依旧繁荣&#xff0c;消费者的延迟满足、替代性满足成为常见心理&#xff0c;面对宏观的不确定性&#xff0c;人们在消费上更需要确定性的…

github 基础

github 基础 前面讲了 git 的基本使用&#xff0c;这里简单的提一下 github 的基本使用&#xff0c;主要还是 pull 和 push 两个部分。其中 pull 好像有了一些变化&#xff0c;现在似乎是需要 rebase 而不是自动就帮你做了……&#xff1f;不过 rebase 的部分之后再提。 当然…

Vuex实现数据共享

目录 一&#xff1a;index.js的创建 二&#xff1a;index.js的引入 三&#xff1a;Count.vue 四&#xff1a;App.vue的使用 五&#xff1a;mapstate等的使用 五&#xff1a;多组件数据共享&#xff08;模块化编程&#xff09; vc通过dispatch联系actions&#xff0c;acti…

Python小姿势 - ###### 随机选取的知识点:Python日期时间处理

随机选取的知识点&#xff1a;Python日期时间处理 Python日期时间处理&#xff1a;一种更简单的方式 日期和时间处理是许多程序中必不可少的部分。Python提供了一个标准库来处理日期和时间&#xff0c;这个库叫做datetime&#xff0c;它提供了一些类来处理不同的日期和时间格式…

远程访问及控制(SSH)

远程访问及控制&#xff08;SSH&#xff09; 一、SSH远程管理二、SSH服务1、ssh远程登录方式2、scp远程复制3、sftp安全FTP4、sshd配置文件5、ssh密钥对配置5.1 ssh密钥对免交互登录 三、TCP wrappers 访问控制1、**TCP wrappers &#xff08;TCP封套&#xff09;**2、**TCP wr…

会话与会话技术(Cookie)

Web应用中的会话过程指的是一个客户端&#xff08;浏览器&#xff09;与Web服务器之间连续发生的一系列请求和响应过程 为保存会话过程产生的数据&#xff0c;Servlet提供了两个用于保存会话数据的对象&#xff0c;分别是Cookie和Session 1、Cookie对象 Cookie是一种会话技术…

SS524V100 RTL8152B(USB转网卡)驱动移植

目录 前言 1. 内核下 USB Host 配置过程 2. 内核下 RTL8152 驱动配置 3. 重新编译内核 4. 测试USB转网卡 5. 总结 前言 本文主要是描述 SS524V100 对 RTL8152B(百兆网卡) 开发、移植的过程。 1. SS524V100 的 USB 2.0 支持 Host 模式&#xff1b; 2. 内核默认自带驱动…

0环境教你怎么安装配置GPU环境运行车流量检测代码

项目效果&#xff1a; python车流量检测双向车流计数 1、环境配置 1.1 安装显卡加速工具 (1) 安装CUDA和cudnn NVIDIA CUDA 深度神经网络库 (cuDNN) 是经 GPU 加速的深度神经网络基元库。cuDNN 可大幅优化标准例程&#xff08;例如用于前向传播和反向传播的卷积层、池化层、…

4月23日作业

#include <iostream> #include <cstring> using namespace std; class Student //学生类 { private: string name; //姓名 int year; //年龄 double sorce; //分数 public: Student (){} //无参构造 Student(string a,int b,double c):name(a),y…

五分钟学会在微信小程序中使用 vantUI 组件库

前言 我们在开发微信小程序时&#xff0c;设计和实现好用的用户界面无疑是至关重要的一步。但是微信小程序官方自带的 UI 组件库无法满足很多使用场景&#xff0c;这个时候就需要我们使用一些第三方的 UI 组件库。而 vant Weapp 作为一款优秀的前端 UI 组件库&#xff0c;可以帮…

MP长篇综述 | 植物泛基因组及其应用

2022年12月15日&#xff0c;中山大学史俊鹏副教授、中国科学院遗传与发育生物学研究所田志喜研究员、中国农业大学赖锦盛教授和上海师范大学黄学辉教授共同撰文&#xff0c;在Molecular Plant杂志发表了题为“Plant pan-genomics and its applications”的长篇综述。该论文对植…

(Ubuntu22.04 Jammy)安装ROS2 Humble

文章目录 (Ubuntu22.04 Jammy)安装ROS2 (Humble)版本一、设置本地区域二、设置源三、安装ROS2软件包四、环境设置五、测试用例Talker-listener 六、卸载ros2 (Ubuntu22.04 Jammy)安装ROS2 (Humble)版本 提示&#xff1a;以下内容是已经安装了ubuntu22.04 下进行安装ros2 一、设…

iptables防火墙和Firewalld

引言 在 Internet 中&#xff0c;企业通过各种应用系统来为用户提供各种服务&#xff0c;如 Web 网站、电子邮件系统、FTP 服务器、数据库系统等&#xff0c;那么&#xff0c;如何来保护这些服务器&#xff0c;过滤企业不需要的访问甚至是恶意的入侵呢&#xff0c;接下来&#…

设计模式--建造者模式

项目需求 盖房需求 (1) 需要建房子:过程为 打地基 砌墙 封顶 (2) 房子有高正各样的,比如 平房和高楼 建房子的过程虽然都一样 但是要求不要相同的细节 传统方式 public abstract class TraditionBuild {//打地基public abstract void foundation();//砌墙public abstract voi…

Linux进程的fork、exit、wait等函数;区分父子进程;GDB调试多进程

Linux系统中进程可以创建子进程。 1. fork函数&#xff1a;创建新进程 #include<sys/types.h> #include<unistd.h>pid_t fork(void); /* 功能&#xff1a;一个进程创建新进程。原进程为父进程&#xff0c;新进程为子进程。 返回值&#xff1a;成功&#xff1a;子…

SuperMap iObjects Docker打包全攻略

SuperMap iObjects Docker打包全攻略 文章目录 SuperMap iObjects Docker打包全攻略说明开始打包iObjects容器启动容器参考 说明 此教程编写时使用的iObjects版本为 10.2.1 &#xff0c;理论高版本同样支持&#xff0c;具体自测。基础镜像为 Docker 官方 ubuntu:16.04完整版。…

C++ 类和对象(中)构造函数 和 析构函数

上篇链接&#xff1a;C 类和对象&#xff08;上&#xff09;_chihiro1122的博客-CSDN博客 类的6个默认成员函数 我们在C当中&#xff0c;在写一些函数的时候&#xff0c;比如在栈的例子&#xff1a; 如上述例子&#xff0c;用C 返回这个栈是否为空&#xff0c;直接返回的话&am…

基于OpenCV-python的图像增强和滤波

目录 彩色空间 直方图均衡化 图像滤波 梯度 一、彩色空间 OpenCV 的颜色空间主要有 BGR、HSV、Lab等&#xff0c;cvtColor 函数可以让图像在不同颜色空间转换。例如通过将花的图像转换到 HSV 颜色空间&#xff0c;在HSV空间内过滤出只含有花瓣颜色的像素&#xff0c;从而提…

公共资源包发布流程详解

文章目录 公有包发布并使用npm安装git仓库协议创建及使用 npm 私有包创建及使用 group npm 私有包私有仓账密存放位置 当公司各个系统都需要使用特定的业务模块时&#xff0c;这时候将代码抽离&#xff0c;发布到 npm 上&#xff0c;供下载安装使用&#xff0c;是个比较好的方案…

SQL Server基础 第七章 连接查询(内连接、表别名、左外连接、右外连接)

前言 连接查询是关系数据库中最主要的查询&#xff0c;主要包括内连接、外连接和交叉连接等。通过连接运算符可以实现多个表查询。前面章节的查询均是基于单表进行&#xff0c;但有时需要获取的信息存储于多张表中&#xff0c;此时就必须使用本章所介绍的多表连接查询技术来获取…