2021-11-21一次关于micropython esp32 PN532的记录

好久没有使用PN532串口读卡器了,上次使用还是在遥远的2016年,当时虽然也留下了笔记但,一是受当时技术水平影响,写的东西杂乱不堪自己也难以理解,二是年头久远毫无印象唯一记得的是这个模块是红色的。。。请添加图片描述

请添加图片描述

接线记录 rx-tx 交叉接线,电压3.3V-5V都可以

首先,这模块带个上位机,软件我就不传了按说买模块找卖家,怎么都能弄个上位机,需要注意的是,模块接TTL-USB模块后要先接在电脑上再开上位机否则无响应不说还拖CPU速度关不上,卡卡更健康的样子~

上位机不难,用处主要是 :

  1. 看模块能不能读卡
  2. 模块尝试进行卡破解读取
  3. 整卡复制,
需要注意的是写卡需要先存DUMP文件,他的存文件位置比较隐蔽在读卡数据表格的左上角的小三角里,这玩意还真得找一找,我这次也找了好一阵子,找到后突然想起上次也找了好一阵子,恶心·~,这次记录下,下次就不用这么找了。

本次主要说的是串口通信,上位机是实用性的,串口才是本次要记录,接法就不废话了,本次主控ESP32。串口引脚 18,19

根据翻阅5年前的资料,其工作流程为唤醒- 寻卡 - 鉴权 -读写块这么个流程那就一项一项来
55 55 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff 03 fd d4 14 01 17 00  唤醒
==>00 00 ff 00 ff 00 00 00 ff 02 fe d5 15 16 00   成功唤醒反馈
00 00 FF 04 FC D4 4A 02 00 E0 00                                         读卡
00 00 fF 0F F1 D4 40 01 60 (07) FF FF FF FF FF FF AD A5 81 14 A3 00        鉴证07块  可带附近几个块

一个参考博客,没办法自己的记录例程虽然能执行,但是流程还不如人家写的好明白呢,贴这里吧
另一个博客,都在这罗列着,嗯,就好像这是一次多人集团记录似的

6年前的代码就不贴了,本次准备重构一个类来方便使用。

记录一个坑:这个模块自己有一个串口缓存,好家伙真坑人,ESP32的MICPython串口也是缓存型的,这就导致一个问题,一旦串口传输数据有遗留,ESP32怎么搞取得数据都是顺序错误的,而且模块很搞笑,举例:你发24位唤醒码给他,它应该回15位正确唤醒码,如果它缓存里有几个之前的数,那它就把之前的数加上本次的数据给你凑15位给你,数据单个都对就是位置不对,防范办法有两个,一旦出现错乱只能断电,第二上电后要严格执行串口读取的时序和延时避免非完整取值。比如我下面程序里的延时就是调整过的.这个坑坑了我90多分钟·~。6年前使用的STM32,没有遭遇这个坑。

既然重写了,我就多花些时间然后就有了下面这个类文件。。。

下面是打包好的类,注释还是很全的,最好自己读一读

from machine import UART 
import time
import struct
u1=UART(1,115200,rx=18,tx=19)
class Pn532(object):
    def __init__(self,uart):
        self.u1 = uart
        self.uid=b''#uid预付值
        self.awaken()
    def checks(self,verify):#取得校验和的后两位的补码并拼接到验证命令后面
        verify_list=struct.unpack('%db'%len(verify),verify) 
        check=struct.pack('bb',~sum(verify_list))
        verify=verify+check
        return verify
    def uart_send(self,data):
        self.u1.read()  #清空串口
        time.sleep_ms(10) #延时
        self.u1.write(data) #唤醒模块
        time.sleep_ms(80)
    def awaken(self):
        while 1:
            data=b'\x55\x55\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x03\xfd\xd4\x14\x01\x17\x00' #唤醒模块
            self.uart_send(data)
            if self.u1.any()>0:
                data1=self.u1.read(15) #读15个数

                if data1==b'\x00\x00\xff\x00\xff\x00\x00\x00\xff\x02\xfe\xd5\x15\x16\x00': #验证数据,正确就跳出
                    print('huanxing  ok',data1)
                    return 'ok'
    def find_card(self,piect):# 寻卡和验证,参数为正整数表示寻找第几块
        
        while 1:
            if self.u1.any()==0: # 确保串口空闲时发送
                data=b'\x00\x00\xff\x04\xfc\xd4\x4a\x02\x00\xe0\x00'  #寻卡指令
                self.uart_send(data)
                if self.u1.any()>0:
                    data=self.u1.read()
                    if len(data) >12: #甄别出有效数据一般应该大于12位
                        uid = data[-6:-2]  #取出获取到的UID
                        verify=b'\x00\x00\xff\x0f\xf1\xd4\x40\x01\x60%c\xff\xff\xff\xff\xff\xff'%piect+uid #把UID拼接到固定命令后
                        verify=self.checks(verify) #验证尾部校验合的函数
                        self.uart_send(verify)
                        date_verify=self.u1.read()
                        if date_verify[-4:-2]==b'\x41\x00':
                            return 'verify_ok'                          
                    time.sleep(0.2)
            else:
                self.u1.read()
    def read(self,piect):
        self.find_card(piect)
        self.u1.read()
        time.sleep_ms(20)
        if self.u1.any()==0:
            
            senddata=b'\x00\x00\xff\x05\xfb\xd4\x40\x01\x30%c'%piect
            senddata=self.checks(senddata)
            self.uart_send(senddata)
            if u1.any()>20:
                rec_data=self.u1.read()
                print(rec_data)
                if rec_data[12:14]==b'\x41\x00': #查看返回是否是正确码
                    return rec_data[-18:-2]
                else:
                    return ''
            else:
                self.u1.read()
                time.sleep_ms(80)
        else:
            self.u1.read()
    def write(self,piect,b_datas):#俩参数前边是块号,后面是16位二进制数格式为b'\x01\x02'这种共16个
        self.find_card(piect)
        self.u1.read()
        time.sleep_ms(20)
        if self.u1.any()==0:
            senddata=b'\x00\x00\xff\x15\xeb\xd4\x40\x01\xa0%c'%piect+b_datas #写入前面是写入命令里边拼接块号,后面再拼入数据 
            senddata=self.checks(senddata)
            self.uart_send(senddata)
            if u1.any()>12:
                rec_data=self.u1.read()
                if rec_data[-4:-2]==b'\x41\x00':
                    print('write ok==> ',rec_data)
                else:
                    print('write err')
            else:
                self.u1.read()
                time.sleep_ms(80)
        else:
            self.u1.read()

if __name__=='__main__':
    u1=UART(1,115200,rx=18,tx=19)
    a=Pn532(u1) #实例化,同时会执行唤醒模块操作
    read_data=a.read(5)  #读块命令,参数为块号,读取成功有返回值,返回为16位块数据,失败返回空
#   验证和读写进行了组合,读写命令都是阻塞等待模式,方便读写卡,可以先执行命令等一会再放卡
    data = b'\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x10\x01\x02\x03\x05\x01' #待写入数据共16位
#   a.write(5,data) #写块命令,前面参数是块号后面是写入的数据,无返回值,成功打印wirte ok ==> b'\x00\x....'


使用方法为:把上边的类存成一个名字为pn532.py的文件,这个文件放在主函数同级目录下,然后主函数执行下面几行就可以调用读写模块了

from machine import UART
from pn532 import Pn532
u1=UART(1,115200,rx=18,tx=19) #注意串口号,按照自己的改
a=Pn532(u1) #实例化,同时会执行唤醒模块操作
read_data=a.read(5)  #读块命令,参数为块号,读取成功有返回值,返回为16位块数据,失败返回空
#   验证和读写进行了组合,读写命令都是阻塞等待模式,方便读写卡,可以先执行命令等一会再放卡
data = b'\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x10\x01\x02\x03\x05\x01' #待写入数据共16位
#   a.write(5,data) #写块命令,前面参数是块号后面是写入的数据,无返回值,成功打印wirte ok ==> b'\x00\x....'

收工截图记录

请添加图片描述

记点别的:IC卡读写要先鉴权再读写,一般一个卡有64个块 标号为0-63,这里边有个特殊的位置就是0号扇区,0号不能写(嗯~~分卡),卡很多种类。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值