射频识别RFID Radio Frequency IDentification 又称无线射频识别,是一种通讯技术,可通过无线电讯号识别特别目标并读写相关数据,而无需识别系统与特定目标之间建立机械或光学接触。、
恩智浦基于MFRC522 IC的RC522 RFID模块通常带有一个具有1KB内存的RFID卡标签和密匙卡标签。它可以编写标签,因此可以在其中存储某种秘密消息。
RC522 RFID 阅读器模块旨在创建13.56MHz的电磁场,用于与RFID标签ISO 14443A标准标签进行通信。阅读器可以通过4引脚串行外设接口SPI与微控制器进行通信,最大数据速率为10Mbps。它还支持通过I2C和UART协议进行通信。
该模块带有一个中断引脚。这很方便,因此不是一直问RFID模块‘是否有卡片在看?’,当标签进入附近时,模块会提醒我们。
该模块的工作电压为2.5V 至3.3V,逻辑引脚可以承受5V电压,可以连接到ESP32或任何5V逻辑微控制器,而无需使用任何逻辑电平转换器。
ESP32 Pico主板 | ESPBlock | MFRC522 RFID射频卡模块 |
---|---|---|
GP5 | 7/GP5 | SDA |
GP18 | 4/GP18 | SCK |
GP23 | 6/GP23 | MOSI |
GP19 | 5/GP19 | MISO |
* | * | IRO |
GND | GND | GND |
3.3V | 3.3V | 3.3V |
35.RFID_write.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ----湖南创乐博智能科技有限公司----
# 文件名:35_RFID_write.py
# 版本:V2.0
# author: zhulin
# 说明:RFID 写入数据
#####################################################
import mfrc522
from machine import Pin, SoftSPI
sck = Pin(18, Pin.OUT)
mosi = Pin(23, Pin.OUT)
miso = Pin(19, Pin.OUT)
spi = SoftSPI(baudrate=100000, polarity=0, phase=0, sck=sck, mosi=mosi, miso=miso)
sda = Pin(5, Pin.OUT)
def do_write():
rdr = mfrc522.MFRC522(spi, sda)
print("")
print("Place card before reader to write address 0x08")
print("")
try:
while True:
#调用 rdr 对象的 request 方法,并将返回的结果赋值给 stat 和 tag_type 两个变量。
(stat, tag_type) = rdr.request(rdr.REQIDL)
if stat == rdr.OK:
(stat, raw_uid) = rdr.anticoll()
if stat == rdr.OK:
print("New card detected")
#tag_type是一个变量,表示卡片的类型,以16进制形式打印。
print(" - tag type: 0x%02x" % tag_type)
# #其中raw_uid是一个包含4个字节的数组,表示卡片的唯一标识符(UID),以16进制形式打印。
print(" - uid : 0x%02x%02x%02x%02x" % (raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3]))
print("")
if rdr.select_tag(raw_uid) == rdr.OK:
key = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
#使用该密钥对读卡器进行认证操作,使用的认证方式是rdr.AUTHENT1A,密钥长度为8字节,认证的目标是raw_uid
if rdr.auth(rdr.AUTHENT1A, 8, key, raw_uid) == rdr.OK:
stat = rdr.write(8, b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f")
rdr.stop_crypto1()
if stat == rdr.OK:
print("Data written to card")
else:
print("Failed to write data to card")
else:
print("Authentication error")
else:
print("Failed to select tag")
except KeyboardInterrupt:
print("Bye")
# 程序入口
if __name__ == '__main__':
do_write() # 写入卡 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]a
写入我们需要写入的数据如: 写入卡[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,15],把RFID标签放在读卡器上,写入成功。
问题: key = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
这是一个长度为6的密钥,由6个十六进制数表示。每个十六进制数的取值范围是0x00到0xFF,即0到255。该密钥的十六进制表示为[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]。
问题: MOSI
MOSI是一种常见的串行通信协议,它是SPI(Serial Peripheral Interface)总线的一部分。SPI是一种用于在微控制器和外部设备之间进行通信的协议。MOSI代表Master Out Slave In,意味着主设备向从设备发送数据。
在SPI总线中,有一个主设备和一个或多个从设备。主设备负责控制通信的时序和传输数据,而从设备则接收主设备发送的数据。MOSI线是主设备向从设备发送数据的线路。
MOSI线是SPI总线中的一个信号线,它用于将数据从主设备发送到从设备。主设备通过MOSI线将数据位发送给从设备,从设备通过MISO(Master In Slave Out)线将数据位发送回主设备。
问题: MISO
MISO是一种通信系统中的术语,代表着"Multiple Input, Single Output",即多输入单输出。在通信系统中,MISO表示有多个发送天线(输入),但只有一个接收天线(输出)。这种配置可以用于无线通信系统,如无线电、移动通信和无线传感器网络等。
MISO系统的优势之一是能够提高通信的可靠性和容量。通过利用多个发送天线,MISO系统可以实现空间多样性,减少信号传输过程中的干扰和衰落。这样可以提高信号的质量和覆盖范围,增加系统的容量和可靠性。
此外,MISO系统还可以通过使用多个发送天线来实现波束成形(beamforming)技术。波束成形可以将信号的能量聚焦在特定的方向上,从而提高信号的传输距离和质量。
总结一下,MISO是一种通信系统配置,它具有多个发送天线和一个接收天线。通过利用多个发送天线,MISO系统可以提高通信的可靠性、容量和覆盖范围。同时,它还可以应用波束成形技术来改善信号传输的距离和质量。
SoftSPI
SoftSPI是一种软件模拟的SPI(Serial Peripheral Interface)通信协议。SPI是一种常用的串行通信协议,用于在微控制器和外部设备之间进行数据传输。SoftSPI通过软件实现SPI的功能,而不需要硬件支持。
SoftSPI通常由以下几个要素组成:
- 主设备(Master):负责发起数据传输的设备。
- 从设备(Slave):接收主设备传输的数据的设备。
- 时钟线(SCK):用于同步主设备和从设备的时钟信号。
- 数据线(MOSI和MISO):用于在主设备和从设备之间传输数据。
SoftSPI的工作原理如下:
- 主设备通过控制时钟线和数据线向从设备发送指令或数据。
- 从设备根据时钟信号接收主设备发送的指令或数据,并通过数据线将响应发送回主设备。
- 主设备根据时钟信号接收从设备的响应。
SoftSPI相对于硬件SPI的优势在于它不依赖特定的硬件接口,可以在任何支持GPIO(通用输入输出)的平台上实现。但是由于软件实现的限制,SoftSPI的速度可能较慢,并且对处理器资源的消耗较大。
spi = SoftSPI(baudrate=100000, polarity=0, phase=0, sck=sck, mosi=mosi, miso=miso)
SPI(Serial Peripheral Interface)是一种串行外设接口,用于在微控制器和外部设备之间进行通信。在你提供的代码中,spi是一个SoftSPI对象,它是通过软件模拟实现的SPI接口。
该SoftSPI对象的初始化参数如下:
- baudrate:指定通信速率,单位为Hz。
- polarity:指定时钟极性,即时钟信号在空闲状态下的电平。0表示空闲状态下为低电平,1表示空闲状态下为高电平。
- phase:指定时钟相位,即数据采样的时机。0表示在时钟的第一个边沿采样数据,1表示在时钟的第二个边沿采样数据。
- sck:指定时钟线的引脚。
- mosi:指定主设备输出从设备输入的引脚。
- miso:指定主设备输入从设备输出的引脚。
通过SoftSPI对象,你可以使用相应的方法来进行SPI通信,例如发送数据、接收数据等。
rdr = mfrc522.MFRC522(spi, sda)
rdr = mfrc522.MFRC522(spi, sda) 是一段Python代码,它创建了一个MFRC522对象,并将其赋值给变量rdr。这段代码使用了mfrc522模块中的MFRC522类,该类用于与MFRC522 RFID读写器进行通信。
在这段代码中,spi和sda是参数,用于指定与MFRC522读写器通信所需的SPI总线和SDA引脚。SPI总线是一种串行通信协议,用于在微控制器和外部设备之间传输数据。SDA引脚是MFRC522读写器的数据线。
通过创建MFRC522对象,您可以使用该对象调用不同的方法来与MFRC522读写器进行交互,例如读取RFID卡片的数据、写入数据到RFID卡片等操作。
print(" - uid : 0x%02x%02x%02x%02x" % (raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3]))
" - uid : 0x"
:这是一个字符串,表示打印UID的前缀部分。%02x
:这是一个格式化字符串,用于将整数以十六进制形式打印出来,并且保证至少两位宽度,不足两位时用0填充。% (raw_uid, raw_uid, raw_uid, raw_uid)
:这是格式化字符串的参数部分,用于指定要插入到格式化字符串中的值。raw_uid
、raw_uid
、raw_uid
、raw_uid
分别表示UID的四个字节的值。
所以,这段代码的作用是将UID的四个字节的值以十六进制形式打印出来,并在前面加上一个固定的前缀。
mfrc522.py
from machine import Pin, SPI
from os import uname
class MFRC522:
OK = 0
NOTAGERR = 1
ERR = 2
REQIDL = 0x26
REQALL = 0x52
AUTHENT1A = 0x60
AUTHENT1B = 0x61
def __init__(self, spi, cs):
self.spi = spi
self.cs = cs
self.cs.value(1)
self.spi.init()
self.init()
def _wreg(self, reg, val):
self.cs.value(0)
self.spi.write(b'%c' % int(0xff & ((reg << 1) & 0x7e)))
self.spi.write(b'%c' % int(0xff & val))
self.cs.value(1)
def _rreg(self, reg):
self.cs.value(0)
self.spi.write(b'%c' % int(0xff & (((reg << 1) & 0x7e) | 0x80)))
val = self.spi.read(1)
self.cs.value(1)
return val[0]
def _sflags(self, reg, mask):
self._wreg(reg, self._rreg(reg) | mask)
def _cflags(self, reg, mask):
self._wreg(reg, self._rreg(reg) & (~mask))
def _tocard(self, cmd, send):
recv = []
bits = irq_en = wait_irq = n = 0
stat = self.ERR
if cmd == 0x0E:
irq_en = 0x12
wait_irq = 0x10
elif cmd == 0x0C:
irq_en = 0x77
wait_irq = 0x30
self._wreg(0x02, irq_en | 0x80)
self._cflags(0x04, 0x80)
self._sflags(0x0A, 0x80)
self._wreg(0x01, 0x00)
for c in send:
self._wreg(0x09, c)
self._wreg(0x01, cmd)
if cmd == 0x0C:
self._sflags(0x0D, 0x80)
i = 2000
while True:
n = self._rreg(0x04)
i -= 1
if ~((i != 0) and ~(n & 0x01) and ~(n & wait_irq)):
break
self._cflags(0x0D, 0x80)
if i:
if (self._rreg(0x06) & 0x1B) == 0x00:
stat = self.OK
if n & irq_en & 0x01:
stat = self.NOTAGERR
elif cmd == 0x0C:
n = self._rreg(0x0A)
lbits = self._rreg(0x0C) & 0x07
if lbits != 0:
bits = (n - 1) * 8 + lbits
else:
bits = n * 8
if n == 0:
n = 1
elif n > 16:
n = 16
for _ in range(n):
recv.append(self._rreg(0x09))
else:
stat = self.ERR
return stat, recv, bits
def _crc(self, data):
self._cflags(0x05, 0x04)
self._sflags(0x0A, 0x80)
for c in data:
self._wreg(0x09, c)
self._wreg(0x01, 0x03)
i = 0xFF
while True:
n = self._rreg(0x05)
i -= 1
if not ((i != 0) and not (n & 0x04)):
break
return [self._rreg(0x22), self._rreg(0x21)]
def init(self):
self.reset()
self._wreg(0x2A, 0x8D)
self._wreg(0x2B, 0x3E)
self._wreg(0x2D, 30)
self._wreg(0x2C, 0)
self._wreg(0x15, 0x40)
self._wreg(0x11, 0x3D)
self.antenna_on()
def reset(self):
self._wreg(0x01, 0x0F)
def antenna_on(self, on=True):
if on and ~(self._rreg(0x14) & 0x03):
self._sflags(0x14, 0x03)
else:
self._cflags(0x14, 0x03)
def request(self, mode):
self._wreg(0x0D, 0x07)
(stat, recv, bits) = self._tocard(0x0C, [mode])
if (stat != self.OK) | (bits != 0x10):
stat = self.ERR
return stat, bits
def anticoll(self):
ser_chk = 0
ser = [0x93, 0x20]
self._wreg(0x0D, 0x00)
(stat, recv, bits) = self._tocard(0x0C, ser)
if stat == self.OK:
if len(recv) == 5:
for i in range(4):
ser_chk = ser_chk ^ recv[i]
if ser_chk != recv[4]:
stat = self.ERR
else:
stat = self.ERR
return stat, recv
def select_tag(self, ser):
buf = [0x93, 0x70] + ser[:5]
buf += self._crc(buf)
(stat, recv, bits) = self._tocard(0x0C, buf)
return self.OK if (stat == self.OK) and (bits == 0x18) else self.ERR
def auth(self, mode, addr, sect, ser):
return self._tocard(0x0E, [mode, addr] + sect + ser[:4])[0]
def stop_crypto1(self):
self._cflags(0x08, 0x08)
def read(self, addr):
data = [0x30, addr]
data += self._crc(data)
(stat, recv, _) = self._tocard(0x0C, data)
return recv if stat == self.OK else None
def write(self, addr, data):
buf = [0xA0, addr]
buf += self._crc(buf)
(stat, recv, bits) = self._tocard(0x0C, buf)
if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A):
stat = self.ERR
else:
buf = []
for i in range(16):
buf.append(data[i])
buf += self._crc(buf)
(stat, recv, bits) = self._tocard(0x0C, buf)
if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A):
stat = self.ERR
return stat
def select_tag(self, ser):
buf = [0x93, 0x70] + ser[:5]
#将buf与通过计算得到的校验码(使用_crc函数计算)拼接在一起。
buf += self._crc(buf)
(stat, recv, bits) = self._tocard(0x0C, buf)
return self.OK if (stat == self.OK) and (bits == 0x18) else self.ERR
[0x93, 0x70]
[0x93, 0x70] 是一个十六进制数表示的列表,它包含两个元素:0x93 和 0x70。在计算机中,0x93 和 0x70 是十六进制数,分别对应十进制数的147 和 112。这个列表可以表示为 [147, 112]。
buf = [0x93, 0x70] + ser[:5]
这段代码的作用是将一个字节数组ser
的前5个元素与[0x93, 0x70]
拼接在一起,结果存储在变量buf
中。
(stat, recv, bits) = self._tocard(0x0C, buf)
调用_tocard
函数,将0x0C和拼接后的数据作为参数传入。该函数会将数据发送给设备,并返回一个元组(stat, recv, bits)
,其中stat
表示状态,recv
表示接收到的数据,bits
表示位数。
0x0C
0x0C是一个十六进制数,表示的是十进制的12。在计算机中,十六进制是一种常用的表示数字的方式,它使用0-9和A-F来表示0-15这16个数。其中,A表示10,B表示11,C表示12,以此类推。
在计算机科学中,0x0C可以表示为二进制的00001100。它在编程中常用于表示字节、内存地址或者其他需要使用十六进制的场景。
0x有什么有什么作用?
在0x0C中,0x表示一个前缀,用于表示后面的数字是十六进制数。十六进制是一种常用的数值表示方式,它使用0-9和A-F来表示数字0-15。在计算机科学中,0x前缀通常用于表示内存地址或者十六进制的数值。
35.RFID_read.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ----湖南创乐博智能科技有限公司----
# 文件名:35_RFID_read.py
# 版本:V2.0
# author: zhulin
# 说明:RFID 读取数据
#####################################################
from time import sleep_ms
from machine import Pin, SoftSPI
from mfrc522 import MFRC522
sck = Pin(18, Pin.OUT)
mosi = Pin(23, Pin.OUT)
miso = Pin(19, Pin.OUT)
spi = SoftSPI(baudrate=100000, polarity=0, phase=0, sck=sck, mosi=mosi, miso=miso)
sda = Pin(5, Pin.OUT)
def do_read():
try:
while True:
rdr = MFRC522(spi, sda)
uid = ""
(stat, tag_type) = rdr.request(rdr.REQIDL)
if stat == rdr.OK:
(stat, raw_uid) = rdr.anticoll()
if stat == rdr.OK:
print("New card detected")
print(" - tag type: 0x%02x" % tag_type)
uid = ("0x%02x%02x%02x%02x" % (raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3]))
print(uid)
if rdr.select_tag(raw_uid) == rdr.OK:
key = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
if rdr.auth(rdr.AUTHENT1A, 8, key, raw_uid) == rdr.OK:
print("Address 8 data: %s" % rdr.read(8))
rdr.stop_crypto1()
else:
print("Authentication error")
else:
print("Failed to select tag")
sleep_ms(100)
except KeyboardInterrupt:
print("Bye")
# 程序入口
if __name__ == '__main__':
do_read() # 读取成功,返回[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]