Qt for android 串口库使用

简介

由于Qt for android并没有提供android的串口执行方案,基于需要又懒得自己去造轮子, 使用开源的
usb-serial-for-android 库进行串口访问读写。

如果有自己的需要和库不满足的点,可以查看库的底层调用的Android相关API + C/C++ 串口库 + 对应串口设备的开源驱动代码进行改造。

Note: 由于我没有系统的学习过Java、Android, 如果涉及到认知冲突, 请信自己[礼貌不失尴尬的微笑]。

步骤

1. 下载 usb-serial-for-android release版本

usb-serial-for-android_v3.7.2.zip

2. 解压缩

解压缩之后目录呈现如下图, 移植的代码在usbSerialForAndroid目录下

3. 加入Qt for Android项目

将usbSerialForAndroid/src/main/java/com目录整个拷入到Qt for

android生成的Android目录下

Qt for android 工程目录下的android源码目录

4. 设置Qt Creator显化java代码

DISTFILES +=

android/src/com/hoho/android/usbserial/driver/.java \
android/src/com/hoho/android/usbserial/util/
.java

5. 编译和解决报错

错误1 BuildConfig不存在

BuildConfig 是 gradle自动生成的,移植的时候并没有一起移植过来, 所以有几种方案:

1) 注释掉掉BuildConfig相关信息代码
2) Qt for android本身的项目也生成BuildConfig, 将 引用包由原先

import com.hoho.android.usbserial.BuildConfig; 改成

import org.qtproject.example.BuildConfig;

3) 创建BuildConfig.java,导入或者自定义相关使用字段(我目前使用的)
java 复制代码
package com.hoho.android.usbserial;
public final class BuildConfig {
  public static final boolean DEBUG = false;
  public static final String APPLICATION_ID = "org.qtproject.example";
  public static final String BUILD_TYPE = "release";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "1.0";
}

或(我暂时使用的方法)

java 复制代码
package com.hoho.android.usbserial;

public final class BuildConfig {
  public static final boolean DEBUG = org.qtproject.example.BuildConfig.DEBUG;
  public static final String APPLICATION_ID = org.qtproject.example.BuildConfig.APPLICATION_ID;
  public static final String BUILD_TYPE = org.qtproject.example.BuildConfig.BUILD_TYPE;
  public static final int VERSION_CODE = org.qtproject.example.BuildConfig.VERSION_CODE;
  public static final String VERSION_NAME = org.qtproject.example.BuildConfig.VERSION_NAME;
}
4) 定义包自身的gradle, 这个我暂时没有去Study和尝试, 懂得朋友开始自己的表演。(推荐)

6. 代码

mainwindows.cpp

cpp 复制代码
void MainWindow::test()
{
    QJniObject str = QJniObject::fromString(ui->cbPortNames->currentText());
    jboolean res = QJniObject::callStaticMethod<jboolean>(
                                       "usb/USBListActivity",
                                       "test",
                                       "(Ljava/lang/String;)Z",
                                       str.object<jstring>());
    if (0 == res)
    {
        logger("test failed");
    }
    else
    {
        logger("test succeed");
    }
}

usb.USBListActivity.java

java 复制代码
package usb;

import java.util.HashMap;
import java.util.Map;
import java.util.Iterator;
import java.io.IOException;

import android.content.Intent;
import android.app.PendingIntent;
import android.util.Log;
import android.os.Bundle;
import android.content.Context;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;

import com.hoho.android.usbserial.driver.Ch34xSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;

public class USBListActivity extends org.qtproject.qt.android.bindings.QtActivity
{
    private static USBListActivity instance = null;
    private static UsbManager usbManager = null;
    private static String tag = "MainClass";
    private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";



    public USBListActivity()
    {
        instance = this;
    }

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        usbManager = (UsbManager)getSystemService(Context.USB_SERVICE);

        // getDeviceList();
    }

    public static boolean test(String portName)
    {
        System.out.println("<-------------->test: " + portName);
        if (portName.isEmpty())
        {
            Log.i(tag, "port empty");
            return false;
        }
        System.out.println("<-------------->test1: " + portName);
        HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
        UsbDevice device = null;
        for (Map.Entry<String, UsbDevice> entry : deviceList.entrySet())
        {
            if (portName.equals(entry.getKey()))
            {
                device = entry.getValue();
                break;
            }
        }
        if (device == null)
        {
            Log.i(tag, "device not exists");
            return false;
        }

        if (!usbManager.hasPermission(device))
        {
            Intent permissionIntent = new Intent(ACTION_USB_PERMISSION);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(instance,
                                                    0,
                                                    permissionIntent,
                                                    PendingIntent.FLAG_UPDATE_CURRENT);
            usbManager.requestPermission(device, pendingIntent);

            if (!usbManager.hasPermission(device))
            {
                Log.i(tag, "permission denied");
                return false;
            }
        }

        UsbDeviceConnection deviceConnection = usbManager.openDevice(device);
        if (null == deviceConnection)
        {
            Log.i(tag, "fail to open device");
            return false;
        }

        Ch34xSerialDriver ch340Device = new Ch34xSerialDriver(device);
        UsbSerialPort serialport = ch340Device.getPorts().get(0);
        /* 打开串口 */
        try {
            serialport.open(deviceConnection);
        } catch (IOException ignored) {
            Log.i(tag, "fail to open serial port");
            return false;
        }

        /* 设置串口参数 */
        try {
            serialport.setParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE);
        }catch (IOException ignored) {
            Log.i(tag, "fail to set parameters");
        }

        /* 向串口发送数据 */
        try {
            serialport.write("Hello, world!".getBytes(), 1000);
        } catch (IOException e) {
            System.out.println("catched write error expected");
        }

        /* 关闭串口 */
        try {
            serialport.close();
        } catch (IOException ignored) {
        }

        return true;
    }

    public void getDeviceList()
    {
        HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
        System.out.println("------------------------->GetDeviceList<-------------------------");
        deviceList.forEach((key, value) -> {
            System.out.println("------------------------->" + key + "<-------------------------");

            System.out.println(value);

            System.out.println("<-------------------------" + key + "------------------------->");

        });
        System.out.println("<-------------------------GetDeviceList------------------------->");
    }
}

7. 连线

  1. PC 和 手机端各接一个USB转TTL线
    RX<->TX
    TX<->RX
    GND<->GND

8. 运行

第一次申请权限时同意了但还是判定失败, 后续解决,第二次执行test时成功...

手机端显示

PC端串口打印


帮助文档

Qt for Android

Qt for android 文档(thinkinginqt.com)
Qt for android 官方文档(Qt6.2LTS)
Qt Project to Manifest Configuration

Android

UsbManager(apiref.com)
UsbManager android-doc.com
UsbManager(matools.com)
Activity 生命周期概念

其他文章

Qt for android 获取USB设备列表(一)Java方式 获取
Qt for android 获取USB设备列表(二)JNI方式 获取
Qt for Android 乱码问题

相关推荐
Sammyyyyy30 分钟前
2025年,Javascript后端应该用 Bun、Node.js 还是 Deno?
开发语言·javascript·node.js
顾林海31 分钟前
Android MMKV 深度解析:原理、实践与源码剖析
android·面试·源码阅读
William一直在路上1 小时前
Python数据类型转换详解:从基础到实践
开发语言·python
雨白1 小时前
TCP/IP 核心概念详解:从网络分层到连接管理
android
看到我,请让我去学习2 小时前
Qt— 布局综合项目(Splitter,Stacked,Dock)
开发语言·qt
创想未来CTF2 小时前
Qt同步处理业务并禁用按钮
qt
GUET_一路向前2 小时前
【C语言防御性编程】if条件常量在前,变量在后
c语言·开发语言·if-else·防御性编程
曳渔2 小时前
UDP/TCP套接字编程简单实战指南
java·开发语言·网络·网络协议·tcp/ip·udp
Wgllss2 小时前
雷电雨效果:Kotlin+Compose+协程+Flow 实现天气UI
android·架构·android jetpack
三千道应用题2 小时前
WPF&C#超市管理系统(6)订单详情、顾客注册、商品销售排行查询和库存提示、LiveChat报表
开发语言·c#·wpf