Android USB转串口编程
安卓手機的對外通信接口就只有USB跟音頻口,我們可采用其進(jìn)行與外設(shè)進(jìn)行通信。今天,我們來講講安卓手機利用USB接口與外設(shè)進(jìn)行通信。此時,有兩種情況。
第一:USB(手機)<--->USB(外設(shè)),就是手機與外設(shè)直接通過USB線進(jìn)行通訊。
第二:USB(手機)<--->UART(外設(shè)),即手機與外設(shè)通過USB轉(zhuǎn)接成串口,再與外設(shè)通信。
外設(shè),說白了就是單片機,單片機端直接通過USB接口跟其他設(shè)備通訊,這種情況還是比較少見的。(另外,單片機是否具備驅(qū)動USB的能力,這個也值得質(zhì)疑。我不是做下位機的,這些問題不太了解,只是說理論上這種方式是可行的而已。)一般來說,我們的單片機是通過串口跟其他設(shè)備進(jìn)行通信的。所以,本文就自第二種情況進(jìn)行闡述。他們的關(guān)系如下圖所示。
在此,轉(zhuǎn)接芯片承擔(dān)著一個USB--UART轉(zhuǎn)接的作用,CH34X是指具體一系列型號的芯片,包括CH340和CH341,此次我選擇的是CH340,之前曾用過PL2303HA芯片作為轉(zhuǎn)接芯片,但是手機端并不能很好地識別到USB設(shè)備,所以后來選擇了CH340。MCU設(shè)備端的編程,是單片機工程師的串口編程,這個我們不太管,本文中我們更關(guān)注的是Android端的USB Host編程。
說到安卓USBHost編程,其實就是安卓的USB HOST編程。這部分網(wǎng)上資料很多,在此我大概用闡述一下。
Android下的USB Host介紹和開發(fā)
??????????一、USB Host介紹
USB Host,中文意思是USB主模式,是相對于USB Accessory(USB副模式)來說的。如果Android工作在USB Host模式下,則連接到Android上的USB設(shè)備把Android類似的看作是一臺PC機,PC機能干的事兒,Android也能干,例如將鼠標(biāo)、鍵盤插入則可以使用鍵盤、鼠標(biāo)來操作Android系統(tǒng),如果插入U盤則,通過Android可以讀寫U盤上的數(shù)據(jù)。而USB Accessory模式表示將Android設(shè)備類似當(dāng)作一個USB的鍵盤、鼠標(biāo)、U盤插入到電腦主機上一樣使用,這兩種模式在Android API level-12以上才支持,即Android3.1及更高的版本支持這兩種模式。
在我們這里,Android端當(dāng)然是主模式。?
要實現(xiàn)安卓USB HOST編程,系統(tǒng)版本只是他的軟件要求,除此之外,當(dāng)然還需要硬件要求。那就是手機必須支持OTG功能。不知道什么是OTG的朋友,請自行百度。
二、USB HOST開發(fā)
?關(guān)于Android USB HOST編程,網(wǎng)上這方面的例子也是不少的,大致可以實現(xiàn)從發(fā)現(xiàn)設(shè)備到打開連接設(shè)備并進(jìn)行數(shù)據(jù)雙向傳輸?shù)墓δ堋5@些例子只是單純的進(jìn)行USB通信,對于我們本文中的例子,是不夠的。我們這里,USB設(shè)備之外是一個UART串口設(shè)備。雖然所對于我們的安卓端來說,轉(zhuǎn)接芯片已經(jīng)幫我們屏蔽了串口,已轉(zhuǎn)接成USB,貌似已不用關(guān)心串口。但是,實際上,串口的 一些參數(shù)配置我們還是需要的。舉個例子:如果MCU端以9600bps的波特率發(fā)送數(shù)據(jù)過來,轉(zhuǎn)接芯片又如何知道應(yīng)該以怎樣的波特率進(jìn)行接收并轉(zhuǎn)換成USB數(shù)據(jù)呢?倘若轉(zhuǎn)接芯片不是以相應(yīng)的波特率接收數(shù)據(jù),手機端必定接收到的是錯誤的數(shù)據(jù)。即使轉(zhuǎn)接芯片默認(rèn)的波特率是9600,得到了正確的數(shù)據(jù),但假如MCU換了波特率,是以115200來發(fā)送呢?所以,我們原則上來說,手機端還是要通過一定的方法,發(fā)送一定的命令給CH340轉(zhuǎn)接芯片,配置相應(yīng)的串口參數(shù)。下面,我將會從如何進(jìn)行USB HOST編程基礎(chǔ)開始講起,對這些問題進(jìn)行闡述。
?其實不管是進(jìn)行什么樣方式的通信,歸納起來,無非就是四個步驟走:發(fā)現(xiàn)設(shè)備----->打開(連接)設(shè)備----->數(shù)據(jù)通信----->關(guān)閉設(shè)備。
?1、添加權(quán)限(安卓動不動就要添加權(quán)限,這個還是些許無聊的。)
<uses-feature android:name="android.hardware.usb.host" />
? ? <uses-permission android:name="android.hardware.usb.host" />
? ? <uses-permission android:name="ANDROID.PERMISSION.HARDWARE_TEST" />
2、添加USB設(shè)備信息
在res目錄下,新建一個xml文件夾,在里面新建一個xml文件,device_filter.xml,用來存放usb的設(shè)備信息。
<?xml version="1.0" encoding="utf-8"?>
<span style="white-space:pre">?? ?</span><resources>
? ?<span style="white-space:pre">?? ??? ?</span> <usb-device product-id="29987" vendor-id="6790" />
<span style="white-space:pre">?? ?</span></resources>
其中的ProductID跟VendorID是你要進(jìn)行通信的USB設(shè)備的供應(yīng)商ID(VID)和產(chǎn)品識別碼(PID),具體數(shù)值多少可以在接下來的枚舉設(shè)備方法里面得知。
??新建完文件,我們自然要引用他,即在manifest.xml文件中聲明。在要啟動的Activity里添加?<meta-data />標(biāo)簽。
<activity
? ? ? ? ? ? android:name=".MainActivity"
? ? ? ? ? ? android:label="@string/app_name"
? ? ? ? ? ? android:launchMode="singleTask" >
? ? ? ? ? ? <intent-filter>
? ? ? ? ? ? ? ? <action android:name="android.intent.action.MAIN" />
? ? ? ? ? ? ? ? <category android:name="android.intent.category.LAUNCHER" />
? ? ? ? ? ? </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" />
? ? ? ? </activity>
此外,我在此Activity中添加一個action為USB_DEVICE_ATTACHED的inten-filter,只是為了在不打開應(yīng)用的時候監(jiān)聽USB設(shè)備的插入,當(dāng)插入USB設(shè)備,則自動打開該應(yīng)用。并且,為了防止我在已打開應(yīng)用的的時候,插入USB設(shè)備他再次打開一個應(yīng)用,所以我設(shè)置其啟動模式為singleTask。
3、枚舉(發(fā)現(xiàn))并獲取相應(yīng)的USB設(shè)備(相關(guān)USB類:UsbManager ,UsbDevice)
?????不管進(jìn)行什么通信,我們首先該做的應(yīng)是獲取相應(yīng)的設(shè)備。此處,應(yīng)是利用UsbManager 類獲取插入到此Andriod手機上的USB設(shè)備,用UsbDevice類表示。
public UsbDevice EnumerateDevice(){
?? ??? ?mUsbmanager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
?? ??? ?mPendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(mString), 0);
?? ??? ?HashMap<String, UsbDevice> deviceList = mUsbmanager.getDeviceList();
?? ??? ?if(deviceList.isEmpty()) {
?? ??? ??? ?Toast.makeText(mContext, "No Device Or Device Not Match", Toast.LENGTH_LONG).show();
?? ??? ??? ?return null;
?? ??? ?}
?? ??? ?Iterator<UsbDevice> localIterator = deviceList.values().iterator();
?? ??? ?while(localIterator.hasNext()) {
?? ??? ??? ?UsbDevice localUsbDevice = localIterator.next();
?? ??? ??? ?for(int i = 0; i < DeviceCount; ++i) {
//?? ??? ??? ??? ? Log.d(TAG, "DeviceCount is " + DeviceCount);
?? ??? ??? ??? ?if(String.format("%04x:%04x", new Object[]{Integer.valueOf(localUsbDevice.getVendorId()),?
?? ??? ??? ??? ??? ??? ?Integer.valueOf(localUsbDevice.getProductId()) }).equals(DeviceNum.get(i))) {
?? ??? ??? ??? ??? ?IntentFilter filter = new IntentFilter(mString);
?? ??? ??? ??? ??? ?filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
?? ??? ??? ??? ??? ?mContext.registerReceiver(mUsbReceiver, filter);
?? ??? ??? ??? ??? ?BroadcastFlag = true;
?? ??? ??? ??? ??? ?return localUsbDevice;
?? ??? ??? ??? ??? ?
?? ??? ??? ??? ?} else {
?? ??? ??? ??? ??? ?Log.d(TAG, "String.format not match");
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?}
?? ??? ?
?? ??? ?return null;
?? ?}
4、打開USB設(shè)備
此處較為復(fù)雜,其實打開設(shè)備只是一個概括性的動作,實際上他還分好幾個動作,不然直接打開設(shè)備的話無法通信。
?打開設(shè)備方法:
public synchronized void OpenUsbDevice(UsbDevice mDevice){
?? ??? ?Object localObject;
?? ??? ?UsbInterface intf;
?? ??? ?if(mDevice == null)
?? ??? ??? ?return;
?? ??? ?intf = getUsbInterface(mDevice);
?? ??? ?if((mDevice != null) && (intf != null)) {
?? ??? ??? ?localObject = this.mUsbmanager.openDevice(mDevice);
?? ??? ??? ?if(localObject != null) {
?? ??? ??? ??? ?if(((UsbDeviceConnection)localObject).claimInterface(intf, true)) {
?? ??? ??? ??? ??? ?this.mUsbDevice = mDevice;
?? ??? ??? ??? ??? ?this.mDeviceConnection = ((UsbDeviceConnection)localObject);
?? ??? ??? ??? ??? ?this.mInterface = intf;
?? ??? ??? ??? ??? ?if(!enumerateEndPoint(intf))
?? ??? ??? ??? ??? ??? ?return;
?? ??? ??? ??? ??? ?Toast.makeText(mContext, "Device Has Attached to Android", Toast.LENGTH_LONG).show();
?? ??? ??? ??? ??? ?if(READ_ENABLE == false){
?? ??? ??? ??? ??? ??? ?READ_ENABLE = true;
?? ??? ??? ??? ??? ??? ?readThread = new read_thread(mBulkInPoint, mDeviceConnection);
?? ??? ??? ??? ??? ??? ?readThread.start();
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?return;
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?}
?? ??? ?
?? ?}
4.1 獲取USB設(shè)備接口
獲取到UsbDevice之后,我們在該設(shè)備上要獲取相應(yīng)的UsbInterface。
private UsbInterface getUsbInterface(UsbDevice paramUsbDevice) {
?? ??? ?if(this.mDeviceConnection != null) {
?? ??? ??? ?if(this.mInterface != null) {
?? ??? ??? ??? ?this.mDeviceConnection.releaseInterface(this.mInterface);
?? ??? ??? ??? ?this.mInterface = null;
?? ??? ??? ?}
?? ??? ??? ?this.mDeviceConnection.close();
?? ??? ??? ?this.mUsbDevice = null;
?? ??? ??? ?this.mInterface = null;
?? ??? ?}
?? ??? ?if(paramUsbDevice == null)
?? ??? ??? ?return null;
?? ??? ?for (int i = 0; i < paramUsbDevice.getInterfaceCount(); i++) {
?? ??? ??? ?UsbInterface intf = paramUsbDevice.getInterface(i);
?? ??? ??? ?if (intf.getInterfaceClass() == 0xff
?? ??? ??? ??? ??? ?&& intf.getInterfaceSubclass() == 0x01
?? ??? ??? ??? ??? ?&& intf.getInterfaceProtocol() == 0x02) {
?? ??? ??? ??? ?return intf;
?? ??? ??? ?}
?? ??? ?}
?? ??? ?return null;
?? ?}
4.2 ?分配端點,IN | OUT|?
獲取到USB設(shè)備接口之后,我們還不能進(jìn)行USB通信,USB通信需要使用UsbEndpoint端點。
private boolean enumerateEndPoint(UsbInterface sInterface){
?? ??? ?if(sInterface == null)
?? ??? ??? ?return false;
?? ??? ?for(int i = 0; i < sInterface.getEndpointCount(); ++i) {
?? ??? ??? ?UsbEndpoint endPoint = sInterface.getEndpoint(i);
?? ??? ??? ?if(endPoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK && endPoint.getMaxPacketSize() == 0x20) {
?? ??? ??? ??? ?if(endPoint.getDirection() == UsbConstants.USB_DIR_IN) {
?? ??? ??? ??? ??? ?mBulkInPoint = endPoint;
?? ??? ??? ??? ?} else {
?? ??? ??? ??? ??? ?mBulkOutPoint = endPoint;
?? ??? ??? ??? ?}
?? ??? ??? ??? ?this.mBulkPacketSize = endPoint.getMaxPacketSize();
?? ??? ??? ?} else if(endPoint.getType() == UsbConstants.USB_ENDPOINT_XFER_CONTROL) {
?? ??? ??? ??? ??? ?mCtrlPoint = endPoint;
?? ??? ??? ?}
?? ??? ?}
?? ??? ?return true;
?? ?}
其中In端點mBulkInPoint是輸入端點,是要來讀數(shù)據(jù)的,Out端點mBulkOutPoint是輸出端點,是寫數(shù)據(jù)用的。
4.3 打開并連接USB設(shè)備
此處跟前面獲取端點是可以互換順序的。但從理解角度來說,我還是傾向于把打開設(shè)備放在最后,因為一般都是把配置方面都做好了,才去連接設(shè)備的。
此處直接使用UsbManager的方法進(jìn)行連接:mUsbmanager.openDevice(mDevice);
到了這里,一般的即可進(jìn)行USB數(shù)據(jù)的讀寫了。
5、讀寫USB數(shù)據(jù)
讀數(shù)據(jù):使用?mConn.bulkTransfer()方法,mBulkInPoint端點。另外,串口是的緩存很小的,最大也就幾K,可認(rèn)為幾乎沒有,具體大小取決于串口設(shè)備端的MCU,所以我們必須開一個線程去不斷循環(huán)讀取數(shù)據(jù),不然倘若讀取速度小于設(shè)備端的發(fā)送速度,這樣就會導(dǎo)致數(shù)據(jù)丟失。
private class read_thread ?extends Thread {
?? ??? ?UsbEndpoint endpoint;
?? ??? ?UsbDeviceConnection mConn;
?? ??? ?read_thread(UsbEndpoint point, UsbDeviceConnection con){
?? ??? ??? ?endpoint = point;
?? ??? ??? ?mConn = con;
?? ??? ??? ?this.setPriority(Thread.MAX_PRIORITY);
?? ??? ?}
?? ??? ?public void run()
?? ??? ?{?? ??? ?
?? ??? ??? ?while(READ_ENABLE == true)
?? ??? ??? ?{
?? ??? ??? ??? ?while(totalBytes > (maxnumbytes - 63))
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?try?
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?Thread.sleep(5);
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?catch (InterruptedException e) {e.printStackTrace();}
?? ??? ??? ??? ?}
?? ??? ??? ??? ?synchronized(ReadQueueLock)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?if(endpoint != null)
?? ??? ??? ??? ??? ?{?? ?
?? ??? ??? ??? ??? ??? ?readcount = mConn.bulkTransfer(endpoint, usbdata, 64, ReadTimeOutMillis);
?? ??? ??? ??? ??? ??? ?if(readcount > 0)
?? ??? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ??? ?for(int count = 0; count< readcount; count++)
?? ??? ??? ??? ??? ??? ??? ?{?? ??? ??? ??? ??? ? ? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ??? ??? ?readBuffer[writeIndex] = usbdata[count];
?? ??? ??? ??? ??? ??? ??? ??? ?writeIndex++;
?? ??? ??? ??? ??? ??? ??? ??? ?writeIndex %= maxnumbytes;
?? ??? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ??? ?if(writeIndex >= readIndex)
?? ??? ??? ??? ??? ??? ??? ??? ?totalBytes = writeIndex-readIndex;
?? ??? ??? ??? ??? ??? ??? ?else
?? ??? ??? ??? ??? ??? ??? ??? ?totalBytes = (maxnumbytes-readIndex)+writeIndex;
?? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?}
?? ?}
當(dāng)要取數(shù)據(jù)的時候,直接去取readBuffer數(shù)組的數(shù)據(jù)即可。
???寫數(shù)據(jù):也是使用?mConn.bulkTransfer()方法,但是卻用的mBulkOutPoint端點。
? public int WriteData(byte[] buf, int length, int timeoutMillis)
?? ?{
?? ??? ?int offset = 0;
?? ??? ?int HasWritten = 0;
?? ??? ?int odd_len = length;
?? ??? ?if(this.mBulkOutPoint == null)
?? ??? ??? ?return -1;
?? ??? ?while(offset < length)
?? ??? ?{
?? ??? ??? ?synchronized(this.WriteQueueLock) {
?? ??? ??? ??? ?int mLen = Math.min(odd_len, this.mBulkPacketSize);
?? ??? ??? ??? ?byte[] arrayOfByte = new byte[mLen];
?? ??? ??? ??? ?if(offset == 0) {
?? ??? ??? ??? ??? ?System.arraycopy(buf, 0, arrayOfByte, 0, mLen);
?? ??? ??? ??? ?} else {
?? ??? ??? ??? ??? ?System.arraycopy(buf, offset, arrayOfByte, 0, mLen);
?? ??? ??? ??? ?}
?? ??? ??? ??? ?HasWritten = this.mDeviceConnection.bulkTransfer(this.mBulkOutPoint, arrayOfByte, mLen, timeoutMillis);
?? ??? ??? ??? ?if(HasWritten < 0) {
?? ??? ??? ??? ??? ?return -2;
?? ??? ??? ??? ?} else {
?? ??? ??? ??? ??? ?offset += HasWritten;
?? ??? ??? ??? ??? ?odd_len -= HasWritten;
//?? ??? ??? ??? ??? ?Log.d(TAG, "offset " + offset + " odd_len " + odd_len);
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?}
?? ??? ?return offset;
?? ?}
到了這里,一般的讀寫已可以了。網(wǎng)上的文章一般也就說到這一步。但是如同開頭所說,并沒有解決串口設(shè)置的問題,此時很大可能會接收到錯誤的數(shù)據(jù),這不是我們所希望的。此時,就需要我們的下一步了。
6、串口配置
在我們的這個CH340單轉(zhuǎn)接芯片里,我們采用的是mDeviceConnection.controlTransfer()這個方法來進(jìn)行配置。
?6.1 :初始化串口:
public boolean UartInit(){
?? ??? ?int ret;
?? ??? ?int size = 8;
?? ??? ?byte[] buffer = new byte[size];
?? ??? ?Uart_Control_Out(UartCmd.VENDOR_SERIAL_INIT, 0x0000, 0x0000);
?? ??? ?ret = Uart_Control_In(UartCmd.VENDOR_VERSION, 0x0000, 0x0000, buffer, 2);
?? ??? ?if(ret < 0)
?? ??? ??? ?return false;
?? ??? ?Uart_Control_Out(UartCmd.VENDOR_WRITE, 0x1312, 0xD982);
?? ??? ?Uart_Control_Out(UartCmd.VENDOR_WRITE, 0x0f2c, 0x0004);
?? ??? ?ret = Uart_Control_In(UartCmd.VENDOR_READ, 0x2518, 0x0000, buffer, 2);
?? ??? ?if(ret < 0)
?? ??? ??? ?return false;
?? ??? ?Uart_Control_Out(UartCmd.VENDOR_WRITE, 0x2727, 0x0000);
?? ??? ?Uart_Control_Out(UartCmd.VENDOR_MODEM_OUT, 0x00ff, 0x0000);
?? ??? ?return true;
?? ?}
public int Uart_Control_Out(int request, int value, int index)
?? ?{
?? ??? ?int retval = 0;
?? ??? ?retval = mDeviceConnection.controlTransfer(UsbType.USB_TYPE_VENDOR | UsbType.USB_RECIP_DEVICE | UsbType.USB_DIR_OUT,
?? ??? ??? ??? ?request, value, index, null, 0, DEFAULT_TIMEOUT);
?? ??? ?
?? ??? ?return retval;
?? ?}
public int Uart_Control_In(int request, int value, int index, byte[] buffer, int length)
?? ?{
?? ??? ?int retval = 0;
?? ??? ?retval = mDeviceConnection.controlTransfer(UsbType.USB_TYPE_VENDOR | UsbType.USB_RECIP_DEVICE | UsbType.USB_DIR_IN,
?? ??? ??? ??? ??? ?request, value, index, buffer, length, DEFAULT_TIMEOUT);
?? ??? ?return retval;
?? ?}
?6.2:配置串口參數(shù)(主要是波特率,數(shù)據(jù)位,停止位,奇偶校驗位以及流控)
public boolean SetConfig(int baudRate, byte dataBit, byte stopBit, byte parity, byte flowControl){
?? ??? ?int value = 0;
?? ??? ?int index = 0;
?? ??? ?char valueHigh = 0, valueLow = 0, indexHigh = 0, indexLow = 0;
?? ??? ?switch(parity) {
?? ??? ?case 0:?? ?/*NONE*/
?? ??? ??? ?valueHigh = 0x00;
?? ??? ??? ?break;
?? ??? ?case 1:?? ?/*ODD*/
?? ??? ??? ?valueHigh |= 0x08;
?? ??? ??? ?break;
?? ??? ?case 2:?? ?/*Even*/
?? ??? ??? ?valueHigh |= 0x18;
?? ??? ??? ?break;
?? ??? ?case 3:?? ?/*Mark*/
?? ??? ??? ?valueHigh |= 0x28;
?? ??? ??? ?break;
?? ??? ?case 4:?? ?/*Space*/
?? ??? ??? ?valueHigh |= 0x38;
?? ??? ??? ?break;
?? ??? ?default:?? ?/*None*/
?? ??? ??? ?valueHigh = 0x00;
?? ??? ??? ?break;
?? ??? ?}
?? ??? ?
?? ??? ?if(stopBit == 2) {
?? ??? ??? ?valueHigh |= 0x04;
?? ??? ?}
?? ??? ?
?? ??? ?switch(dataBit) {
?? ??? ?case 5:
?? ??? ??? ?valueHigh |= 0x00;
?? ??? ??? ?break;
?? ??? ?case 6:
?? ??? ??? ?valueHigh |= 0x01;
?? ??? ??? ?break;
?? ??? ?case 7:
?? ??? ??? ?valueHigh |= 0x02;
?? ??? ??? ?break;
?? ??? ?case 8:
?? ??? ??? ?valueHigh |= 0x03;
?? ??? ??? ?break;
?? ??? ?default:
?? ??? ??? ?valueHigh |= 0x03;
?? ??? ??? ?break;
?? ??? ?}
?? ??? ?
?? ??? ?valueHigh |= 0xc0;
?? ??? ?valueLow = 0x9c;
?? ??? ?
?? ??? ?value |= valueLow;
?? ??? ?value |= (int)(valueHigh << 8);
?? ??? ?
?? ??? ?switch(baudRate) {
?? ??? ?case 50:
?? ??? ??? ?indexLow = 0;
?? ??? ??? ?indexHigh = 0x16;
?? ??? ??? ?break;
?? ??? ?case 75:
?? ??? ??? ?indexLow = 0;
?? ? ? ? ? ?indexHigh = 0x64;
?? ? ? ? ? ?break;
?? ??? ?case 110:
? ? ? ? ? ? indexLow = 0;
? ? ? ? ? ? indexHigh = 0x96;
? ? ? ? ? ? break;
? ? ? ? case 135:
? ? ? ? ? ? indexLow = 0;
? ? ? ? ? ? indexHigh = 0xa9;
? ? ? ? ? ? break;
? ? ? ? case 150:
? ? ? ? ? ? indexLow = 0;
? ? ? ? ? ? indexHigh = 0xb2;
? ? ? ? ? ? break; ? ?
?? ??? ?case 300:
?? ??? ??? ?indexLow = 0;
?? ??? ??? ?indexHigh = 0xd9;
?? ??? ??? ?break;
?? ??? ?case 600:
?? ??? ??? ?indexLow = 1;
?? ??? ??? ?indexHigh = 0x64;
?? ??? ??? ?break;
?? ??? ?case 1200:
?? ??? ??? ?indexLow = 1;
?? ??? ??? ?indexHigh = 0xb2;
?? ??? ??? ?break;
?? ??? ?case 1800:
? ? ? ? ? ? indexLow = 1;
? ? ? ? ? ? indexHigh = 0xcc;
? ? ? ? ? ? break;
?? ??? ?case 2400:
?? ??? ??? ?indexLow = 1;
?? ? ? ? ? ?indexHigh = 0xd9;
?? ??? ??? ?break;
?? ??? ?case 4800:
?? ??? ??? ?indexLow = 2;
?? ? ? ? ? ?indexHigh = 0x64;
?? ??? ??? ?break;
?? ??? ?case 9600:
?? ??? ??? ?indexLow = 2;
?? ? ? ? ? ?indexHigh = 0xb2;
?? ??? ??? ?break;
?? ??? ?case 19200:
?? ??? ??? ?indexLow = 2;
?? ? ? ? ? ?indexHigh = 0xd9;
?? ??? ??? ?break;
?? ??? ?case 38400:
?? ??? ??? ?indexLow = 3;
?? ? ? ? ? ?indexHigh = 0x64;
?? ??? ??? ?break;
?? ??? ?case 57600:
?? ??? ??? ?indexLow = 3;
?? ? ? ? ? ?indexHigh = 0x98;
?? ??? ??? ?break;
?? ??? ?case 115200:
?? ??? ??? ?indexLow = 3;
?? ? ? ? ? ?indexHigh = 0xcc;
?? ??? ??? ?break;
?? ??? ?case 230400:
?? ??? ??? ?indexLow = 3;
?? ? ? ? ? ?indexHigh = 0xe6;
?? ??? ??? ?break;
?? ??? ?case 460800:
?? ??? ??? ?indexLow = 3;
?? ? ? ? ? ?indexHigh = 0xf3;
?? ??? ??? ?break;?? ??? ??? ??? ? ? ?
?? ??? ?case 500000:
? ? ? ? ? ? indexLow = 3; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? indexHigh = 0xf4;
? ? ? ? ? ? break;
? ? ? ? case 921600:
? ? ? ? ? ? indexLow = 7;
? ? ? ? ? ? indexHigh = 0xf3;
? ? ? ? ? ? break;
? ? ? ? case 1000000:
? ? ? ? ? ? indexLow = 3;
? ? ? ? ? ? indexHigh = 0xfa;
? ? ? ? ? ? break;
? ? ? ? case 2000000:
? ? ? ? ? ? indexLow = 3;
? ? ? ? ? ? indexHigh = 0xfd;
? ? ? ? ? ? break;
? ? ? ? case 3000000:
? ? ? ? ? ? indexLow = 3;
? ? ? ? ? ? indexHigh = 0xfe;
? ? ? ? ? ? break;
?? ??? ?default:?? ?// default baudRate "9600"
?? ??? ??? ?indexLow = 2;
?? ? ? ? ? ?indexHigh = 0xb2;
?? ??? ??? ?break;?
?? ??? ?}
?? ??? ?
?? ??? ?index |= 0x88 |indexLow;
?? ??? ?index |= (int)(indexHigh << 8);
?? ??? ?
?? ??? ?Uart_Control_Out(UartCmd.VENDOR_SERIAL_INIT, value, index);
?? ??? ?if(flowControl == 1) {
?? ??? ??? ?Uart_Tiocmset(UartModem.TIOCM_DTR | UartModem.TIOCM_RTS, 0x00);
?? ??? ?}
?? ??? ?return true;
?? ?}
這樣,串口已經(jīng)初始化,以及配置好相關(guān)的波特率之類的,就可以進(jìn)行正確的數(shù)據(jù)收發(fā)了,就可以實現(xiàn)我們的USB--UART串口通信了。
7、關(guān)閉設(shè)備
當(dāng)然,最后不要忘記關(guān)閉設(shè)備,釋放資源。
?? ?public synchronized void CloseDevice() {
?? ??? ?try {
?? ??? ??? ?Thread.sleep(10);
?? ??? ?} catch (Exception e) {
?? ??? ?}
?
?? ??? ?if (this.mDeviceConnection != null) {
?? ??? ??? ?if (this.mInterface != null) {
?? ??? ??? ??? ?this.mDeviceConnection.releaseInterface(this.mInterface);
?? ??? ??? ??? ?this.mInterface = null;
?? ??? ??? ?}
?
?? ??? ??? ?this.mDeviceConnection.close();
?? ??? ?}
?
?? ??? ?if (this.mUsbDevice != null) {
?? ??? ??? ?this.mUsbDevice = null;
?? ??? ?}
?
?? ??? ?if (this.mUsbmanager != null) {
?? ??? ??? ?this.mUsbmanager = null;
?? ??? ?}
?
?? ??? ?if (READ_ENABLE == true) {
?? ??? ??? ?READ_ENABLE = false;
?? ??? ?}
?
?? ??? ?/*
?? ??? ? * No need unregisterReceiver
?? ??? ? */
?? ??? ?if (BroadcastFlag == true) {
?? ??? ??? ?this.mContext.unregisterReceiver(mUsbReceiver);
?? ??? ??? ?BroadcastFlag = false;
?? ??? ?}
?
?? ??? ?// System.exit(0);
?? ?}
本文主要參考CH34X系列廠商提供的官方開發(fā)手冊以及demo,有興趣的朋友可以直接前往官網(wǎng)下載相關(guān)資料。
http://www.wch.cn/download/CH341SER_ANDROID_ZIP.html
原文:https://blog.csdn.net/ever_gz/article/details/49669729?
?
總結(jié)
以上是生活随笔為你收集整理的Android USB转串口编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我的职场战争--一年来的开发组内战实录
- 下一篇: android sina oauth2.