Python串口通讯发送指令读写NFC源码 支持windows、linux系统

 本示例使用的读卡器介绍:RS232串口RFID NFC IC卡读写器可二次开发编程发卡器USB转COM-淘宝网 (taobao.com)

#pip3 install pyserial   安装Python串口通讯库

import serial
import time
import serial.tools.list_ports

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QDateTime
from PyQt5.QtWidgets import QApplication, QWidget, QDesktopWidget,QMessageBox
from PyQt5.QtGui import QFont
from IC07UIS import Ui_Frame
import sys

import struct  # struct的pack函数把任意数据类型变成字符串
import ctypes  # 调用DLL动态库要有这个引用

selecom=0
ser = serial.Serial()
ComIsOpen=False
OrderCode=0
RcvBuff=b''

class SerialListenThread(QThread):       # 串口侦听线程
    serial_data = pyqtSignal(int,str)    # 创建一个信号,触发时传递显示信息给槽函数

    def run(self):
        global ComIsOpen
        global OrderCode
        global RcvBuff
        while ComIsOpen:
            try:
                rcvdata = ser.read_all()
                if (len(rcvdata) > 0):
                    if (OrderCode<=1):
                        GetData = '接收数据:'
                        for num in range(0, len(rcvdata)):
                            GetData = GetData + '%02X ' % (rcvdata[num])
                        self.serial_data.emit(1, GetData)
                    else:
                        RcvBuff = RcvBuff + rcvdata
                        if (len(RcvBuff)>=RcvBuff[0]+2):
                            deldata=RcvBuff[0:RcvBuff[0]+2]
                            GetData = '接收数据:'
                            for num in range(0, len(deldata)):
                                GetData = GetData + '%02X ' % (deldata[num])
                            self.serial_data.emit(1, GetData)

                            crc = 0  # 计算返回数据的校验位
                            for num in range(1, len(deldata) - 1):
                                crc = crc ^ deldata[num]
                            if (crc == deldata[len(deldata) - 1]):
                                if(OrderCode==2):     #寻卡指令返回信息
                                    if (deldata[0] == 1 and deldata[1] == 8):
                                        self.serial_data.emit(2, '未寻到卡!')
                                    elif (deldata[0] == 1 and deldata[1] == 9):
                                        self.serial_data.emit(2, '两张以上卡片同时在感应区,发生冲突!')
                                    elif (deldata[0] == 1 and deldata[1] == 10):
                                        self.serial_data.emit(2, '无法选择激活卡片!')
                                    elif (deldata[0] == 5):
                                        self.serial_data.emit(2, '寻到IC卡,16进制卡号:%02X %02X %02X %02X ' % (deldata[2], deldata[3], deldata[4], deldata[5]))

                                elif(OrderCode==3):   #轻松读IC卡扇区指令返回数据
                                    if (deldata[0] == 1 and deldata[1] == 8):
                                        self.serial_data.emit(2, '未寻到卡!')
                                    elif (deldata[0] == 1 and deldata[1] == 9):
                                        self.serial_data.emit(2, '两张以上卡片同时在感应区,发生冲突!')
                                    elif (deldata[0] == 5):
                                        if (deldata[1] == 1):
                                            self.serial_data.emit(2, '寻到IC卡,16进制卡号:%02X %02X %02X %02X ' % (deldata[2], deldata[3], deldata[4], deldata[5]) + ',密码认证成功,但读取扇区内容失败!')
                                        elif (deldata[1] == 2):
                                            self.serial_data.emit(2, '寻到IC卡,16进制卡号:%02X %02X %02X %02X ' % (deldata[2], deldata[3], deldata[4], deldata[5]) + ',第0块读出,但第1、2块没读出,仅扇区内容前16个字节的数据有效!')
                                        elif (deldata[1] == 3):
                                            self.serial_data.emit(2, '寻到IC卡,16进制卡号:%02X %02X %02X %02X ' % (deldata[2], deldata[3], deldata[4], deldata[5]) + ',第0、1块读出,但第2块没读出,仅扇区内容前32个字节的数据有效!')
                                        elif (deldata[1] == 10):
                                            self.serial_data.emit(2, '寻到IC卡,16进制卡号:%02X %02X %02X %02X ' % (deldata[2], deldata[3], deldata[4], deldata[5]) + ',无法选择激活卡片!')
                                        elif (deldata[1] == 12):
                                            self.serial_data.emit(2, '寻到IC卡,16进制卡号:%02X %02X %02X %02X ' % (deldata[2], deldata[3], deldata[4], deldata[5]) + ',密码认证失败!')
                                        else:
                                            self.serial_data.emit(2, '操作失败,错误代码:' + str(deldata[1]))
                                    elif (deldata[0] == 53):
                                        self.serial_data.emit(2, '寻到IC卡,16进制卡号:%02X %02X %02X %02X ' % (deldata[2], deldata[3], deldata[4], deldata[5]) + ',读取扇区数据成功!')
                                        ReturnInf = ''
                                        for num in range(6, len(deldata) - 1):
                                            ReturnInf = ReturnInf + '%02X ' % (deldata[num])
                                        self.serial_data.emit(3,ReturnInf)

                                elif (OrderCode == 4):
                                    if (deldata[0] == 1 and deldata[1] == 8):
                                        self.serial_data.emit(2, '未寻到卡!')
                                    elif (deldata[0] == 1 and deldata[1] == 9):
                                        self.serial_data.emit(2, '两张以上卡片同时在感应区,发生冲突!')
                                    elif (deldata[0] == 5):
                                        if (deldata[1] == 0):
                                            self.serial_data.emit(4, '寻到IC卡,16进制卡号:%02X %02X %02X %02X ' % (deldata[2], deldata[3], deldata[4], deldata[5]) + ',写扇区数据成功!')
                                        elif (deldata[1] == 1):
                                            self.serial_data.emit(2, '寻到IC卡,16进制卡号:%02X %02X %02X %02X ' % (deldata[2], deldata[3], deldata[4], deldata[5]) + ',密码认证成功,但写扇区内容失败!')
                                        elif (deldata[1] == 2):
                                            self.serial_data.emit(2, '寻到IC卡,16进制卡号:%02X %02X %02X %02X ' % (deldata[2], deldata[3], deldata[4], deldata[5]) + ',第0块写入成功,但第1、2块写入失败!')
                                        elif (deldata[1] == 3):
                                            self.serial_data.emit(2, '寻到IC卡,16进制卡号:%02X %02X %02X %02X ' % (deldata[2], deldata[3], deldata[4], deldata[5]) + ',第0、1块写入成功,但第2块写入失败!')
                                        elif (deldata[1] == 10):
                                            self.serial_data.emit(2, '寻到IC卡,16进制卡号:%02X %02X %02X %02X ' % (deldata[2], deldata[3], deldata[4], deldata[5]) + ',无法选择激活卡片!')
                                        elif (deldata[1] == 12):
                                            self.serial_data.emit(2, '寻到IC卡,16进制卡号:%02X %02X %02X %02X ' % (deldata[2], deldata[3], deldata[4], deldata[5]) + ',密码认证失败!')
                                        else:
                                            self.serial_data.emit(2, '操作失败,错误代码:' + str(deldata[1]))

                                elif (OrderCode == 5):
                                    if (deldata[0] == 1 and deldata[1] == 8):
                                        self.serial_data.emit(2, '未寻到卡!')
                                    elif (deldata[0] == 1 and deldata[1] == 9):
                                        self.serial_data.emit(2, '两张以上卡片同时在感应区,发生冲突!')
                                    elif (deldata[0] == 5):
                                        if (deldata[1] == 0):
                                            self.serial_data.emit(4, '寻到IC卡,16进制卡号:%02X %02X %02X %02X ' % (deldata[2], deldata[3], deldata[4], deldata[5]) + ',修改IC卡密码成功!')
                                        elif (deldata[1] == 10):
                                            self.serial_data.emit(2, '寻到IC卡,16进制卡号:%02X %02X %02X %02X ' % (deldata[2], deldata[3], deldata[4], deldata[5]) + ',无法选择激活卡片!')
                                        elif (deldata[1] == 12):
                                            self.serial_data.emit(2, '寻到IC卡,16进制卡号:%02X %02X %02X %02X ' % (deldata[2], deldata[3], deldata[4], deldata[5]) + ',密码认证失败!')
                                        else:
                                            self.serial_data.emit(2, '操作失败,错误代码:' + str(deldata[1]))

                                elif (OrderCode == 6):      # 写Ntag卡返回状态
                                    if (deldata[1] == 0):
                                        cardnohex='%02X%02X%02X%02X%02X%02X%02X' %(deldata[2], deldata[3], deldata[4], deldata[5], deldata[6], deldata[7], deldata[8])
                                        self.serial_data.emit(6, '卡号:' + cardnohex+',写卡成功!')
                                    elif (deldata[1] == 8):
                                        self.serial_data.emit(6, '未寻到卡!')
                                    elif (deldata[1] == 9):
                                        self.serial_data.emit(6, '两张以上卡片同时在感应区,发生冲突!')
                                    elif (deldata[1] == 12):
                                        self.serial_data.emit(6, '卡号:' + cardnohex+',密码认证失败!')
                                    elif (deldata[1] == 14):
                                        self.serial_data.emit(6, '卡号:' + cardnohex+',写卡失败,可能要带密码操作!')
                                    else:
                                        self.serial_data.emit(6, '写卡错误,返回代码:%d' %(deldata[1]))

                                elif (OrderCode == 7):      # 读Ntag卡返回状态
                                    if (deldata[1] == 0):
                                        cardnohex='%02X%02X%02X%02X%02X%02X%02X' %(deldata[2], deldata[3], deldata[4], deldata[5], deldata[6], deldata[7], deldata[8])
                                        self.serial_data.emit(6, '卡号:' + cardnohex+',读卡成功!')
                                        GetdataStr=''
                                        for num in range(11 , len(deldata)-1 ):
                                            GetdataStr=GetdataStr+ '%02X '%(deldata[num])
                                        self.serial_data.emit(7, GetdataStr)
                                    elif (deldata[1] == 8):
                                        self.serial_data.emit(6, '未寻到卡!')
                                    elif (deldata[1] == 9):
                                        self.serial_data.emit(6, '两张以上卡片同时在感应区,发生冲突!')
                                    elif (deldata[1] == 12):
                                        self.serial_data.emit(6, '卡号:' + cardnohex+',密码认证失败!')
                                    elif (deldata[1] == 13):
                                        self.serial_data.emit(6, '卡号:' + cardnohex+',读卡失败,可能要带密码操作!')
                                    else:
                                        self.serial_data.emit(6, '写卡错误,返回代码:%d' %(deldata[1]))

                            RcvBuff = RcvBuff[RcvBuff[0] + 2:]
                            if(len(RcvBuff)==0):
                                OrderCode=0
            except:
                self.serial_data.emit(9, '串口通讯异常,请重新打开与设备相连的串口继续......')


class MainWindow(QtWidgets.QMainWindow, Ui_Frame):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)

        self.Butt_Open.clicked.connect(self.Butt_Open_click)
        self.Butt_Beep.clicked.connect(self.Butt_Beep_click)
        self.Butt_Request.clicked.connect(self.Butt_Request_click)
        self.Com_Serial.currentIndexChanged.connect(self.Com_Serialselectionchange)
        self.Butt_ReadCard.clicked.connect(self.Butt_ReadCard_click)
        self.Butt_Writecard.clicked.connect(self.Butt_Writecard_click)
        self.Butt_Changekey.clicked.connect(self.Butt_Changekey_click)
        self.Butt_Sendhex.clicked.connect(self.Butt_Sendhex_click)
        self.Butt_Clear.clicked.connect(self.Butt_Clear_click)

        self.checkBox_authen.toggled.connect(self.checkBox_authen_toggled)
        self.PB_init.clicked.connect(self.PB_init_clicked)
        self.PB_easyread.clicked.connect(self.PB_easyread_clicked)
        self.PB_easywrite.clicked.connect(self.PB_easywrite_clicked)

    def SerialGetData(self,dispcode,Getdata):
        global ComIsOpen
        global ser
        if (dispcode == 1):
            self.ListAddItem(Getdata)
        elif (dispcode == 2):
            self.Label_Cardno.setText(Getdata)
        elif (dispcode == 3):
            self.Text_Data.setText(Getdata)
            self.Butt_Beep_click()
        elif (dispcode == 4):
            self.Label_Cardno.setText(Getdata)
            self.Butt_Beep_click()
        elif (dispcode == 6):
            self.Label_status.setText(Getdata)
        elif (dispcode == 7):
            self.Text_TagData.setPlainText(Getdata)
        elif (dispcode == 9):
            self.ListAddItem(Getdata)
            ser = serial.Serial()
            ser.close()
            ComIsOpen = False
            self.Butt_Open.setText('打开串口')

            self.Com_Serial.clear()  # 刷新串口列表,看是否有新串口
            port_list = list(serial.tools.list_ports.comports())
            for i in range(0, len(port_list)):
                self.Com_Serial.addItem(list(port_list[i])[0])
            if (self.Com_Serial.count() - 1 >= selecom):
                self.Com_Serial.setCurrentIndex(selecom)
            else:
                self.Com_Serial.setCurrentIndex(0)

    def checkBox_authen_toggled(self):
        if self.checkBox_authen.isChecked():
            self.lineEdit_authkey.setVisible(True)
        else:
            self.lineEdit_authkey.setVisible(False)

    def Butt_Clear_click(self):
        self.List_Info.clear()

    def ListAddItem(self,itemstr):
        if self.List_Info.count() > 10:
            self.List_Info.clear()
        self.List_Info.addItem(itemstr)
        self.List_Info.scrollToBottom()
        seleid = self.List_Info.count() - 1
        self.List_Info.item(seleid).setSelected(True)

    def Com_Serialselectionchange(self):
        global ComIsOpen
        global ser
        ser = serial.Serial()
        ser.close()
        ComIsOpen = False
        self.Butt_Open.setText('打开串口')

    def Butt_Open_click(self):
        global ComIsOpen
        global ser
        global selecom
        global RcvBuff
        if (self.Butt_Open.text() == '打开串口'):
            port_serial = self.Com_Serial.currentText()
            port_baud = int(self.Com_Baud.currentText())
            port_bytesize = int(self.Com_Size.currentText())
            port_parity = self.Com_Parity.currentText()
            port_stopbits = int(self.Com_Stop.currentText())
            try:
                ser = serial.Serial(port_serial, port_baud, bytesize=port_bytesize, parity=port_parity,
                                    stopbits=port_stopbits, xonxoff=False, rtscts=False, dsrdtr=False)
                if (ser.isOpen()):
                    selecom = self.Com_Serial.currentIndex()

                    self.subSerialListenThread = SerialListenThread()
                    self.subSerialListenThread.serial_data.connect(self.SerialGetData)
                    self.subSerialListenThread.start()  # 开启串口接收线程

                    RcvBuff = b''
                    ComIsOpen = True
                    self.Butt_Open.setText('关闭串口')
            except:
                res = QMessageBox.critical(self, "警告", "     您选择的串口打开失败,请检查该串口是否已被其他应用占用!", QMessageBox.Yes)

                self.Com_Serial.clear()  # 刷新串口列表,看是否有新串口
                port_list = list(serial.tools.list_ports.comports())
                for i in range(0, len(port_list)):
                    self.Com_Serial.addItem(list(port_list[i])[0])
                if (self.Com_Serial.count() - 1 >= selecom):
                    self.Com_Serial.setCurrentIndex(selecom)
                else:
                    self.Com_Serial.setCurrentIndex(0)
        else:
            ser = serial.Serial()
            ser.close()
            ComIsOpen = False
            self.Butt_Open.setText('打开串口')

            self.Com_Serial.clear()  # 刷新串口列表,看是否有新串口
            port_list = list(serial.tools.list_ports.comports())
            for i in range(0, len(port_list)):
                self.Com_Serial.addItem(list(port_list[i])[0])
            if (self.Com_Serial.count() - 1 >= selecom):
                self.Com_Serial.setCurrentIndex(selecom)
            else:
                self.Com_Serial.setCurrentIndex(0)

    def Butt_Beep_click(self):
        global ComIsOpen
        global ser
        global OrderCode
        global RcvBuff
        if(ComIsOpen):
            OrderCode=1
            beepdelay = self.Sp_Delay.value()   # 响声时长,单位豪秒
            sdata = bytes([eval('0x03')])  # 1字节指令长度
            sdata = sdata + bytes([eval('0x0F')])  # 1字节功能码
            sdata = sdata + bytes([beepdelay % 256])  # 2字节蜂鸣响声延时 低位
            sdata = sdata + bytes([beepdelay // 256])  # 高位
            sdata = sdata + bytes([sdata[1] ^ sdata[2] ^ sdata[3]])  # 1字节异或和校验码
            RcvBuff=b''
            ser.write(sdata)  # 向串口写入数据
            SendInf=''
            for num in range(0, len(sdata)):
                SendInf = SendInf + '%02X ' % (sdata[num])
            self.Text_HexData.setText(SendInf)
            self.ListAddItem('发送数据:'+SendInf)
        else:
            QMessageBox.critical(self, "提示", "请先选择打开与读写器相连的串口!", QMessageBox.Yes)

    def Butt_Request_click(self):
        global ComIsOpen
        global ser
        global OrderCode
        global RcvBuff
        if(ComIsOpen):
            self.Label_Cardno.setText('')
            OrderCode=2
            sdata = bytes([eval('0x01'), eval('0xF0'), eval('0xF0')])
            RcvBuff=b''
            ser.write(sdata)  # 向串口写入数据
            SendInf=''
            for num in range(0, len(sdata)):
                SendInf = SendInf + '%02X ' % (sdata[num])
            self.Text_HexData.setText(SendInf)
            self.ListAddItem('发送数据:'+SendInf)
        else:
            QMessageBox.critical(self, "提示", "请先选择打开与读写器相连的串口!", QMessageBox.Yes)

    def Butt_ReadCard_click(self):
        global ComIsOpen
        global ser
        global OrderCode
        global RcvBuff
        if(ComIsOpen):
            try:
                keys = bytes.fromhex(self.Text_key.toPlainText())
            except:
                QMessageBox.critical(self, "提示", "卡密码输入错误!", QMessageBox.Yes)
                return

            if(len(keys)!=6):
                QMessageBox.critical(self, "提示", "卡密码输入错误!", QMessageBox.Yes)
                return
            sdata = bytes([eval('0x0E'), eval('0x78'), eval('0x17')])    # 指令长度 、功能码、读写卡操作权限
            sdata = sdata + bytes.fromhex('00000000')                    # 4字节的16进制 要操作的卡号,如果全部取0表示可以 操作任意卡
            sdata = sdata + bytes([self.Com_Area.currentIndex()])  # 操作扇区号,取值0-15
            sdata = sdata + bytes([self.Com_Auth.currentIndex()])  # 卡片认证方式,1为A密码认证,0为B密码认证,推荐取1
            sdata = sdata + keys                                         # 6字节的16进制 卡片认证密码
            crc = 0  # 计算校验位
            for num in range(1, 15):
                crc = crc ^ sdata[num]
            sdata = sdata + bytes([crc])
            OrderCode=3
            RcvBuff=b''
            ser.write(sdata)  # 向串口写入数据
            SendInf = ''
            for num in range(0, len(sdata)):
                SendInf = SendInf + '%02X ' % (sdata[num])
            self.Text_HexData.setText(SendInf)
            self.ListAddItem('发送数据:' + SendInf)
        else:
            QMessageBox.critical(self, "提示", "请先选择打开与读写器相连的串口!", QMessageBox.Yes)

    def Butt_Writecard_click(self):
        global ComIsOpen
        global ser
        global OrderCode
        global RcvBuff
        if(ComIsOpen):
            try:
                keys = bytes.fromhex(self.Text_key.toPlainText())
            except:
                QMessageBox.critical(self, "提示", "卡密码输入错误!", QMessageBox.Yes)
                return
            if(len(keys)!=6):
                QMessageBox.critical(self, "提示", "卡密码输入错误!", QMessageBox.Yes)
                return

            try:
                wdata = bytes.fromhex(self.Text_Data.toPlainText())
            except:
                QMessageBox.critical(self, "提示", "写卡数据输入错误!", QMessageBox.Yes)
                return
            if(len(wdata)<48):
                res = QMessageBox.question(self, "提示", "写卡数据不足48位,是否要补足48位写入?",QMessageBox.Yes | QMessageBox.No)
                if (QMessageBox.No == res):
                    return
                else:
                    for num in range(0, 48):
                        wdata=wdata+bytes([0])

            wdata=wdata[0:48]

            sdata = bytes([eval('0x3E'), eval('0x69'), eval('0x17')])   # 指令长度 、功能码、读写卡操作权限
            sdata = sdata + bytes.fromhex('00000000')                   # 4字节的16进制 要操作的卡号,如果全部取0表示可以 操作任意卡
            sdata = sdata + bytes([self.Com_Area.currentIndex()])       # 操作扇区号,取值0-15
            sdata = sdata + bytes([self.Com_Auth.currentIndex()])       # 卡片认证方式,1为A密码认证,0为B密码认证,推荐取1
            sdata = sdata + keys                                        # 6字节的16进制 卡片认证密码
            sdata = sdata + wdata                                       # 48个字节的写入数据

            crc = 0  # 计算校验位
            for num in range(1, 63):
                crc = crc ^ sdata[num]
            sdata = sdata + bytes([crc])
            OrderCode=4
            RcvBuff=b''
            ser.write(sdata)  # 向串口写入数据
            SendInf = ''
            for num in range(0, len(sdata)):
                SendInf = SendInf + '%02X ' % (sdata[num])
            self.Text_HexData.setText(SendInf)
            self.ListAddItem('发送数据:' + SendInf)
        else:
            QMessageBox.critical(self, "提示", "请先选择打开与读写器相连的串口!", QMessageBox.Yes)

    def Butt_Changekey_click(self):
        global ComIsOpen
        global ser
        global OrderCode
        global RcvBuff
        if(ComIsOpen):
            try:
                keys = bytes.fromhex(self.Text_key.toPlainText())
            except:
                QMessageBox.critical(self, "提示", "卡密码输入错误!", QMessageBox.Yes)
                return
            if(len(keys)!=6):
                QMessageBox.critical(self, "提示", "卡密码输入错误!", QMessageBox.Yes)
                return
            try:
                newkey = bytes.fromhex(self.Text_Newkey.toPlainText())
            except:
                QMessageBox.critical(self, "提示", "新密码及控制位输入错误!", QMessageBox.Yes)
                return
            if(len(newkey)!=16):
                QMessageBox.critical(self, "提示", "新密码及控制位输入错误,请输入6字节新A密码+4字节控制位+6字节新B密码!", QMessageBox.Yes)
                return
            res = QMessageBox.question(self, "警告", "     您确定要继续执行修改卡密码及控制位的操作吗?如确定修改请务必记住卡的新密码,否则卡片将报废!",QMessageBox.Yes | QMessageBox.No)
            if (QMessageBox.Yes == res):
                sdata = bytes([eval('0x1F'), eval('0xF1'), eval('0x17')])   # 指令长度 、功能码、读写卡操作权限
                sdata = sdata + bytes.fromhex('00000000')                   # 4字节的16进制 要操作的卡号,如果全部取0表示可以 操作任意卡
                sdata = sdata + bytes([self.Com_Area.currentIndex()])       # 操作扇区号,取值0-15
                sdata = sdata + bytes([self.Com_Auth.currentIndex()])       # 卡片认证方式,1为A密码认证,0为B密码认证,推荐取1
                sdata = sdata + keys                                        # 6字节的16进制 卡片认证密码
                sdata = sdata + newkey                                      # 16个字节的新密码
                sdata = sdata + bytes([3])                                  # 取值0只修改A密码,取值2修改AB密码,取值3修改AB密码及控制位

                crc = 0  # 计算校验位
                for num in range(1, 32):
                    crc = crc ^ sdata[num]
                sdata = sdata + bytes([crc])
                OrderCode=5
                RcvBuff=b''
                ser.write(sdata)  # 向串口写入数据
                SendInf = ''
                for num in range(0, len(sdata)):
                    SendInf = SendInf + '%02X ' % (sdata[num])
                self.Text_HexData.setText(SendInf)
                self.ListAddItem('发送数据:' + SendInf)
        else:
            QMessageBox.critical(self, "提示", "请先选择打开与读写器相连的串口!", QMessageBox.Yes)

    def Butt_Sendhex_click(self):
        global ComIsOpen
        global ser
        global OrderCode
        global RcvBuff
        if(ComIsOpen):
            self.Label_Cardno.setText('')
            try:
                sdata = bytes.fromhex(self.Text_HexData.toPlainText())
            except:
                QMessageBox.critical(self, "提示", "发送数据输入错误!", QMessageBox.Yes)
                return
            if(len(sdata)==0):
                QMessageBox.critical(self, "提示", "请输入要向串口发送的十六进制数据!", QMessageBox.Yes)
                return

            OrderCode=0
            RcvBuff=b''
            ser.write(sdata)  # 向串口写入数据
            SendInf=''
            for num in range(0, len(sdata)):
                SendInf = SendInf + '%02X ' % (sdata[num])
            self.Text_HexData.setText(SendInf)
            self.ListAddItem('发送数据:'+SendInf)
        else:
            QMessageBox.critical(self, "提示", "请先选择打开与读写器相连的串口!", QMessageBox.Yes)

    def PB_init_clicked(self):
        global ComIsOpen
        global ser
        global OrderCode
        global RcvBuff

        self.Label_status.setText('')
        if (ComIsOpen):
            myctrlword = 0
            if self.checkBox_authen.isChecked(): #需要先认证卡片密钥
                oldkeystr=self.lineEdit_authkey.text().strip()
                if is_valid_hex(oldkeystr)==False or len(bytes.fromhex(oldkeystr))!=4 :
                    QMessageBox.critical(self, "提示", "认证密钥输入错误,请输入8位16进制认证密钥!", QMessageBox.Yes)
                    self.lineEdit_authkey.setFocus()
                    return
                myctrlword=16
            else:
                oldkeystr ='00000000'

            if self.Com_keyen.currentIndex() ==0: #开启卡密钥保护
                newkeystr=self.lineEdit_newkey.text().strip()
                if is_valid_hex(newkeystr)==False or len(bytes.fromhex(newkeystr))!=4 :
                    QMessageBox.critical(self, "提示", "新密钥输入错误,请输入8位16进制密钥!", QMessageBox.Yes)
                    self.lineEdit_newkey.setFocus()
                    return

                errnum=self.Sp_errnum.value() % 8       #启用密码认证次数
                if self.Com_RWKeyOn.currentIndex() ==1: #读卡也要认证密码
                    errnum=errnum+128

                myctrlword = myctrlword + 7
                configdata = bytes.fromhex('000000')
                configdata=configdata+bytes([self.Sp_initbeg.value()]) #起始保护页
                configdata = configdata + bytes([errnum])
                configdata = configdata + bytes.fromhex('000000')
                configdata = configdata + bytes.fromhex(newkeystr)
                configdata = configdata + bytes.fromhex('16160000')
            else:                                 #关闭卡密钥保护
                myctrlword = myctrlword + 3
                configdata=bytes.fromhex('000000FF000000000000000000000000')

            sdata = bytes.fromhex('1D16') #指令长度、功能码
            sdata = sdata + bytes([myctrlword])
            sdata = sdata + bytes.fromhex('00000000000000')    #7字节要操作的卡片UID,全取0表示操作发卡器上任意卡
            sdata = sdata + bytes.fromhex(oldkeystr) #4字节卡认证密钥
            sdata = sdata + configdata

            crc=0
            for num in range(1,len(sdata)):
                crc=crc ^ sdata[num]

            sdata = sdata + bytes([crc])

            OrderCode = 6
            RcvBuff = b''
            ser.write(sdata)  # 向串口写入数据
            SendInf = ''
            for num in range(0, len(sdata)):
                SendInf = SendInf + '%02X ' % (sdata[num])
            self.Text_HexData.setText(SendInf)
            self.ListAddItem('发送数据:' + SendInf)
        else:
            QMessageBox.critical(self, "提示", "请先选择打开与读写器相连的串口!", QMessageBox.Yes)

    def PB_easyread_clicked(self):
        global ComIsOpen
        global ser
        global OrderCode
        global RcvBuff

        self.Label_status.setText('')
        self.Text_TagData.setPlainText('')

        if (ComIsOpen):
            myctrlword = 0
            if self.checkBox_authen.isChecked():  # 需要先认证卡片密钥
                oldkeystr = self.lineEdit_authkey.text().strip()
                if is_valid_hex(oldkeystr) == False or len(bytes.fromhex(oldkeystr)) != 4:
                    QMessageBox.critical(self, "提示", "认证密钥输入错误,请输入8位16进制认证密钥!", QMessageBox.Yes)
                    self.lineEdit_authkey.setFocus()
                    return
                myctrlword = 16
            else:
                oldkeystr = '00000000'

            if  self.Sp_RWNum.value()>12:
                QMessageBox.critical(self, "提示", "每次读取页数取值范围 0~12!", QMessageBox.Yes)
                return

            sdata = bytes.fromhex('0F1B')                    # 指令长度、功能码
            sdata = sdata + bytes([myctrlword])              # 控制字 0 表示无需密码操作任意卡; +8 表示指定卡;+16表示 带密码操作
            sdata = sdata + bytes.fromhex('00000000000000')  # 7字节要操作的卡片UID,全取0表示操作发卡器上任意卡
            sdata = sdata + bytes.fromhex(oldkeystr)         # 4字节卡认证密钥
            sdata = sdata + bytes([self.Sp_RWBegin.value()]) # 读起始页
            sdata = sdata + bytes([self.Sp_RWNum.value()])   # 读取页数

            crc = 0
            for num in range(1, len(sdata)):
                crc = crc ^ sdata[num]

            sdata = sdata + bytes([crc])

            OrderCode = 7
            RcvBuff = b''
            ser.write(sdata)  # 向串口写入数据
            SendInf = ''
            for num in range(0, len(sdata)):
                SendInf = SendInf + '%02X ' % (sdata[num])
            self.Text_HexData.setText(SendInf)
            self.ListAddItem('发送数据:' + SendInf)
        else:
            QMessageBox.critical(self, "提示", "请先选择打开与读写器相连的串口!", QMessageBox.Yes)

    def PB_easywrite_clicked(self):
        global ComIsOpen
        global ser
        global OrderCode
        global RcvBuff

        self.Label_status.setText('')
        if (ComIsOpen):
            myctrlword = 0
            if self.checkBox_authen.isChecked():  # 需要先认证卡片密钥
                oldkeystr = self.lineEdit_authkey.text().strip()
                if is_valid_hex(oldkeystr) == False or len(bytes.fromhex(oldkeystr)) != 4:
                    QMessageBox.critical(self, "提示", "认证密钥输入错误,请输入8位16进制认证密钥!", QMessageBox.Yes)
                    self.lineEdit_authkey.setFocus()
                    return
                myctrlword = 16
            else:
                oldkeystr = '00000000'

            if  self.Sp_RWNum.value()==0 or self.Sp_RWNum.value()>11:
                QMessageBox.critical(self, "提示", "每次写页数取值范围 1~11!", QMessageBox.Yes)
                return

            WriteLen = self.Sp_RWNum.value()*4
            writedatastr=self.Text_TagData.toPlainText().strip()
            if is_valid_hex(writedatastr) == False or len(bytes.fromhex(writedatastr)) < WriteLen:
                QMessageBox.critical(self, "提示", "写入数据错误,请输入 %d" %(WriteLen*2) +" 位16进制的写入数据!", QMessageBox.Yes)
                return
            writedatabuf=bytes.fromhex(writedatastr)[:WriteLen]

            sdata = bytes([15+WriteLen])            # 指令长度
            sdata = sdata + bytes([eval('0x1C')])   # 功能码
            sdata = sdata + bytes([myctrlword])  # 控制字 0 表示无需密码操作任意卡; +8 表示指定卡;+16表示 带密码操作
            sdata = sdata + bytes.fromhex('00000000000000')  # 7字节要操作的卡片UID,全取0表示操作发卡器上任意卡
            sdata = sdata + bytes.fromhex(oldkeystr)  # 4字节卡认证密钥
            sdata = sdata + bytes([self.Sp_RWBegin.value()])  # 读起始页
            sdata = sdata + bytes([self.Sp_RWNum.value()])  # 读取页数
            sdata = sdata + writedatabuf

            crc = 0
            for num in range(1, len(sdata)):
                crc = crc ^ sdata[num]

            sdata = sdata + bytes([crc])

            OrderCode = 6
            RcvBuff = b''
            ser.write(sdata)  # 向串口写入数据
            SendInf = ''
            for num in range(0, len(sdata)):
                SendInf = SendInf + '%02X ' % (sdata[num])
            self.Text_HexData.setText(SendInf)
            self.ListAddItem('发送数据:' + SendInf)
        else:
            QMessageBox.critical(self, "提示", "请先选择打开与读写器相连的串口!", QMessageBox.Yes)

def is_valid_hex(input_str):
    input_str = input_str.replace(" ", "")
    try:
        if (len(bytes.fromhex(input_str)) == len(input_str) / 2):
            return True
        else:
            return False
    except:
        return False

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    mainWindow = MainWindow()

    screen = QDesktopWidget().screenGeometry()
    size = mainWindow.geometry()
    # 获得窗口相关坐标
    newLeft = (screen.width() - size.width()) // 2
    newTop = (screen.height() - size.height()) // 2
    # 移动窗口使其居中
    mainWindow.move(newLeft, newTop)

    mainWindow.setWindowTitle("IC-07串口读写器 Python Demo")
    mainWindow.show()

    port_list = list(serial.tools.list_ports.comports())
    for i in range(0, len(port_list)):
        mainWindow.Com_Serial.addItem(list(port_list[i])[0])

    mainWindow.Com_Baud.setCurrentIndex(2)
    mainWindow.Com_Size.setCurrentIndex(3)
    mainWindow.Com_Stop.setCurrentIndex(0)
    mainWindow.Sp_Delay.setMaximum(65535)
    mainWindow.Sp_Delay.setValue(50)
    mainWindow.Com_Auth.setCurrentIndex(1)
    mainWindow.lineEdit_authkey.setVisible(False)
    mainWindow.Com_keyen.setCurrentIndex(1)
    mainWindow.Label_Cardno.setStyleSheet("color: red;")
    mainWindow.label_8.setStyleSheet('color:blue;')
    mainWindow.label_14.setStyleSheet('color:blue;')
    mainWindow.Label_status.setStyleSheet("color: red;")

    sys.exit(app.exec_())
源码下载:Python串口读写器windows、linux系统源码资源-CSDN文库

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

vx_13822155058

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值