简介
由于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. 连线
- 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 乱码问题