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 串口通信功能,并根据需要扩展数据处理逻辑。

相关推荐
TDengine (老段)9 分钟前
TDengine 使用最佳实践
java·大数据·数据库·物联网·时序数据库·iot·tdengine
怦然心动~22 分钟前
springboot 3 集成Redisson
java·spring boot·redisson
每次的天空24 分钟前
kotlin与MVVM的结合使用总结(二)
android·开发语言·kotlin
李艺为1 小时前
Android Studio执行Run操作报Couldn‘t terminate previous instance of app错误
android·ide·android studio
小Mie不吃饭1 小时前
Maven | 站在初学者的角度配置
java·spring boot·maven
林犀居士1 小时前
JVM系统变量的妙用
java·jvm系统变量
北枫寒夜2 小时前
JVM和运行时数据区
java·jvm
StevenLdh2 小时前
Java Spring Boot 常用技术及核心注解
java·开发语言·spring boot
考虑考虑2 小时前
JDK21中的Switch模式匹配
java·后端·java ee