串口发送实质就是向串口设备写入、读取字节流,和文件的操作很相似,安卓官方已经提供了android-serialport-api,在开源社区上也有很多衍生项目可以借鉴,本文介绍其中一种用法。
- 添加依赖
在Module下的 build.gradle 中添加:
implementation 'com.aill:AndroidSerialPort:1.0.8'
- 检测权限
首先要有ROOT权限,而且打开串口时,检测读写权限,当没有权限时,会尝试对其进行授权,默认su路径是/system/bin/su,有些设备su路径是/system/xbin/su:
SerialPort.setSuPath("/system/xbin/su");
- 串口 打开及关闭
/**
* @param 1 串口路径
* @param 2 波特率
*@param 3 flags 给0就好
*/
SerialPort serialPort = new SerialPort(new File("/dev/ttyS1"), 9600, 0);
//关闭串口
serialPort.close();
- 往串口中写入数据
//从串口对象中获取输出流
OutputStream outputStream = serialPort.getOutputStream();
//定义需要发送的数据
byte[] data = new byte[2];
data[0] = 0x01;
data[1] = 0x02;
//写入数据
outputStream.write(data);
outputStream.flush();
五、读取串口数据
读取数据时候会遇到不能一次性读取正确的完整的数据,可以这样解决:
1、在开始读取数据前,让读取数据的线程先睡眠一段时间,等待数据都准备好,再开始读取出来,这样应该可以避免大部分的分包情况
2、如果是固定的数据长度,循环读取完固定长度的字节数据再退出
//从串口对象中获取输入流
InputStream inputStream = serialPort.getInputStream();
//循环读取数据,放到子线程去,避免堵塞主线程
boolean readContinue=true;
new Thread(new Runnable() {
@Override
public void run() {
while (readContinue) {
if (inputStream.available() > 0) {
//等待一段时间再读取数据,基本上大部分情况下都是完整的数据
Thread.sleep(50);
byte[] buffer = new byte[12];
int readCount=0;
int availableCount=inputStream.available();
//每次接收都是固定长度的字节
while (readCount < 12 && availableCount > 0) {
readCount += inputStream.read(buffer, readCount, 12 -readCount);
Thread.sleep(5);
availableCount = inputStream.available();
}
}
}
}
}).start();
3、在实际开发中,有一种应用场景是先发送数据到开发板,开发板再响应返回数据,而且是循环发送读取数据,时间间隔要求极其短,很可能出现了数据错乱情况,可以先在发送数据前判断输入流中有无数据,有数据时先读取完流中的数据。
while (readContinue) {
//先判断输入流中有无数据,有数据先读取完清空缓冲,即清空残留数据
while (inputStream.available() > 0) {
byte[] buffer = new byte[12];
inputStream.read(buffer);
Thread.sleep(5);
}
//写入数据
outputStream.write(data);
outputStream.flush();
//开始读数据及其他操作
while (readCount < 12 && availableCount > 0) {
readCount += inputStream.read(buffer, readCount, 12 -readCount);
Thread.sleep(5);
availableCount = inputStream.available();
}
Thread.sleep(100);
}