最近涉及到android串口和usb的開發(fā)商虐,花費不少時間找文章參考。主要時間花費在串口連接上,由于計算機實際中沒有串口的設備接口缀壤,只能用 虛擬串口 進行通信;且 USB 連接模擬器又是一番費神操作纠亚。
用到的工具 提取碼: djss
搭建虛擬環(huán)境(有實際串口接口可忽略)
-
打開 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串口
成功回顯
此處添加的虛擬串口是成對出現(xiàn)蒂胞。 -
Oracle VM VirtualBox 開啟使用虛擬串口
android模擬設備開啟串口
由于 成功回顯圖 模擬的串口名為COM2和COM3图呢,此處僅開啟COM2的映射即可。
-
Oracle VM VirtualBox 開啟使用USB設備
usb設備映射
此處選擇自己開發(fā)的相應設備即可骗随。 -
使用 串口調(diào)試精靈 模擬數(shù)據(jù)的發(fā)送與接收
開啟COM3
上圖為 開啟狀態(tài) 蛤织,默認是關閉的 最后就是接下來要說的開啟 android模擬器 并編寫的程序進行通信
一、串口通信
參考鏈接 主要參考其使用谷歌的串口so庫加載打開串口類
搭建項目
- 復制so庫至android項目中
復制so庫
這里有個7.0系統(tǒng)會報錯鸿染,so庫版本問題指蚜,直接去谷歌開源拿比較穩(wěn)
- 設置so庫目錄
android {
...
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
...
}
- 復制包及SerialPort類
串口打開工具類
注:android_serialport_api 包名不可更改
- 串口基本操作(打開,關閉牡昆,發(fā)送姚炕,接收)
//isConConnectionStatus 串口的連接狀態(tài)
/**
* 打開串口
* @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();//接收函數(shù)摊欠,主要實現(xiàn)開啟子線程并讀取數(shù)據(jù)
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;
}
/**
* 接收串口數(shù)據(jù)
*/
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) {
//回調(diào)數(shù)據(jù)
Log.i(TAG, "readData:" + Arrays.toString(readData));
}
} catch (IOException e) {
Log.e(TAG, "讀取數(shù)據(jù)失敗..." + e);
}
}
}
};
receiveThread.start();
}
/**
* 發(fā)送串口指令
*/
public boolean sendData(byte[] data) {
boolean result = false;
if (isConConnectionStatus) {
try {
outputStream.write(data);
outputStream.flush();
result = true;
} catch (IOException e) {
Log.e(TAG, "串口數(shù)據(jù)發(fā)送失敗:" + 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通信
- 設置靜態(tài)權限
<uses-feature android:name="android.hardware.usb.host" />
- USB基本操作(打開、關閉掸刊、接收免糕、發(fā)送)
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, "讀取數(shù)據(jù)失敗忧侧!\n" + e);
}
} catch (InterruptedException e) {
Log.e(TAG, "數(shù)據(jù)讀取異常:" + e);
}
}
}
}
/**
* 發(fā)送串口指令(字符串)
*
* @param sendBytes 需要發(fā)送的字節(jié)數(shù)據(jù)
*/
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權限獲取失敗回調(diào) */
void onUsbPermissionFail();
/** 當權限通過回調(diào) */
void onUsbPermissionAllow(UsbDevice usbDevice);
}
}
到此Android 串口和USB的通信開發(fā)完結石窑。