本文提供了一个完整的 Android TTL 串口通信工具类封装,支持串口的打开、关闭、数据发送和接收功能。通过回调接口处理接收到的数据,工具类简洁易用,适合快速集成到项目中。
功能特性
- 串口配置 :
- 支持配置串口路径、波特率、数据位、停止位和校验位。
- 数据发送 :
- 支持发送字节数组数据。
- 数据接收 :
- 通过回调接口返回接收到的数据。
- 错误处理 :
- 通过回调接口返回错误信息。
- 线程安全 :
- 使用
synchronized
关键字确保线程安全。
- 使用
- 资源管理 :
- 在关闭串口时正确释放所有资源。
代码实现
1. 串口配置类
java
public class SerialPortConfig {
private final String devicePath; // 串口设备路径
private final int baudRate; // 波特率
private final int dataBits; // 数据位
private final int stopBits; // 停止位
private final int parity; // 校验位
public SerialPortConfig(String devicePath, int baudRate, int dataBits, int stopBits, int parity) {
this.devicePath = devicePath;
this.baudRate = baudRate;
this.dataBits = dataBits;
this.stopBits = stopBits;
this.parity = parity;
}
public String getDevicePath() {
return devicePath;
}
public int getBaudRate() {
return baudRate;
}
public int getDataBits() {
return dataBits;
}
public int getStopBits() {
return stopBits;
}
public int getParity() {
return parity;
}
}
2. 串口工具类
java
import android.serialport.SerialPort;
import android.serialport.SerialPortFinder;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
public class SerialPortHelper {
private SerialPort serialPort;
private InputStream inputStream;
private OutputStream outputStream;
private final AtomicBoolean isOpen = new AtomicBoolean(false);
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
private final SerialPortConfig config;
private OnDataReceivedListener onDataReceivedListener;
private OnErrorListener onErrorListener;
public SerialPortHelper(SerialPortConfig config) {
this.config = config;
}
/**
* 打开串口
*/
public synchronized boolean open() {
if (isOpen.get()) {
return true;
}
try {
serialPort = new SerialPort(
new File(config.getDevicePath()),
config.getBaudRate(),
config.getDataBits(),
config.getStopBits(),
config.getParity()
);
inputStream = serialPort.getInputStream();
outputStream = serialPort.getOutputStream();
isOpen.set(true);
// 启动数据读取任务
executorService.submit(this::readData);
return true;
} catch (IOException e) {
handleError("Failed to open serial port", e);
close();
return false;
}
}
/**
* 关闭串口
*/
public synchronized void close() {
if (!isOpen.get()) {
return;
}
isOpen.set(false);
executorService.shutdownNow();
if (serialPort != null) {
serialPort.close();
serialPort = null;
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
handleError("Failed to close input stream", e);
}
inputStream = null;
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
handleError("Failed to close output stream", e);
}
outputStream = null;
}
}
/**
* 发送数据
*/
public synchronized void send(byte[] data) {
if (!isOpen.get() || outputStream == null) {
throw new IllegalStateException("Serial port is not open");
}
try {
outputStream.write(data);
outputStream.flush();
} catch (IOException e) {
handleError("Failed to send data", e);
close();
}
}
/**
* 读取数据
*/
private void readData() {
byte[] buffer = new byte[1024];
while (isOpen.get() && !Thread.currentThread().isInterrupted()) {
try {
if (inputStream == null) return;
// 读取数据
int size = inputStream.read(buffer);
if (size > 0 && onDataReceivedListener != null) {
onDataReceivedListener.onDataReceived(buffer, size);
}
} catch (IOException e) {
handleError("Failed to read data", e);
close();
break;
}
}
}
/**
* 错误处理
*/
private void handleError(String message, Throwable throwable) {
if (onErrorListener != null) {
onErrorListener.onError(message, throwable);
} else {
if (throwable != null) {
throwable.printStackTrace();
}
}
}
/**
* 数据接收回调接口
*/
public interface OnDataReceivedListener {
void onDataReceived(byte[] data, int size);
}
/**
* 错误回调接口
*/
public interface OnErrorListener {
void onError(String message, Throwable throwable);
}
public void setOnDataReceivedListener(OnDataReceivedListener listener) {
this.onDataReceivedListener = listener;
}
public void setOnErrorListener(OnErrorListener listener) {
this.onErrorListener = listener;
}
public boolean isOpen() {
return isOpen.get();
}
}
3. 使用示例
java
public class MainActivity extends AppCompatActivity {
private SerialPortHelper serialPortHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化串口配置
SerialPortConfig config = new SerialPortConfig("/dev/ttyS1", 9600, 8, 1, 0);
serialPortHelper = new SerialPortHelper(config);
// 设置数据接收监听器
serialPortHelper.setOnDataReceivedListener((data, size) -> {
String receivedData = new String(data, 0, size);
Log.d("SerialPort", "Received: " + receivedData);
});
// 设置错误监听器
serialPortHelper.setOnErrorListener((message, throwable) -> {
Log.e("SerialPort", message, throwable);
});
// 打开串口
if (serialPortHelper.open()) {
Log.d("SerialPort", "串口打开成功");
} else {
Log.d("SerialPort", "串口打开失败");
}
// 发送数据
byte[] sendData = "Hello, Serial Port!".getBytes();
serialPortHelper.send(sendData);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 关闭串口
serialPortHelper.close();
}
}
注意事项
- 权限问题 :
- 访问串口设备需要 root 权限,或者设备已正确配置权限。
- 硬件兼容性 :
- 确保串口配置(波特率、数据位等)与硬件设备一致。
- 性能优化 :
- 如果数据量较大,可以调整缓冲区大小或优化数据处理逻辑。
通过这个工具类,您可以快速实现 Android 平台上的 TTL 串口通信功能,并根据需要扩展数据处理逻辑。