最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入解析Python如何利用PyUSB輕松操控USB設(shè)備

 更新時間:2026年01月05日 14:23:44   作者:蕭鼎  
本文將從?基礎(chǔ)概念、安裝配置、核心?API、實戰(zhàn)案例、調(diào)試技巧到高級應(yīng)用,系統(tǒng)性地介紹?PyUSB,幫助你掌握如何用?Python?高效、安全地與?USB?設(shè)備交互,感興趣的小伙伴可以了解下

引言:為什么需要 PyUSB?

在嵌入式系統(tǒng)、工業(yè)自動化、物聯(lián)網(wǎng)(IoT)以及硬件交互開發(fā)中,與 USB 設(shè)備通信是一項常見但技術(shù)門檻較高的任務(wù)。傳統(tǒng)上,開發(fā)者需使用 C/C++ 編寫底層驅(qū)動或調(diào)用操作系統(tǒng)特定的 API(如 Windows 的 WinUSB、Linux 的 libusb),不僅代碼復(fù)雜,還缺乏跨平臺能力。

而 PyUSB 的出現(xiàn),徹底改變了這一局面。作為 Python 生態(tài)中用于 USB 通信的核心庫,PyUSB 提供了一套簡潔、統(tǒng)一、跨平臺的接口,讓開發(fā)者無需深入操作系統(tǒng)內(nèi)核,即可通過幾行 Python 代碼讀寫 USB 設(shè)備、控制端點(diǎn)、枚舉設(shè)備信息,甚至實現(xiàn)自定義 HID(人機(jī)接口設(shè)備)或 CDC(通信設(shè)備類)協(xié)議。

本文將從 基礎(chǔ)概念、安裝配置、核心 API、實戰(zhàn)案例、調(diào)試技巧到高級應(yīng)用,系統(tǒng)性地介紹 PyUSB,幫助你掌握如何用 Python 高效、安全地與 USB 設(shè)備交互。無論你是想讀取 USB 溫度傳感器、控制 LED 燈帶,還是開發(fā)自己的 USB 外設(shè)固件測試工具,PyUSB 都是你不可或缺的利器。

一、USB 基礎(chǔ)知識回顧

在深入 PyUSB 之前,有必要簡要了解 USB 協(xié)議的基本結(jié)構(gòu),這有助于理解后續(xù)的代碼邏輯。

1.1 USB 設(shè)備層級模型

一個 USB 設(shè)備由以下邏輯單元組成:

  • 設(shè)備(Device):物理 USB 設(shè)備本身,具有唯一的 Vendor ID(VID)和 Product ID(PID)。
  • 配置(Configuration):一個設(shè)備可有多個配置(通常為1),描述供電、接口數(shù)量等。
  • 接口(Interface):功能單元,如一個 USB 音頻設(shè)備可能包含“麥克風(fēng)”和“揚(yáng)聲器”兩個接口。
  • 端點(diǎn)(Endpoint):數(shù)據(jù)傳輸?shù)慕K點(diǎn)。分四種類型:
  • Control(控制):用于設(shè)備配置和狀態(tài)查詢(端點(diǎn)0,雙向);
  • Bulk(批量):高可靠、低實時性,如打印機(jī)、存儲設(shè)備;
  • Interrupt(中斷):低延遲、小數(shù)據(jù)量,如鍵盤、鼠標(biāo);
  • Isochronous(同步):高帶寬、容忍丟包,如攝像頭、音頻流。

注意:PyUSB 主要操作 端點(diǎn) 來進(jìn)行數(shù)據(jù)收發(fā)。

1.2 標(biāo)準(zhǔn)請求與 Class 規(guī)范

USB 協(xié)議定義了標(biāo)準(zhǔn)設(shè)備請求(如 GET_DESCRIPTOR、SET_CONFIGURATION),同時也允許廠商自定義命令。此外,USB-IF 制定了多種 設(shè)備類(Device Class) 規(guī)范,如:

  • HID(Human Interface Device):鍵盤、鼠標(biāo)、游戲手柄;
  • CDC(Communication Device Class):虛擬串口(如 Arduino);
  • MSC(Mass Storage Class):U 盤;
  • DFU(Device Firmware Upgrade):固件升級。

PyUSB 不依賴這些高層協(xié)議,它工作在 傳輸層,因此適用于任何 USB 設(shè)備——包括沒有標(biāo)準(zhǔn)驅(qū)動的“裸設(shè)備”。

二、PyUSB 安裝與環(huán)境配置

2.1 安裝 PyUSB

PyUSB 是純 Python 庫,但依賴底層 USB 后端(backend)。安裝命令如下:

pip install pyusb

注意:PyUSB 本身不包含后端實現(xiàn),需額外安裝支持庫。

2.2 后端選擇與配置

PyUSB 支持三種主流后端:

后端適用系統(tǒng)安裝方式
libusb1Linux / macOS / Windowssudo apt install libusb-1.0-0-dev (Linux) 或 libusb.org 下載 Windows DLL
libusb0舊版 Linux / Windows已基本淘汰,不推薦
OpenUSBSolaris極少使用

推薦使用 libusb1,因其跨平臺性好、維護(hù)活躍。

Windows 用戶特別說明:

  • 下載 libusb-1.0.dll
  • 將 DLL 文件放入 C:\Windows\System32 或 Python 腳本同目錄
  • 或使用 Zadig 工具為設(shè)備安裝 WinUSB 驅(qū)動(關(guān)鍵步驟?。?/li>

若未正確安裝驅(qū)動,Windows 會阻止用戶態(tài)程序訪問 USB 設(shè)備,報錯 Access denied 或 No backend available。

Linux 用戶權(quán)限問題:

默認(rèn)情況下,普通用戶無權(quán)訪問 /dev/bus/usb/*。解決方法:

# 創(chuàng)建 udev 規(guī)則(以 VID=0x1234, PID=0x5678 為例)
echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="1234", ATTR{idProduct}=="5678", MODE="0666"' | sudo tee /etc/udev/rules.d/99-myusb.rules
sudo udevadm control --reload-rules && sudo udevadm trigger

三、PyUSB 核心 API 詳解

PyUSB 的設(shè)計哲學(xué)是“簡單即強(qiáng)大”。其核心模塊為 usb.core 和 usb.util。

3.1 枚舉與查找設(shè)備

使用 usb.core.find() 查找設(shè)備:

import usb.core
import usb.util

# 方法1:通過 VID/PID 查找
dev = usb.core.find(idVendor=0x1234, idProduct=0x5678)

# 方法2:查找所有設(shè)備
devices = usb.core.find(find_all=True)

# 方法3:自定義查找函數(shù)
def my_filter(dev):
    return dev.idVendor == 0x1234 and dev.manufacturer == "MyCompany"

dev = usb.core.find(custom_match=my_filter)

若未找到,返回 None;若找到多個且未用 find_all=True,拋出 ValueError。

3.2 設(shè)備信息獲取

一旦獲得 dev 對象(usb.core.Device 實例),可讀取其描述符:

print(f"Manufacturer: {usb.util.get_string(dev, dev.iManufacturer)}")
print(f"Product: {usb.util.get_string(dev, dev.iProduct)}")
print(f"Serial: {usb.util.get_string(dev, dev.iSerialNumber)}")

# 打印所有配置
for cfg in dev:
    print(f"Config {cfg.bConfigurationValue}")
    for intf in cfg:
        print(f"  Interface {intf.bInterfaceNumber}: {intf.bNumEndpoints} endpoints")
        for ep in intf:
            print(f"    EP {ep.bEndpointAddress:02x} ({'IN' if ep.bEndpointAddress & 0x80 else 'OUT'}), Type: {ep.bmAttributes & 0x03}")

注意:字符串描述符需通過 usb.util.get_string() 解碼,直接訪問 dev.iProduct 返回的是索引。

3.3 聲明接口與釋放內(nèi)核驅(qū)動

在 Linux/macOS 上,若設(shè)備已被系統(tǒng)驅(qū)動占用(如 HID 鍵盤被內(nèi)核接管),需先 分離內(nèi)核驅(qū)動:

if dev.is_kernel_driver_active(0):  # 接口0
    dev.detach_kernel_driver(0)

操作完成后,應(yīng)重新附加驅(qū)動(良好實踐):

dev.attach_kernel_driver(0)

Windows 通常無需此步驟(因使用 WinUSB 驅(qū)動時內(nèi)核未接管)。

3.4 設(shè)置配置與聲明接口

大多數(shù)設(shè)備只需使用默認(rèn)配置:

dev.set_configuration()  # 使用第一個配置
cfg = dev.get_active_configuration()
intf = cfg[(0, 0)]       # 獲取接口0,備用設(shè)置0

3.5 端點(diǎn)通信:讀寫數(shù)據(jù)

寫數(shù)據(jù)(OUT 端點(diǎn)):

# 假設(shè)端點(diǎn)地址為 0x01(OUT)
ep_out = usb.util.find_descriptor(intf, custom_match=lambda e: \
    usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT)

if ep_out:
    data = b'\x01\x02\x03\x04'
    bytes_written = dev.write(ep_out.bEndpointAddress, data, timeout=1000)
    print(f"Sent {bytes_written} bytes")

讀數(shù)據(jù)(IN 端點(diǎn)):

# 假設(shè)端點(diǎn)地址為 0x81(IN)
ep_in = usb.util.find_descriptor(intf, custom_match=lambda e: \
    usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_IN)

if ep_in:
    try:
        data = dev.read(ep_in.bEndpointAddress, ep_in.wMaxPacketSize, timeout=1000)
        print(f"Received: {data}")
    except usb.core.USBError as e:
        if e.errno == 110:  # 超時
            print("Read timeout")

關(guān)鍵參數(shù):

  • timeout:單位毫秒,避免無限阻塞;
  • wMaxPacketSize:端點(diǎn)最大包長,可作為讀緩沖區(qū)大小。

四、實戰(zhàn)案例:與自定義 USB 設(shè)備通信

假設(shè)我們有一個基于 STM32 的 USB CDC 設(shè)備(虛擬串口),但希望繞過操作系統(tǒng)串口驅(qū)動,直接通過 PyUSB 控制。

4.1 設(shè)備信息分析

首先,用 lsusb -v(Linux)或 USBTreeView(Windows)查看設(shè)備描述符:

Bus 001 Device 005: ID 0483:5740 STMicroelectronics Virtual COM Port
Device Descriptor:
  bcdUSB               2.00
  bDeviceClass          2 Communications
  bDeviceSubClass       0 
  bDeviceProtocol       0 
  idVendor           0x0483 STMicroelectronics
  idProduct          0x5740 Virtual COM Port
  ...
  Interface Descriptor:
    bInterfaceNumber     0
    bInterfaceClass      2 Communications
    bInterfaceSubClass   2 Abstract (modem)
    bInterfaceProtocol   1 AT-commands (v.25ter)
    Endpoint Descriptor:
      bEndpointAddress     0x81  EP 1 IN
      bmAttributes            3
        Transfer Type            Interrupt
      wMaxPacketSize     0x0008
    Endpoint Descriptor:
      bEndpointAddress     0x01  EP 1 OUT
      bmAttributes            2
        Transfer Type            Bulk

可見,該設(shè)備有兩個端點(diǎn):0x81(IN,中斷)、0x01(OUT,批量)。

4.2 編寫通信腳本

import usb.core
import usb.util
import sys

# 查找設(shè)備
dev = usb.core.find(idVendor=0x0483, idProduct=0x5740)
if dev is None:
    raise ValueError('Device not found')

# 分離內(nèi)核驅(qū)動(Linux/macOS)
if sys.platform != "win32":
    if dev.is_kernel_driver_active(0):
        dev.detach_kernel_driver(0)

# 設(shè)置配置
dev.set_configuration()

# 獲取接口
cfg = dev.get_active_configuration()
intf = cfg[(0, 0)]

# 查找端點(diǎn)
ep_out = usb.util.find_descriptor(
    intf,
    custom_match=lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT
)
ep_in = usb.util.find_descriptor(
    intf,
    custom_match=lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_IN
)

if not ep_out or not ep_in:
    raise ValueError("Endpoints not found")

# 發(fā)送 AT 命令
command = b"AT\r\n"
dev.write(ep_out.bEndpointAddress, command, timeout=1000)

# 讀取響應(yīng)
try:
    response = dev.read(ep_in.bEndpointAddress, 64, timeout=1000)
    print("Response:", response.tobytes().decode('utf-8', errors='replace'))
except usb.core.USBError as e:
    print("Read error:", e)

運(yùn)行結(jié)果可能為:

Response: AT
OK

此例展示了如何繞過 pyserial,直接與 CDC 設(shè)備通信,適用于需要低延遲或自定義協(xié)議的場景。

五、常見問題與調(diào)試技巧

5.1 “No backend available” 錯誤

原因:未安裝 libusb 或 DLL 未找到。

解決:

  • Linux:sudo apt install libusb-1.0-0-dev
  • Windows:將 libusb-1.0.dll 放入 PATH 或腳本目錄;
  • 指定后端:usb.core.find(backend=usb.backend.libusb1.get_backend())

5.2 “Access denied” 或 “Operation not permitted”

Linux:檢查 udev 規(guī)則,確保用戶有權(quán)限;

Windows:用 Zadig 為設(shè)備安裝 WinUSB 驅(qū)動(替換原有驅(qū)動);

macOS:可能需要禁用 SIP 或使用 IOKit 后端(較少見)。

5.3 讀寫超時或無響應(yīng)

檢查端點(diǎn)方向是否正確(IN/OUT);

確認(rèn)設(shè)備固件是否處于接收狀態(tài);

增加 timeout 值;

使用 USB 協(xié)議分析儀(如 Wireshark + USBPcap)抓包驗證。

5.4 設(shè)備被系統(tǒng)占用

在 Windows 上,HID 設(shè)備常被 hidusb.sys 占用,需用 Zadig 替換為 WinUSB;

在 Linux 上,使用 detach_kernel_driver()。

六、高級應(yīng)用:構(gòu)建 USB 測試框架

PyUSB 可用于自動化測試嵌入式設(shè)備的 USB 功能。例如,驗證設(shè)備在不同命令下的響應(yīng):

class USBDeviceTester:
    def __init__(self, vid, pid):
        self.dev = usb.core.find(idVendor=vid, idProduct=pid)
        assert self.dev, "Device not found"
        self.dev.set_configuration()
        self._setup_endpoints()

    def _setup_endpoints(self):
        cfg = self.dev.get_active_configuration()
        intf = cfg[(0, 0)]
        self.ep_out = ...  # find OUT
        self.ep_in = ...   # find IN

    def send_command(self, cmd: bytes) -> bytes:
        self.dev.write(self.ep_out.bEndpointAddress, cmd, timeout=2000)
        return self.dev.read(self.ep_in.bEndpointAddress, 256, timeout=2000).tobytes()

    def test_led_on(self):
        resp = self.send_command(b"LED ON\n")
        assert b"OK" in resp, "LED ON failed"

    def test_temperature(self):
        resp = self.send_command(b"TEMP?\n")
        temp = float(resp.strip())
        assert 20 <= temp <= 30, f"Invalid temperature: {temp}"

此類框架可集成到 CI/CD 流程中,實現(xiàn)硬件回歸測試。

七、PyUSB 與其他庫的對比

優(yōu)點(diǎn)缺點(diǎn)適用場景
PyUSB跨平臺、底層控制、靈活需處理 USB 協(xié)議細(xì)節(jié)自定義設(shè)備、協(xié)議開發(fā)
pyserial簡單易用僅限 CDC/串口設(shè)備Arduino、ESP32 通信
hidapi(via hid專為 HID 優(yōu)化僅支持 HID 類鍵盤、游戲手柄
libusb-py更底層已停止維護(hù)不推薦

結(jié)論:PyUSB 是通用 USB 通信的首選。

結(jié)語:讓 Python 成為你的 USB 開發(fā)利器

PyUSB 以極簡的 API 封裝了復(fù)雜的 USB 通信細(xì)節(jié),使 Python 開發(fā)者能夠輕松進(jìn)入硬件交互領(lǐng)域。無論是快速原型驗證、自動化測試,還是構(gòu)建跨平臺的設(shè)備管理工具,PyUSB 都提供了強(qiáng)大而可靠的支持。

然而,能力越大,責(zé)任越大。直接操作 USB 設(shè)備意味著你需要理解端點(diǎn)、傳輸類型、描述符等概念,并謹(jǐn)慎處理權(quán)限與資源釋放。建議在開發(fā)中始終遵循:

  • 先枚舉,再操作;
  • 及時釋放內(nèi)核驅(qū)動;
  • 設(shè)置合理超時;
  • 異常處理全覆蓋。

最后,記住:最好的 USB 代碼,是那些即使設(shè)備拔掉也不會崩潰的代碼。

到此這篇關(guān)于深入解析Python如何利用PyUSB輕松操控USB設(shè)備的文章就介紹到這了,更多相關(guān)Python PyUSB控制USB設(shè)備內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Conda環(huán)境離線遷移全過程

    Conda環(huán)境離線遷移全過程

    這篇文章主要介紹了Conda環(huán)境離線遷移全過程,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-10-10
  • python 統(tǒng)計文件中的字符串?dāng)?shù)目示例

    python 統(tǒng)計文件中的字符串?dāng)?shù)目示例

    今天小編就為大家分享一篇python 統(tǒng)計文件中的字符串?dāng)?shù)目示例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • Python中的查找算法代碼實例

    Python中的查找算法代碼實例

    這篇文章主要介紹了Python中的查找算法代碼實例,算法是解決一系列問題的清晰指令,也就是,能對一定規(guī)范的輸入,在有限的時間內(nèi)獲得所要求的輸出,簡單來說,算法就是解決一個問題的具體方法和步驟,算法是程序的靈魂,需要的朋友可以參考下
    2023-07-07
  • Python使用Vagrant搭建開發(fā)環(huán)境的具體步驟

    Python使用Vagrant搭建開發(fā)環(huán)境的具體步驟

    使用 Vagrant 搭建開發(fā)環(huán)境是一個非常方便的方式,它可以幫助你快速創(chuàng)建、配置和管理虛擬機(jī),確保開發(fā)環(huán)境的一致性,以下是使用 Vagrant 搭建開發(fā)環(huán)境的具體步驟,需要的朋友可以參考下
    2024-09-09
  • pycharm配置anaconda環(huán)境時找不到python.exe的兩種解決辦法

    pycharm配置anaconda環(huán)境時找不到python.exe的兩種解決辦法

    如果你在Anaconda中創(chuàng)建了虛擬環(huán)境,但是無法找到python.exe,可能是因為虛擬環(huán)境的Python路徑?jīng)]有添加到系統(tǒng)環(huán)境變量中,這篇文章主要給大家介紹了關(guān)于pycharm配置anaconda環(huán)境時找不到python.exe的兩種解決辦法,需要的朋友可以參考下
    2024-07-07
  • 關(guān)于python爬蟲模塊urllib庫詳解

    關(guān)于python爬蟲模塊urllib庫詳解

    這篇文章主要介紹了關(guān)于python爬蟲模塊urllib庫詳解,學(xué)習(xí)爬蟲,最初的操作便是模擬瀏覽器向服務(wù)端發(fā)出請求,這里我們就學(xué)習(xí)使用urlib庫的用法,需要的朋友可以參考下
    2023-07-07
  • Python采集電視劇《開端》彈幕做成詞云圖

    Python采集電視劇《開端》彈幕做成詞云圖

    大家好,本篇文章主要講的是Python采集電視劇《開端》彈幕做成詞云圖,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • 詳解matplotlib技巧之縮放和投影

    詳解matplotlib技巧之縮放和投影

    我們在使用matplotlib繪制圖形時,有兩個重要的技巧:一種是?Scale(縮放),一種是Projection(投影),縮放和投影在matplotlib繪圖中起著至關(guān)重要的作用,它們幫助我們更好地展示和理解數(shù)據(jù),本文將詳細(xì)的給大家介紹這兩個技巧,需要的朋友可以參考下
    2024-01-01
  • python利用tkinter實現(xiàn)屏保

    python利用tkinter實現(xiàn)屏保

    這篇文章主要為大家詳細(xì)介紹了python利用tkinter實現(xiàn)屏保,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • Python2.7版os.path.isdir中文路徑返回false的解決方法

    Python2.7版os.path.isdir中文路徑返回false的解決方法

    這篇文章主要為大家詳細(xì)介紹了Python2.7版os.path.isdir中文路徑返回false的解決方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-06-06

最新評論

紫云| 石家庄市| 墨脱县| 富平县| 泾源县| 沙田区| 驻马店市| 阿坝| 信阳市| 安阳县| 澄迈县| 南木林县| 西昌市| 义马市| 靖州| 泾阳县| 三台县| 连州市| 乌拉特前旗| 贺兰县| 锡林浩特市| 迭部县| 泰顺县| 互助| 洪湖市| 铜陵市| 新津县| 冷水江市| 磐石市| 巴彦县| 黔西县| 青铜峡市| 乌兰县| 丹巴县| 始兴县| 道孚县| 横山县| 漠河县| 凯里市| 榆林市| 永城市|