Android 串口和USB通信开发

最近涉及到android串口和usb的开发,花费不少时间找文章参考。主要时间花费在串口连接上,由于计算机实际中没有串口的设备接口,只能用 虚拟串口 进行通信;且 USB 连接模拟器又是一番费神操作。
用到的工具 提取码: djss


搭建虚拟环境(有实际串口接口可忽略)
  • 打开 Genymotion 安装android虚拟机

    添加虚拟机

    安装完成后

  • 打开android studio 添加 Genymotion 插件

    AS添加插件

    安装完成重启AS后会看到此图标

  • 打开 Oracle VM VirtualBox 添加 Oracle_VM_VirtualBox_Extension_Pack 插件

    全局设定

    添加扩展支持

添加此支持在使用USB挂载android模拟器时必须使用,否则android模拟设备无法识别连接设备。

  • 打开 Configure Virtual Serial Port Driver 添加虚拟串口

    添加COM2和COM3串口

    成功回显

    此处添加的虚拟串口是成对出现。

  • Oracle VM VirtualBox 开启使用虚拟串口

    android模拟设备开启串口

由于 成功回显图 模拟的串口名为COM2和COM3,此处仅开启COM2的映射即可。

  • Oracle VM VirtualBox 开启使用USB设备

    usb设备映射

    此处选择自己开发的相应设备即可。

  • 使用 串口调试精灵 模拟数据的发送与接收

    开启COM3

    上图为 开启状态 ,默认是关闭的

  • 最后就是接下来要说的开启 android模拟器 并编写的程序进行通信

一、串口通信

参考链接 主要参考其使用谷歌的串口so库加载打开串口类

搭建项目
  • 复制so库至android项目中

复制so库

这里有个7.0系统会报错,so库版本问题,直接去谷歌开源拿比较稳

  • 设置so库目录
  android { 
      ...
      sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
      }
    ...
  }
  • 复制包及SerialPort类
串口打开工具类

注:android_serialport_api 包名不可更改

  • 串口基本操作(打开,关闭,发送,接收)
//isConConnectionStatus  串口的连接状态
 /**
   * 打开串口
   * @param pathname  串口路径
   * @param baudrate  波特率
   */
  public boolean openSerialPort(String pathname, int baudrate) {
      boolean isopen = false;
       try {
            serialPort = new SerialPort(new File(pathname), baudrate, 0);
            inputStream = serialPort.getInputStream();
            outputStream = serialPort.getOutputStream();
            receive();//接收函数,主要实现开启子线程并读取数据
            isConConnectionStatus = isopen = true;
        } catch (IOException e) {
            Log.e(TAG, "打开串口异常" + e);
        } catch (SecurityException e) {
             Log.e(TAG, "无串口操作权限" + e);
        } catch (UnsatisfiedLinkError e) {
             Log.e(TAG, "so文件无法加载" + e);
        }
      return isopen;
  }
  
   /**
     * 接收串口数据
     */
    public void receive() {
        if (receiveThread != null && !isConConnectionStatus) {
            return;
        }
        receiveThread = new Thread() {
            @Override
            public void run() {
                while (isConConnectionStatus) {
                    try {
                        byte[] readData = new byte[32];
                        if (inputStream == null) {
                            return;
                        }
                        int size = inputStream.read(readData);
                        if (size > 0 && isConConnectionStatus) {
                            //回调数据
                            Log.i(TAG, "readData:" + Arrays.toString(readData));
                        }
                    } catch (IOException e) {
                        Log.e(TAG, "读取数据失败..." + e);
                    }
                }
            }
        };
        receiveThread.start();
    }

   /**
     * 发送串口指令
     */
    public boolean sendData(byte[] data) {
        boolean result = false;
        if (isConConnectionStatus) {
           try {
               outputStream.write(data);
               outputStream.flush();
               result  = true;
            } catch (IOException e) {
               Log.e(TAG, "串口数据发送失败:" + e);
            }
        }
        return result;
    }

 /**
   * 关闭串口
   */
  public boolean closeSerialPort() {
      boolean isclose = false;
      if (isConConnectionStatus) {
           try {
               if (inputStream != null) {
                  inputStream.close();
               }
               if (outputStream != null) {
                  outputStream.close();
               }
               isConConnectionStatus = false;
               isClose = true;
            } catch (IOException e) {
                Log.e(TAG, "关闭串口异常" + e);
            }
       }
      return isclose ;
  }

串口的操作就在这里完结撒花。

二、USB通信

  • 设置静态权限
<uses-feature android:name="android.hardware.usb.host" />
  • USB基本操作(打开、关闭、接收、发送)
  public void open() {
      usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
        if (usbManager != null) {
            UsbDevice result = null;
            HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
            for (String key : deviceList.keySet()) {
                UsbDevice usbDevice = deviceList.get(key);
                if (usbDevice != null &&
                        usbDevice.getProductId() == PID &&
                        usbDevice.getVendorId() == UID) {
                    result = usbDevice;
                    break;
                }
            }
            if (result != null) {
                if (usbManager.hasPermission(result)) {
                    onUsbPermissionAllow(result);//权限通过
                } else {
                    //申请USB权限
                    mUsbPermissionActionReceiver = new UsbPermissionActionReceiver();
                    mUsbPermissionActionReceiver.setListener(this);
                    Intent intent = new Intent(UsbPermissionActionReceiver.ACTION_USB_PERMISSION);
                    PendingIntent mPermissionIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
                    IntentFilter permissionFilter = new IntentFilter(UsbPermissionActionReceiver.ACTION_USB_PERMISSION);
                    context.registerReceiver(mUsbPermissionActionReceiver, permissionFilter);
                    usbManager.requestPermission(result, mPermissionIntent);
                }
            } else {
                onUsbPermissionAllow(null);
            }
        } else {
            onUsbPermissionFail();//未获取到权限
        }
  }
  
  public void onUsbPermissionFail() {
    if (mUsbPermissionActionReceiver != null && context != null) {
        context.unregisterReceiver(mUsbPermissionActionReceiver);
    }
  }

  public void onUsbPermissionAllow() {
    usbDeviceConnection = usbManager.openDevice(usbDevice);//获取usb连接
    if (usbDeviceConnection != null) {
         if (usbRequest == null) {
             usbRequest = new UsbRequest();
         }
         usbRequest.initialize(usbDeviceConnection, usbEndpointIn);
         isConConnectionStatus = true;
         new ReceiveThread().start();
     }
    if (mUsbPermissionActionReceiver != null && context != null) {
        context.unregisterReceiver(mUsbPermissionActionReceiver);
    }
  }

  /**
    * 接收线程
    */
  private class ReceiveThread extends Thread {
        @Override
        public void run() {
            super.run();
            while (isConConnectionStatus) {
                try {
                    int maxSize = usbEndpointIn.getMaxPacketSize();
                    receiveBytes = new byte[maxSize];
                    boolean result = false;
                    if (usbDeviceConnection != null && usbInterface != null) {
                          usbDeviceConnection.claimInterface(usbInterface, true);//独占接口
                          result = usbDeviceConnection.bulkTransfer(usbEndpointIn, receiveBytes, receiveBytes.length, DEFAULT_TIMEOUT) != -1;
                    }
                    if (result) {
                        //获取成功
                        Log.e(TAG, "data:" +  e);
                    } else {
                            Log.e(TAG, "读取数据失败!\n" +  e);
                    }
                } catch (InterruptedException e) {
                    Log.e(TAG, "数据读取异常:" + e);
                }
            }
        }
    }

  /**
     * 发送串口指令(字符串)
     *
     * @param sendBytes 需要发送的字节数据
     */
    private boolean sendData(final byte[] sendBytes) {
        boolean sendResult = false;
        if (usbEndpointOut != null && sendBytes != null && sendBytes.length > 0) {
            sendResult = usbDeviceConnection.bulkTransfer(usbEndpointOut, sendBytes, sendBytes.length, DEFAULT_TIMEOUT) != -1;
        }
        Log.i(TAG, "sendData:" + sendResult);
        return sendResult;
    }

  /**
    * 关闭USB连接
    */
  public boolean close() {
    boolean result = false;
        if (isConConnectionStatus) {
            if (usbDeviceConnection != null && usbInterface != null) {
                isConConnectionStatus = false;
                usbDeviceConnection.releaseInterface(usbInterface);
                usbDeviceConnection.close();
                result = true;
            }
        }
    return result;
  }


UsbPermissionActionReceiver 类

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.util.Log;
import ehe.etsa.serialport.IETSAFactory;

public class UsbPermissionActionReceiver extends BroadcastReceiver {

    private OnUsbPermissionListener listener;
    public static final String ACTION_USB_PERMISSION = "com.demo.USB_PERMISSION";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (ACTION_USB_PERMISSION.equals(action)) {
            synchronized (this) {
                UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                    if (null != usbDevice && listener != null) {
                        listener.onUsbPermissionAllow(usbDevice);
                    }
                } else {
                    Log.e(IETSAFactory.TAG, "Permission denied for device(获取设备的权限被拒绝):\n" + usbDevice);
                    if (listener != null) {
                        listener.onUsbPermissionFail();
                    }
                }
            }
        }
    }

    public void setListener(OnUsbPermissionListener listener) {
        this.listener = listener;
    }

    public interface OnUsbPermissionListener {
        /** 当USB权限获取失败回调 */
        void onUsbPermissionFail();

        /** 当权限通过回调 */
        void onUsbPermissionAllow(UsbDevice usbDevice);
    }
}

到此Android 串口和USB的通信开发完结。


没有最好,只有最合适
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342