《物联网实验》
实验报告
题 目 | : | 实验3 RFID-UHF超高频实验 |
姓 名 | : | 高星杰 |
学 号 | : | 2021307220712 |
专 业 | : | 计算机科学与技术 |
上课时间 | : | 2024春 |
授课教师 | : | 朱容波 |
2024 年 6月 18 日
[TOC]
实验3 RFID-UHF超高频实验
实验目的
- 掌握 UHF 超高频通讯原理;
- 掌握 UHF 超高频通讯协议;
- 掌握读卡器操作流程;
- 了解 UHF 超高频应用;
实验设备
- 硬件:提供电源、PC、USB口、RS232串口、RJ45以太口、5539光敏传感器、蜂鸣传感器、CC Debugger仿真器一套。
- 软件:ZigBee基础实验平台软件、python3.8、IAR Embedded WorkBench,ZStack协议栈,Keil开发软件。
实验要求
- 参考视频实现UHF超高频RFID通信
- 通过Python编写界面程序实现RFID端口数据通信
实验原理
在进行实验之前我们要先了解实验的原理,为了能够讲解清楚实验的原理,我将以问答的形式介绍本次实验的原理。
什么是RFID?
RFID,即射频识别(Radio Frequency Identification),是一种通过无线电波进行非接触式数据通信的技术,用于自动识别和追踪物体。RFID系统通常由三部分组成:标签(Tag)、读写器(Reader)和数据处理系统。
- RFID标签(Tag)
RFID标签包含一个芯片和一个天线,芯片中存储有唯一标识信息。根据能量来源,RFID标签可以分为以下三类:
- 无源标签(Passive Tag):没有电池,依靠读写器发出的电磁场供电,反射信号回读写器。
- 有源标签(Active Tag):内置电池,能主动发送信号,读取距离较远。
- 半有源标签(Semi-passive Tag):内置电池,但只在被激活时发送信号。
2. RFID读写器(Reader)
RFID读写器通过天线发出无线电波,与RFID标签通信,读取或写入标签中的数据。读写器根据使用频率和应用场景,可以分为低频(LF)、高频(HF)和超高频(UHF)等类型。
3. 数据处理系统
数据处理系统接收来自读写器的数据,对数据进行处理、存储和分析。这些数据通常通过网络传输到中央数据库或管理系统,用于进一步的应用和决策支持。
RFID工作原理
RFID系统的工作过程通常包括以下步骤:
- 读写器发射信号:RFID读写器通过天线发射无线电信号,形成一个电磁场。
- 标签接收信号:当RFID标签进入读写器的读写范围时,标签天线接收信号,激活标签内的芯片。
- 标签回应信号:无源标签通过反射读写器的信号回应数据,有源标签则使用自身电源主动发送数据。
- 读写器接收信号:读写器接收到来自标签的信号,将标签中的数据读取出来。
- 数据处理:读写器将读取到的数据传输到数据处理系统,进行存储、分析和应用。
RFID的应用
RFID技术具有识别距离远、多目标识别、抗干扰能力强、数据存储容量大等优点,被广泛应用于各个领域:
- 物流与仓储管理:用于自动化库存管理、货物追踪、仓库盘点等,提高管理效率。
- 交通与自动收费:用于不停车收费系统(ETC)、公交卡、门禁系统等,方便快捷。
- 零售与防盗:用于商品防盗、库存管理和快速结算等,提升购物体验。
- 医疗与健康管理:用于病人身份识别、药品追踪、医疗设备管理等,确保安全和准确性。
- 农业与畜牧业:用于动物身份识别、养殖管理、环境监控等,提升管理效率和生产效益。
什么是UHF?
UHF(Ultra High Frequency,超高频)是一种射频识别(RFID)技术使用的频率范围,通常指频率范围在300 MHz到3 GHz之间。UHF RFID技术具有较长的读取距离和较快的数据传输速度,因此在许多应用中被广泛采用。
UHF的特点
- 频率范围:UHF频段通常在300 MHz到3 GHz之间。常见的UHF RFID系统工作频率为860-960 MHz。
- 读取距离:UHF RFID标签的读取距离较长,一般可以达到几米到十几米,甚至更远,具体距离取决于读写器的功率、天线设计和环境因素。
- 数据传输速度:UHF RFID系统的数据传输速度较快,适用于需要快速读取大量标签的应用场景。
- 抗干扰能力:UHF RFID系统采用多种技术减少干扰,如频率跳变、调制技术等,能够在复杂环境中稳定工作。
- 成本:UHF RFID标签的成本较低,适合大规模应用。
UHF RFID的工作原理
UHF RFID系统的工作过程如下:
- 读写器发射射频信号:UHF RFID读写器通过天线发射射频信号。
- 标签接收信号:UHF RFID标签的天线接收射频信号,激活标签内的芯片。无源标签依靠接收到的信号供电,有源标签则使用内置电池供电。
- 标签回应信号:标签芯片处理信号后,将存储的数据通过反射或主动发射的方式回应给读写器。
- 读写器接收信号:读写器接收到标签发回的信号,并将数据解码,传输到数据处理系统。
UHF RFID的应用
由于UHF RFID技术的特点,它在多个领域中得到广泛应用:
- 物流与供应链管理:UHF RFID用于自动化仓库管理、货物追踪、库存盘点等,提高供应链效率。
- 零售业:用于商品防盗、库存管理、快速结算等,提高购物体验和运营效率。
- 交通与自动收费:用于高速公路不停车收费系统(ETC)、停车场管理等,提高交通管理效率。
- 制造业:用于生产线自动化、设备管理、产品追踪等,提高生产效率和质量控制。
- 医疗与健康管理:用于病人身份识别、药品管理、医疗设备追踪等,提高医疗服务质量。
- 资产管理:用于公司资产的标识和追踪,提高资产利用率和管理效率。
实验步骤
1. 盘存操作
-
发送盘存指令
- 在串口调试助手上发送以下盘存指令:
73 00 01 00 00 00 20 00 02 00 01 90 01 00
- 首先返回命令成功数据:
73 00 03 00 01 00 20 00 04 00 00 00 00 00 00
- 在串口调试助手上发送以下盘存指令:
-
读取EPC码
- 将超高频标签置于读写器天线上方,返回的数据中包含EPC码:
E2 00 41 27 88 14 01 01 22 70 29 DB
- 将超高频标签置于读写器天线上方,返回的数据中包含EPC码:
2. 停止盘存
- 发送停止盘存指令:
73 00 01 00 00 00 20 00 02 00 00 00 00 00
- 成功返回数据:
73 00 03 00 01 00 20 00 04 00 00 00 00 00 00 00 73 00 00 01 00 20 00 04 00 00 00 00 00 00
3. 标签扇区读取操作
3.1 读取EPC码
- 扇区读取命令0x22可读取标签的四个分区数据。
- EPC码长度为96位(6个word),从地址0x02开始。
- 发送读取EPC码的指令:
73 00 01 00 00 00 22 00 0C 00 03 C9 00 00 00 00 00 00 01 00 02 00 06 00
- 返回的数据中最后的6个word即为EPC码。
3.2 读取TID码
- TID码长度为96位(6个word),从地址0x00开始。
- 发送读取TID码的指令:
73 00 01 00 00 00 22 00 0C 00 02 42 00 00 00 00 00 00 02 00 00 00 06 00
- 返回的数据中最后的6个word即为TID码。
4. 标签扇区写操作
- 在AITGM-UHF接口应用程序上,发送以下十六进制数据:
73 00 01 00 00 00 30 00 18 00 25 F0 00 00 00 00 00 00 01 00 02 00 06 00 E2 00 41 27 88 14 01 04 04 80 E1 6E
- 返回的数据中最后4个字节全为0表示执行成功。
5. 使用Python可视化
- 使用Python第三方库Serial读取串口接收到的传输信息。
- 使用Tkinter创建可视化界面,显示发送与接收情况。
实验结果
1 盘存操作
将超高频标签置于读写器天线上方
输入指令
发送指令并返回结果
2 停止存盘
输入停止存盘指令并发送,可以发现返回数据停止了。
3 标签扇区读取操作
3.1 读取EPC码
3.2 读取TID码
4 标签扇区写操作
返回末尾是 00 00
说明成功
5 读取EPC码
可以发现已经写入成功
6 实时盘存
7 Python可视化
实验代码
import binascii # 用于二进制和ASCII字符串的相互转换
import tkinter as tk # Tkinter是Python的标准GUI库
from tkinter import ttk # ttk模块提供了若干新小部件
import serial # pySerial库,用于串口通信
import threading # 用于实现多线程
# 一个简单的信息窗口类
class InformWindow:
def __init__(self, informStr):
self.window = tk.Tk()
self.window.title("Information") # 设置窗口标题
self.window.geometry("220x60") # 设置窗口大小
label = tk.Label(self.window, text=informStr) # 显示信息的标签
buttonOK = tk.Button(self.window, text="OK", command=self.processButtonOK) # 确定按钮
label.pack(side=tk.TOP)
buttonOK.pack(side=tk.BOTTOM)
self.window.mainloop() # 进入消息循环
def processButtonOK(self):
self.window.destroy() # 销毁窗口
# 主GUI类
class mainGUI:
def __init__(self):
window = tk.Tk()
window.title("GUI UART Tx/Rx Demo") # 设置窗口标题
self.uartState = False # 标识串口是否打开
# 包含COM信息和开始/停止按钮的框架
frame_COMinf = tk.Frame(window)
frame_COMinf.grid(row=1, column=1)
labelCOM = tk.Label(frame_COMinf, text="COMx: ") # COM端口标签
self.COM = tk.StringVar(value="COM1") # COM端口变量
ertryCOM = tk.Entry(frame_COMinf, textvariable=self.COM) # 输入COM端口
labelCOM.grid(row=1, column=1, padx=5, pady=3)
ertryCOM.grid(row=1, column=2, padx=5, pady=3)
labelBaudrate = tk.Label(frame_COMinf, text="Baudrate: ") # 波特率标签
self.Baudrate = tk.IntVar(value=115200) # 波特率变量
ertryBaudrate = tk.Entry(frame_COMinf, textvariable=self.Baudrate) # 输入波特率
labelBaudrate.grid(row=1, column=3, padx=5, pady=3)
ertryBaudrate.grid(row=1, column=4, padx=5, pady=3)
labelParity = tk.Label(frame_COMinf, text="Parity: ") # 校验位标签
self.Parity = tk.StringVar(value="NONE") # 校验位变量
comboParity = ttk.Combobox(frame_COMinf, width=17, textvariable=self.Parity) # 校验位下拉框
comboParity["values"] = ("NONE", "ODD", "EVEN", "MARK", "SPACE")
comboParity["state"] = "readonly"
labelParity.grid(row=2, column=1, padx=5, pady=3)
comboParity.grid(row=2, column=2, padx=5, pady=3)
labelStopbits = tk.Label(frame_COMinf, text="Stopbits: ") # 停止位标签
self.Stopbits = tk.StringVar(value="1") # 停止位变量
comboStopbits = ttk.Combobox(frame_COMinf, width=17, textvariable=self.Stopbits) # 停止位下拉框
comboStopbits["values"] = ("1", "1.5", "2")
comboStopbits["state"] = "readonly"
labelStopbits.grid(row=2, column=3, padx=5, pady=3)
comboStopbits.grid(row=2, column=4, padx=5, pady=3)
self.buttonSS = tk.Button(frame_COMinf, text="Start", command=self.processButtonSS) # 开始/停止按钮
self.buttonSS.grid(row=3, column=4, padx=5, pady=3, sticky=tk.E)
# 串口对象
self.ser = serial.Serial()
# 串口读取线程
self.ReadUARTThread = threading.Thread(target=self.ReadUART)
self.ReadUARTThread.start()
# 接收数据的框架
frameRecv = tk.Frame(window)
frameRecv.grid(row=2, column=1)
labelOutText = tk.Label(frameRecv, text="ReceivedData:") # 接收数据标签
labelOutText.grid(row=1, column=1, padx=3, pady=2, sticky=tk.W)
frameRecvSon = tk.Frame(frameRecv)
frameRecvSon.grid(row=2, column=1)
scrollbarRecv = tk.Scrollbar(frameRecvSon)
scrollbarRecv.pack(side=tk.RIGHT, fill=tk.Y)
self.OutputText = tk.Text(frameRecvSon, wrap=tk.WORD, width=60, height=20, yscrollcommand=scrollbarRecv.set) # 显示接收数据的文本框
self.OutputText.pack()
# 发送数据的框架
frameTrans = tk.Frame(window)
frameTrans.grid(row=3, column=1)
labelInText = tk.Label(frameTrans, text="To Transmit Data:") # 发送数据标签
labelInText.grid(row=1, column=1, padx=3, pady=2, sticky=tk.W)
frameTransSon = tk.Frame(frameTrans)
frameTransSon.grid(row=2, column=1)
scrollbarTrans = tk.Scrollbar(frameTransSon)
scrollbarTrans.pack(side=tk.RIGHT, fill=tk.Y)
self.InputText = tk.Text(frameTransSon, wrap=tk.WORD, width=60, height=5, yscrollcommand=scrollbarTrans.set) # 输入发送数据的文本框
self.InputText.pack()
self.buttonSend = tk.Button(frameTrans, text="Send", command=self.processButtonSend) # 发送按钮
self.buttonSend.grid(row=3, column=1, padx=5, pady=3, sticky=tk.E)
window.mainloop()
def processButtonSS(self):
if (self.uartState):
self.ser.close() # 关闭串口
self.buttonSS["text"] = "Start" # 更改按钮文字
self.uartState = False
else:
# 重新启动串口
self.ser.port = self.COM.get()
self.ser.baudrate = self.Baudrate.get()
strParity = self.Parity.get()
if (strParity == "NONE"):
self.ser.parity = serial.PARITY_NONE
elif (strParity == "ODD"):
self.ser.parity = serial.PARITY_ODD
elif (strParity == "EVEN"):
self.ser.parity = serial.PARITY_EVEN
elif (strParity == "MARK"):
self.ser.parity = serial.PARITY_MARK
elif (strParity == "SPACE"):
self.ser.parity = serial.PARITY_SPACE
strStopbits = self.Stopbits.get()
if (strStopbits == "1"):
self.ser.stopbits = serial.STOPBITS_ONE
elif (strStopbits == "1.5"):
self.ser.stopbits = serial.STOPBITS_ONE_POINT_FIVE
elif (strStopbits == "2"):
self.ser.stopbits = serial.STOPBITS_TWO
try:
self.ser.open() # 打开串口
except:
informStr = "Can't open " + self.ser.port
InformWindow(informStr)
if (self.ser.isOpen()): # 打开成功
self.buttonSS["text"] = "Stop" # 更改按钮文字
self.uartState = True
def processButtonSend(self):
if (self.uartState):
strToSend = self.InputText.get(1.0, tk.END)
bytesToSend = bytes.fromhex(strToSend[0:-1]) # 将输入的十六进制字符串转换为字节
self.ser.write(bytesToSend) # 发送数据
print(bytesToSend)
else:
informStr = "UART is not open"
InformWindow(informStr)
def ReadUART(self):
while True:
if (self.uartState):
try:
ch = self.ser.read() # 读取一个字节
print(ch, end='')
data = str(binascii.b2a_hex(ch)) # 将字节转换为十六进制字符串
print(str(data[1:]).split('\\x'))
self.OutputText.insert(tk.END, data.split('b\'\\x')) # 在文本框中显示接收到的数据
except:
informStr = "Error reading UART"
InformWindow(informStr)
self.ser.close() # 关闭串口
self.buttonSS["text"] = "Start"
self.uartState = False
# 启动主GUI
mainGUI()
代码分析
- 导入必要的库
- binascii: 用于二进制和ASCII字符串的相互转换。
- tkinter和ttk: 用于创建图形用户界面。
- serial: pySerial库,用于串口通信。
- threading: 用于实现多线程。
- 信息窗口类
InformWindow
这个类用于创建一个简单的信息窗口,用于显示错误或状态信息。窗口包含一个标签和一个“OK”按钮,点击按钮后窗口关闭。
- 主GUI类
mainGUI
- 初始化GUI窗口: 创建主窗口并设置标题。
- 串口信息框架: 包含COM端口、波特率、校验位和停止位的输入字段,以及一个开始/停止按钮。用户可以在这里输入串口的相关信息并启动或停止串口通信。
- 串口对象: 创建一个串口对象
self.ser
,用于串口通信。- 串口读取线程: 创建并启动一个线程
self.ReadUARTThread
,用于后台读取串口数据。- 接收数据框架: 一个文本框,用于显示从串口接收到的数据。包含一个滚动条,可以滚动查看长数据。
- 发送数据框架: 一个文本框,用于输入需要通过串口发送的数据,以及一个发送按钮。
processButtonSS
方法
- 处理开始/停止按钮的点击事件:
- 如果串口已打开,则关闭串口,并将按钮文字改为“Start”。
- 如果串口未打开,则根据用户输入的串口配置信息,配置并尝试打开串口。打开成功后,将按钮文字改为“Stop”。
processButtonSend
方法
- 处理发送按钮的点击事件:
- 如果串口已打开,则读取用户输入的数据,将其转换为字节并发送到串口。
- 如果串口未打开,则弹出信息窗口提示用户串口未打开。
ReadUART
方法
- 后台线程方法: 不断检查串口是否已打开,如果打开,则读取串口数据,将数据转换为十六进制字符串并显示在接收数据框架的文本框中。
- 启动主GUI
- 创建并启动
mainGUI
对象,进入Tkinter主事件循环。
总体功能
创建了一个GUI界面,用于通过串口发送和接收数据。用户可以输入串口的相关配置信息(COM端口、波特率、校验位和停止位),启动或停止串口通信,发送和接收数据,并在界面上实时查看接收到的数据。通过多线程实现了后台读取串口数据,保证界面响应不被阻塞。
实验总结与感悟
在这次UHF超高频通信实验中,我们不仅仅是按照步骤进行操作,更是一次深刻的学习和探索之旅。这个实验让我对UHF超高频通信技术有了更深刻的理解,也让我感受到团队合作和动手实践的无穷魅力。
实验开始,我们怀着好奇和期待,通过发送盘存指令,成功读取到了标签的EPC码。这一刻,看到屏幕上跳动的数据,我们兴奋不已。这不仅仅是对硬件设备的成功操作,更是对我们理论知识的一次有力验证。紧接着,我们发送停止盘存指令,读写器按照我们的指令停止了操作,这种掌控感让我们对技术的敬畏和热爱又增加了几分。
在接下来的标签扇区读取和写入操作中,我们遇到了一些小挑战,但通过团队的智慧和不懈努力,我们逐一攻克。成功读取EPC码和TID码,并对EPC码进行了修改,看到实验数据准确无误地返回,内心的成就感难以言表。这不仅是实验的成功,更是我们不断学习和探索的成果。
通过这次实验,我深刻体会到了理论与实践相结合的重要性。书本上的知识在实际操作中变得鲜活起来,每一次成功的操作都是对我们学习成果的肯定。团队合作在这次实验中发挥了至关重要的作用,大家一起讨论、解决问题,在合作中碰撞出智慧的火花。这种合作精神和默契也将成为我们未来学习和工作的宝贵财富。
这次实验还极大地提升了我的编程技能和实际操作能力。通过编写和调试Python代码,我们实现了串口数据的实时发送、接收和显示,这不仅增强了我们的动手能力,也让我们更加熟悉了Python编程和Tkinter图形界面的使用。在代码调试过程中,每一个问题的解决都让我对编程有了更多的信心和热爱。
这次UHF超高频通信实验,不仅让我深入了解了这一前沿技术,还让我感受到物联网技术在现代生活中的巨大潜力和广阔前景。通过这次实验,我更加坚定了继续深入学习物联网技术的信心和决心。实验中的每一次成功和挑战,都将成为我学习道路上的宝贵经验和动力。
这次实验经历,不仅是对知识的学习和技术的掌握,更是对自己能力的提升和信心的培养。它将激励我在未来的学习和研究中,不断探索和创新,为物联网的发展贡献自己的力量。感谢这次实验,让我更加热爱这个充满无限可能的领域。