Android AS下的OTG串口设备读写

2024-08-21 12:48
文章标签 android 串口 读写 设备 otg

本文主要是介绍Android AS下的OTG串口设备读写,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Android AS下的OTG串口设备读写

  • 新建工程
  • 添加工具类
  • 添加设备参数列表
  • 具体实现
  • WIFI adb

了解嵌入式的读者应该知道在单片机编程中串口(uart)通讯接口最常用的就是TTL和USB接口,将单片机TTL转USB就可以接入电脑查看串口数据实现电脑与单片机通讯,在Android AS下的NDK开发中讲解了Android使用TTL方式的接口收发数据,当然咱们常用的Android手机没有这样的接口,要实现手机和单片机串口通讯就可以用OTG来实现。

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

新建工程

在这里插入图片描述

添加工具类

在添加工具类时可能会有错误提示,只是包名错了,修改报错文件的包成自己当前工程的包名即可解决问题:
在这里插入图片描述

添加设备参数列表

在AndroidManifest中声明指定的USB设备,设备信息存放在resource="@xml/device_filter"
在这里插入图片描述

<intent-filter><action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
</intent-filter>
<meta-dataandroid:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"android:resource="@xml/device_filter"/>

xml文件夹下命名为device_filter.xml:
在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<resources><!-- 0x0403 / 0x6001: FTDI FT232R UART --><usb-device vendor-id="1027" product-id="24577" /><!-- 0x0403 / 0x6015: FTDI FT231X --><usb-device vendor-id="1027" product-id="24597" /><!-- 0x2341 / Arduino --><usb-device vendor-id="9025" /><!-- 0x16C0 / 0x0483: Teensyduino  --><usb-device vendor-id="5824" product-id="1155" /><!-- 0x10C4 / 0xEA60: CP210x UART Bridge --><usb-device vendor-id="4292" product-id="60000" /><!-- 0x067B / 0x2303: Prolific PL2303 --><usb-device vendor-id="1659" product-id="8963" />
</resources>

至于这个文件里面的数据表示的是什么,将USB转TTL模块插入电脑,在设备管理器里面可以看到:
在这里插入图片描述
PID_2303:2303的10进制是8963,也就是:product-id=“8963”
VID_067B:067B的10进制是1659,vendor-id=“1659”
不同的模块这两个值就不一样,所以就有了这样一个列表,当然这也不全,没有包含所有的型号。

具体实现

在MainActivity里面就可以写设备获取与数据收发了:

package com.example.otgdemo;import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;import com.example.otgdemo.usbserial.driver.UsbSerialDriver;
import com.example.otgdemo.usbserial.driver.UsbSerialProber;
import com.example.otgdemo.usbserial.util.SerialInputOutputManager;
import com.example.otgdemo.utils.LogUtils;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class MainActivity extends AppCompatActivity {private UsbManager mUsbManager;         // usb设备管理private List<DeviceEntry> mEntries;     // 串口设备列表private static UsbSerialDriver sDriver; // 打开的串口设备private static SerialInputOutputManager mSerialIoManager;   //数据发送、接收工具private ExecutorService mExecutorService;   //数据读取线程管理@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 获取USB_SERVICE的管理器mUsbManager = (UsbManager)getSystemService(this.USB_SERVICE);mEntries = new ArrayList<>();mExecutorService = Executors.newSingleThreadExecutor();refreshDeviceList();}/*** 刷新usb设备列表*/private void refreshDeviceList() {new AsyncTask<Void, Void, List<DeviceEntry>>() {@Overrideprotected List<DeviceEntry> doInBackground(Void... params) {Log.d("log","刷新设备列表 ...");final List<DeviceEntry> result = new ArrayList<>();Map<String, UsbDevice> deviceList = mUsbManager.getDeviceList();if (deviceList.isEmpty()) {Log.d("log","设备列表为空");} else {for (final UsbDevice device : mUsbManager.getDeviceList().values()) {final List<UsbSerialDriver> drivers = UsbSerialProber.probeSingleDevice(mUsbManager, device);Log.d("log","发现设备: " + device);if (drivers.isEmpty()) {Log.d("log","  - 空设备列表.");result.add(new DeviceEntry(null));} else {for (UsbSerialDriver driver : drivers) {Log.d("log","  + " + driver);result.add(new DeviceEntry(driver));}}}}return result;}@Overrideprotected void onPostExecute(List<DeviceEntry> result) {if (result.isEmpty()) {Toast.makeText(MainActivity.this, "没发现可用设备!", Toast.LENGTH_SHORT).show();return;}mEntries.clear();mEntries.addAll(result);sDriver = mEntries.get(0).driver;reStart();Log.d("log","停止刷新,发现" + mEntries.size() + " 个设备.");}}.execute((Void) null);}/*** 打开串口*/private void reStart() {if (sDriver == null) {Toast.makeText(this, "没有发现串口设备.", Toast.LENGTH_SHORT).show();} else {try {sDriver.open();sDriver.setParameters(57600, 8, UsbSerialDriver.STOPBITS_1, UsbSerialDriver.PARITY_NONE);} catch (IOException e) {LogUtils.d("设备打开错误: " + e.getMessage(), e);Toast.makeText(this, "设备打开错误: " + e.getMessage(), Toast.LENGTH_SHORT).show();try {sDriver.close();} catch (IOException e2) {// Ignore.}sDriver = null;return;}Toast.makeText(this, " 串口设备: " + sDriver.getClass().getSimpleName(), Toast.LENGTH_SHORT).show();}onDeviceStateChange();}/*** 重置串口*/private void onDeviceStateChange() {stopIoManager();startIoManager();}/*** 关闭串口*/private void stopIoManager() {if (mSerialIoManager != null) {LogUtils.d("Stopping io manager ..");mSerialIoManager.stop();mSerialIoManager = null;}}/*** 打开串口*/private void startIoManager() {if (sDriver != null) {LogUtils.d("Starting io manager ..");mSerialIoManager = new SerialInputOutputManager(sDriver, mListener);mExecutorService.submit(mSerialIoManager);//开启数据读取线程}}/*** Simple container for a UsbDevice and its driver.*/private static class DeviceEntry {public UsbSerialDriver driver;DeviceEntry(UsbSerialDriver driver) {this.driver = driver;}}/*** 数据读取回调*/private final SerialInputOutputManager.Listener mListener = new SerialInputOutputManager.Listener() {@Overridepublic void onRunError(Exception e) {LogUtils.d("Runner stopped.");}// 数据接收的回调函数@Overridepublic void onNewData(byte[] data, int len) {}};/*** 数据发送** @param data 要发送的数据*/public static void sendData(byte[] data) {if (mSerialIoManager != null) {mSerialIoManager.writeAsync(data);}}
}

WIFI adb

如果手机要调试那么会占用手机的usb端口,要下程序又要接OTG,来回拔插比较麻烦,可以在AS中使用wifi adb方式来部署应用。在file->seting->Plugins下选择下方中间一项:
在这里插入图片描述

右侧会有一个install的按钮,我之前安装过了就是这个样子:
在这里插入图片描述
安装完后会有这样一个图标:
在这里插入图片描述
在usb接到手机之后点击这个图标,出现如下,点击右侧的CONNECT即可:
在这里插入图片描述
变成这样就说明链接成功,就可以拔掉usb线了:
在这里插入图片描述
最新demo加入了CH340支持。

这篇关于Android AS下的OTG串口设备读写的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1093210

相关文章

10. 文件的读写

10.1 文本文件 操作文件三大类: ofstream:写操作ifstream:读操作fstream:读写操作 打开方式解释ios::in为了读文件而打开文件ios::out为了写文件而打开文件,如果当前文件存在则清空当前文件在写入ios::app追加方式写文件ios::trunc如果文件存在先删除,在创建ios::ate打开文件之后令读写位置移至文件尾端ios::binary二进制方式

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

如何编写Linux PCIe设备驱动器 之二

如何编写Linux PCIe设备驱动器 之二 功能(capability)集功能(capability)APIs通过pci_bus_read_config完成功能存取功能APIs参数pos常量值PCI功能结构 PCI功能IDMSI功能电源功率管理功能 功能(capability)集 功能(capability)APIs int pcie_capability_read_wo

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使