编程进阶网 编程进阶网
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • Android提升进阶

    • 库的解读

    • 专栏博客

    • 智能硬件

      • README
      • 实体卡开发和实践
      • 继电器和韦根协议
      • 设备串口通信实践
      • USB开发设计实践
        • 01.基础概念介绍
          • 1.1 理解USB接口
          • 1.2 USB开发步骤
          • 1.3 USB主机和配件
          • 1.4 两种模式区别
          • 1.5 USB开发相关类
        • 02.常见思路和做法
          • 2.1 开发场景说明
          • 2.2 USB开发思路
          • 2.3 发现设备实践
          • 2.4 打开设备实践
          • 2.5 设备建立连接
          • 2.6 数据传输实践
          • 2.7 关闭设备操作
        • 03.USB其他功能
          • 3.1 判断请求USB权限
          • 3.2 处理USB监听广播
          • 3.3 UsbEndpoint设备端点
          • 3.4 定期检查连接设备
        • 04.Api调用说明
        • 05.原理和遇到的坑
        • 06.其他问题说明
          • 5.4 其他推荐
          • 5.5 博客
      • UVC相机设计实践
      • 原生相机采集图片库
      • 蓝牙开发业务实践
  • iOS开发和进阶

  • Web开发和进阶

  • Linux应用开发

  • Apps
  • Android提升进阶
  • 智能硬件
杨充
2025-06-30
目录

USB开发设计实践

# 04.USB开发设计实践

# 目录介绍

  • 01.基础概念介绍
    • 1.1 理解USB接口
    • 1.2 USB开发步骤
    • 1.3 USB主机和配件
    • 1.4 两种模式区别
    • 1.5 USB开发相关类
  • 02.常见思路和做法
    • 2.1 开发场景说明
    • 2.2 USB开发思路
    • 2.3 发现设备实践
    • 2.4 打开设备实践
    • 2.5 设备建立连接
    • 2.6 数据传输实践
    • 2.7 关闭设备操作
  • 03.USB其他功能
    • 3.1 判断请求USB权限
    • 3.2 处理USB监听广播
    • 3.3 UsbEndpoint设备端点
    • 3.4 定期检查连接设备

# 01.基础概念介绍

# 1.1 理解USB接口

  • 如何理解USB
    • USB是英文Universal Serial Bus(通用串行总线)的缩写,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯。
    • AOA协议是Google公司推出的用于实现Android设备与外围设备之间USB通信的协议。
    • 该协议拓展了Android设备USB接口的功能,为基于Android系统的智能设备应用于数据采集和设备控制领域提供了条件。

# 1.2 USB开发步骤

  • Android USB 配件必须遵从 Android Open Accessory(AOA)协议,该协议定义了配件如何检测和建立与 Android 设备的通信。配件应执行以下步骤:
    • 等待并检测连接的设备
    • 确定设备的配件模式支持
    • 尝试以配件模式下启动设备(如果需要)
    • 如果设备支持 AOA,与设备建立通信
  • UsbManager官方文档
    • https://developer.android.google.cn/reference/android/hardware/usb/

# 1.3 USB主机和配件

  • 在 USB 配件模式下(USB accessory)
    • 外部 USB 硬件充当 USB 主机。配件示例可能包括机器人控制器、扩展坞、诊断和音乐设备、自助服务终端、读卡器等等。
    • 这样,不具备主机功能的 Android 设备就能够与 USB 硬件互动。Android USB 配件必须设计为与 Android 设备兼容,并且必须遵守 Android 配件通信协议。
  • 在 USB 主机模式下(USB host)
    • Android 设备充当主机。设备示例包括数码相机、键盘、鼠标和游戏控制器。即:安卓平板作为主机,usb外设作为从机进行数据通信。

# 1.4 两种模式区别

  • 两种模式之间的差异。
    • 当 Android 设备处于主机模式时,它会充当 USB 主机并为总线供电。
    • 当 Android 设备处于 USB 配件模式时,所连接的 USB 硬件(本例中为 Android USB 配件)充当主机并为总线供电。

# 1.5 USB开发相关类

  • android.hardware.usb包下提供了USB开发的相关类。
  • 我们需要了解UsbManager、UsbDevice、UsbInterface、UsbEndpoint、UsbDeviceConnection、UsbRequest、UsbConstants。
    • 1、UsbManager:获得Usb的状态,与连接的Usb设备通信。
    • 2、UsbDevice:Usb设备的抽象,它包含一个或多个UsbInterface,而每个UsbInterface包含多个UsbEndpoint。Host与其通信,先打开UsbDeviceConnection,使用UsbRequest在一个端点(endpoint)发送和接收数据。
    • 3、UsbInterface:定义了设备的功能集,一个UsbDevice包含多个UsbInterface,每个Interface都是独立的。
    • 4、UsbEndpoint:endpoint是interface的通信通道。
    • 5、UsbDeviceConnection:host与device建立的连接,并在endpoint传输数据。
    • 6、UsbRequest:usb 请求包。可以在UsbDeviceConnection上异步传输数据。注意是只在异步通信时才会用到它。
    • 7、UsbConstants:usb常量的定义,对应linux/usb/ch9.h

# 02.常见思路和做法

# 2.1 开发场景说明

开发使用的是usb主机模式,即:安卓机器作为主机,usb外设作为从机进行数据通信。然后主机和联动设备需要交互。

# 2.2 USB开发思路

大概思路如下:

  • 第一步:发现设备。通过UsbManager调用getDeviceList可以获取当前连接的所有usb设备。
  • 第二步:打开设备。可以将机具与usb外设之间的连接想象成一个通道,只有把通道的门打开后,两边才能进行通信。
  • 第三步:数据传输。已经可以与usb外设进行数据传输

# 2.3 发现设备实践

第一步:发现设备。通过UsbManager调用getDeviceList可以获取当前连接的所有usb设备。

通过UsbManager这个系统提供的类,我们可以枚举出当前连接的所有usb设备,我们主要需要的是UsbDevice对象。

UsbDevice,这个类就代表了Android所连接的usb设备。通过getDeviceList()获取已连接的USB设备列表。

UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
Map<String, UsbDevice> usbList = usbManager.getDeviceList();
1
2

请注意,为了使用UsbManager,你需要在AndroidManifest.xml文件中声明USB权限:

<uses-permission android:name="android.permission.USB_PERMISSION" />
1

# 2.4 打开设备实践

第二步:打开设备。可以将机具与usb外设之间的连接想象成一个通道,只有把通道的门打开后,两边才能进行通信。

需要打开刚刚搜索到的usb设备,我们可以将平板与usb外设之间的连接想象成一个通道,只有把通道的门打开后,两边才能进行通信。

注意:在没有定制的android设备上首次访问usb设备的时候,默认是没有访问权限的,因此首先要判断对当前要打开的usbDevice是否有访问权限。

需要和usb外设建立一个UsbDeviceConnection,大部分情况下还需要对usb串口进行一些配置,比如波特率,停止位,数据控制等,不然两边配置不同,收到的数据会乱码。

  • 2.1 申请权限
  • 2.2 获得连接口UsbInterface
  • 2.3 获得连接端口UsbEndpoint

选择要打开的设备,并请求权限。使用requestPermission()方法请求USB设备的权限。你需要提供一个PendingIntent对象,用于接收权限请求的结果。

PendingIntent permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
usbManager.requestPermission(device, permissionIntent);
1
2

如何打开设备

mUsbManager.openDevice(device);
1

在广播接收器中处理权限请求结果。

private static final String ACTION_USB_PERMISSION = "com.example.myapp.USB_PERMISSION";
private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (ACTION_USB_PERMISSION.equals(action)) {
            synchronized (this) {
                UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                    if (device != null) {
                        // 权限已授予,可以打开设备
                        UsbDeviceConnection connection = usbManager.openDevice(device);
                        if (connection != null) {
                            // 打开设备成功,进行相关操作
                        }
                    }
                } else {
                    // 权限被拒绝
                }
            }
        }
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 2.5 设备建立连接

  • 使用usbManager.openDevice()方法打开USB设备,并获取一个UsbDeviceConnection对象。如果连接建立成功,使用该连接对象进行后续的USB通信操作。
    • 获取连接接口,interfaceIndex是你要获取的连接接口的索引。一个USB设备可能有多个接口,每个接口都有自己的功能和设置。
    • USB接口的索引从0开始,你可以使用device.getInterfaceCount()方法获取USB设备的接口数量。
    • 可以使用UsbInterface对象来获取接口的相关信息,如端点(endpoint)和接口设置等。
      UsbInterface usbInterface = device.getInterface(interfaceIndex);
      
      1

# 2.6 数据传输实践

  • 第三步:数据传输。已经可以与usb外设进行数据传输
    • 向usb外设发送数据。使用usbDeviceConnection.bulkTransfer这个函数用于在给定的端口进行数据传输。返回值代表发送成功的字节数,如果返回-1,那就是发送失败了。
    • 接受usb外设发送来的数据。找到了数据输入端口usbEndpointIn,因为数据的输入是不定时的,因此我们可以另开一个线程,来专门接受数据。
    • 3.1 发送数据。调用bulkTransfer方法发送数据
    • 3.2 接收数据。找到了数据输入端口usbEndpointIn,因为数据的输入是不定时的,因此我们可以另开一个线程,来专门接受数据
  • 发送控制请求:
    • 使用controlTransfer()方法发送控制请求到USB设备。你需要提供请求类型、请求码、值、索引、数据缓冲区、超时时间等参数。该方法将返回操作结果。
      int requestType = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_OUT;
      int request = 0x01;
      int value = 0x00;
      int index = 0x00;
      byte[] buffer = new byte[4];
      int timeout = 1000;
      int result = connection.controlTransfer(requestType, request, value, index, buffer, buffer.length, timeout);
      
      1
      2
      3
      4
      5
      6
      7
  • 读取数据:
    • 使用bulkTransfer()方法从USB设备的输入端点(IN)读取数据。你需要提供输入端点、数据缓冲区、缓冲区大小和超时时间等参数。该方法将返回读取的字节数。
      byte[] buffer = new byte[64];
      int timeout = 1000;
      int bytesRead = connection.bulkTransfer(endpointIn, buffer, buffer.length, timeout);
      
      1
      2
      3
  • 写入数据:
    • 使用bulkTransfer()方法向USB设备的输出端点(OUT)写入数据。你需要提供输出端点、数据缓冲区、缓冲区大小和超时时间等参数。该方法将返回写入的字节数。
      byte[] buffer = new byte[64];
      int timeout = 1000;
      int bytesWritten = connection.bulkTransfer(endpointOut, buffer, buffer.length, timeout);
      
      1
      2
      3
  • 释放连接:
    • 在不再需要与USB设备通信时,你可以使用close()方法释放UsbDeviceConnection对象。
      connection.close();
      
      1

# 2.7 关闭设备操作

  • 当我们要退出App的时候,需要去关闭串口
    mUsbManager.openDevice(device);
    
    1

# 03.USB其他功能

# 3.1 判断请求USB权限

  • 判断设备是否有权限,核心代码如下所示:
    hasPermission = mUsbManager.hasPermission(device);
    
    1
  • 如果没有权限,需要先申请权限,这一步很主要,要不然后面肯定是读取不到串口的数据的。
    • 你可以使用usbManager.requestPermission()方法来请求权限,并在回调中处理用户的响应。
      mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
      mUsbManager.requestPermission(device, mPermissionIntent);
      
      1
      2

# 3.2 处理USB监听广播

  • 注册USB广播监听,主要是监听USB逻辑
    • 创建一个广播接收器类,继承自BroadcastReceiver,并实现onReceive()方法。在onReceive()方法中处理USB相关的广播事件。
    • 声明了USB权限android.permission.USB_PERMISSION,以及我们创建的广播接收器USBReceiver和相关的广播动作。
      public class USBReceiver extends BroadcastReceiver {
          @Override
          public void onReceive(Context context, Intent intent) {
              String action = intent.getAction();
              if (action != null && action.equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
                  // 处理USB设备连接事件
                  UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
              } else if (action != null && action.equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
                  // 处理USB设备断开事件
              }
          }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12

# 3.3 UsbEndpoint设备端点

  • UsbEndpoint表示USB设备的端点,用于在USB设备和主机之间进行数据传输。每个UsbInterface都包含一个或多个UsbEndpoint。
    • 获取UsbEndpoint,遍历连接接口的所有端点,并选择类型为UsbConstants.USB_ENDPOINT_XFER_BULK的端点。
    • 你可以根据你的需求选择不同类型的端点,如批量传输(bulk transfer)、中断传输(interrupt transfer)或等时传输(isochronous transfer)。
      private UsbEndpoint epOut;
      private UsbEndpoint epIn;
      for (int i = 0; i < usbInterface.getEndpointCount(); i++) {
          UsbEndpoint tempEndpoint = usbInterface.getEndpoint(i);
          if (tempEndpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
               if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
                    epOut = ep;
                } else {
                    epIn = ep;
                }
          }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
  • 可以使用UsbEndpoint对象的方法,如getAddress()、getDirection()和getMaxPacketSize()等,来获取端点的相关信息。

# 3.4 定期检查连接设备

  • 开启一个心跳轮训,使用HandlerThread,具有独立looper的线程。在注册的时候发送检查健康消息,然后轮训。大概思路如下
    mAsyncHandler.postDelayed(mDeviceCheckRunnable, 1000);
    private final Runnable mDeviceCheckRunnable = new Runnable() {
        @Override
        public void run() {
            //获取设备列表,检查是否有权限
            //间隔2秒钟检查一下
            mAsyncHandler.postDelayed(this, 2000);
        }
    };
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

# 04.Api调用说明

# 05.原理和遇到的坑

# 06.其他问题说明

# 5.4 其他推荐

  • https://github.com/felHR85/UsbSerial

# 5.5 博客

  • USB识别开发
    • https://blog.csdn.net/c19344881x/article/details/124838289
  • Android USB转串口通信开发实例详解【好案例】
    • https://blog.csdn.net/u011555996/article/details/86220900
  • Android Usb(OTG)串口通信
    • https://blog.csdn.net/MSONG93/article/details/130730467
  • 安卓与串口通信-实践篇
    • https://blog.csdn.net/sinat_17133389/article/details/130788942
  • Android的USB通信(AOA连接)
    • https://blog.csdn.net/CJohn1994/article/details/124669291
  • Android-USB通信
    • https://blog.csdn.net/dream_xang/article/details/124274920
  • Android 沾包处理,以串口接入为例 (usb-serial-for-android)
    • https://blog.csdn.net/EthanCo/article/details/129194519
上次更新: 2026/06/10, 11:13:41
设备串口通信实践
UVC相机设计实践

← 设备串口通信实践 UVC相机设计实践→

最近更新
01
信号崩溃快速排查
06-15
02
CoreDump破案
06-15
03
perf火焰图实战
06-15
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式