6

这是一个更新和缩短的问题。

通过PyUSB与 USB 设备通信应该很容易。所以,我试图在 Win10 下使用 PyUSB 从 USB 设备(示波器)读取数据。显然,自从找到设备以来,USB 驱动程序(libusb-win32 v1.2.6.0)已正确安装,并且我得到了一些响应print(dev)(见下文)。从这里我可以看到输出端点地址是0x3,输入端点地址是0x81

根据示波器手册,我应该发送:SDSLSCPI#到设备以将其设置为 SCPI 模式,并且应该得到响应“:SCPION”。但是,当发送:SDSLSCPI#可再现的示波器监视器时会冻结并重新启动。

如果我发送*IDN?我应该得到响应,P1337,1842237,V2.4.0->。但前提是设备已经处于 SCPI 模式。显然,它不是,我得到一个超时错误(见下文)。

那么,我在这里做错了什么?我在PyUSB 教程中缺少什么信息。我使用了错误的 PyUSB 命令/参数,还是缺少其他驱动程序,还是与硬件有关,无论是 Win10 还是设备硬件?感谢您提供有关如何找出问题所在的提示。

顺便说一句, 中的第二个值是dev.read(0x81,7)多少?要读取的字节数?好吧,通常我不知道设备会发送多少字节。我期待一个命令在超时时间内读取到换行符或其他终止符。我在哪里可以找到有关 PyUSB 的“万无一失”的文档、教程和示例?

代码:

import usb.core
import usb.util

dev = usb.core.find(idVendor=0x5345, idProduct=0x1234)
if dev is None:
    raise ValueError('Device is not found')
# device is found :-)
print(dev)

dev.set_configuration()

msg = ':SDSLSCPI#'
print("Write:", msg, dev.write(3,msg))

print("Read:", dev.read(0x81,7))

输出print(dev)

DEVICE ID 5345:1234 on Bus 000 Address 001 =================
 bLength                :   0x12 (18 bytes)
 bDescriptorType        :    0x1 Device
 bcdUSB                 :  0x200 USB 2.0
 bDeviceClass           :    0x0 Specified at interface
 bDeviceSubClass        :    0x0
 bDeviceProtocol        :    0x0
 bMaxPacketSize0        :   0x40 (64 bytes)
 idVendor               : 0x5345
 idProduct              : 0x1234
 bcdDevice              :  0x294 Device 2.94
 iManufacturer          :    0x1 System CPU
 iProduct               :    0x2 Oscilloscope
 iSerialNumber          :    0x3 SERIAL
 bNumConfigurations     :    0x1
  CONFIGURATION 1: 500 mA ==================================
   bLength              :    0x9 (9 bytes)
   bDescriptorType      :    0x2 Configuration
   wTotalLength         :   0x20 (32 bytes)
   bNumInterfaces       :    0x1
   bConfigurationValue  :    0x1
   iConfiguration       :    0x5 Bulk Data Configuration
   bmAttributes         :   0xc0 Self Powered
   bMaxPower            :   0xfa (500 mA)
    INTERFACE 0: Physical ==================================
     bLength            :    0x9 (9 bytes)
     bDescriptorType    :    0x4 Interface
     bInterfaceNumber   :    0x0
     bAlternateSetting  :    0x0
     bNumEndpoints      :    0x2
     bInterfaceClass    :    0x5 Physical
     bInterfaceSubClass :    0x6
     bInterfaceProtocol :   0x50
     iInterface         :    0x4 Bulk Data Interface
      ENDPOINT 0x81: Bulk IN ===============================
       bLength          :    0x7 (7 bytes)
       bDescriptorType  :    0x5 Endpoint
       bEndpointAddress :   0x81 IN
       bmAttributes     :    0x2 Bulk
       wMaxPacketSize   :  0x200 (512 bytes)
       bInterval        :    0x0
      ENDPOINT 0x3: Bulk OUT ===============================
       bLength          :    0x7 (7 bytes)
       bDescriptorType  :    0x5 Endpoint
       bEndpointAddress :    0x3 OUT
       bmAttributes     :    0x2 Bulk
       wMaxPacketSize   :  0x200 (512 bytes)
       bInterval        :    0x0

错误信息:

Traceback (most recent call last):
  File "Osci.py", line 15, in <module>
    print("Read:", dev.read(0x81,7))
  File "C:\Users\Test\Programs\Python3.7.4\lib\site-packages\usb\core.py", line 988, in read
    self.__get_timeout(timeout))
  File "C:\Users\Test\Programs\Python3.7.4\lib\site-packages\usb\backend\libusb0.py", line 542, in bulk_read
    timeout)
  File "C:\Users\Test\Programs\Python3.7.4\lib\site-packages\usb\backend\libusb0.py", line 627, in __read
    timeout
  File "C:\Users\Test\Programs\Python3.7.4\lib\site-packages\usb\backend\libusb0.py", line 431, in _check
    raise USBError(errmsg, ret)
usb.core.USBError: [Errno None] b'libusb0-dll:err [_usb_reap_async] timeout error\n'

更新:

我收到了卖家的回复。他确认示波器(或至少这个特定系列)在发送命令时崩溃:SDSLSCPI#。他将联系下周回来的开发商。好的,到目前为止,我似乎没有机会让它与这个特定的设备和可用的文档一起运行:-(。

4

5 回答 5

6

我想除非有人已经经历过同样的问题,否则没有机会回答这个问题。我很抱歉你们所有人(@Alex P.、@Turbo J、@igrinis、@2xB)花时间提出建议来提供帮助。

我的发现:(我希望它们对其他人有用):

  1. PyUSB 似乎一切正常。
  2. 供应商提供了过时和错误的文件。我非常希望他们能尽快更新主页上的文档。
  3. 发送命令:SDSLSCPI#不是进入 SCPI 模式所必需的(但实际上会导致崩溃/重新启动)
  4. 例如::CHAN1:SCAL 10v是错误的,它必须是:CH1:SCALe 10v(命令显然不能缩写,尽管在文档中提到也:CH1:SCAL 10v应该有效。)
  5. 手册中缺少获取数据的基本命令:DATA:WAVE:SCREen:CH1?

它为我工作的方式(到目前为止):

以下是我期望供应商/制造商提供的最少代码。但相反,我浪费了大量时间调试他们的文档。但是,仍然有一些奇怪的事情发生,例如,似乎只有在您事先要求标头时才能获得数据。但是,这不是原始问题的主题。

代码:

### read data from a Peaktech 1337 Oscilloscope (OWON)
import usb.core
import usb.util

dev = usb.core.find(idVendor=0x5345, idProduct=0x1234)

if dev is None:
    raise ValueError('Device not found')
else:
    print(dev)
    dev.set_configuration()

def send(cmd):
    # address taken from results of print(dev):   ENDPOINT 0x3: Bulk OUT
    dev.write(3,cmd)
    # address taken from results of print(dev):   ENDPOINT 0x81: Bulk IN
    result = (dev.read(0x81,100000,1000))
    return result

def get_id():
    return send('*IDN?').tobytes().decode('utf-8')

def get_data(ch):
    # first 4 bytes indicate the number of data bytes following
    rawdata = send(':DATA:WAVE:SCREen:CH{}?'.format(ch))
    data = []
    for idx in range(4,len(rawdata),2):
        # take 2 bytes and convert them to signed integer using "little-endian"
        point = int().from_bytes([rawdata[idx], rawdata[idx+1]],'little',signed=True)
        data.append(point/4096)  # data as 12 bit
    return data

def get_header():
    # first 4 bytes indicate the number of data bytes following
    header = send(':DATA:WAVE:SCREen:HEAD?')
    header = header[4:].tobytes().decode('utf-8')
    return header

def save_data(ffname,data):
    f = open(ffname,'w')
    f.write('\n'.join(map(str, data)))
    f.close()

print(get_id())
header = get_header()
data = get_data(1)
save_data('Osci.dat',data)
### end of code

结果:(使用gnuplot)

在此处输入图像描述

于 2020-02-05T09:46:22.370 回答
1

一旦您收到设备对*IDN?查询的响应,您就可以开始了。这是SCPI ;)

尝试发送:CHAN1:SCAL 10v,并观看显示。它应该将通道 1 的垂直刻度更改为 10V/div。

观看此视频,它将帮助您掌握。

关于你关于read()参数的问题。引用 PyUSB 源代码:

def read(self, endpoint, size_or_buffer, timeout = None):
    r"""Read data from the endpoint.
    This method is used to receive data from the device. The endpoint
    parameter corresponds to the bEndpointAddress member whose endpoint
    you want to communicate with. The size_or_buffer parameter either
    tells how many bytes you want to read or supplies the buffer to
    receive the data (it *must* be an object of the type array).
    The timeout is specified in miliseconds.
    If the size_or_buffer parameter is the number of bytes to read, the
    method returns an array object with the data read. If the
    size_or_buffer parameter is an array object, it returns the number
    of bytes actually read.
    """

当省略超时时,它被用作Device.default_timeout property操作超时。值以毫秒为单位。

如果您将缓冲区大小设置得足够大,您将只获得实际读取的字节。所以你的期望是正确的。

于 2020-01-31T20:26:11.643 回答
1

首先请注意,@igrinis 发布了一段视频,展示了您想要达到的目标。

(如@igrinis 所述:)对于 中的第二个值read(...),您在理论上是正确的。好消息是,实际上你可以要求更长的答案。因此,请尝试请求 256 个字节并查看是否修复了您当前的代码。

如果这不能解决您的问题:

您可以尝试使用制造商提供的能够与设备通信的软件的第二台 PC/笔记本电脑,并使用 Wireshark(安装了 USBPcap)来读取设备通信。发送和接收的 USB 批量数据写入 Wiresharks “Leftover Capture Data”字段。通过查看,您可以比较脚本发送的内容以及发现错误的外观。您可以通过右键单击并选择“应用为列”将其作为列添加到数据包列表中。例如,您的问题可能是将您的命令编码为大端或小端。

PyUSB 的文档:

[更新] 为已经给出了一些答案的精彩评论添加了提示等等。

于 2020-02-03T14:32:58.223 回答
1

msg = '*IDN?'

这不是一个完整的 SCPI 命令:它缺少\n末尾的换行符。

这也是设备无法通过 USB 发送答案的原因。

于 2019-11-29T16:59:17.157 回答
0

SCPI 在 OWON 设备上默认未启用。根据手册的第 3 页,您需要发送:SDSLSCPI#命令以切换到 SCPI 模式。

于 2019-12-04T21:05:48.177 回答