Android开发必备:USB串口通信全攻略
本文介绍了在安卓设备中通过USB实现串口通信的技术方案。文章分为四个部分:首先说明硬件准备和软件权限配置,包括USB Host模式支持、USB-to-Serial适配器选择及权限声明;其次详细讲解核心实现步骤,涵盖设备检测、权限请求、串口参数配置以及数据读写操作;然后列举常见问题及解决方法;最后总结整个流程,推荐使用usb-serial-for-android库简化开发。该方案适用于工业控制、物联
目录
在安卓设备中,通过 USB 与外部设备(如传感器、单片机、PLC 等)进行串口通信是工业控制、物联网等场景的常见需求。核心原理是通过 USB-to-Serial 适配器将 USB 信号转换为串口(UART)信号,再通过安卓的 USB Host API 与适配器交互,实现数据收发。
一、准备工作
1. 硬件要求
- 安卓设备支持 USB Host 模式:需设备硬件支持(大部分手机 / 平板支持),可在系统设置中查看 “USB 主机模式” 是否开启(部分设备默认开启)。
- USB-to-Serial 适配器:用于将 USB 信号转为 TTL/RS232 串口信号,连接外部设备。
- 物理连接:安卓设备(通过 OTG 线)→ USB-to-Serial 适配器 → 外部串口设备(如单片机的 UART 接口)。
2. 软件权限配置
需在 AndroidManifest.xml 中声明 USB 相关权限和特性:
<!-- 声明支持USB Host模式 -->
<uses-feature android:name="android.hardware.usb.host" android:required="true" />
<!-- USB设备访问权限 -->
<uses-permission android:name="android.permission.USB_PERMISSION" />
<!-- (可选)针对特定设备的过滤,在<intent-filter>中添加 -->
<activity ...>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<!-- 设备过滤规则:指定要通信的USB设备的VID和PID(可通过adb命令查看) -->
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/usb_device_filter" />
</activity>
在 res/xml/ 下创建 usb_device_filter.xml,定义需要过滤的 USB 设备(根据适配器的 VID 和 PID 填写,如 VID=0x1A86,PID=0x7523):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 匹配CH340适配器 -->
<usb-device vendor-id="6790" product-id="29987" /> <!-- 1A86转10进制=6790,7523转10进制=29987 -->
<!-- 可添加其他设备:如PL2303(VID=0x067B, PID=0x2303) -->
<usb-device vendor-id="1659" product-id="8963" />
</resources>
二、核心实现步骤
1. 检测 USB 设备连接
通过 UsbManager 管理 USB 设备,并注册广播接收器监听设备的 “插入 / 拔出” 事件:
// 获取UsbManager实例
UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
// 注册广播接收器,监听USB设备插入/拔出
private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
// 设备插入:获取设备
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device != null) {
// 检查是否有权限,若无则请求
requestUsbPermission(device);
}
} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
// 设备拔出:关闭连接、释放资源
closeSerialConnection();
} else if (UsbManager.ACTION_USB_PERMISSION.equals(action)) {
// 权限请求结果
synchronized (this) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false) && device != null) {
// 权限已授予:打开设备并初始化串口
openSerialDevice(device);
} else {
Toast.makeText(context, "未获取USB权限", Toast.LENGTH_SHORT).show();
}
}
}
}
};
// 注册接收器(在onCreate中调用)
private void registerUsbReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
filter.addAction(UsbManager.ACTION_USB_PERMISSION);
registerReceiver(usbReceiver, filter);
}
2. 请求 USB 设备访问权限
安卓要求必须获得用户授权才能访问 USB 设备,通过 UsbManager.requestPermission() 发起请求:
// 请求USB设备权限
private void requestUsbPermission(UsbDevice device) {
if (usbManager.hasPermission(device)) {
// 已有权限:直接打开设备
openSerialDevice(device);
} else {
// 无权限:向用户请求
PendingIntent permissionIntent = PendingIntent.getBroadcast(this, 0,
new Intent(UsbManager.ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE);
usbManager.requestPermission(device, permissionIntent);
}
}
3. 打开设备并配置串口参数
USB-to-Serial 适配器本质是 USB 设备,需找到其对应的 接口(UsbInterface) 和 端点(UsbEndpoint)(串口通信通常使用 “批量传输端点”:BULK_IN 用于接收,BULK_OUT 用于发送)。
不同芯片的配置逻辑不同,推荐使用第三方库简化操作(如 usb-serial-for-android,已封装多种芯片的驱动)。
方式 1:使用第三方库(推荐)
usb-serial-for-android 是开源库,支持主流芯片,无需手动处理不同芯片的驱动差异。
-
添加依赖(在
build.gradle):implementation 'com.hoho.android:usb-serial-for-android:3.7.0' -
打开设备并配置参数:
private UsbSerialPort serialPort; // 串口端口实例 private OutputStream outputStream; // 输出流(发送数据) private InputStream inputStream; // 输入流(接收数据) // 打开设备并初始化串口 private void openSerialDevice(UsbDevice device) { // 获取设备支持的驱动(库自动匹配芯片型号) List<UsbSerialDriver> drivers = UsbSerialProber.getDefaultProber().findAllDrivers(usbManager); UsbSerialDriver driver = null; for (UsbSerialDriver d : drivers) { if (d.getDevice().getDeviceId() == device.getDeviceId()) { driver = d; break; } } if (driver == null) { Toast.makeText(this, "未找到支持的驱动", Toast.LENGTH_SHORT).show(); return; } try { // 打开设备连接 UsbDeviceConnection connection = usbManager.openDevice(driver.getDevice()); if (connection == null) { Toast.makeText(this, "无法打开设备连接", Toast.LENGTH_SHORT).show(); return; } // 获取串口端口(通常一个设备只有一个端口) serialPort = driver.getPorts().get(0); // 打开端口并配置参数(波特率、数据位、停止位、校验位) serialPort.open(connection); serialPort.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE); // 获取输入输出流 outputStream = serialPort.getOutputStream(); inputStream = serialPort.getInputStream(); // 启动线程监听接收数据 startReadThread(); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "打开串口失败:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } }
4. 数据读写操作
发送数据
通过 OutputStream 发送字节数据:
// 发送数据(字符串转字节数组)
public void sendData(String data) {
if (outputStream == null) return;
try {
outputStream.write(data.getBytes(StandardCharsets.UTF_8));
outputStream.flush(); // 立即发送
} catch (IOException e) {
e.printStackTrace();
}
}
接收数据
需在子线程中读取(避免阻塞 UI 线程),通过 InputStream 读取字节:
// 启动接收线程
private void startReadThread() {
new Thread(() -> {
byte[] buffer = new byte[1024]; // 缓冲区
int bytesRead;
while (true) {
try {
// 读取数据(阻塞操作,无数据时等待)
if ((bytesRead = inputStream.read(buffer)) != -1) {
// 转换为字符串(根据实际协议处理)
String receivedData = new String(buffer, 0, bytesRead, StandardCharsets.UTF_8);
// 切换到UI线程更新界面
runOnUiThread(() -> {
// 处理接收的数据(如显示到TextView)
tvReceived.setText(receivedData);
});
}
} catch (IOException e) {
e.printStackTrace();
break; // 读取失败(如设备断开),退出线程
}
}
}).start();
}
5. 关闭连接与释放资源
设备断开或页面销毁时,需关闭串口连接,避免资源泄漏:
// 关闭串口连接
private void closeSerialConnection() {
if (serialPort != null) {
try {
serialPort.close();
} catch (IOException e) {
e.printStackTrace();
}
serialPort = null;
}
outputStream = null;
inputStream = null;
}
// 在Activity销毁时调用
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(usbReceiver); // 注销广播接收器
closeSerialConnection(); // 关闭连接
}
三、常见问题与排查
-
设备不识别:
- 检查 OTG 线是否正常,安卓设备是否开启 USB Host 模式。
- 通过
adb shell dumpsys usb查看已连接的 USB 设备 VID/PID,确认是否在usb_device_filter.xml中正确配置。
-
权限请求失败:
- 确保
PendingIntent的 Flag 正确(如FLAG_IMMUTABLE,适配 Android 12+)。 - 手动在系统设置中授予应用 “USB 权限”。
- 确保
-
数据收发异常:
- 检查串口参数(波特率、数据位等)是否与外部设备一致(必须完全匹配)。
- 排查硬件连接(如 Tx/Rx 线是否接反,地线是否连接)。
-
驱动不支持:
- 确认
usb-serial-for-android库是否支持当前适配器芯片(可查看库的文档,不支持的芯片需自行开发驱动)。
- 确认
四、总结
安卓通过 USB 进行串口通信的核心流程是:检测设备→请求权限→打开设备并配置参数→数据读写→释放资源。使用第三方库(如 usb-serial-for-android)可大幅简化不同芯片的驱动适配工作,推荐优先采用。实际开发中需注意线程管理(避免 UI 阻塞)和异常处理(如设备突然断开),确保通信稳定。
更多推荐



所有评论(0)