使用树莓派SPI驱动RC522模块,读取block 0数据成功,但是写入block 0失败。参照网上资料,写入block 0前需要先写入两个特殊指令0x40和0x43,但是当我通过调用函数
MFRC522_WriteReg(BitFramingReg, 0x07)
MFRC522_ToCard(PCD_TRANSCEIVE, 0x40) //0x40
MFRC522_WriteReg(BitFramingReg, 0x00)
MFRC522_ToCard(PCD_TRANSCEIVE, 0x43) //0x43
写入这两个命令时总是报错超时失败。但是其他request,select等流程调用
这两个函数都能成功,是在不知哪里有问题。怀疑是不是买的卡片不支持写入block 0,但是买的时候确实说是支持的。
下面是具体代码:
RC522.py:
import RPi.GPIO as GPIO
import spi
import signal
import time
class MFRC522:
PCD_IDLE = 0x00 # cancel current command
PCD_AUTHENT = 0x0E # authent
PCD_RECEIVE = 0x08 # receive data
PCD_TRANSMIT = 0x04 # send data
PCD_TRANSCEIVE = 0x0C # send & receive data
PCD_RESETPHASE = 0x0F # reset
PCD_CALCCRC = 0x03 # CRC calculate
PICC_REQIDL = 0x26 # detect cards, not slepp
PICC_REQALL = 0x52 # detect cards, all
PICC_ANTICOLL = 0x93 # anti collision
PICC_SElECTTAG = 0x93 # select card
PICC_AUTHENT1A = 0x60 # authent A
PICC_AUTHENT1B = 0x61 # authent B
PICC_READ = 0x30 # read block
PICC_WRITE = 0xA0 # write block
PICC_DECREMENT = 0xC0 # dec money
PICC_INCREMENT = 0xC1 # inc money
PICC_RESTORE = 0xC2 # send data to buf
PICC_TRANSFER = 0xB0 # save date from buf
PICC_HALT = 0x50 # idle status
Reserved00 = 0x00 # register
CommandReg = 0x01
CommIEnReg = 0x02
DivlEnReg = 0x03
CommIrqReg = 0x04
DivIrqReg = 0x05
ErrorReg = 0x06
Status1Reg = 0x07
Status2Reg = 0x08
FIFODataReg = 0x09
FIFOLevelReg = 0x0A
WaterLevelReg = 0x0B
ControlReg = 0x0C
BitFramingReg = 0x0D
CollReg = 0x0E
Reserved01 = 0x0F
Reserved10 = 0x10
ModeReg = 0x11
TxModeReg = 0x12
RxModeReg = 0x13
TxControlReg = 0x14
TxAutoReg = 0x15
TxSelReg = 0x16
RxSelReg = 0x17
RxThresholdReg = 0x18
DemodReg = 0x19
Reserved11 = 0x1A
Reserved12 = 0x1B
MifareReg = 0x1C
Reserved13 = 0x1D
Reserved14 = 0x1E
SerialSpeedReg = 0x1F
Reserved20 = 0x20
CRCResultRegM = 0x21
CRCResultRegL = 0x22
Reserved21 = 0x23
ModWidthReg = 0x24
Reserved22 = 0x25
RFCfgReg = 0x26
GsNReg = 0x27
CWGsPReg = 0x28
ModGsPReg = 0x29
TModeReg = 0x2A
TPrescalerReg = 0x2B
TReloadRegH = 0x2C
TReloadRegL = 0x2D
TCounterValueRegH = 0x2E
TCounterValueRegL = 0x2F
Reserved30 = 0x30
TestSel1Reg = 0x31
TestSel2Reg = 0x32
TestPinEnReg = 0x33
TestPinValueReg = 0x34
TestBusReg = 0x35
AutoTestReg = 0x36
VersionReg = 0x37
AnalogTestReg = 0x38
TestDAC1Reg = 0x39
TestDAC2Reg = 0x3A
TestADCReg = 0x3B
Reserved31 = 0x3C
Reserved32 = 0x3D
Reserved33 = 0x3E
Reserved34 = 0x3F
NRSTPD = 22
MAX_LEN = 18
MI_OK = 0
MI_NOTAGERR = 1
MI_ERR = 2
MI_TIMEOUT = 3
def __init__(self, dev='/dev/spidev0.0', spd=1000000):
self.dev0 = spi.openSPI(device=dev, speed=spd)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(self.NRSTPD, GPIO.OUT)
GPIO.output(self.NRSTPD, 1)
self.MFRC522_Init()
def MFRC522_WriteReg(self, addr, val):
spi.transfer(self.dev0, ((addr<<1)&0x7E, val))
def MFRC522_ReadReg(self, addr):
val = spi.transfer(self.dev0, (((addr<<1)&0x7E) | 0x80, 0))
return val[1]
def MFRC522_SetRegBitMask(self, reg, mask):
tmp = self.MFRC522_ReadReg(reg)
self.MFRC522_WriteReg(reg, tmp | mask)
def MFRC522_ClearRegBitMask(self, reg, mask):
tmp = self.MFRC522_ReadReg(reg)
self.MFRC522_WriteReg(reg, tmp & (~mask))
def MFRC522_ToCard(self, command, sendData):
retStatus = self.MI_OK
backData = []
backLen = 0
irqEn = 0x00
waitIRq = 0x00
lastBits = None
n = 0
i = 0
if command == self.PCD_AUTHENT:
irqEn = 0x12
waitIRq = 0x10
if command == self.PCD_TRANSCEIVE:
irqEn = 0x77
waitIRq = 0x30
self.MFRC522_WriteReg(self.CommIEnReg, irqEn|0x80) # enable interupt
self.MFRC522_ClearRegBitMask(self.CommIrqReg, 0x80) # clear interupt flags
self.MFRC522_SetRegBitMask(self.FIFOLevelReg, 0x80) # init FIFO
self.MFRC522_WriteReg(self.CommandReg, self.PCD_IDLE) # cancel current command
for i in range(len(sendData)):
self.MFRC522_WriteReg(self.FIFODataReg, sendData[i])
self.MFRC522_WriteReg(self.CommandReg, command)
if command == self.PCD_TRANSCEIVE:
self.MFRC522_SetRegBitMask(self.BitFramingReg, 0x80)
i = 2000
while True:
n = self.MFRC522_ReadReg(self.CommIrqReg)
i -= 1
if ~((i!=0) and ~(n&0x01) and ~(n&waitIRq)):
break
self.MFRC522_ClearRegBitMask(self.BitFramingReg, 0x80)
if i != 0:
if (self.MFRC522_ReadReg(self.ErrorReg) & 0x1B) == 0x00:
if n & irqEn & 0x01:
retStatus = self.MI_NOTAGERR
if command == self.PCD_TRANSCEIVE:
n = self.MFRC522_ReadReg(self.FIFOLevelReg)
lastBits = self.MFRC522_ReadReg(self.ControlReg) & 0x07
if lastBits != 0:
backLen = (n-1)*8 + lastBits
else:
backLen = n*8
if n == 0:
n = 1
if n > self.MAX_LEN:
n = self.MAX_LEN
for i in range(n):
backData.append(self.MFRC522_ReadReg(self.FIFODataReg))
else:
retStatus = self.MI_ERR
else:
retStatus = self.MI_TIMEOUT
return (retStatus, backData, backLen)
def _CalulateCRC(self, indata):
self.MFRC522_ClearRegBitMask(self.DivIrqReg, 0x04)
self.MFRC522_SetRegBitMask(self.FIFOLevelReg, 0x80)
for i in range(len(indata)):
self.MFRC522_WriteReg(self.FIFODataReg, indata[i])
self.MFRC522_WriteReg(self.CommandReg, self.PCD_CALCCRC)
i = 255
while True:
n = self.MFRC522_ReadReg(self.DivIrqReg)
i -= 1
if ~((i != 0) and ~(n&0x04)):
break
crc = []
crc.append(self.MFRC522_ReadReg(self.CRCResultRegL))
crc.append(self.MFRC522_ReadReg(self.CRCResultRegM))
return crc
# function : read block
# parameter : blockAddr(0~63)
# return : retStatus
# backData[16]
def MFRC522_ReadBolock(self, blockAddr):
retStatus = self.MI_OK
# cmd: 0x0c
# buf: 0x30 blockAddr crc[2]
buf = []
buf.append(self.PICC_READ)
buf.append(blockAddr)
crc = self._CalulateCRC(buf)
buf.append(crc[0])
buf.append(crc[1])
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf)
if (status != self.MI_OK) or (backLen != 8*self.MAX_LEN):
retStatus = self.MI_ERR
return (retStatus, backData)
# function : write block
# parameter : blockAddr(0~63)
# writeData[16]
# return : retStatus
def MFRC522_WriteBlock(self, blockAddr, writeData):
retStatus = self.MI_OK
# cmd: 0x0c
# buf: 0xA0 blockAddr crc[2]
buf = []
buf.append(self.PICC_WRITE)
buf.append(blockAddr)
crc = self._CalulateCRC(buf)
buf.append(crc[0])
buf.append(crc[1])
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf)
if (status != self.MI_OK) or ((backData[0]&0x0F) != 0x0A) or (backLen != 4):
retStatus = self.MI_ERR
if status == self.MI_OK:
# cmd: 0x0c
# buf: writeData[16] crc[2]
buf2 = []
for i in range(16):
buf2.append(writeData[i])
crc = self._CalulateCRC(buf2)
buf2.append(crc[0])
buf2.append(crc[1])
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf2)
if (status != self.MI_OK) or ((backData[0]&0x0F) != 0x0A) or (backLen != 4):
retStatus = self.MI_ERR
return retStatus
def MFRC522_Init(self):
self.MFRC522_Reset()
self.MFRC522_WriteReg(self.TModeReg, 0x8D)
self.MFRC522_WriteReg(self.TPrescalerReg, 0x3E)
self.MFRC522_WriteReg(self.TReloadRegL, 30)
self.MFRC522_WriteReg(self.TReloadRegH, 0)
self.MFRC522_WriteReg(self.TxAutoReg, 0x40)
self.MFRC522_WriteReg(self.ModeReg, 0x3D)
self.MFRC522_AntennaOn()
def MFRC522_Reset(self):
# reg: 0x01
# buf: 0x0F
self.MFRC522_WriteReg(self.CommandReg, self.PCD_RESETPHASE)
def MFRC522_AntennaOn(self):
# reg: 0x14
# buf: 0bxxxxxx11
temp = self.MFRC522_ReadReg(self.TxControlReg)
if not(temp & 0x03):
self.MFRC522_SetRegBitMask(self.TxControlReg, 0x03)
def MFRC522_AntennaOff(self):
# reg: 0x14
# buf: 0bxxxxxx00
self.MFRC522_ClearRegBitMask(self.TxControlReg, 0x03)
# function : detect card
# parameter : reqMode: detect mode
# 0x52 = detect all cards
# 0x26 = detect not sleep cards
# return : retStatus
# backData: card type, 2 bytes
# 0x4400 = Mifare_UltraLight
# 0x0400 = Mifare_One(S50)
# 0x0200 = Mifare_One(S70)
# 0x0800 = Mifare_Pro(X)
# 0x4403 = Mifare_DESFire
def MFRC522_Request(self, reqMode):
retStatus = self.MI_OK
self.MFRC522_WriteReg(self.BitFramingReg, 0x07)
# cmd: 0x0c
# buf: 0x26/0x52
buf = []
buf.append(reqMode)
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf)
if (status != self.MI_OK) or (backLen != 0x10):
retStatus = self.MI_ERR
return (retStatus, backData)
# function : anticoll
# parameter :
# return : retStatus
# backData(Uid, 4 bytes)
def MFRC522_Anticoll(self):
retStatus = self.MI_OK
serNumCheck = 0
self.MFRC522_WriteReg(self.BitFramingReg, 0x00)
# cmd: 0x0c
# buf: 0x93 0x20
buf = []
buf.append(self.PICC_ANTICOLL)
buf.append(0x20)
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf)
if (status==self.MI_OK) and (len(backData)==5):
for i in range(4):
serNumCheck ^= backData[i]
if serNumCheck != backData[4]:
retStatus = self.MI_ERR
else:
retStatus = self.MI_ERR
return (retStatus, backData)
# function : select card
# parameter : Uid
# return : retStatus
def MFRC522_Select(self, Uid):
retStatus = self.MI_OK
serNumCheck = 0
# cmd: 0x0c
# buf: 0x93 0x70 Uid[4] check crc[2]
buf = []
buf.append(self.PICC_SElECTTAG)
buf.append(0x70)
for i in range(4):
buf.append(Uid[i])
serNumCheck ^= Uid[i]
buf.append(serNumCheck)
crc = self._CalulateCRC(buf)
buf.append(crc[0])
buf.append(crc[1])
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf)
if (status != self.MI_OK) or (backLen != 0x18):
retStatus = self.MI_ERR
return retStatus
# function : auth sectorkey
# parameter : authMode(PICC_AUTHENT1A/PICC_AUTHENT1B)
# blockAddr
# sectorkey(6 bytes)
# Uid(4 bytes)
# return : retStatus
def MFRC522_Auth(self, authMode, blockAddr, sectorkey, Uid):
retStatus = self.MI_OK
# cmd: 0x0e
# buf: authMode blockAddr sectorkey[6] Uid[4]
buf = []
buf.append(authMode)
buf.append(blockAddr)
for i in range(6):
buf.append(sectorkey[i])
for i in range(4):
buf.append(Uid[i])
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_AUTHENT, buf)
if (status != self.MI_OK) or not(self.MFRC522_ReadReg(self.Status2Reg)&0x08):
retStatus = self.MI_ERR
return retStatus
# function : idle
# parameter :
# return : retStatus
def MFRC522_Halt(self):
retStatus = self.MI_OK
# cmd: 0x0c
# buf: 0x50 0x00 crc[2]
buf = []
buf.append(self.PICC_HALT)
buf.append(0)
crc = self._CalulateCRC(buf)
buf.append(crc[0])
buf.append(crc[1])
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf)
retStatus = status
return retStatus
def MFRC522_WriteCmd40(self):
retStatus = self.MI_OK
self.MFRC522_WriteReg(self.BitFramingReg, 0x07)
# cmd: 0x0c
# buf: 0x40
buf = []
buf.append(0x40)
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf)
if (status != self.MI_OK) or (backData[0] != 0x0a):
retStatus = status
return retStatus
def MFRC522_WriteCmd43(self):
retStatus = self.MI_OK
self.MFRC522_WriteReg(self.BitFramingReg, 0x00)
# cmd: 0x0c
# buf: 0x43
buf = []
buf.append(0x43)
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf)
if (status != self.MI_OK) or (backData[0] != 0x0a):
retStatus = status
return retStatus
def MFRC522_StopCrypto1(self):
self.MFRC522_ClearRegBitMask(self.Status2Reg, 0x08)
def MFRC522_CloseSPI(self):
spi.closeSPI(self.dev0)
main.py:
import RPi.GPIO as GPIO
import MFRC522
import signal
rc = MFRC522.MFRC522()
dataBlock0 = [0x65, 0xa0, 0x8a, 0xe1, 0xae, 0x08, 0x04, 0x00, 0x01, 0x69, 0x21, 0x1a, 0x3c, 0xeb, 0xa9, 0x1d]
sectorkey = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
def read_block0():
(status, tagType) = rc.MFRC522_Request(rc.PICC_REQIDL)
if status != rc.MI_OK:
print("MFRC522_Request error")
return
print("MFRC522_Request success, tagType: %#x %#x" %(tagType[0], tagType[1]))
(status, Uid) = rc.MFRC522_Anticoll()
if status != rc.MI_OK:
print("MFRC522_Anticoll error")
return
print("MFRC522_Anticoll success, Uid: %#x %#x %#x %#x" %(Uid[0], Uid[1], Uid[2], Uid[3]))
status = rc.MFRC522_Select(Uid)
if status != rc.MI_OK:
print("MFRC522_Select error")
return
print("MFRC522_Select success")
status = rc.MFRC522_Auth(rc.PICC_AUTHENT1A, 1, sectorkey, Uid)
if status != rc.MI_OK:
print("MFRC522_Auth error")
return
print("MFRC522_Auth success")
(status, dataBlock0) = rc.MFRC522_ReadBolock(0)
if status != rc.MI_OK:
print("MFRC522_ReadBolock error")
return
print("MFRC522_ReadBolock success, block0: %#x %#x %#x %#x %#x %#x %#x %#x %#x %#x %#x %#x %#x %#x %#x %#x"
%(dataBlock0[0], dataBlock0[1], dataBlock0[2], dataBlock0[3], dataBlock0[4], dataBlock0[5], dataBlock0[6], dataBlock0[7],
dataBlock0[8], dataBlock0[9], dataBlock0[10], dataBlock0[11], dataBlock0[12], dataBlock0[13], dataBlock0[14], dataBlock0[15]))
rc.MFRC522_StopCrypto1()
def write_block0():
(status, tagType) = rc.MFRC522_Request(rc.PICC_REQIDL)
if status != rc.MI_OK:
print("MFRC522_Request error")
return
print("MFRC522_Request success, tagType: %#x %#x" %(tagType[0], tagType[1]))
(status, Uid) = rc.MFRC522_Anticoll()
if status != rc.MI_OK:
print("MFRC522_Anticoll error")
return
print("MFRC522_Anticoll success, Uid: %#x %#x %#x %#x" %(Uid[0], Uid[1], Uid[2], Uid[3]))
status = rc.MFRC522_Select(Uid)
if status != rc.MI_OK:
print("MFRC522_Select error")
return
print("MFRC522_Select success")
status = rc.MFRC522_Halt()
print("MFRC522_Halt %d" %status)
status = rc.MFRC522_WriteCmd40()
if (status != rc.MI_OK):
print("MFRC522_ToCard 0x40 error, status:%d" %status)
return
print("MFRC522_ToCard 0x40 success")
status = rc.MFRC522_WriteCmd43()
if (status != rc.MI_OK):
print("MFRC522_ToCard 0x43 error, status:%d" %status)
return
print("MFRC522_ToCard 0x43 success")
status = rc.MFRC522_WriteBlock(0, dataBlock0)
if status != rc.MI_OK:
print("MFRC522_WriteBlock error")
return
print("MFRC522_WriteBlock success")
rc.MFRC522_StopCrypto1()
def closeSPI():
rc.MFRC522_CloseSPI()
if __name__ == '__main__':
while True:
action = input("Enter action r/w: ")
if action == 'r':
read_block0()
elif action == 'w':
write_block0()
elif action == 'q':
closeSPI()
break
print("exit procedure")
我也遇到了一样的问题,状态返回是0X02,返回bit长度为0X04,无法进行写块0;请教下,你的这个问题有没有解决呢,