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 乱码问题

相关推荐
重生之我是数学王子1 分钟前
QT基础 编码问题 定时器 事件 绘图事件 keyPressEvent QT5.12.3环境 C++实现
开发语言·c++·qt
Ai 编码助手3 分钟前
使用php和Xunsearch提升音乐网站的歌曲搜索效果
开发语言·php
学习前端的小z7 分钟前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
神仙别闹14 分钟前
基于C#和Sql Server 2008实现的(WinForm)订单生成系统
开发语言·c#
XINGTECODE15 分钟前
海盗王集成网关和商城服务端功能golang版
开发语言·后端·golang
zwjapple32 分钟前
typescript里面正则的使用
开发语言·javascript·正则表达式
小五Five33 分钟前
TypeScript项目中Axios的封装
开发语言·前端·javascript
前端每日三省35 分钟前
面试题-TS(八):什么是装饰器(decorators)?如何在 TypeScript 中使用它们?
开发语言·前端·javascript
凡人的AI工具箱1 小时前
15分钟学 Go 第 60 天 :综合项目展示 - 构建微服务电商平台(完整示例25000字)
开发语言·后端·微服务·架构·golang
chnming19871 小时前
STL关联式容器之map
开发语言·c++