简介
由于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,导入或者自定义相关使用字段(我目前使用的)
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";
}
或(我暂时使用的方法)
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
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
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;}@Overridepublic 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. 连线
- 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 乱码问题