Android USB串口开发
因為第一次接觸Android下的串口開發,在網上找了很多例子都不能滿足自己的需要以及不能正常使用,于是結合網上的資源以及查閱資料,終于完成了關于這個串口的開發,在此記錄下usb轉串口通信開發的過程。
Android串口開發步驟總共分為四大類,如下?
1. 權限獲取?
2. 發現打開串口?
3. 串口操作(發送與讀取)?
4. 關閉串口
一、權限獲取
首先我們需要在AndroidMainfest.xml文件中配置USB使用權限
<uses-feature android:name="android.hardware.usb.host" />
1
并在我們的Activity標簽中配置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" />
1
2
3
4
5
6
7
resource資源為res資源文件夾下的xml文件下的device_filter.xml文件。device_filter.xml文件是我們需要知道我們USB設備硬件的vendor-id和product-id。文件內容如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
? ? <usb-device
? ? ? ? vendor-id="xxxx"
? ? ? ? product-id="xxxx"/>
</resources>
1
2
3
4
5
6
其中vendor-id以及product-id我們可以通過計算機管理 -> 電腦電腦設備管理器,Android Phone 查看詳細信息,屬性選擇硬件ID。?
二、發現打開串口?
首先我們需要獲取到UsbManager管理類,通過此類的getDeviceList()方法得到包含所有已連接的USB設備的列表。最后,通過設備名稱來得到給設備對象。
UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceMap = usbManager.getDeviceList();
UsbDevice device = deviceMap.get("deviceName");
1
2
3
上面是獲取指定的串口設備,如果你想獲取到所有的可以通過usbManager.getDeviceList().values();獲取在foreach循環迭代拿到每一個設備。
當我們獲取到一個設備之后,我們首先要判斷是否有該權限,通過usbManager.hasPermission(device)判斷是否有該權限。當有權限我們就可以打開串口設備以及對他設置波特率、檢驗位等參數信息。
?private void permissionAllow(UsbDevice device) {
? ? ? ? List<UsbSerialPort> result = new ArrayList<>();
? ? ? ? for (final UsbSerialDriver driver : drivers) {
? ? ? ? ? ? final List<UsbSerialPort> ports = driver.getPorts();
? ? ? ? ? ? result.addAll(ports);
? ? ? ? }
? ? ? ? UsbDeviceConnection usbDeviceConnection = usbManager.openDevice(device);
? ? ? ? try {
? ? ? ? ? ? serialPort = result.get(0);
? ? ? ? ? ? serialPort.open(usbDeviceConnection);
? ? ? ? ? ? // 第一個參數為波特率 第二個為停止位 第三個為奇偶校驗,具體的應該根據自己的協議來配置
? ? ? ? ? ? serialPort.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? ? ? UsbInterface anInterface = device.getInterface(0);
? ? ? ? if (anInterface == null) {
? ? ? ? ? ? Toast.makeText(this, "初始化失敗", Toast.LENGTH_SHORT).show();
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? // 判斷端口號
? ? ? ? for (int i = 0; i < anInterface.getEndpointCount(); i++) {
? ? ? ? ? ? UsbEndpoint endpoint = anInterface.getEndpoint(i);
? ? ? ? ? ? if (endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
? ? ? ? ? ? ? ? if (endpoint.getDirection() == UsbConstants.USB_DIR_IN) {
? ? ? ? ? ? ? ? ? ? // 輸入端口
? ? ? ? ? ? ? ? ? ? usbEndpointIn = endpoint;
? ? ? ? ? ? ? ? } else if (endpoint.getDirection() == UsbConstants.USB_DIR_OUT) {
? ? ? ? ? ? ? ? ? ? // 輸出端口
? ? ? ? ? ? ? ? ? ? usbEndpointOut = endpoint;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
當沒有權限的使用,需要注冊本地廣播去申請權限
// ?private static final String ACTION_USB_PERMISSION = "android.hardware.usb.action.USB_DEVICE_ATTACHED";
UsbPermissionActionReceiver mUsbPermissionActionReceiver = new UsbPermissionActionReceiver();
Intent intent = new Intent(ACTION_USB_PERMISSION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
IntentFilter intentFilter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbPermissionActionReceiver, intentFilter);
usbManager.requestPermission(device, pendingIntent);
private class UsbPermissionActionReceiver extends BroadcastReceiver {
? ? ? ? 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)) {
? ? ? ? ? ? ? ? ? ? ? ? // user choose YES for your previously popup window asking for grant perssion for this usb device
? ? ? ? ? ? ? ? ? ? ? ? if (null != usbDevice) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? permissionAllow(usbDevice);
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? //user choose NO for your previously popup window asking for grant perssion for this usb device
? ? ? ? ? ? ? ? ? ? ? ? Toast.makeText(context, String.valueOf("Permission denied for device" + usbDevice), Toast.LENGTH_LONG).show();
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
三、串口操作
通過以上我們已經對串口的獲取以及配對都已經完成了,接下來只需要發送數據給串口就OK了。
private void sendToUsb(String[] hexString) throws Exception {
// 在這里需要轉換byte數組,因為串口按位(bit)發送和接收字節
? ? ?byte[] bytes = new byte[hexString.length];
? ? ?for (int i = 0; i < hexString.length; i++) {
? ? ? ? ?bytes[i] = (byte) Integer.parseInt(hexString[i].substring(2), 16);
? ? ?}
? ? ?serialPort.write(bytes, bytes.length);
?}
1
2
3
4
5
6
7
8
已某一個指令為例
private void studyCode() {
? ? ?try {
? ? ? // 該數據為協議規定的十六進制的數據值
? ? ? ? ?String[] studyCodeStrArr = "0X55 0X4C 0X42 0X00 0X00 0X00 0X00 0X01 0X00 0X00 0X00 0X00 0X00 0X00 0X00 0X01 0X0A 0X00 0XEF".replace("X", "x").split(" ");
? ? ? ? ?sendToUsb(studyCodeStrArr);
? ? ?} catch (Exception e) {
? ? ? ? ?Toast.makeText(this, "學碼失敗", Toast.LENGTH_SHORT).show();
? ? ? ? ?e.printStackTrace();
? ? ?}
?}
1
2
3
4
5
6
7
8
9
10
11
四、關閉串口
當你完成數據的傳輸或者你的設備已拔出時,通過調用releaseInterface()和 close()來關閉接口和連接。
支持已完成了串口的開發,下面附上完整代碼。
package com.huruwo.serialporthelper;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
?* author: YJZ
?* date: ?2018/6/15
?* des: USB串口開發
?*/
public class MainActivity extends AppCompatActivity implements View.OnClickListener, IAudioListen, SeekBar.OnSeekBarChangeListener {
? ? private UsbEndpoint usbEndpointIn;
? ? private UsbEndpoint usbEndpointOut;
? ? private UsbManager usbManager;
? ? private UsbSerialPort serialPort;
? ? private TextView textView;
? ? private TextView seekBarValue;
? ? private List<UsbSerialDriver> drivers;
? ? public MainActivity() {
? ? }
? ? @Override
? ? protected void onCreate(@Nullable Bundle savedInstanceState) {
? ? ? ? super.onCreate(savedInstanceState);
? ? ? ? setContentView(R.layout.activity_test);
? ? ? ? initView();
? ? ? ? initUsbSerial();
? ? }
? ? private void initUsbSerial() {
? ? ? ? // 1.查找設備
? ? ? ? usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
? ? ? ? drivers = UsbSerialProber.getDefaultProber().findAllDrivers(usbManager);
? ? ? ? if (drivers.size() <= 0) {
? ? ? ? ? ? Toast.makeText(this, "無串口設備", Toast.LENGTH_SHORT).show();
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? UsbDevice device = drivers.get(0).getDevice();
? ? ? ? if (usbManager.hasPermission(device)) {
? ? ? ? ? ? permissionAllow(device);
? ? ? ? } else {
? ? ? ? ? ? Log.e("TAG", "沒有權限");
? ? ? ? ? ? UsbPermissionActionReceiver mUsbPermissionActionReceiver = new UsbPermissionActionReceiver();
? ? ? ? ? ? Intent intent = new Intent(ACTION_USB_PERMISSION);
? ? ? ? ? ? PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
? ? ? ? ? ? IntentFilter intentFilter = new IntentFilter(ACTION_USB_PERMISSION);
? ? ? ? ? ? registerReceiver(mUsbPermissionActionReceiver, intentFilter);
? ? ? ? ? ? usbManager.requestPermission(device, pendingIntent);
? ? ? ? }
? ? }
? ? private void permissionAllow(UsbDevice device) {
? ? ? ? List<UsbSerialPort> result = new ArrayList<>();
? ? ? ? for (final UsbSerialDriver driver : drivers) {
? ? ? ? ? ? final List<UsbSerialPort> ports = driver.getPorts();
? ? ? ? ? ? result.addAll(ports);
? ? ? ? }
? ? ? ? UsbDeviceConnection usbDeviceConnection = usbManager.openDevice(device);
? ? ? ? try {
? ? ? ? ? ? serialPort = result.get(0);
? ? ? ? ? ? serialPort.open(usbDeviceConnection);
? ? ? ? ? ? serialPort.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? ? ? UsbInterface anInterface = device.getInterface(0);
? ? ? ? if (anInterface == null) {
? ? ? ? ? ? Toast.makeText(this, "初始化失敗", Toast.LENGTH_SHORT).show();
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? // 判斷端口號
? ? ? ? for (int i = 0; i < anInterface.getEndpointCount(); i++) {
? ? ? ? ? ? UsbEndpoint endpoint = anInterface.getEndpoint(i);
? ? ? ? ? ? if (endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
? ? ? ? ? ? ? ? if (endpoint.getDirection() == UsbConstants.USB_DIR_IN) {
? ? ? ? ? ? ? ? ? ? // 輸入端口
? ? ? ? ? ? ? ? ? ? usbEndpointIn = endpoint;
? ? ? ? ? ? ? ? } else if (endpoint.getDirection() == UsbConstants.USB_DIR_OUT) {
? ? ? ? ? ? ? ? ? ? // 輸出端口
? ? ? ? ? ? ? ? ? ? usbEndpointOut = endpoint;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? private static final String ACTION_USB_PERMISSION = "android.hardware.usb.action.USB_DEVICE_ATTACHED";
? ? @Override
? ? public void top() {
? ? ? ? topTurn();
? ? }
? ? @Override
? ? public void pause() {
? ? ? ? pauseTurn();
? ? }
? ? @Override
? ? public void update(final double volume) {
? ? ? ? runOnUiThread(new Runnable() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? textView.setText("分貝:" + String.valueOf(volume));
? ? ? ? ? ? }
? ? ? ? });
? ? ? ? Log.e("TAG", "volume = " + volume);
? ? }
? ? @Override
? ? public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
? ? ? ? AudioRecordDemo.MAX_VOLUME = progress;
? ? ? ? seekBarValue.setText(String.format(Locale.CHINA, "閥值:%s", progress));
? ? }
? ? @Override
? ? public void onStartTrackingTouch(SeekBar seekBar) {
? ? }
? ? @Override
? ? public void onStopTrackingTouch(SeekBar seekBar) {
? ? }
? ? private class UsbPermissionActionReceiver extends BroadcastReceiver {
? ? ? ? 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)) {
? ? ? ? ? ? ? ? ? ? ? ? // user choose YES for your previously popup window asking for grant perssion for this usb device
? ? ? ? ? ? ? ? ? ? ? ? if (null != usbDevice) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? permissionAllow(usbDevice);
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? //user choose NO for your previously popup window asking for grant perssion for this usb device
? ? ? ? ? ? ? ? ? ? ? ? Toast.makeText(context, String.valueOf("Permission denied for device" + usbDevice), Toast.LENGTH_LONG).show();
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? private void initView() {
? ? ? ? findViewById(R.id.study_code).setOnClickListener(this);
? ? ? ? findViewById(R.id.top).setOnClickListener(this);
? ? ? ? findViewById(R.id.pause).setOnClickListener(this);
? ? ? ? findViewById(R.id.bottom).setOnClickListener(this);
? ? ? ? findViewById(R.id.start_audio).setOnClickListener(this);
? ? ? ? findViewById(R.id.stop_audio).setOnClickListener(this);
? ? ? ? SeekBar seekBar = findViewById(R.id.seek_bar);
? ? ? ? seekBarValue = findViewById(R.id.seek_bar_value);
? ? ? ? seekBar.setOnSeekBarChangeListener(this);
? ? ? ? textView = findViewById(R.id.value);
? ? }
? ? @Override
? ? public void onClick(View v) {
? ? ? ? switch (v.getId()) {
? ? ? ? ? ? case R.id.study_code:
? ? ? ? ? ? ? ? studyCode();
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case R.id.top:
? ? ? ? ? ? ? ? topTurn();
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case R.id.pause:
? ? ? ? ? ? ? ? pauseTurn();
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case R.id.bottom:
? ? ? ? ? ? ? ? bottomTurn();
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case R.id.start_audio:
? ? ? ? ? ? ? ? AudioRecordDemo demo = new AudioRecordDemo();
? ? ? ? ? ? ? ? demo.setAudioRecordListener(this);
? ? ? ? ? ? ? ? demo.getNoiseLevel();
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case R.id.stop_audio:
? ? ? ? ? ? ? ? AudioRecordDemo.isGetVoiceRun = false;
? ? ? ? ? ? ? ? break;
? ? ? ? }
? ? }
? ? private void bottomTurn() {
? ? ? ? try {
? ? ? ? ? ? String[] bottomStrArr = "0X55 0X4C 0X42 0X00 0X00 0X00 0X00 0X01 0X00 0X00 0X00 0X00 0X00 0X00 0X00 0X01 0X0C 0X00 0XF1".replace("X", "x").split(" ");
? ? ? ? ? ? sendToUsb(bottomStrArr);
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? Toast.makeText(this, "失敗", Toast.LENGTH_SHORT).show();
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
? ? private void pauseTurn() {
? ? ? ? try {
? ? ? ? ? ? String[] pauseStrArr = "0X55 0X4C 0X42 0X00 0X00 0X00 0X00 0X01 0X00 0X00 0X00 0X00 0X00 0X00 0X00 0X01 0X0D 0X00 0XF2".replace("X", "x").split(" ");
? ? ? ? ? ? sendToUsb(pauseStrArr);
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? Toast.makeText(this, "失敗", Toast.LENGTH_SHORT).show();
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
? ? private void topTurn() {
? ? ? ? try {
? ? ? ? ? ? String[] topStrArr = "0X55 0X4C 0X42 0X00 0X00 0X00 0X00 0X01 0X00 0X00 0X00 0X00 0X00 0X00 0X00 0X01 0X0E 0X00 0XF3".replace("X", "x").split(" ");
? ? ? ? ? ? sendToUsb(topStrArr);
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? Toast.makeText(this, "失敗", Toast.LENGTH_SHORT).show();
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
? ? private void studyCode() {
? ? ? ? try {
? ? ? ? ? ? String[] studyCodeStrArr = "0X55 0X4C 0X42 0X00 0X00 0X00 0X00 0X01 0X00 0X00 0X00 0X00 0X00 0X00 0X00 0X01 0X0A 0X00 0XEF".replace("X", "x").split(" ");
? ? ? ? ? ? sendToUsb(studyCodeStrArr);
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? Toast.makeText(this, "學碼失敗", Toast.LENGTH_SHORT).show();
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
? ? private void sendToUsb(String[] hexString) throws Exception {
? ? ? ? byte[] bytes = new byte[hexString.length];
? ? ? ? for (int i = 0; i < hexString.length; i++) {
? ? ? ? ? ? bytes[i] = (byte) Integer.parseInt(hexString[i].substring(2), 16);
? ? ? ? }
? ? ? ? serialPort.write(bytes, bytes.length);
? ? }
? ? @Override
? ? protected void onPause() {
? ? ? ? super.onPause();
? ? ? ? AudioRecordDemo.isGetVoiceRun = false;
? ? }
? ? @Override
? ? protected void onDestroy() {
? ? ? ? super.onDestroy();
? ? ? ? AudioRecordDemo.isGetVoiceRun = false;
? ? }
}
原文:https://blog.csdn.net/weixin_37185329/article/details/80759555?
?
總結
以上是生活随笔為你收集整理的Android USB串口开发的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android USB 开发详解
- 下一篇: Android USB转串口通信开发实例