Android OTG之USB轉串口模塊通信

 

微信公衆號:CodingAndroid
CSDN:http://blog.csdn.net/xinpengfei521java

1.背景簡介

咱們公司開發了一款室內機平板APP應用,要求平板能去控制智能門鎖、等其餘智能設備,智能門鎖不是咱們公司開發的,與咱們公司屬於合做關係。android

2.分析及實現思路

  1. 智能門鎖的控制是經過使用 433射頻(不瞭解的請百度)來進行通信的;
  2. 平板是無法與智能門鎖直接進行通信,可是廠家提供了一個433通信模塊(支持串口);
  3. 而平板(支持OTG)是支持USB轉串口模塊的,因此整個流程是能夠走通的,以下圖

3.主要代碼實現

3.1初始化USB轉串口模塊

因爲咱們選用的是CH340模塊,咱們先導入ch340的 jar 包,而後在代碼中檢查手機/平板是否支持USB HOST模式,若是支持咱們就初始化通信時的相關參數:波特率、數據位、中止位等,具體的參數看大家之間通信的協議。初始化完成以後,咱們就能夠打開USB進行通信了,同時初始化完成以後咱們須要開啓一個讀取數據的線程,這樣,一旦收到數據或者相應的響應包(通常也叫ACK)咱們就能夠進行相應的處理了。git

下面貼上初始化、及開啓讀取數據線程的代碼實現:github

 1    /**
2 * initialize ch340 parameters.
3 *
4 * @param context Application context.
5 */

6 public static void initCH340(Context context) {
7 if (context == null) return;
8 Context appContext = context.getApplicationContext();
9 mUsbManager = (UsbManager) appContext.getSystemService(Context.USB_SERVICE);
10 if (mUsbManager != null) {
11 HashMap<String, UsbDevice> deviceHashMap = mUsbManager.getDeviceList();
12 for (UsbDevice device : deviceHashMap.values()) {
13 if (device.getProductId() == 29987 && device.getVendorId() == 6790) {
14 mUsbDevice = device;
15 if (mUsbManager.hasPermission(device)) {
16 loadDriver(appContext, mUsbManager);
17 } else {
18 if (listener != null) {
19 listener.result(false);
20 }
21 }
22 break;
23 }
24 }
25 }
26 }
27 /**
28 * load ch340 driver.
29 *
30 * @param appContext
31 * @param usbManager
32 */

33 public static void loadDriver(Context appContext, UsbManager usbManager) {
34 driver = new CH34xUARTDriver(usbManager, appContext, ACTION_USB_PERMISSION);
35 // 判斷系統是否支持USB HOST
36 if (!driver.UsbFeatureSupported()) {
37 InLog.e(TAG, "Your mobile phone does not support USB HOST, please change other phones to try again!");
38 } else {
39 openCH340();
40 }
41 }
42 /**
43 * config and open ch340.
44 */

45 private static void openCH340() {
46 int ret_val = driver.ResumeUsbList();
47 InLog.d(TAG, ret_val + "");
48 // ResumeUsbList方法用於枚舉CH34X設備以及打開相關設備
49 if (ret_val == -1) {
50 InLog.d(TAG, ret_val + "Failed to open device!");
51 driver.CloseDevice();
52 } else if (ret_val == 0) {
53 if (!driver.UartInit()) { //對串口設備進行初始化操做
54 InLog.d(TAG, ret_val + "Failed device initialization!");
55 InLog.d(TAG, ret_val + "Failed to open device!");
56 return;
57 }
58 InLog.d(TAG, ret_val + "Open device successfully!");
59 if (!isOpenDeviceCH340) {
60 isOpenDeviceCH340 = true;
61 configParameters();//配置ch340的參數、須要先配置參數
62 }
63 } else {
64 InLog.d(TAG, "The phone couldn't find the device!");
65 }
66 }
67 /**
68 * config ch340 parameters.
69 * 配置串口波特率,函數說明可參照編程手冊
70 */

71 private static void configParameters() {
72 if (driver.SetConfig(baudRate, dataBit, stopBit, parity, flowControl)) {
73 InLog.d(TAG, "Successful serial port Settings!");
74 if (readDataRunnable == null) {
75 readDataRunnable = new ReadDataRunnable();
76 }
77 mThreadPool.execute(readDataRunnable);
78 } else {
79 InLog.d(TAG, "Serial port Settings failed!");
80 }
81 }

3.2發送和接收數據

發送和接收數據都是按16進制進行發送和處理的,因此咱們寫了一個工具類方便發送,以下:編程

 1/**
2 * Created by xpf on 2018/2/6 :)
3 * Function:CH340數據處理工具類
4 */

5public class CH340Util {
6 /**
7 * write data in ch340.
8 *
9 * @param byteArray 字節數組
10 * @return 返回寫入的結果,-1表示寫入失敗!
11 */

12 public static int writeData(@NonNull byte[] byteArray) {
13 // 將此處收到的數組轉化爲HexString
14 String hexString = bytesToHexString(byteArray, byteArray.length);
15 InLog.i("TAG", "WriteHexString===" + hexString);
16 return InitCH340.getDriver().WriteData(byteArray, byteArray.length);
17 }
18 /**
19 * byte[]轉換爲hexString
20 *
21 * @param buffer 數據
22 * @param size 字符數
23 * @return 返回轉換後的十六進制字符串
24 */

25 public static String bytesToHexString(byte[] buffer, final int size) {
26 StringBuilder stringBuilder = new StringBuilder("");
27 if (buffer == null || size <= 0) return null;
28 for (int i = 0; i < size; i++) {
29 String hex = Integer.toHexString(buffer[i] & 0xff);
30 if (hex.length() < 2) stringBuilder.append(0);
31 stringBuilder.append(hex);
32 }
33 return stringBuilder.toString();
34 }
35}

而後基本的發送和接收數據就寫完了,發送數據時調用 writeData() 方法就能夠了,接收數據也相似,具體的業務及通信的協議、加密規則等都須要你和硬件提供方進行協商對接制定,因爲涉及到公司機密,此處我就不進行說明了,只說一下最基本的發送和接收數據。數組

4.插入模塊實現自動打開APP

Android中USB的插拔都會發送一個廣播,咱們只須要在AndroidMenifest.xml文件中接收這個廣播就能夠了,當咱們入模塊的時候就會啓動咱們的APP,第一次會彈出一個對話框詢問咱們是否打開xxx應用,咱們點擊確認便可,另外不是咱們插入任何USB設備都打開咱們的應用,因此咱們須要過濾掉對咱們沒有用的設備,在res下建一個xml目錄,新建usb_filter.xml文件,配置好咱們這個USB設備模塊的product-id和vendor-id,每一個模塊廠家這個值都是不同的,有兩種獲取方式,一個是代碼中枚舉USB設備而後打印出來,另一種方法是打開Logcat觀察,而後插入USB設備,你會發現系統會打印出來這個USB設備等信息。微信

最後不要忘了添加權限:app

1    <uses-feature
2 android:name="android.hardware.usb.host"
3 android:required="true" />

4 <uses-permission android:name="android.hardware.usb.host" />

此處因爲篇幅緣由就不具體展開講解更多細節了,核心的代碼和實現我都已經貼出來了,要想查看更具體的實現,請下載個人demo:函數

https://github.com/xinpengfei520/USB-OTG-CH340-UART-interface工具

若在閱讀過程當中遇到什麼問題,或有好提議,歡迎在公衆號「CodingAndroid」中提出

長按後點擊掃一掃關注!長按後點擊掃一掃關注!
相關文章
相關標籤/搜索