Android TTL 串口通信工具类封装

本文提供了一个完整的 Android TTL 串口通信工具类封装,支持串口的打开、关闭、数据发送和接收功能。通过回调接口处理接收到的数据,工具类简洁易用,适合快速集成到项目中。


功能特性

  1. 串口配置
    • 支持配置串口路径、波特率、数据位、停止位和校验位。
  2. 数据发送
    • 支持发送字节数组数据。
  3. 数据接收
    • 通过回调接口返回接收到的数据。
  4. 错误处理
    • 通过回调接口返回错误信息。
  5. 线程安全
    • 使用 synchronized 关键字确保线程安全。
  6. 资源管理
    • 在关闭串口时正确释放所有资源。

代码实现

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();
    }
}

注意事项

  1. 权限问题
    • 访问串口设备需要 root 权限,或者设备已正确配置权限。
  2. 硬件兼容性
    • 确保串口配置(波特率、数据位等)与硬件设备一致。
  3. 性能优化
    • 如果数据量较大,可以调整缓冲区大小或优化数据处理逻辑。

通过这个工具类,您可以快速实现 Android 平台上的 TTL 串口通信功能,并根据需要扩展数据处理逻辑。

相关推荐
gechunlian8818 分钟前
Spring Boot中的404错误:原因、影响及处理策略
java·spring boot·后端
岁岁种桃花儿29 分钟前
AI超级智能开发系列从入门到上天第四篇:AI应用方案设计
java·服务器·开发语言
2501_915918411 小时前
苹果App Store上架审核卡住原因分析与解决方案指南
android·ios·小程序·https·uni-app·iphone·webview
架构师沉默1 小时前
Java 终于有自己的 AI Agent 框架了?
java·后端·架构
程序员爱酸奶1 小时前
ThreadLocal内存泄漏深度解析
java
skiy1 小时前
MySQL Workbench菜单汉化为中文
android·数据库·mysql
czlczl200209251 小时前
JVM创建对象过程
java·开发语言
一直都在5721 小时前
线程间的通信
java·jvm
小小小点2 小时前
Android四大常用布局详解与实战
android
GIOTTO情2 小时前
Infoseek危机公关全链路技术解析:基于近期热点舆情的落地实践
java