当前位置:首页 > 行业动态 > 正文

安卓开发如何用串口收发数据

安卓串口通信基础

安卓系统基于Linux内核,支持通过/dev/ttyS/dev/ttyUSB访问串口设备,但需注意:

  1. 权限限制:普通应用无权限直接访问串口,需声明USB_PERMISSION权限
  2. 设备路径:不同设备串口路径不同(如/dev/ttyS1/dev/ttyUSB0
  3. 驱动支持:需确保设备已正确加载串口驱动

实现步骤与关键技术

权限配置

<uses-feature android:name="android.hardware.usb.host" />
<uses-permission android:name="android.permission.USB_PERMISSION" />

串口操作核心流程

步骤 说明 关键API
获取设备节点 通过UsbManager查找设备 UsbManager.getDeviceList()
打开串口 使用FileInputStream/FileOutputStream new FileInputStream(devicePath)
配置参数 设置波特率/校验位等 termios结构体配置
数据收发 读写输入输出流 inputStream.read()
outputStream.write()
关闭资源 释放文件描述符 close()方法

JNI串口操作示例代码

// Native方法声明
public native int openSerial(String path, int baudrate);
public native int writeSerial(byte[] data);
public native int readSerial(byte[] buffer);
public native void closeSerial();
// JNI实现(C语言)
#include <jni.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
JNIEXPORT jint JNICALL Java_com_example_SerialPort_openSerial(JNIEnv env, jobject obj, jstring path, jint baudrate) {
    const char device = (env)->GetStringUTFChars(env, path, NULL);
    int fd = open(device, O_RDWR | O_NOCTTY);
    if (fd == -1) return -1;
    struct termios options;
    tcgetattr(fd, &options);
    cfsetispeed(&options, baudrate); // 设置输入波特率
    cfsetospeed(&options, baudrate); // 设置输出波特率
    options.c_cflag &= ~PARENB;      // 无校验位
    options.c_cflag |= CS8;         // 8数据位
    options.c_cflag |= CLOCAL;      // 本地连接
    options.c_cflag &= ~CRTSCTS;    // 无硬件流控
    tcsetattr(fd, TCSANOW, &options);
    return fd;
}

推荐第三方库

库名称 特点 适用场景
SerialPort API 纯Java实现 快速集成,无需JNI
FTDI Driver 支持FTDI芯片 USB转串口设备
UsbSerial Prolific/CH341驱动 国产USB转串口芯片

完整操作示例(使用SerialPort API)

// 1. 初始化串口
SerialPort serialPort = new SerialPort(new File("/dev/ttyS1"), 9600, 0);
// 2. 发送数据
String sendData = "Hello Serial";
serialPort.getOutputStream().write(sendData.getBytes());
// 3. 接收数据(需开线程)
new Thread(() -> {
    byte[] buffer = new byte[1024];
    int size = serialPort.getInputStream().read(buffer);
    String received = new String(buffer, 0, size);
    Log.d("Serial", "Received: " + received);
}).start();
// 4. 关闭串口
serialPort.close();

常见问题与解决方案

问题现象 原因分析 解决方案
EACCES权限错误 未获取USB权限 动态请求UsbManager权限
设备节点不匹配 设备路径错误 使用adb shell ls /dev/确认路径
乱码/丢包 波特率不匹配 双方统一设置波特率/校验位
无法识别设备 驱动未加载 手动加载模块insmod或重启设备

相关问题与解答

Q1:安卓11+系统如何突破SELinux限制访问串口?
A1:需将应用配置为系统签名应用,或通过sysfs接口间接操作,建议将串口设备添加到/etc/selinux/rules白名单。

Q2:如何检测USB转串口设备是否已连接?
A2:通过UsbManager.getDeviceList()遍历设备,检查USB_CLASS_CDC_DATA或特定厂商ID/产品ID,示例代码:

UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> devices = manager.getDeviceList();
for (UsbDevice device : devices.values()) {
    if (device.getProductId() == 0x1234) { // 替换为目标PID
        // 找到目标设备
    }
}
0