上一篇
安卓开发如何用串口收发数据
- 行业动态
- 2025-04-22
- 4
安卓串口通信基础
安卓系统基于Linux内核,支持通过/dev/ttyS
或/dev/ttyUSB
访问串口设备,但需注意:
- 权限限制:普通应用无权限直接访问串口,需声明
USB_PERMISSION
权限 - 设备路径:不同设备串口路径不同(如
/dev/ttyS1
、/dev/ttyUSB0
) - 驱动支持:需确保设备已正确加载串口驱动
实现步骤与关键技术
权限配置
<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 // 找到目标设备 } }