Android AS下的OTG串口设备读写

Android AS下的OTG串口设备读写

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

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

Android AS下的OTG串口设备读写_第1张图片Android AS下的OTG串口设备读写_第2张图片
Android AS下的OTG串口设备读写_第3张图片

新建工程

Android AS下的OTG串口设备读写_第4张图片

添加工具类

在添加工具类时可能会有错误提示,只是包名错了,修改报错文件的包成自己当前工程的包名即可解决问题:
Android AS下的OTG串口设备读写_第5张图片

添加设备参数列表

在AndroidManifest中声明指定的USB设备,设备信息存放在resource="@xml/device_filter"
Android AS下的OTG串口设备读写_第6张图片

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

xml文件夹下命名为device_filter.xml:
Android AS下的OTG串口设备读写_第7张图片

<?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模块插入电脑,在设备管理器里面可以看到:
Android AS下的OTG串口设备读写_第8张图片
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;   //数据读取线程管理

    @Override
    protected 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>>() {
            @Override
            protected 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;
            }

            @Override
            protected 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() {

        @Override
        public void onRunError(Exception e) {
            LogUtils.d("Runner stopped.");
        }

		// 数据接收的回调函数
        @Override
        public 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下选择下方中间一项:
Android AS下的OTG串口设备读写_第9张图片

右侧会有一个install的按钮,我之前安装过了就是这个样子:
Android AS下的OTG串口设备读写_第10张图片
安装完后会有这样一个图标:
Android AS下的OTG串口设备读写_第11张图片
在usb接到手机之后点击这个图标,出现如下,点击右侧的CONNECT即可:
Android AS下的OTG串口设备读写_第12张图片
变成这样就说明链接成功,就可以拔掉usb线了:
Android AS下的OTG串口设备读写_第13张图片
最新demo加入了CH340支持。

你可能感兴趣的:(Android)