Android实现读写USB串口数据
作者:zhoupuxian 时间:2023-10-21 19:12:56
本文实例为大家分享了Android实现读写USB串口数据的具体代码,供大家参考,具体内容如下
最近在研究USB方面的内容;先后做了关于Android读写HID、串口设备的DEMO。本文比较简单,主要介绍的是Android实现读取串口数据的功能
废话不多说,先看一下业务层是如何调用的;如图:
首先,监听USB连接状况,当USB 进行请求USB权限,当USB权限申请成功,进行调用打开Usb设备的方法;当监听到USB断开,进行关闭连接;
这是向串口写入数据的方法;
本DEMO主要使用Handle进行数据各个线程之间的数据传到,以及USB连接读写情况的反馈;
下面直接上代码:
连接USB设备的代码
public void openCDC(UsbDevice usbDevice, UsbDeviceConnection usbDeviceConnection)
{
this.usbDeviceConnection = usbDeviceConnection;
usbInterface = usbDevice.getInterface(findCDC(usbDevice)); //获取USB设备接口
if (usbDeviceConnection == null) //判断USB设备链路是否为空
{
myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED);
return;
}
if (!usbDeviceConnection.claimInterface(usbInterface,true)) //USB设备链路绑定获取到的接口
{
myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED);
return;
}
int numberEndpoints = usbInterface.getEndpointCount(); //获取USB设备接口的数据传输通道数量
for (int num = 0; num <= numberEndpoints-1; num++)
{
UsbEndpoint usbEndpoint = usbInterface.getEndpoint(num);
switch (usbEndpoint.getType())
{
//USB控制传输模式通道
case UsbConstants.USB_ENDPOINT_XFER_CONTROL:
controlUsbEndpoint = usbEndpoint;
break;
//USB块传输模式通道
case UsbConstants.USB_ENDPOINT_XFER_BULK:
switch (usbEndpoint.getDirection())
{
case UsbConstants.USB_DIR_OUT:
bulkOutUsbEndpoint = usbEndpoint; //USB块传输模式输出通道
break;
case UsbConstants.USB_DIR_IN:
bulkInUsbEndpoint = usbEndpoint; //USB块传输模式输入通道
break;
}
break;
//USB中断传输模式通道
case UsbConstants.USB_ENDPOINT_XFER_INT:
switch (usbEndpoint.getDirection())
{
case UsbConstants.USB_DIR_OUT:
intOutUsbEndpoint = usbEndpoint;
break;
case UsbConstants.USB_DIR_IN:
intInUsbEndpoint = usbEndpoint;
break;
}
break;
}
}
if (bulkOutUsbEndpoint != null && bulkInUsbEndpoint != null) //如果USB块传输模式输入输通道都不为空出
{
//USB连接成功
connect = true;
//获取到USB设备的ID、VID、PID
String usbData = "Name:"+usbDevice.getDeviceName()+"\nID:"+usbDevice.getDeviceId()+" VID:"+usbDevice.getVendorId()+" PID:"+usbDevice.getProductId();
mes = new Message();
mes.obj = usbData;
mes.what = MyHandler.USB_CONNECT_SUCCESS;
myHandler.sendMessage(mes);
threadReadData.start(); //开启接收数据线程
}
else
{
//USB连接失败
connect = false;
myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED);
}
}
这个代码有点多,可能看的不太清楚,我删减一下,是这样的
public void openCDC(UsbDevice usbDevice, UsbDeviceConnection usbDeviceConnection)
{
this.usbDeviceConnection = usbDeviceConnection;
usbInterface = usbDevice.getInterface(findCDC(usbDevice)); //获取USB设备接口
int numberEndpoints = usbInterface.getEndpointCount(); //获取USB设备接口的数据传输通道数量
for (int num = 0; num <= numberEndpoints-1; num++)
{
UsbEndpoint usbEndpoint = usbInterface.getEndpoint(num);
switch (usbEndpoint.getType())
{
//USB控制传输模式通道
case UsbConstants.USB_ENDPOINT_XFER_CONTROL:
controlUsbEndpoint = usbEndpoint;
break;
//USB块传输模式通道
case UsbConstants.USB_ENDPOINT_XFER_BULK:
switch (usbEndpoint.getDirection())
{
case UsbConstants.USB_DIR_OUT:
bulkOutUsbEndpoint = usbEndpoint; //USB块传输模式输出通道
break;
case UsbConstants.USB_DIR_IN:
bulkInUsbEndpoint = usbEndpoint; //USB块传输模式输入通道
break;
}
break;
//USB中断传输模式通道
case UsbConstants.USB_ENDPOINT_XFER_INT:
switch (usbEndpoint.getDirection())
{
case UsbConstants.USB_DIR_OUT:
intOutUsbEndpoint = usbEndpoint;
break;
case UsbConstants.USB_DIR_IN:
intInUsbEndpoint = usbEndpoint;
break;
}
break;
}
}
}
设备打开之后,就可以进行读写了;
Android 读取串口数据
public String readData()
{
byte[] tempByte = new byte[4096];
int i = usbDeviceConnection.bulkTransfer(bulkInUsbEndpoint,tempByte,tempByte.length,100);//读取数据,100为超时时间,接收的数据为数组类型
//将接收的数组转为字符串并返回
byte[] messageByte = new byte[i];
System.arraycopy(tempByte,0, messageByte,0, i);
return new String(messageByte);
}
这里主要通过调用谷歌提供的bulkTransfer方法进行的,传递的参数分别有endpoint,要读取的数据长度,和放要读取的数据的数组,超时时间
有了读,当然也需要写,向串口写入数据;代码如下:
public boolean send(String message)
{
byte[] messageBytes = message.getBytes(); //字符串转为数组
int result = usbDeviceConnection.bulkTransfer(bulkOutUsbEndpoint,messageBytes,messageBytes.length,100);//发送数据,发送转换为数组后的数据,超时时间为100毫秒
if ((result >= 0)) //发送数据返回值大于等于0代表发送成功
{
//向信息处理中心发送“发送成功”的信息,并将信息内容传递过去
return true;
}
else
{
//发送失败
connect = false;
return false;
}
}
传输数据的方式是用Handler;以下是Handler类的写法
public void handleMessage(@NonNull Message msg)
{
switch (msg.what)
{
case USB_CONNECT_SUCCESS: //USB设备连接成功
MyHandler.USB_CONNECT_STATE = true; //连接状态改变为true
bt_send.setEnabled(true); //发送控件可以使用
bt_sendTiming.setEnabled(true);
bt_send.setTextColor(Color.BLACK); //定时发送控件可以使用
bt_sendTiming.setTextColor(Color.BLACK);
tv_usbDataShow.setText(msg.obj.toString()); //填充意图发送过来的信息
Toast.makeText(context,"连接成功",Toast.LENGTH_LONG).show();
break;
case USB_CONNECT_FAILED: //USB设备连接失败
MyHandler.USB_CONNECT_STATE = false;
bt_send.setEnabled(false);
bt_sendTiming.setEnabled(false);
bt_send.setTextColor(Color.GRAY);
bt_sendTiming.setTextColor(Color.GRAY);
bt_sendTiming.setText("定时发送");
tv_usbDataShow.setText("未连接设备");
mainActivity.closeAll(); //连接断开或连接失败,执行关闭所有连接和对象的方法
Toast.makeText(context,"断开连接",Toast.LENGTH_LONG).show();
break;
case OUTPUT: //发送消息
if (messageShowNeedRoll(tv_sendMessageShow) != 0) tv_sendMessageShow.scrollTo(0, messageShowNeedRoll(tv_sendMessageShow));//如果TextView填充满可使用高度就滚动到最新更新处
tv_sendMessageShow.append("[TX]"+gteNowDate()+": "+msg.obj.toString()+"\n"); //给控件填充意图发送来的信息
break;
case INPUT: //接收消息
if (messageShowNeedRoll(tv_receiveMessageShow) != 0) tv_receiveMessageShow.scrollTo(0, messageShowNeedRoll(tv_receiveMessageShow));
tv_receiveMessageShow.append("[RX]"+gteNowDate()+": "+msg.obj.toString()+"\n");
break;
}
}
主要代码已展示完毕,接下来展示具体代码
先看USB类,如下:
public class UsbCDC
{
private boolean connect; //USB连接状态
private UsbInterface usbInterface; //USB设备的物理接口
//控制传输模式通道
private UsbEndpoint controlUsbEndpoint;
//块传输模式通道
private UsbEndpoint bulkInUsbEndpoint;
private UsbEndpoint bulkOutUsbEndpoint;
//中断传输模式通道
private UsbEndpoint intInUsbEndpoint;
private UsbEndpoint intOutUsbEndpoint;
private UsbDeviceConnection usbDeviceConnection; //USB设备连接链路,用来进行设备通讯
private Message mes; //信息包
private MyHandler myHandler;//信息处理中心对象
UsbCDC(MyHandler myHandler)
{
this.myHandler = myHandler;
}
/**
* 向USB设备发送数据
* @param message 要发送的数据,字符串类型
* @return 数据发送结果,true代表发送成功
*/
public boolean send(String message)
{
if (this.usbDeviceConnection == null) //判断USB链路是否获取到,不为空才能进行数据发送
{
//如果USB链路为空,执行该作用域代码
connect = false;
myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED);
return false;
}
byte[] messageBytes = message.getBytes(); //字符串转为数组
int result = usbDeviceConnection.bulkTransfer(bulkOutUsbEndpoint,messageBytes,messageBytes.length,100);//发送数据,发送转换为数组后的数据,超时时间为100毫秒
if ((result >= 0)) //发送数据返回值大于等于0代表发送成功
{
//向信息处理中心发送“发送成功”的信息,并将信息内容传递过去
mes = new Message();
mes.obj = new String(messageBytes);
mes.what = MyHandler.OUTPUT;
myHandler.sendMessage(mes);
return true;
}
else
{
//发送失败
connect = false;
myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED);
return false;
}
}
/**
* 接收数据
* @return 接收的数据内容
*/
public String readData()
{
byte[] tempByte = new byte[4096];
if (usbDeviceConnection == null) //判断USB连接链路是否为空,不为空才能进行数据接收
{
connect = false;
myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED);
return null;
}
int i = usbDeviceConnection.bulkTransfer(bulkInUsbEndpoint,tempByte,tempByte.length,100);//读取数据,100为超时时间,接收的数据为数组类型
if (i < 0) //小于0代表接收失败或未接收到数据,接收结果也受USB设备的影响
{
return null;
}
//将接收的数组转为字符串并返回
byte[] messageByte = new byte[i];
System.arraycopy(tempByte,0, messageByte,0, i);
return new String(messageByte);
}
/**
* 设置USB设备的波特率,方法内涉及算法等;
* @param paramInt 要设置波特率的数值
* @return 设置结果,true代表设置成功
*/
public boolean configUsb(int paramInt)
{
if (usbDeviceConnection != null)
{
byte[] arrayOfByte = new byte[8];
usbDeviceConnection.controlTransfer(192, 95, 0, 0, arrayOfByte, 8, 1000);
usbDeviceConnection.controlTransfer(64, 161, 0, 0, null, 0, 1000);
long l1 = 1532620800 / paramInt;
for (int i = 3; ; i--)
{
if ((l1 <= 65520L) || (i <= 0))
{
long l2 = 65536L - l1;
int j = (short) (int) (0xFF00 & l2 | i);
int k = (short) (int) (0xFF & l2);
usbDeviceConnection.controlTransfer(64, 154, 4882, j, null, 0, 1000);
usbDeviceConnection.controlTransfer(64, 154, 3884, k, null, 0, 1000);
usbDeviceConnection.controlTransfer(192, 149, 9496, 0, arrayOfByte, 8, 1000);
usbDeviceConnection.controlTransfer(64, 154, 1304, 80, null, 0, 1000);
usbDeviceConnection.controlTransfer(64, 161, 20511, 55562, null, 0, 1000);
usbDeviceConnection.controlTransfer(64, 154, 4882, j, null, 0, 1000);
usbDeviceConnection.controlTransfer(64, 154, 3884, k, null, 0, 1000);
usbDeviceConnection.controlTransfer(64, 164, 0, 0, null, 0, 1000);
return true;
}
l1 >>= 3;
}
}
else return false;
}
/**
* 获取收发数据的通道
* @param usbDevice USB设备
* @param usbDeviceConnection USB连接链路
*/
public void openCDC(UsbDevice usbDevice, UsbDeviceConnection usbDeviceConnection)
{
this.usbDeviceConnection = usbDeviceConnection;
usbInterface = usbDevice.getInterface(findCDC(usbDevice)); //获取USB设备接口
if (usbDeviceConnection == null) //判断USB设备链路是否为空
{
myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED);
return;
}
if (!usbDeviceConnection.claimInterface(usbInterface,true)) //USB设备链路绑定获取到的接口
{
myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED);
return;
}
int numberEndpoints = usbInterface.getEndpointCount(); //获取USB设备接口的数据传输通道数量
for (int num = 0; num <= numberEndpoints-1; num++)
{
UsbEndpoint usbEndpoint = usbInterface.getEndpoint(num);
switch (usbEndpoint.getType())
{
//USB控制传输模式通道
case UsbConstants.USB_ENDPOINT_XFER_CONTROL:
controlUsbEndpoint = usbEndpoint;
break;
//USB块传输模式通道
case UsbConstants.USB_ENDPOINT_XFER_BULK:
switch (usbEndpoint.getDirection())
{
case UsbConstants.USB_DIR_OUT:
bulkOutUsbEndpoint = usbEndpoint; //USB块传输模式输出通道
break;
case UsbConstants.USB_DIR_IN:
bulkInUsbEndpoint = usbEndpoint; //USB块传输模式输入通道
break;
}
break;
//USB中断传输模式通道
case UsbConstants.USB_ENDPOINT_XFER_INT:
switch (usbEndpoint.getDirection())
{
case UsbConstants.USB_DIR_OUT:
intOutUsbEndpoint = usbEndpoint;
break;
case UsbConstants.USB_DIR_IN:
intInUsbEndpoint = usbEndpoint;
break;
}
break;
}
}
if (bulkOutUsbEndpoint != null && bulkInUsbEndpoint != null) //如果USB块传输模式输入输通道都不为空出
{
//USB连接成功
connect = true;
//获取到USB设备的ID、VID、PID
String usbData = "Name:"+usbDevice.getDeviceName()+"\nID:"+usbDevice.getDeviceId()+" VID:"+usbDevice.getVendorId()+" PID:"+usbDevice.getProductId();
mes = new Message();
mes.obj = usbData;
mes.what = MyHandler.USB_CONNECT_SUCCESS;
myHandler.sendMessage(mes);
threadReadData.start(); //开启接收数据线程
}
else
{
//USB连接失败
connect = false;
myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED);
}
}
/**
* USB接收数据线程
*/
private Thread threadReadData = new Thread(new Runnable()
{
String message = "";
@Override
public void run()
{
while (connect) //USB处于连接状态就循环执行
{
String temMes = readData(); //获取到接收到的字符串
if (temMes != null)
{
//如果接收到的数据不为空,就一直拼接,因为这些可能属于同一组数据(除非USB设备发送频率小于我们设置的超时时间100毫秒)
message = message+temMes;
continue;
}
else
{
//接收到的数据为空了,表示该组数据接收完整了,就可以发送给消息处理中心进行处理了
if (!message.equals("")) //接收到的数据要不为空,不然没意义
{
mes = new Message();
mes.obj = message;
mes.what = MyHandler.INPUT;
myHandler.sendMessage(mes);
message = "";
}
}
}
}
});
/**
* 获取USB可以收发数据的接口号
* @param usbDevice USB设备
* @return USB可以收发数据的接口号
*/
private int findCDC(UsbDevice usbDevice)
{
int interfaceCount = usbDevice.getInterfaceCount(); //获取USB设备接口数量
for (int count = 0; count < interfaceCount; ++count)
{
//遍历获取到的接口进行判断是否为收发数据的接口,是就返回该接口号
if (usbDevice.getInterface(count).getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA)
{
return count;
}
}
// 如果获取到的所有接口没有我们需要的就返回-1
return -1;
}
/**
* 关闭USB连接、链路、数据通道等
*/
public void close()
{
connect = false; //连接状态为false
usbDeviceConnection.releaseInterface(usbInterface); //USB设备链路解绑接口
usbDeviceConnection.close(); //关闭USB设备链路
usbDeviceConnection = null; //USB设备链路赋值为空
bulkOutUsbEndpoint = null; //输出通道赋值为空
bulkInUsbEndpoint = null; //输入通道赋值为空
}
}
接下来是连接USB类与业务层的中枢,HANDLER类:
package com.jlkj.lsk.usb_host;
import android.content.Context;
import android.graphics.Color;
import android.os.Handler;
import android.os.Message;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyHandler extends Handler
{
public static final int OUTPUT = 0; //发送消息
public static final int INPUT = 1; //接收消息
public static final int USB_CONNECT_SUCCESS = 2; //USB设备连接成功
public static final int USB_CONNECT_FAILED = 3; //USB设备连接失败或断开连接
public static boolean USB_CONNECT_STATE = false; //当前USB设备连接状态
private Button bt_send,bt_sendTiming;
private TextView tv_sendMessageShow,tv_receiveMessageShow,tv_usbDataShow;
private Context context; //上下文
private MainActivity mainActivity;
MyHandler(TextView tv_sendMessageShow, TextView tv_receiveMessageShow, TextView tv_usbDataShow, Button bt_send, Button bt_sendTiming, Context context,MainActivity mainActivity)
{
this.bt_send = bt_send;
this.tv_sendMessageShow = tv_sendMessageShow;
this.tv_receiveMessageShow = tv_receiveMessageShow;
this.tv_usbDataShow = tv_usbDataShow;
this.bt_sendTiming = bt_sendTiming;
this.context = context;
this.mainActivity = mainActivity;
}
@Override
public void handleMessage(@NonNull Message msg)
{
switch (msg.what)
{
case USB_CONNECT_SUCCESS: //USB设备连接成功
MyHandler.USB_CONNECT_STATE = true; //连接状态改变为true
bt_send.setEnabled(true); //发送控件可以使用
bt_sendTiming.setEnabled(true);
bt_send.setTextColor(Color.BLACK); //定时发送控件可以使用
bt_sendTiming.setTextColor(Color.BLACK);
tv_usbDataShow.setText(msg.obj.toString()); //填充意图发送过来的信息
Toast.makeText(context,"连接成功",Toast.LENGTH_LONG).show();
break;
case USB_CONNECT_FAILED: //USB设备连接失败
MyHandler.USB_CONNECT_STATE = false;
bt_send.setEnabled(false);
bt_sendTiming.setEnabled(false);
bt_send.setTextColor(Color.GRAY);
bt_sendTiming.setTextColor(Color.GRAY);
bt_sendTiming.setText("定时发送");
tv_usbDataShow.setText("未连接设备");
mainActivity.closeAll(); //连接断开或连接失败,执行关闭所有连接和对象的方法
Toast.makeText(context,"断开连接",Toast.LENGTH_LONG).show();
break;
case OUTPUT: //发送消息
if (messageShowNeedRoll(tv_sendMessageShow) != 0) tv_sendMessageShow.scrollTo(0, messageShowNeedRoll(tv_sendMessageShow));//如果TextView填充满可使用高度就滚动到最新更新处
tv_sendMessageShow.append("[TX]"+gteNowDate()+": "+msg.obj.toString()+"\n"); //给控件填充意图发送来的信息
break;
case INPUT: //接收消息
if (messageShowNeedRoll(tv_receiveMessageShow) != 0) tv_receiveMessageShow.scrollTo(0, messageShowNeedRoll(tv_receiveMessageShow));
tv_receiveMessageShow.append("[RX]"+gteNowDate()+": "+msg.obj.toString()+"\n");
break;
}
}
/**
* 返回格式化后的当前时间
* @return 当前时间字符串形式
*/
private String gteNowDate()
{
SimpleDateFormat sdf = new SimpleDateFormat();// 格式化时间
sdf.applyPattern("HH:mm:ss");// 时:分:秒
Date date = new Date();// 获取当前时间戳
return sdf.format(date); //返回格式化后的时间戳
}
/**
* 判断当前TextView是否已经填充满控件可使用高度,如果高度已满就滚动需要的距离高度
* @param textView 需要判断的TextView控件
* @return 已满就返回对应高度,否则就返回0
*/
private int messageShowNeedRoll(TextView textView)
{
int offset = textView.getLineCount() * textView.getLineHeight(); //添加的textview数量 x 字体高度
if (offset > textView.getHeight()) return offset - tv_receiveMessageShow.getHeight(); //如果乘积大于控件高度就返回需要滚动的距离
else return 0; //小于就返回0
}
}
监听USB连接状况的广播类,如下:
package com.jlkj.lsk.usb_host;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.widget.TextView;
import android.widget.Toast;
import java.util.HashMap;
public class UsbMonitor extends BroadcastReceiver //继承USB广播对象
{
private static final String ACTION_USB_PERMISSION = "com.spark.teaching.answertool.USB_PERMISSION"; //USB设备的操作权限,可自定义
//private static final String ACTION_USB_PERMISSION = "android.USB"; //USB设备的操作权限,可自定义
private int VID = 1155; //USB设备生产厂商ID,用来区分选择目标USB设备,如果不是该ID的USB设备,不对其进行操作
private int PID = 1155; //USB设备生产厂商ID,用来区分选择目标USB设备,如果不是该ID的USB设备,不对其进行操作
private UsbController usbController; //USB动作管理接口
private UsbManager usbManager; //USB状态、管理对象
private UsbDevice usbDevice; //USB设备
private Context context; //上下文
private TextView tv_usbDeviceDataShow; //USB信息数据展示控件
/**
* 数据初始化
* @param usbController usb控制器接口
* @param context 上下文
* @param tv_usbDeviceDataShow USB信息数据展示控件
*/
UsbMonitor(UsbController usbController,Context context,TextView tv_usbDeviceDataShow)
{
this.usbController = usbController;
this.context = context;
this.tv_usbDeviceDataShow = tv_usbDeviceDataShow;
}
/**
* 注册USB广播监听、USB权限
*/
public void register()
{
if (this.context != null)
{
IntentFilter intentFilter = new IntentFilter(); //意图过滤器
intentFilter.addAction(ACTION_USB_PERMISSION); //添加USB设备的操作权限意图
intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); //添加设备接入意图
intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); //添加设备拔出意图
this.context.registerReceiver(this, intentFilter); //注册添加的意图
usbManager = (UsbManager)this.context.getSystemService(Context.USB_SERVICE); //获取USB设备管理
if (usbManager != null)
{
HashMap<String,UsbDevice> list = usbManager.getDeviceList(); //获取USB设备,返回的是 UsbDevice 的Hash列表,里面是所有当前连接主机的USB设备
for (UsbDevice usbDevice : list.values()) //遍历获取到的UsbDevice
{
if ((usbDevice.getVendorId() == VID)&&(usbDevice.getProductId() == PID)) //找到目标USB设备
{
this.usbDevice = usbDevice;
usbController.onDeviceInsert(this, usbManager,usbDevice); //执行USB接入时接口
break;
}
}
tv_usbDeviceDataShow.setText("不支持该设备"); //如果列表里面没有目标USB设备,执行该操作
}
tv_usbDeviceDataShow.setText("未连接设备"); //如果没有USB设备接入,执行该操作
}
}
/**
* 请求打开此USB设备的权限
* @param usbDevice usb设备
*/
public void requestOpenDevice(UsbDevice usbDevice)
{
if (usbManager != null)
{
if (usbManager.hasPermission(usbDevice))//如果有该USB设备的操作权限
{
usbController.onDeviceOpen(this,usbManager,usbDevice);//连接USB设备(打开USB设备)
}
else
{
usbManager.requestPermission(usbDevice,PendingIntent.getBroadcast(context, 666, new Intent(ACTION_USB_PERMISSION), 0));//如果没有USB操作权限则请求权限
}
}
}
/**
* 注销USB广播监听
*/
public void unregister()
{
if (context != null)
{
context.unregisterReceiver(this); //注销USB设备广播监听
context = null;
usbManager = null;
usbController = null;
}
}
/**
* 广播事务处理中心
* @param context 上下文
* @param intent 意图
*/
@Override
public void onReceive(Context context, Intent intent)
{
if (intent.getExtras() != null && !intent.getExtras().isEmpty())
{
usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); //获取意图中的USB设备
switch(intent.getAction())
{
case UsbManager.ACTION_USB_DEVICE_ATTACHED: //USB设备接入
Toast.makeText(context, "设备接入", Toast.LENGTH_LONG).show();
if ((usbDevice.getVendorId() == VID)&&(usbDevice.getProductId() == PID)) usbController.onDeviceInsert(this, usbManager,usbDevice); //找到目标USB设备,执行USB设备接入时接口
else tv_usbDeviceDataShow.setText("不支持该设备"); //未找到目标USB设备
break;
case UsbManager.ACTION_USB_DEVICE_DETACHED: //USB设备拔出
Toast.makeText(context, "设备断开", Toast.LENGTH_LONG).show();
usbController.onDevicePullOut(this,usbManager,usbDevice); //执行USB设备拔出时接口
break;
case UsbMonitor.ACTION_USB_PERMISSION: //请求USB设备操作权限
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false))
{
//同意USB权限
usbController.onDeviceOpen(this,usbManager,usbDevice); //执行连接USB设备接口
}
else
{
//拒绝USB权限
Toast.makeText(context, "拒绝USB权限!", Toast.LENGTH_LONG).show();
}
break;
}
}
else
{
Toast.makeText(this.context,"请检查USB设备!",Toast.LENGTH_LONG).show();
}
}
}
接口类 UsbController
public interface UsbController
{
/**
* USB设备接入时的接口
* @param usbMonitor USB监听广播对象
* @param usbManager USB状态、管理对象
* @param usbDevice USB设备对象
*/
void onDeviceInsert(UsbMonitor usbMonitor, UsbManager usbManager, UsbDevice usbDevice);
//USB设备拔出时的接口
void onDevicePullOut(UsbMonitor usbMonitor, UsbManager usbManager, UsbDevice usbDevice);
//连接USB设备(打开USB设备)的接口
void onDeviceOpen(UsbMonitor usbMonitor, UsbManager usbManager, UsbDevice usbDevice);
}
activity类
package com.jlkj.lsk.usb_host;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.graphics.Color;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends AppCompatActivity implements UsbController
{
private Timer timer; //计时器对象
private TimerTask timerTask; //计时器任务对象
private UsbCDC usbCDC; //当前连接的USB设备对象
private MyHandler myHandler; //消息处理中心对象
private UsbMonitor usbMonitor; //USB监听广播对象
private TextView m_tv_sendMessageShow,m_tv_receiveMessageShow,m_tv_usbDataShow,m_tv_porterShow;
private EditText m_et_messageText,m_et_time;
private Button m_bt_send,m_bt_sendTiming,m_bt_clean,m_tv_porterSet;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView(); //实例化当前页面控件
initData(); //加载初始数据
m_bt_send.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
//开启新线程进行数据发送
new Thread(new Runnable()
{
@Override
public void run()
{
usbCDC.send(m_et_messageText.getText().toString()); //向当前连接的USB设备发送消息
}
}).start();
}
});
m_bt_clean.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
m_tv_sendMessageShow.setText(""); //清除发送的消息文本
m_tv_receiveMessageShow.setText(""); //清除接收的消息文本
m_tv_sendMessageShow.scrollTo(0, 0); //发送的消息文本回滚到最顶部
m_tv_receiveMessageShow.scrollTo(0, 0); //接收的消息文本回滚到最顶部
}
});
m_bt_sendTiming.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
//判断计时器是否为空,不为就代表正在执行计时任务,就停止当前任务
if (timer != null)
{
timer.cancel(); //停止计时器
timer = null; //计时器设为空
m_bt_sendTiming.setTextColor(Color.BLACK); //改变定时发送控件的颜色
m_bt_sendTiming.setText("定时发送"); //控件 恢复为“定时发送”
}
else
{
//如果为空,就开始定时发送任务
if (!m_et_time.getText().toString().equals("")) //获取定时任务的时间间隔
{
timer = new Timer(); //创建定时器
timerTask = new TimerTask() //创建定时任务
{
@Override
public void run()
{
//定时任务要执行的内容
usbCDC.send(m_et_messageText.getText().toString());
}
};
new Thread(new Runnable() //开启新线程执行 开启计时器
{
@Override
public void run()
{
//开启计时器
timer.schedule(timerTask,0,Integer.parseInt(m_et_time.getText().toString()));
}
}).start();
m_bt_sendTiming.setTextColor(Color.RED);
m_bt_sendTiming.setText("停止"); //计时器开始后“定时发送”控件就改变颜色和字体
}
else
{
//判断计时器是否为空,如果为空,就执行该作用域内容
Toast.makeText(MainActivity.this,"定时不能为空",Toast.LENGTH_LONG).show();
}
}
}
});
m_tv_porterSet.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
//展示设置波特率的diaog对象
setPorter();
}
});
}
@Override
public void onDeviceInsert(UsbMonitor usbMonitor, UsbManager usbManager, UsbDevice usbDevice)
{
usbMonitor.requestOpenDevice(usbDevice); //请求USB连接权限
}
@Override
public void onDevicePullOut(UsbMonitor usbMonitor, UsbManager usbManager, UsbDevice usbDevice)
{
closeAll(); //执行关闭所有连接的方法
myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED); //向消息中心发送 断开连接 信息
}
@Override
public void onDeviceOpen(UsbMonitor usbMonitor, UsbManager usbManager, UsbDevice usbDevice)
{
usbCDC = new UsbCDC(myHandler); //创建USB连接的对象
UsbDeviceConnection connection = usbManager.openDevice(usbDevice); //获取此USB链路
usbCDC.openCDC(usbDevice, connection); //连接USB设备(打开USB设备)
}
@Override
protected void onDestroy()
{
super.onDestroy();
closeAll();//执行关闭所有连接的方法
myHandler.sendEmptyMessage(MyHandler.USB_CONNECT_FAILED);//向消息中心发送 断开连接 信息
}
//关闭所有连接
public void closeAll()
{
if (usbCDC != null)
{
usbCDC.close();
usbCDC = null;
}
if (timer != null)
{
timer.cancel();
timer = null;
}
}
//展示设置波特率dialog的对象,用一个AlertDialog让用户进行选择比特率
private void setPorter()
{
final String[] items = {"2400","4800","9600","19200","38400","57600","115200","230400","460800","1700000","2300000","3400000"};
AlertDialog.Builder listDialog = new AlertDialog.Builder(MainActivity.this);
listDialog.setTitle("设置波特率");
listDialog.setItems(items, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
//判断当前USB设备是否连接,连接之后才可以设置波特率
if (usbCDC != null)
{
boolean porter = usbCDC.configUsb(Integer.parseInt(items[which])); //执行设置波特率的对象,返回true代表设置成功
m_tv_porterShow.setText(porter ? "波特率:"+items[which]:"波特率:9600"); //设置波特率对象返回true才改变控件字体,否则设置失败,不改变控件字体
}
else
{
//判断当前USB设备是否连接,未连接则提示 设备未连接
Toast.makeText(MainActivity.this,"设备未连接",Toast.LENGTH_LONG).show();
}
}
});
listDialog.show(); //展示dialog
}
//加载数据
private void initData()
{
myHandler = new MyHandler(m_tv_sendMessageShow,m_tv_receiveMessageShow,m_tv_usbDataShow,m_bt_send,m_bt_sendTiming,this,MainActivity.this); //实例化消息处理中心
usbMonitor = new UsbMonitor(this,this,m_tv_usbDataShow); //实例化USB广播监听
usbMonitor.register(); //注册USB广播监听,注册之后,才可以正常监听USB设备
}
//实例化控件
private void initView()
{
m_tv_receiveMessageShow = (TextView)findViewById(R.id.m_tv_receiveMessageShow);
m_tv_receiveMessageShow.setMovementMethod(ScrollingMovementMethod.getInstance());
m_tv_sendMessageShow = (TextView)findViewById(R.id.m_tv_sendMessageShow);
m_tv_sendMessageShow.setMovementMethod(ScrollingMovementMethod.getInstance());
m_tv_usbDataShow = (TextView)findViewById(R.id.m_tv_usbDataShow);
m_et_messageText = (EditText)findViewById(R.id.m_et_messageText);
m_et_time = (EditText)findViewById(R.id.m_et_time);
m_bt_sendTiming = (Button)findViewById(R.id.m_bt_sendTiming);
m_bt_clean = (Button)findViewById(R.id.m_bt_clean);
m_bt_send = (Button)findViewById(R.id.m_bt_send);
m_tv_porterShow = (TextView)findViewById(R.id.m_tv_porterShow);
m_tv_porterSet = (Button)findViewById(R.id.m_bt_porterSet);
}
}
这个比较初级,接下来,我会再出一个精简版本;详细探讨Android读取USB串口、HID设备的实现;我把这两个集成在了一起,并打包成了arr文件,这个库可以自动识别USB 串口或USB hid ,当连接成功,就可以自动读写;代码比这个更为精简;接下来我会慢慢的记录下来。
来源:https://blog.csdn.net/zhoupuxian/article/details/124309055