Android USB转串口通信开发实例详解
好久沒(méi)有寫(xiě)文章了,年前公司新開(kāi)了一個(gè)項(xiàng)目,是和usb轉(zhuǎn)串口通信相關(guān)的,需求是用安卓平板通過(guò)usb轉(zhuǎn)接后與好幾個(gè)外設(shè)進(jìn)行通信,一直忙到最近,才慢慢閑下來(lái),趁著這個(gè)周末不忙,記錄下usb轉(zhuǎn)串口通信開(kāi)發(fā)的基本流程。
我們開(kāi)發(fā)使用的是usb主機(jī)模式,即:安卓平板作為主機(jī),usb外設(shè)作為從機(jī)進(jìn)行數(shù)據(jù)通信。整個(gè)開(kāi)發(fā)流程可以總結(jié)為以下幾點(diǎn):
1.發(fā)現(xiàn)設(shè)備
| 1 2 | UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); Map<String, UsbDevice> usbList = usbManager.getDeviceList(); |
通過(guò)UsbManager這個(gè)系統(tǒng)提供的類(lèi),我們可以枚舉出當(dāng)前連接的所有usb設(shè)備,我們主要需要的是UsbDevice對(duì)象,關(guān)于UsbDevice這個(gè)類(lèi),官方是這樣注釋的:
| 1 2 | This class?represents a USB device attached to the android device with the android device ?acting as the USB host. |
是的,這個(gè)類(lèi)就代表了Android所連接的usb設(shè)備。
2.打開(kāi)設(shè)備
接下來(lái),我們需要打開(kāi)剛剛搜索到的usb設(shè)備,我們可以將平板與usb外設(shè)之間的連接想象成一個(gè)通道,只有把通道的門(mén)打開(kāi)后,兩邊才能進(jìn)行通信。
一般來(lái)說(shuō),在沒(méi)有定制的android設(shè)備上首次訪問(wèn)usb設(shè)備的時(shí)候,默認(rèn)我們是沒(méi)有訪問(wèn)權(quán)限的,因此我們首先要判斷對(duì)當(dāng)前要打開(kāi)的usbDevice是否有訪問(wèn)權(quán)限:
| 1 2 3 4 5 6 7 8 9 | if?(!usbManager.hasPermission(usbDevice)) { ????usbPermissionReceiver = new?UsbPermissionReceiver(); ????//申請(qǐng)權(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)成功的廣播后做一些其他處理:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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)行打開(kāi)設(shè)備操作 ???????????} else?{ ????????????//授權(quán)失敗 ???????????} ?????????} ???????} ?????} ???} ?} |
接下來(lái),我們要找到具有數(shù)據(jù)傳輸功能的接口UsbInterface,從它里邊兒找到數(shù)據(jù)輸入和輸出端口UsbEndpoint,一般情況下,一個(gè)usbDevice有多個(gè)UsbInterface,我們需要的一般是第一個(gè),所以:
| 1 | usbInterface=usbDevice.getInterface(0); |
同樣的,一個(gè)usbInterface有多個(gè)UsbEndpoint,有控制端口和數(shù)據(jù)端口等,因此我們需要根據(jù)類(lèi)型和數(shù)據(jù)流向來(lái)找到我們需要的數(shù)據(jù)輸入和輸出兩個(gè)端口:
| 1 2 3 4 5 6 7 8 9 10 | 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; ??????????} ????????} ??????} |
最后,才是真正的打開(kāi)usb設(shè)備,我們需要和usb外設(shè)建立一個(gè)UsbDeviceConnection,它的注釋很簡(jiǎn)介的說(shuō)明了它的用途:
| 1 | This class?is used for?sending and receiving data and control messages to a USB device. |
它的獲取也很簡(jiǎn)單,就一句代碼:
| 1 | usbDeviceConnection = usbManager.openDevice(usbDevice); |
到這里,理論上平板和usb外設(shè)之間的連接已經(jīng)建立了,也可以首發(fā)數(shù)據(jù)了,但是,我們大部分情況下還需要對(duì)usb串口進(jìn)行一些配置,比如波特率,停止位,數(shù)據(jù)控制等,不然兩邊配置不同,收到的數(shù)據(jù)會(huì)亂碼。具體怎么配置,就看你使用的串口芯片是什么了,目前流行的有pl2303,ch340等,由于篇幅問(wèn)題,需要具體配置串口代碼的朋友私信我我發(fā)給你。
3.數(shù)據(jù)傳輸
到這里,我們已經(jīng)可以與usb外設(shè)進(jìn)行數(shù)據(jù)傳輸了,首先來(lái)看怎么向usb設(shè)備發(fā)送數(shù)據(jù)。
?1.向usb外設(shè)發(fā)送數(shù)據(jù)
在第二步中,我們已經(jīng)獲取了數(shù)據(jù)的輸出端口usbEndpointIn,我們向外設(shè)發(fā)送數(shù)據(jù)就是通過(guò)這個(gè)端口來(lái)實(shí)現(xiàn)的。來(lái)看怎么用:
| 1 | int?ret = usbDeviceConnection.bulkTransfer(usbEndpointOut, data, data.length, DEFAULT_TIMEOUT); |
bulkTransfer這個(gè)函數(shù)用于在給定的端口進(jìn)行數(shù)據(jù)傳輸,第一個(gè)參數(shù)就是此次傳輸?shù)亩丝?#xff0c;這里我們用的輸出端口,第二個(gè)參數(shù)是要發(fā)送的數(shù)據(jù),類(lèi)型為字節(jié)數(shù)組,第三個(gè)參數(shù)代表要發(fā)送的數(shù)據(jù)長(zhǎng)度,最后一個(gè)參數(shù)是超時(shí),返回值代表發(fā)送成功的字節(jié)數(shù),如果返回-1,那就是發(fā)送失敗了。
2.接受usb外設(shè)發(fā)送來(lái)的數(shù)據(jù)
同理,我們已經(jīng)找到了數(shù)據(jù)輸入端口usbEndpointIn,因?yàn)閿?shù)據(jù)的輸入是不定時(shí)的,因此我們可以另開(kāi)一個(gè)線程,來(lái)專(zhuān)門(mén)接受數(shù)據(jù),接受數(shù)據(jù)的代碼如下:
| 1 2 3 4 5 6 7 8 9 10 11 | 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)串口通信的基本流程,有些地方寫(xiě)的不是很全面,比如接收usb外設(shè)數(shù)據(jù)的方法應(yīng)該還有別的,不足之處歡迎指正。
?
原文鏈接:http://blog.csdn.net/weixin_38251977/article/details/69944095
總結(jié)
以上是生活随笔為你收集整理的Android USB转串口通信开发实例详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: gcc编译流程及中间表示层RTL的探索
- 下一篇: 我的职场战争--一年来的开发组内战实录