索引:
第一部分 理论
- Section 1 RFID 介绍
- Section 2 标签及设备
- Section 3 RFID工作原理
- Section 4 RFID的应用
- Section 5 RFID 追踪
- Section 6 未来展望
第二部分 实践
- Section 1 电路图
- Section 2 常用功能函数
- Section 3 读取数据实例
- Section 4 改变UID
这里才是开始
第一部分 理论
Section 1 RFID介绍
用于:
- 药品:用于最终一些处方药
- 商品:例如沃尔玛的商品分发全部使用RFID
- 动物追踪:比如农场中记录动物的信息
- 物品追踪:比如航空行李或物流
历史:
- 起源于英国二战识别敌我方战机
- 1975年美国用于银行安全、药品追踪
- 1983正式命名为RFID
优势:
- 高效的:可以置于纸中,塑料中甚至人体中
- 投资回报率高:比传统的条形码贵,但是更加的高效,不能复制。
- 可以嵌入物体中
- 永久识别:永远不能别盗取或改变
- 容易安装
- 能够存储2kb的数据,条形码智能存储10-12个数值
- 可以同时读取多个RFID
- 外资高敏感度方向的天线可以用于扫描标签
缺点:
- 水和金属会影响读取
- 分发中心附近设备会受到干扰,因为那里标签太多
- 不同国家的频率不一样
条形码和RFID优缺点比较:
条形码和RFID总体比较:
Section 2 标签及设备
RFID标签的组成:
- 一个内置电路用来存储和传输信息,并调制解调一个射频(RF)信号,从读取器中收集直流电来驱动。
- 一个天线来传输和接收信号。
包含三个组件:
- 芯片
- 天线
- 基质
功能上分类:
- 读取/写入:可以写入数据和读取数据
- 只读:只能读取数据不能修改数据,一般这种是使用UID和数据库连接
一般有三种配置类型:
- 主动:有内置电源,比较贵大约15-50美元,寿命3-8年,但是读取器便宜,读取距离大约27米
- 半被动:也有内置电路,用的很少
- 被动:大约20美分,目前有更新的技术能够使其嵌入到材料和产品中,很小,常见的大小和硬币差不多,大约能够存储2KB的数据,但是不能存储复杂数据。最远读取距离为6米,。这取决于读取器的power,常常置于塑料之中。
外形上分类:
- 按钮(像按钮)标签,通常在衣服上
- 金属标签:通常用于环境恶劣的环境,高污染、灰尘环境,如车辆
- 钥匙标签:用于门禁系统
- 耳朵标签:通常用于牲畜
- 人体玻璃管标签:存于一个小玻璃中,用于高度安全性的场所识别人员:
Section 3 RFID 工作原理
一个RFID系统包含三个部分组成:
- 标签
- 读取器
- 数据库
不同读取器的类型:
- 工作站型:一般识别距离2-6米
- 可移动型
- 手持型
- 接触型
工作流程:
总的来说,就是读取器读取tag的UID,然后在数据库中查找这个UID的信息并返回数据库中的数据给客户端,或者根据这个UID向数据库中添加数据。
Section 4 RFID的应用
应用一:入口控制:
- 加强区域的安全性
- 跟踪员工活动(出入)
- 一般使用LF(低频)或者HF(高频)
应用二:销售:
- 无人超市:使用RFID同时读取客户要支付的商品(条形码只能一个一个的扫描)
- 商品追踪:商品运输时候对商品进行溯源
应用三:健康
- 医院监控病人排队等待时间
- 处方药监管
- 通过卡片上的标签追踪病人的病例
- 健康中心的人员会带一个RFID的手环来记录洗手的次数和洗手的时间(这个手环也是门禁系统的一部分)
应用四:供应链管理
- 用于制造到产品再到销售的全过程追踪
应用五:图书馆
- 在图书馆的标签上大部分已经使用RFID替换条形码
- 安全性考虑
- 方便扫描和管理,管理人员能够快速扫描很多书
应用六:学校
- 门禁系统
- 学生id
- 让家长知道学生到校、离校时间
应用7:体育
- 确定运动员同时起泡(移动时间)
- 读取器相当于布满赛道
应用8:停车系统
- 在入口和出口处设置读取器来识别车辆进行自动扣费
- 要求每个车辆都使用RFID,因此目前逐渐部车票识别系统替代
- 高速收费目前还是使用的RFID,用的是主动型
应用9:交通
- 公交卡
- 单车租赁
Section 5 RFID追踪
职员追踪:
- 员工安全性
- 区域的安全性
包裹跟踪:
- 方便记录包裹的信息
- 记录包裹运输过程,出现包裹丢失能够找到丢失环节
机场包裹:
- 快速确认包裹数量
- 记录包裹信息
- 减少因为包裹确认数量耽误的时间
动物追踪:
由于牲畜是运行的,因此传统的识别方法已经收集数据的方法不太高效,尤其是在大型的农场。RFID可以使追踪牲畜更加的高效,不需要看见或者排列成特定的方式就可以进行跟踪,能够安全的最终牲畜的整个生命流程。由于RFID的UID的唯一性,牲畜的信息比如说繁殖、哺乳、数量甚至每天实物的信息等等就可以被数据库记录,用于最终牲畜的整个成长过程。另一方面能够在牲畜生命的时候快速定位牲畜的位置从而对牲畜进行有效的隔离以防止病情的迅速传播,隔绝病情的传播速度从而拯救其他的牲畜。
另一方面,通过记录牲畜的哺育、食物、重量、产蛋量等数据能够拿到大量的数据进行进一步的分析从而对牲畜的饮食结构、生活习性进行调整,来获取更高的收益。
优点:
- 提供源头信息的证明(食品追溯)
- 生长年龄验证
- 病情控制
- 自动获取数据,不需要过多的人工干预
- 获取信息进行进一步分析从而提高更多的产出
- 增强客户的可信度
特点:
- 永久识别
- 不需要在视线内
- 同时可以进行多个牲畜的识别
- 能够在苛刻环境下使用
工业制造流程追踪:
- 跟踪制造中的工件,从而防止流水线部分出现异常影响整个流水线
- 要结合算法使用
Section 6 未来展望
目前RFID标签随处都是,已经从基本的识别功能变成了追踪、定位、监视、控制的功能
未来发展趋势:
- 更远距离
- 更多信息存储
- 进行简单的逻辑处理
- 洗衣机各根据衣服上的标签来进行洗衣方案
- 逛衣服店的时候可以带一个RFID标签存储个人信息,推荐系统根据个人喜好走过可能喜欢的衣服旁边就会提示
- 个人RFID进行购买,不需要等待支付,直接拿走物品即可
第二部分 实践
Section 1 电路接线图
所有的例子将使用下图的接线方式:
UNO:
Nano:
Section 2 常用功能函数
使用的库文件是MRFC522
- #define RST_PIN 9 定义reset pin
- #define SS_PIN 10 定义SS pin
- MFRC522 mfrc522(SS_PIN, RST_PIN); 创建RFID实例
- SPI.begin(); 初始化SPI通信
- mfrc522.PCD_Init(); 初始化MFRC522
- mfrc522.PCD_DumpVersionToSerial() 显示读卡器信息
- mfrc522.PICC_IsNewCardPresent() 检测是否有卡(新卡)
- mfrc522.PICC_ReadCardSerial() 读取卡的信息(如果有新的卡在附近就会选择一张读取)
- mfrc522.PICC_DumpToSerial(&(mfrc522.uid)) 串口打印卡所有信息
- #define NEW_UID {0xDE, 0xAD, 0xBE, 0xEF} 需要使用十六进制来定义UID
- MFRC522::MIFARE_Key key;
- 打印UID
1 2 3 4 5 |
Serial.print(F("Card UID:")); for (byte i = 0; i < mfrc522.uid.size; i++) { Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "); Serial.print(mfrc522.uid.uidByte[i], HEX); } |
- 写入新的UID
1 2 3 4 |
byte newUid[] = NEW_UID; if ( mfrc522.MIFARE_SetUid(newUid, (byte)4, true) ) { Serial.println(F("Wrote new UID to card.")); } |
- 暂停PICC并导出写入的UID
1 2 3 4 |
mfrc522.PICC_HaltA(); if ( ! mfrc522.PICC_IsNewCardPresent() || ! mfrc522.PICC_ReadCardSerial() ) { return; } |
- 读取存储的数据
1 2 |
Serial.println(F("New UID and contents:")); mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); |
Section 3 读取数据实例
1.读取卡中全部数据(执行选择一个标签来读)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#include <SPI.h> #include <MFRC522.h> #define RST_PIN 9 // 配置引脚 #define SS_PIN 10 // 配置引脚 MFRC522 mfrc522(SS_PIN, RST_PIN); // 创建一个MFRC522实例 void setup() { Serial.begin(9600); // 初始化串口通讯 while (!Serial); // 如果串口打开就什么都不做 (用于ATMEGA32U4) SPI.begin(); // 初始化SPI通信 mfrc522.PCD_Init(); // 初始化 MFRC522 mfrc522.PCD_DumpVersionToSerial(); // 显示PCD内容-读取器的信息 Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks...")); } void loop() { // 等待新的卡 if ( ! mfrc522.PICC_IsNewCardPresent()) { return; } // 选择其中一张卡 if ( ! mfrc522.PICC_ReadCardSerial()) { return; } // 输出所有的信息 mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); } |
2.同时读取多个标签信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
#include <SPI.h> #include <MFRC522.h> #define RST_PIN 9 // Configurable, see typical pin layout above #define SS_1_PIN 10 // Configurable, take a unused pin, only HIGH/LOW required, must be diffrent to SS 2 #define SS_2_PIN 8 // Configurable, take a unused pin, only HIGH/LOW required, must be diffrent to SS 1 #define NR_OF_READERS 2 byte ssPins[] = {SS_1_PIN, SS_2_PIN}; MFRC522 mfrc522[NR_OF_READERS]; // Create MFRC522 instance. /** * Initialize. */ void setup() { Serial.begin(9600); // 初始化串口通信 while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) SPI.begin(); // 初始化SPI通信 for (uint8_t reader = 0; reader < NR_OF_READERS; reader++) { mfrc522[reader].PCD_Init(ssPins[reader], RST_PIN); // 初始化每一个标签 Serial.print(F("Reader ")); Serial.print(reader); Serial.print(F(": ")); mfrc522[reader].PCD_DumpVersionToSerial(); } } /** * Main loop. */ void loop() { for (uint8_t reader = 0; reader < NR_OF_READERS; reader++) { // 寻找新的卡 if (mfrc522[reader].PICC_IsNewCardPresent() && mfrc522[reader].PICC_ReadCardSerial()) { Serial.print(F("Reader ")); Serial.print(reader); // 显示 PICC 的信息 (that is: the tag/card) Serial.print(F(": Card UID:")); dump_byte_array(mfrc522[reader].uid.uidByte, mfrc522[reader].uid.size); Serial.println(); Serial.print(F("PICC type: ")); MFRC522::PICC_Type piccType = mfrc522[reader].PICC_GetType(mfrc522[reader].uid.sak); Serial.println(mfrc522[reader].PICC_GetTypeName(piccType)); // 停止 PICC mfrc522[reader].PICC_HaltA(); // 停止加密 PCD mfrc522[reader].PCD_StopCrypto1(); } //if (mfrc522[reader].PICC_IsNewC } //for(uint8_t reader } /** * Helper routine to dump a byte array as hex values to Serial. */ void dump_byte_array(byte *buffer, byte bufferSize) { for (byte i = 0; i < bufferSize; i++) { Serial.print(buffer[i] < 0x10 ? " 0" : " "); Serial.print(buffer[i], HEX); } |
Section 4 改变UID
注意,一些标签的UID是出厂的时候写死的不可更改。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
#include <SPI.h> #include <MFRC522.h> #define RST_PIN 9 // 配置引脚 #define SS_PIN 10 // 配置引脚 MFRC522 mfrc522(SS_PIN, RST_PIN); // 创建一个mfrc实例 /* 设置新的UID */ #define NEW_UID {0xDE, 0xAD, 0xBE, 0xEF} MFRC522::MIFARE_Key key; void setup() { Serial.begin(9600); // Initialize serial communications with the PC while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) SPI.begin(); // Init SPI bus mfrc522.PCD_Init(); // Init MFRC522 card Serial.println(F("Warning: this example overwrites the UID of your UID changeable card, use with care!")); // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory. for (byte i = 0; i < 6; i++) { key.keyByte[i] = 0xFF; } } void loop() { // 寻找标签,如果有多个就选择一个 if ( ! mfrc522.PICC_IsNewCardPresent() || ! mfrc522.PICC_ReadCardSerial() ) { delay(50); return; } // Now a card is selected. The UID and SAK is in mfrc522.uid. // 输出UID Serial.print(F("Card UID:")); for (byte i = 0; i < mfrc522.uid.size; i++) { Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "); Serial.print(mfrc522.uid.uidByte[i], HEX); } Serial.println(); // 设置新的UID byte newUid[] = NEW_UID; if ( mfrc522.MIFARE_SetUid(newUid, (byte)4, true) ) { Serial.println(F("Wrote new UID to card.")); } // 停止PICC把这张卡的信息打出来 mfrc522.PICC_HaltA(); if ( ! mfrc522.PICC_IsNewCardPresent() || ! mfrc522.PICC_ReadCardSerial() ) { return; } // 打印内存信息 Serial.println(F("New UID and contents:")); mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); delay(2000); } |