Android USB轉(zhuǎn)串口通信開發(fā)實(shí)例詳解
Android USB轉(zhuǎn)串口通信開發(fā)實(shí)例詳解
好久沒有寫文章了,年前公司新開了一個(gè)項(xiàng)目,是和usb轉(zhuǎn)串口通信相關(guān)的,需求是用安卓平板通過usb轉(zhuǎn)接后與好幾個(gè)外設(shè)進(jìn)行通信,一直忙到最近,才慢慢閑下來,趁著這個(gè)周末不忙,記錄下usb轉(zhuǎn)串口通信開發(fā)的基本流程。
我們開發(fā)使用的是usb主機(jī)模式,即:安卓平板作為主機(jī),usb外設(shè)作為從機(jī)進(jìn)行數(shù)據(jù)通信。整個(gè)開發(fā)流程可以總結(jié)為以下幾點(diǎn):
1.發(fā)現(xiàn)設(shè)備
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); Map<String, UsbDevice> usbList = usbManager.getDeviceList();
通過UsbManager這個(gè)系統(tǒng)提供的類,我們可以枚舉出當(dāng)前連接的所有usb設(shè)備,我們主要需要的是UsbDevice對象,關(guān)于UsbDevice這個(gè)類,官方是這樣注釋的:
This class represents a USB device attached to the android device with the android device acting as the USB host.
是的,這個(gè)類就代表了Android所連接的usb設(shè)備。
2.打開設(shè)備
接下來,我們需要打開剛剛搜索到的usb設(shè)備,我們可以將平板與usb外設(shè)之間的連接想象成一個(gè)通道,只有把通道的門打開后,兩邊才能進(jìn)行通信。
一般來說,在沒有定制的android設(shè)備上首次訪問usb設(shè)備的時(shí)候,默認(rèn)我們是沒有訪問權(quán)限的,因此我們首先要判斷對當(dāng)前要打開的usbDevice是否有訪問權(quán)限:
if (!usbManager.hasPermission(usbDevice)) {
usbPermissionReceiver = new UsbPermissionReceiver();
//申請權(quán)限
Intent intent = new Intent(ACTION_DEVICE_PERMISSION);
PendingIntent mPermissionIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
IntentFilter permissionFilter = new IntentFilter(ACTION_DEVICE_PERMISSION);
context.registerReceiver(usbPermissionReceiver, permissionFilter);
usbManager.requestPermission(usbDevice, mPermissionIntent);
}
這里我們聲明一個(gè)廣播UsbPermissionReceiver,當(dāng)接受到授權(quán)成功的廣播后做一些其他處理:
private class UsbPermissionReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_DEVICE_PERMISSION.equals(action)) {
synchronized (this) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device.getDeviceName().equals(usbDevice.getDeviceName()) {
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
//授權(quán)成功,在這里進(jìn)行打開設(shè)備操作
} else {
//授權(quán)失敗
}
}
}
}
}
}
接下來,我們要找到具有數(shù)據(jù)傳輸功能的接口UsbInterface,從它里邊兒找到數(shù)據(jù)輸入和輸出端口UsbEndpoint,一般情況下,一個(gè)usbDevice有多個(gè)UsbInterface,我們需要的一般是第一個(gè),所以:
usbInterface=usbDevice.getInterface(0);
同樣的,一個(gè)usbInterface有多個(gè)UsbEndpoint,有控制端口和數(shù)據(jù)端口等,因此我們需要根據(jù)類型和數(shù)據(jù)流向來找到我們需要的數(shù)據(jù)輸入和輸出兩個(gè)端口:
for (int index = 0; index < usbInterface.getEndpointCount(); index++) {
UsbEndpoint point = usbInterface.getEndpoint(index);
if (point.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
if (point.getDirection() == UsbConstants.USB_DIR_IN) {
usbEndpointIn = point;
} else if (point.getDirection() == UsbConstants.USB_DIR_OUT) {
usbEndpointOut = point;
}
}
}
最后,才是真正的打開usb設(shè)備,我們需要和usb外設(shè)建立一個(gè)UsbDeviceConnection,它的注釋很簡介的說明了它的用途:
This class is used for sending and receiving data and control messages to a USB device.
它的獲取也很簡單,就一句代碼:
usbDeviceConnection = usbManager.openDevice(usbDevice);
到這里,理論上平板和usb外設(shè)之間的連接已經(jīng)建立了,也可以首發(fā)數(shù)據(jù)了,但是,我們大部分情況下還需要對usb串口進(jìn)行一些配置,比如波特率,停止位,數(shù)據(jù)控制等,不然兩邊配置不同,收到的數(shù)據(jù)會(huì)亂碼。具體怎么配置,就看你使用的串口芯片是什么了,目前流行的有pl2303,ch340等,由于篇幅問題,需要具體配置串口代碼的朋友私信我我發(fā)給你。
3.數(shù)據(jù)傳輸
到這里,我們已經(jīng)可以與usb外設(shè)進(jìn)行數(shù)據(jù)傳輸了,首先來看怎么向usb設(shè)備發(fā)送數(shù)據(jù)。
1.向usb外設(shè)發(fā)送數(shù)據(jù)
在第二步中,我們已經(jīng)獲取了數(shù)據(jù)的輸出端口usbEndpointIn,我們向外設(shè)發(fā)送數(shù)據(jù)就是通過這個(gè)端口來實(shí)現(xiàn)的。來看怎么用:
int ret = usbDeviceConnection.bulkTransfer(usbEndpointOut, data, data.length, DEFAULT_TIMEOUT);
bulkTransfer這個(gè)函數(shù)用于在給定的端口進(jìn)行數(shù)據(jù)傳輸,第一個(gè)參數(shù)就是此次傳輸?shù)亩丝冢@里我們用的輸出端口,第二個(gè)參數(shù)是要發(fā)送的數(shù)據(jù),類型為字節(jié)數(shù)組,第三個(gè)參數(shù)代表要發(fā)送的數(shù)據(jù)長度,最后一個(gè)參數(shù)是超時(shí),返回值代表發(fā)送成功的字節(jié)數(shù),如果返回-1,那就是發(fā)送失敗了。
2.接受usb外設(shè)發(fā)送來的數(shù)據(jù)
同理,我們已經(jīng)找到了數(shù)據(jù)輸入端口usbEndpointIn,因?yàn)閿?shù)據(jù)的輸入是不定時(shí)的,因此我們可以另開一個(gè)線程,來專門接受數(shù)據(jù),接受數(shù)據(jù)的代碼如下:
int inMax = inEndpoint.getMaxPacketSize();
ByteBuffer byteBuffer = ByteBuffer.allocate(inMax);
UsbRequest usbRequest = new UsbRequest();
usbRequest.initialize(connection, inEndpoint);
usbRequest.queue(byteBuffer, inMax);
if(connection.requestWait() == usbRequest){
byte[] retData = byteBuffer.array();
for(Byte byte1 : retData){
System.err.println(byte1);
}
}
以上,就是usb轉(zhuǎn)串口通信的基本流程,有些地方寫的不是很全面,比如接收usb外設(shè)數(shù)據(jù)的方法應(yīng)該還有別的,不足之處歡迎指正。
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關(guān)文章
Android AndBase框架使用封裝好的函數(shù)完成Http請求(三)
這篇文章主要介紹了Android AndBase框架使用封裝好的函數(shù)完成Http請求的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-03-03
Android開發(fā)之BottomSheetDialog組件的使用
BottomSheetDialog是底部操作控件,可在屏幕底部創(chuàng)建一個(gè)支持滑動(dòng)關(guān)閉視圖。本文將通過示例詳細(xì)講解它的使用,感興趣的小伙伴可以了解一下2023-01-01
Android彈出dialog后無法捕捉back鍵的解決方法
這篇文章主要為大家詳細(xì)介紹了Android彈出dialog后無法捕捉back鍵的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09
Android微信自動(dòng)搶紅包插件優(yōu)化和實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了Android微信自動(dòng)搶紅包插件優(yōu)化和實(shí)現(xiàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12
Android開發(fā)基礎(chǔ)簡化Toast調(diào)用方法詳解
這篇文章主要為大家介紹了Android開發(fā)基礎(chǔ)簡化Toast調(diào)用方法的相關(guān)資料,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
Android Studio中使用jni進(jìn)行opencv開發(fā)的環(huán)境配置方法
今天小編就為大家分享一篇Android Studio中使用jni進(jìn)行opencv開發(fā)的環(huán)境配置方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08
AndroidStudio接入U(xiǎn)nity工程并實(shí)現(xiàn)相互跳轉(zhuǎn)的示例代碼
這篇文章主要介紹了AndroidStudio接入U(xiǎn)nity工程并實(shí)現(xiàn)相互跳轉(zhuǎn),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
詳解Android如何實(shí)現(xiàn)好的彈層體驗(yàn)效果
當(dāng)前?App?的設(shè)計(jì)趨勢越來越希望給用戶沉浸式體驗(yàn),這種設(shè)計(jì)會(huì)讓用戶盡量停留在當(dāng)前的界面,而不需要太多的跳轉(zhuǎn),這就需要引入彈層。本篇我們就來講講彈層這塊需要注意哪些用戶體驗(yàn)2022-11-11

