zoukankan      html  css  js  c++  java
  • python 之serial、pyusb 使用开发

    说明:本次是在windows 系统操作实现的。

    serial

    使用场景,获取得力扫码枪的扫码数据,该扫码枪支持三种通讯接口设置,如下图

    即插即用的是 USB-KBW功能,插上去即可获取扫码数据,第二种是通过USB虚拟串口功能实现的,即通过com 口,

    使用前可以通过扫码这三种方式中的其中一种进行设置通讯方式。 

    首先介绍第二种方式

    第二种方式打开后,本机打开记事本,扫码是获取不到扫码数据的,询问客服,客服说该扫码枪不支持该功能。

    但是通过程序监控com口是可以实现获取数据的。具体是通过serial模块进行操作的,具体介绍如下:

    安装 pyserial模块

    pip install pyserial
    # 介绍一下serial的相关方法
    
    open()                        #打开端口
    close()                        #立即关闭端口
    setBaudrate(波特率)  #在打开的端口上更改波特率
    inWaiting()                  #返回接收缓冲区中的字符数
    read(size = 1)             #读取“size”字符
    write(s)                       #将字符串s写入端口
    flushInput()                 #刷新输入缓冲区,丢弃所有的内容
    flushOutput()              #刷新输出缓冲区,中止输出
    sendBreak()               #发送中断条件
    setRTS(level = 1)       #设置RTS线路为指定的逻辑电平
    setDTR(level = 1)       #设置DTR行为指定的逻辑级别
    getCTS()                    #返回CTS行的状态
    getDSR()                    #返回DSR行的状态
    getRI()                        #返回RI行的状态
    getCD()                      #返回CD行的状态

    实例介绍

    检查是否有使用端口欧

    # FileName : demo.py
    # Author   : Adil
    # DateTime : 2019/9/1 7:03
    # SoftWare : PyCharm
    
    
    import serial
    # 这里使用的是windwos 
    from serial.tools.list_ports_windows import *
    
    plist = list(comports())
    
    if len(plist) <= 0:
        print ("The Serial port can't find!")
    else:
        plist_0 =list(plist[0])
        serialName = plist_0[0]
        serialFd = serial.Serial(serialName,9600,timeout = 60)
        print ("check which port was really used >",serialFd.name)

    实际读取端口数据

    # FileName : test.py
    # Author   : Adil
    # DateTime : 2019/9/1 7:25
    # SoftWare : PyCharm
    
    
    import serial
    
    
    ser = serial.Serial('COM6', 9600,timeout=0.5)
    # ser = serial.Serial('COM6', 9600)
    
    print(ser.name)
    
    print(ser.port)
    
    if not ser.isOpen():
        ser.open()
        print('com3 is open', ser.isOpen())
    
    
    
    # 获取一行信息
    def recv(serial):
        print('2')
        data = ''
        while serial.inWaiting() > 0:
            print(serial.inWaiting())
            print('3')
            # data += str(serial.read(15)) # ok 要配合timeout 使用, 否则要传入已知 的 size
            # data += str(serial.readline())  # ok 要配合timeout 使用
            # data += str(serial.readlines())  # ok 要配合timeout 使用
            # data += str(serial.readall())     # ok 要配合timeout 使用
            data += str(serial.read_all())    # ok 要配合timeout 使用
    
            print("************************************")
            #print(serial.read(13))
            print('准备打印data')
            # data = str(serial.read(19))
            print(data)
            print('data:%s'%data)
            print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
    
        return data
    
    
    
    # cursor.execute("DROP TABLE IF EXISTS productinfo")
    
    '''
    sql="""CREATE TABLE productinfo(
            code  CHAR(18),
            price double(9,2),
            info  CHAR(25))"""
    cursor.execute(sql)
    '''
    
    sum = 0.0
    while True:
        print('1')
        data = recv(ser)
        print('4')
        if data != '':
            print('5')
            print(data)
            break
    
    
    ser.close()
    print ser.name#打印设备名称
    
    print ser.port#打印设备名
    
    ser.open() #打开端口
    
    s = ser.read(10)#从端口读10个字节
    
    ser.write("hello")#向端口些数据
    
    ser.close()#关闭端口
    
    data = ser.read(20)#是读20个字符
    
    data = ser.readline() #是读一行,以/n结束,要是没有/n就一直读,阻塞。
    
    data = ser.readlines()和ser.xreadlines()#都需要设置超时时间
    
    ser.baudrate = 9600 #设置波特率
    
     
    
    ser.isOpen() #看看这个串口是否已经被打开

    获得串行口状态、属性

    串行口的属性:

    name:设备名字

    portstr:已废弃,用name代替

    port:读或者写端口

    baudrate:波特率

    bytesize:字节大小

    parity:校验位

    stopbits:停止位

    timeout:读超时设置

    writeTimeout:写超时

    xonxoff:软件流控

    rtscts:硬件流控

    dsrdtr:硬件流控

    interCharTimeout:字符间隔超时

    属性的使用方法:

    ser=serial.Serial("/dev/ttyAMA0",9600,timeout=0.5)

    ser.open()

    print ser.name

    print ser.port

    print ser.baudrate#波特率

    print ser.bytesize#字节大小

    print ser.parity#校验位N-无校验,E-偶校验,O-奇校验

    print ser.stopbits#停止位

    print ser.timeout#读超时设置

    print ser.writeTimeout#写超时

    print ser.xonxoff#软件流控

    print ser.rtscts#硬件流控

    print ser.dsrdtr#硬件流控

    print ser.interCharTimeout#字符间隔超时

    ser.close()

    设置串行口状态

    需要用的常量

    bytesize:FIVE BITS、SIXBITS、SEVENBITS、EIGHTBITS

    parity: PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE

    stopbits: STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO

    异常:

    ValueError:参数错误

    SerialException:找不到设备或不能配置

    ser.baudrate=9600#设置波特率

    ser.bytesize=8#字节大小

    ser.bytesize=serial.EiGHTBITS#8位数据位

    ser.parity=serial.PARITY_EVEN#偶校验

    ser.parity=serial.PARITY_NONE#无校验

    ser.parity=serial.PARITY_ODD#奇校验

    ser.stopbits=1#停止位

    ser.timeout=0.5#读超时设置

    ser.writeTimeout=0.5#写超时

    ser.xonxoff#软件流控

    ser.rtscts#硬件流控

    ser.dsrdtr#硬件流控

    ser.interCharTimeout#字符间隔超时

    Read

    是读一行,以/n结束,要是没有/n就一直读,阻塞。

    使用readline()时应该注意:打开串口时应该指定超时,否则如果串口没有收到新行,则会一直等待。如果没有超时,readline会报异常。

    其中,read(value)方法的参数value为需要读取的字符长度。 如果想要全部读取,提供两个方法:

    inWaiting:监测接收字符。

    inWaitting返回接收字符串的长度值,然后把这个值赋给read做参数。

    data =readall()::读取全部字符。

    data = ser.read()可以读一个字符

    data = ser.read(20) 是读20个字符

    data = ser.readline() 是读一行,以/n结束,要是没有/n就一直读,阻塞。

    data = ser.readlines()和ser.xreadlines()都需要设置超时时间

    import serial
    import serial.tools.list_ports
    
    
    #测试调试输出开关,正式发布需调整为False
    mytest = True
    #mytest = False
    
    def getPort():
        port_serial=[]#返回串口列表
        port_list = list(serial.tools.list_ports.comports())  
    
        if len(port_list) <= 0:  
            print("The Serial port can't find!")      
        else:  
            #if(mytest):print("port_list: ",port_list)
            for port in port_list:
                #if(mytest):print("port: ",port)
                port_serial.append(str(port).split(' ')[0])
               # if(mytest):print("port_serial: ",port_serial)
                
        return(port_serial)   
    
    '''
    ** Descriptions:      发送串口数据
    ** Parameters:        
    ** Returned value:    
    ** Created By:        yanerfree
    ** Created on:        2018年10月16日
    ** Remarks:以二进制读取
    '''  
    def send_data(serial_port="COM6", baudrate=115200, bytesize=8,
                  parity=serial.PARITY_NONE,stopbit=1,
                  timeout=5, filename="F:	est.txt"):
        serial_port_1 = serial_port
        baudrate_1 = int(baudrate)
        bytesize_1 = int(bytesize)
        parity_1 = parity[:1]
        stopbit_1 = int(stopbit)
        timeout_1 = timeout
        filename_1 = filename
        print(serial_port_1,baudrate_1,bytesize_1,parity_1,stopbit_1,timeout_1,filename_1)
        try:
            print("初始化串口")
    #         ser_port = serial.Serial("COM6",115200,timeout=1.5,parity=serial.PARITY_NONE,
    #                     stopbits=serial.STOPBITS_ONE,
    #                     bytesize=serial.EIGHTBITS)
            ser_port = serial.Serial(serial_port_1, baudrate_1,bytesize_1,parity_1,stopbit_1, timeout_1)
            print("串口是否打开:",ser_port.isOpen())
            if not ser_port.isOpen():
                ser_port.open()
            print("串口是否打开:",ser_port.isOpen())
            
            f = open(filename_1,'rb')#打开或者新建一个文件
            i=0
            while 1:
                i = i + 1
                print("读取文 件第  %d 行"%i)
                #fileData=f.readline().strip('
    ').encode(encoding='utf_8')#编码转换成字节发送
                fileData=f.readline().strip(b'
    ')
                fileData=fileData.strip(b'
    ')
                if fileData==b'':
                    break
                #fileData_1=(fileData+'SDSA
    '.encode(encoding='utf_8'))
                fileData_1=(fileData+b'SDSA
    ')
                print("发送数据为:",fileData_1)
                ser_port.write(fileData_1)
                #print("fileData[-11:]",fileData[-11:])
                if fileData[-11:]==b'***[END]***':
                #if fileData[-11:]=='***[END]***':
                    print("检测到文件结束符,退出")
                    break;
                print("等待2s")
                time.sleep(2)
        except Exception:
            print("发送脚本失败")
        finally:
            f.close()
            ser_port.close()      
    
     
    '''
    ** Descriptions:      获取串口数据
    ** Parameters:        
    ** Returned value:    
    ** Created By:        yanerfree
    ** Created on:        2018年10月17日
    ** Remarks:二进制保存
    '''      
    def receive_data(serial_port="COM6", baudrate=115200, bytesize=8,
                     parity=serial.PARITY_NONE,stopbit=1,
                     timeout=5,filename="F:	est.txt"):
        serial_port_1 = serial_port
        baudrate_1 = int(baudrate)
        bytesize_1 = int(bytesize)
        parity_1 = parity[:1]
        stopbit_1 = int(stopbit)
        timeout_1 = timeout
        filename_1 = filename
        print(serial_port_1,baudrate_1,bytesize_1,parity_1,stopbit_1,timeout_1,filename_1)
        try:
            print("初始化串口")
            #ser_port = serial.Serial(serial_port, baudrate,bytesize,parity,stopbit, timeout)
            ser_port = serial.Serial(serial_port_1, baudrate_1,bytesize_1,parity_1,stopbit_1, timeout_1)
            print("串口是否打开:",ser_port.isOpen())
            if not ser_port.isOpen():
                ser_port.open()
            print("串口是否打开:",ser_port.isOpen())
            
            #f = open(filename_1,'w',encoding='utf-8')#打开或者新建一个文件
            f = open(filename_1,'wb')#以二进制打开或创建一个文件
           
            while True:
                fileData=ser_port.readline()
                if(len(fileData)==0 or fileData[-6:]!=b'SDSA
    '):
                    continue;
                print("接收到的数据:",fileData)
                fileData1=fileData.split(b'SDSA
    ')[0]
                fileData2=fileData1+b'
    '#'0X0D'
                filedata_str=fileData1.decode(encoding='utf_8')
                content = filedata_str + '
    '
                print("保存的数据为:",fileData2)
                #saveFile(filename_1,fileData1)
                f.write(fileData2)
                if filedata_str[-11:]=='***[END]***':
                    break;
                sleep(1)
        except Exception:
            print("获取脚本失败")
        finally:
            f.close()
            ser_port.close()
            if mytest: print("串口是否打开:",ser_port.isOpen())

    pyusb

    安装模块

    pip install pyusb

    在设备列表中找到要使用的USB,如下图所示:

    请注意上述的VID_0A12以及PID_0001;这个在使用USB接口时要用到VID以及PID; 

    # FileName : usbdemo.py
    # Author   : Adil
    # DateTime : 2019/9/1 10:26
    # SoftWare : PyCharm
    
    import usb
    
    
    
    all_devs = usb.core.find(find_all=True)
    
    print(all_devs)
    for d in all_devs:
        if (d.idVendor == 'VID_04F2') & (d.idProduct == 'PID_B541'):
            print(d)

    遇到报错:“usb.core.NoBackendError No backend available”

    如果执行时遇到上面的错误,解决办法 

    最近一个案子是要用到USB信息交互,获取电脑连接的USB设备,主要是用到pyusb的库,按照网上的教程和代码,但是遇到了报错:usb.core.NoBackendError No backend available ,网上关于这个错误的解决方案也有不少,但是大部分都是英文,而且有些试了下并没有效果,不过好在最后还是完美解决,这里记录下。

     我是根据他的解决方案来解决的,我的操作系统是Windows10_64位。

     首先,打开链接,网页会自动下载libusb-1.0.20的压缩包

    打开压缩包,选择MS64dlllibusb-1.0.dll,复制到C:WindowsSystem32

        然后选择同目录下的libusb-1.0.lib到Python环境,我用的环境是conda的Python,所以就复制到D:Anaconda3Lib下

    然后执行程序即可打印usb信息。

  • 相关阅读:
    即将到来的Android N,将具备这些新特性
    刚挣钱的程序猿同学该怎样花钱?
    Swift函数
    MVC
    css3硬件加速
    node+mongoDB+express项目需求解释
    柯里化
    web安全
    缓存机制详解
    nodejs --- crypto实现加密(转)
  • 原文地址:https://www.cnblogs.com/BlueSkyyj/p/11445724.html
Copyright © 2011-2022 走看看