3.5 haas506开发教程-example-rc522
  61vaxOJzUnAU 2023年11月02日 59 0



haas506开发教程-example-rc522

  • 1.简介
  • 2.硬件接线
  • 3.测试代码
  • 4.测试结果
  • 5.手机读卡
  • 6. 总结


1.简介

  • 实物图

3.5 haas506开发教程-example-rc522_数据

  • 扇区介绍
    (1)每张IC卡都有16个扇区,包括1个公共区和15个数据区。
    (2)每个扇区有4个块,每个块占16字节。
    (3)第0扇区的块0为厂商代码,已经固化。包括芯片序列号UID,ATQA和SAK
    (4)每个扇区的块3为控制块,用来存放密码和控制权限 ,不能用来存储数据。
    (5)每个扇区的块0,块1,块2可以用来存储数据(扇区0的块0除外)。
    (6)块3的前6个字节为KeyA,后6个字节为KeyB。中间的4个字节为存储控制。

3.5 haas506开发教程-example-rc522_haas506_02

  • 加密
    (1)非加密卡中所有扇区的KEYA和KEYB数值都是默认值FFFFFFFFFFFF
    (2)加密卡中,其中有扇区的KEYA和KEYB不等于FFFFFFFFFFFF,部分扇区加密的卡称半加密卡,所有扇区都加密的卡称全加密卡

2.硬件接线

 将rc522模块的SDA、SCK、MOSI、MISO、GND、RST、3.3V引脚接入到haas506开发板的相应位置。需要注意的有:

 (1)很多rc522模块没有标记CS引脚,只有SDA引脚,此时SDA即为CS。

 (2)board.json将gpio31设置成了rst,实际测试的时候,有没有rst都可以运行程序

 (3)在spi写/读寄存器时,需要切换cs的高低电平值。如下图所示:

3.5 haas506开发教程-example-rc522_数据_03

3.测试代码

  • main.py
import read
import write
import utime as time
if __name__=="__main__":
    print("enter test")
    #手动选择使用读卡/写卡功能,当前只提供测试用例,用户可以在这个基础上优化一下代码
    #write.do_write()
    read.do_read()
  • mfrc522.py
from driver import SPI
from driver import GPIO


class MFRC522:

	OK = 0
	NOTAGERR = 1
	ERR = 2

	REQIDL = 0x26
	REQALL = 0x52
	AUTHENT1A = 0x60   #验证A密钥
	AUTHENT1B = 0x61   #验证B密钥


	def __init__(self):
		self.spi=SPI()
		self.spi.open('SPI0')
		self.cs=GPIO()
		self.rst=GPIO()
		self.cs.open('cs')
		self.rst.open('rst')
		self.rst.write(0)
		self.cs.write(1)		
		self.rst.write(1)
		self.init()

	def _wreg(self, reg, val):
		writeBuf=bytearray([int(0xff & ((reg << 1) & 0x7e)),int(0xff & val)])
		self.cs.write(0)
		self.spi.write(writeBuf,2)
		self.cs.write(1)

	def _rreg(self, reg):
		readBuf=bytearray(1)
		writeBuf=bytearray([int(0xff & (((reg << 1) & 0x7e) | 0x80))])
		self.cs.write(0)
		self.spi.write(writeBuf,1)
		self.spi.read(readBuf,1)
		self.cs.write(1)
		return readBuf[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
  • read.py
    读卡函数中,用户只需关注从哪个扇区哪块读取数据
import mfrc522
import utime as time

def do_read():
	rdr=mfrc522.MFRC522()
	try:
		while True:
			(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)
					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]
						#自定义密钥
						# key = [0x61, 0x73, 0x64, 0x38, 0x38, 0x38]
						if rdr.auth(rdr.AUTHENT1A, 1, key, raw_uid) == rdr.OK:         # 验证密钥
							# 例如扇区0:块0、块1、块2、块3 
							# 0x00就是扇区0块0数据的地址
							# 0x01是扇区0的块1数据的地址
							# 0x02 就是扇区0块2数据的地址
							# 每增加一个块  地址就加1,有很多个扇区
							# 每个扇区的 块3是校验密钥的,即存放密码的
							# 当前读取的是 0x01,即扇区0块1的数据
							print("data: %s" % rdr.read(1))  
							rdr.stop_crypto1()
						else:
							print("Authentication error")
					else:
						print("Failed to select tag")
			#set period of reading			
			time.sleep(1)			
	except KeyboardInterrupt:
		print("Bye")
  • write.py
    写卡函数中,用户只需关注往哪个扇区哪个块写数据。
import mfrc522
import utime as time

def do_write():
	rdr = mfrc522.MFRC522()
	try:
		while True:
			(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)
					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]
						if rdr.auth(rdr.AUTHENT1A, 1, key, raw_uid) == rdr.OK:
							#往指定的块中 写数据,数据长度最大为16个字节
							#当前 是往 0x01即扇区0块1写数据
							stat = rdr.write(1, 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")
			#set period of writing			
			time.sleep(1)			
	except KeyboardInterrupt:
		print("Bye")
  • board.json
{
    "name": "haas506",
    "version": "1.0.0",
    "io": {
      "KEY1": {
        "type": "GPIO",
        "port": 44,
        "dir": "irq",
        "pull": "pullup",
        "intMode": "rising"
      },      
      "led1": {
        "type": "GPIO",
        "port": 7,
        "dir": "output",
        "pull": "pulldown"
      },
      "led_g": {
        "type": "GPIO",
        "port": 32,
        "dir": "output",
        "pull": "pulldown"
      },
      "cs": {
        "type": "GPIO",
        "port": 15,
        "dir": "output",
        "pull": "pullup"
      },
      "rst":{
        "type":"GPIO",
        "port": 31,
        "dir": "output",
        "pull":"pullup"
      },         
      "SPI0": {
        "type": "SPI",
        "port": 0,
        "mode": "master",
        "freq": 2000000
      },
      "serial1": {
        "type": "UART",
        "port": 0,
        "dataWidth": 8,
        "baudRate": 115200,
        "stopBits": 1,
        "flowControl": "disable",
        "parity": "none",
        "timeout": 1000
      },
      "serial2": {
        "type": "UART",
        "port": 1,
        "dataWidth": 8,
        "baudRate": 9600,
        "stopBits": 1,
        "flowControl": "disable",
        "parity": "none",
        "timeout": 1000
      },
      "serial3": {
        "type": "UART",
        "port": 2,
        "dataWidth": 8,
        "baudRate": 115200,
        "stopBits": 1,
        "flowControl": "disable",
        "parity": "none",
        "timeout": 1000
      }
    },
    "debugLevel": "ERROR",
    "repl": "enable",
    "replPort": 0
  }

4.测试结果

  • 写卡
    使用写卡函数往扇区0块1中写入16字节的数据,即0x01…0x0f。写卡操作成功后,会打印Data written to card。写卡周期为1s,用户可以自行设置。
enter test
New card detected
  - tag type: 0x10
  - uid  : 0xf2e273e9
Data written to card

New card detected
  - tag type: 0x10
  - uid  : 0xf2e273e9
Data written to card

New card detected
  - tag type: 0x10
  - uid  : 0xf2e273e9
Data written to card
...
  • 读卡
    使用读卡函数,读取扇区0块1的数据,获取到的数据为0, 1, 2, …14, 15,数据为十进制。读卡周期为1s,用户可以执行设置。
enter test
New card detected
  - tag type: 0x10
  - uid  : 0xf2e273e9
data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

New card detected
  - tag type: 0x10
  - uid  : 0xf2e273e9
data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

New card detected
  - tag type: 0x10
  - uid  : 0xf2e273e9
data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
...

5.手机读卡

 用户手机拥有nfc功能的,可以在应用市场上下载一个 nfc reader tool。可以实现简单的读卡写卡功能。

(1)

3.5 haas506开发教程-example-rc522_嵌入式开发_04

(2)

3.5 haas506开发教程-example-rc522_micropython_05

(3)可以使用这个软件查看到我们在代码中写入扇区0块1的数据

3.5 haas506开发教程-example-rc522_数据_06

6. 总结

 本节介绍了如何使用haas506实现读卡写卡功能。当前案例只是一个测试用例,用户可以在这个基础上优化一下代码。


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论