欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android USB串口开发

程序员文章站 2024-02-22 10:08:40
...

因为第一次接触Android下的串口开发,在网上找了很多例子都不能满足自己的需要以及不能正常使用,于是结合网上的资源以及查阅资料,终于完成了关于这个串口的开发,在此记录下usb转串口通信开发的过程。

Android串口开发步骤总共分为四大类,如下
1. 权限获取
2. 发现打开串口
3. 串口操作(发送与读取)
4. 关闭串口

一、权限获取

首先我们需要在AndroidMainfest.xml文件中配置USB使用权限

<uses-feature android:name="android.hardware.usb.host" />

并在我们的Activity标签中配置intent-filter

<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" />

resource资源为res资源文件夹下的xml文件下的device_filter.xml文件。device_filter.xml文件是我们需要知道我们USB设备硬件的vendor-id和product-id。文件内容如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <usb-device
        vendor-id="xxxx"
        product-id="xxxx"/>
</resources>

其中vendor-id以及product-id我们可以通过计算机管理 -> 电脑电脑设备管理器,Android Phone 查看详细信息,属性选择硬件ID。
Android USB串口开发

二、发现打开串口
首先我们需要获取到UsbManager管理类,通过此类的getDeviceList()方法得到包含所有已连接的USB设备的列表。最后,通过设备名称来得到给设备对象。

UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceMap = usbManager.getDeviceList();
UsbDevice device = deviceMap.get("deviceName");

上面是获取指定的串口设备,如果你想获取到所有的可以通过usbManager.getDeviceList().values();获取在foreach循环迭代拿到每一个设备。

当我们获取到一个设备之后,我们首先要判断是否有该权限,通过usbManager.hasPermission(device)判断是否有该权限。当有权限我们就可以打开串口设备以及对他设置波特率、检验位等参数信息。

 private void permissionAllow(UsbDevice device) {

        List<UsbSerialPort> result = new ArrayList<>();

        for (final UsbSerialDriver driver : drivers) {
            final List<UsbSerialPort> ports = driver.getPorts();
            result.addAll(ports);
        }

        UsbDeviceConnection usbDeviceConnection = usbManager.openDevice(device);

        try {
            serialPort = result.get(0);
            serialPort.open(usbDeviceConnection);
            // 第一个参数为波特率 第二个为停止位 第三个为奇偶校验,具体的应该根据自己的协议来配置
            serialPort.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
        } catch (IOException e) {
            e.printStackTrace();
        }

        UsbInterface anInterface = device.getInterface(0);

        if (anInterface == null) {
            Toast.makeText(this, "初始化失败", Toast.LENGTH_SHORT).show();
            return;
        }

        // 判断端口号
        for (int i = 0; i < anInterface.getEndpointCount(); i++) {
            UsbEndpoint endpoint = anInterface.getEndpoint(i);
            if (endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                if (endpoint.getDirection() == UsbConstants.USB_DIR_IN) {
                    // 输入端口
                    usbEndpointIn = endpoint;
                } else if (endpoint.getDirection() == UsbConstants.USB_DIR_OUT) {
                    // 输出端口
                    usbEndpointOut = endpoint;
                }
            }
        }
    }

当没有权限的使用,需要注册本地广播去申请权限

//  private static final String ACTION_USB_PERMISSION = "android.hardware.usb.action.USB_DEVICE_ATTACHED";
UsbPermissionActionReceiver mUsbPermissionActionReceiver = new UsbPermissionActionReceiver();
Intent intent = new Intent(ACTION_USB_PERMISSION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
IntentFilter intentFilter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbPermissionActionReceiver, intentFilter);
usbManager.requestPermission(device, pendingIntent);


private class UsbPermissionActionReceiver extends BroadcastReceiver {
        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)) {
                        // user choose YES for your previously popup window asking for grant perssion for this usb device
                        if (null != usbDevice) {
                            permissionAllow(usbDevice);
                        }
                    } else {
                        //user choose NO for your previously popup window asking for grant perssion for this usb device
                        Toast.makeText(context, String.valueOf("Permission denied for device" + usbDevice), Toast.LENGTH_LONG).show();
                    }
                }
            }
        }
    }

三、串口操作

通过以上我们已经对串口的获取以及配对都已经完成了,接下来只需要发送数据给串口就OK了。

private void sendToUsb(String[] hexString) throws Exception {
// 在这里需要转换byte数组,因为串口按位(bit)发送和接收字节
     byte[] bytes = new byte[hexString.length];
     for (int i = 0; i < hexString.length; i++) {
         bytes[i] = (byte) Integer.parseInt(hexString[i].substring(2), 16);
     }
     serialPort.write(bytes, bytes.length);
 }

已某一个指令为例

private void studyCode() {
     try {
      // 该数据为协议规定的十六进制的数据值
         String[] studyCodeStrArr = "0X55 0X4C 0X42 0X00 0X00 0X00 0X00 0X01 0X00 0X00 0X00 0X00 0X00 0X00 0X00 0X01 0X0A 0X00 0XEF".replace("X", "x").split(" ");
         sendToUsb(studyCodeStrArr);
     } catch (Exception e) {
         Toast.makeText(this, "学码失败", Toast.LENGTH_SHORT).show();
         e.printStackTrace();
     }
 }

四、关闭串口

当你完成数据的传输或者你的设备已拔出时,通过调用releaseInterface()和 close()来关闭接口和连接。

支持已完成了串口的开发,下面附上完整代码。

package com.huruwo.serialporthelper;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

/**
 * author: YJZ
 * date:  2018/6/15
 * des: USB串口开发
 */

public class MainActivity extends AppCompatActivity implements View.OnClickListener, IAudioListen, SeekBar.OnSeekBarChangeListener {

    private UsbEndpoint usbEndpointIn;
    private UsbEndpoint usbEndpointOut;

    private UsbManager usbManager;
    private UsbSerialPort serialPort;
    private TextView textView;
    private TextView seekBarValue;
    private List<UsbSerialDriver> drivers;

    public MainActivity() {
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_test);

        initView();

        initUsbSerial();
    }

    private void initUsbSerial() {

        // 1.查找设备
        usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);

        drivers = UsbSerialProber.getDefaultProber().findAllDrivers(usbManager);

        if (drivers.size() <= 0) {
            Toast.makeText(this, "无串口设备", Toast.LENGTH_SHORT).show();
            return;
        }

        UsbDevice device = drivers.get(0).getDevice();

        if (usbManager.hasPermission(device)) {
            permissionAllow(device);
        } else {
            Log.e("TAG", "没有权限");
            UsbPermissionActionReceiver mUsbPermissionActionReceiver = new UsbPermissionActionReceiver();
            Intent intent = new Intent(ACTION_USB_PERMISSION);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
            IntentFilter intentFilter = new IntentFilter(ACTION_USB_PERMISSION);
            registerReceiver(mUsbPermissionActionReceiver, intentFilter);
            usbManager.requestPermission(device, pendingIntent);
        }

    }

    private void permissionAllow(UsbDevice device) {

        List<UsbSerialPort> result = new ArrayList<>();

        for (final UsbSerialDriver driver : drivers) {
            final List<UsbSerialPort> ports = driver.getPorts();
            result.addAll(ports);
        }

        UsbDeviceConnection usbDeviceConnection = usbManager.openDevice(device);

        try {
            serialPort = result.get(0);
            serialPort.open(usbDeviceConnection);
            serialPort.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
        } catch (IOException e) {
            e.printStackTrace();
        }

        UsbInterface anInterface = device.getInterface(0);

        if (anInterface == null) {
            Toast.makeText(this, "初始化失败", Toast.LENGTH_SHORT).show();
            return;
        }

        // 判断端口号
        for (int i = 0; i < anInterface.getEndpointCount(); i++) {
            UsbEndpoint endpoint = anInterface.getEndpoint(i);
            if (endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                if (endpoint.getDirection() == UsbConstants.USB_DIR_IN) {
                    // 输入端口
                    usbEndpointIn = endpoint;
                } else if (endpoint.getDirection() == UsbConstants.USB_DIR_OUT) {
                    // 输出端口
                    usbEndpointOut = endpoint;
                }
            }
        }
    }

    private static final String ACTION_USB_PERMISSION = "android.hardware.usb.action.USB_DEVICE_ATTACHED";

    @Override
    public void top() {
        topTurn();
    }

    @Override
    public void pause() {
        pauseTurn();
    }

    @Override
    public void update(final double volume) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                textView.setText("分贝:" + String.valueOf(volume));
            }
        });

        Log.e("TAG", "volume = " + volume);
    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        AudioRecordDemo.MAX_VOLUME = progress;
        seekBarValue.setText(String.format(Locale.CHINA, "阀值:%s", progress));
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {

    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {

    }

    private class UsbPermissionActionReceiver extends BroadcastReceiver {
        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)) {
                        // user choose YES for your previously popup window asking for grant perssion for this usb device
                        if (null != usbDevice) {
                            permissionAllow(usbDevice);
                        }
                    } else {
                        //user choose NO for your previously popup window asking for grant perssion for this usb device
                        Toast.makeText(context, String.valueOf("Permission denied for device" + usbDevice), Toast.LENGTH_LONG).show();
                    }
                }
            }
        }
    }

    private void initView() {
        findViewById(R.id.study_code).setOnClickListener(this);
        findViewById(R.id.top).setOnClickListener(this);
        findViewById(R.id.pause).setOnClickListener(this);
        findViewById(R.id.bottom).setOnClickListener(this);
        findViewById(R.id.start_audio).setOnClickListener(this);
        findViewById(R.id.stop_audio).setOnClickListener(this);
        SeekBar seekBar = findViewById(R.id.seek_bar);
        seekBarValue = findViewById(R.id.seek_bar_value);
        seekBar.setOnSeekBarChangeListener(this);
        textView = findViewById(R.id.value);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.study_code:
                studyCode();
                break;

            case R.id.top:
                topTurn();
                break;

            case R.id.pause:
                pauseTurn();
                break;

            case R.id.bottom:
                bottomTurn();
                break;

            case R.id.start_audio:
                AudioRecordDemo demo = new AudioRecordDemo();
                demo.setAudioRecordListener(this);
                demo.getNoiseLevel();
                break;

            case R.id.stop_audio:
                AudioRecordDemo.isGetVoiceRun = false;
                break;
        }
    }


    private void bottomTurn() {
        try {
            String[] bottomStrArr = "0X55 0X4C 0X42 0X00 0X00 0X00 0X00 0X01 0X00 0X00 0X00 0X00 0X00 0X00 0X00 0X01 0X0C 0X00 0XF1".replace("X", "x").split(" ");
            sendToUsb(bottomStrArr);
        } catch (Exception e) {
            Toast.makeText(this, "失败", Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }
    }

    private void pauseTurn() {
        try {
            String[] pauseStrArr = "0X55 0X4C 0X42 0X00 0X00 0X00 0X00 0X01 0X00 0X00 0X00 0X00 0X00 0X00 0X00 0X01 0X0D 0X00 0XF2".replace("X", "x").split(" ");
            sendToUsb(pauseStrArr);
        } catch (Exception e) {
            Toast.makeText(this, "失败", Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }
    }

    private void topTurn() {
        try {
            String[] topStrArr = "0X55 0X4C 0X42 0X00 0X00 0X00 0X00 0X01 0X00 0X00 0X00 0X00 0X00 0X00 0X00 0X01 0X0E 0X00 0XF3".replace("X", "x").split(" ");
            sendToUsb(topStrArr);
        } catch (Exception e) {
            Toast.makeText(this, "失败", Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }
    }

    private void studyCode() {
        try {
            String[] studyCodeStrArr = "0X55 0X4C 0X42 0X00 0X00 0X00 0X00 0X01 0X00 0X00 0X00 0X00 0X00 0X00 0X00 0X01 0X0A 0X00 0XEF".replace("X", "x").split(" ");
            sendToUsb(studyCodeStrArr);
        } catch (Exception e) {
            Toast.makeText(this, "学码失败", Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }
    }

    private void sendToUsb(String[] hexString) throws Exception {
        byte[] bytes = new byte[hexString.length];
        for (int i = 0; i < hexString.length; i++) {
            bytes[i] = (byte) Integer.parseInt(hexString[i].substring(2), 16);
        }
        serialPort.write(bytes, bytes.length);
    }

    @Override
    protected void onPause() {
        super.onPause();
        AudioRecordDemo.isGetVoiceRun = false;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        AudioRecordDemo.isGetVoiceRun = false;
    }
}
相关标签: USB串口