<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在不會使用串列埠通訊之前,暫且可以把它理解為“一個可通訊的口”;使用篇不深入探討理論及原理。能理解串列埠如何使用之後,可以檢視淺談Android串列埠通訊SerialPort原理
1.)在 module 中的 build.gradle 中的 dependencies 中新增以下依賴:
dependencies { //串列埠 implementation 'com.github.licheedev:Android-SerialPort-API:2.0.0' }
2.)低版本的 gradle 在Project 中的 build.gradle 中的 allprojects 中新增以下 maven倉庫 (不新增任然無法載入SerialPort);
allprojects { repositories { maven { url "https://jitpack.io" }//maven倉庫 } }
高版本的 gradle 已經廢棄了 allprojects 在 settings.gradle 中 repositories 新增以下maven倉庫(不新增任然無法載入SerialPort);
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() jcenter() // Warning: this repository is going to shut down soon maven { url "https://jitpack.io" }//maven倉庫 } }
1.)串列埠處理類:SerialHandle ;簡單概括這個類,就是通過串列埠物件去獲取兩個流(輸入流、輸出流),通過者兩個流來監聽資料或者寫入指令,硬體收到後執行。同時注意設定引數(只要支援串列埠通訊的硬體,一般說明書上都會有寫)
package com.chj233.serialmode.serialUtil; import android.serialport.SerialPort; import android.util.Log; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; /** * 串列埠實處理類 */ public class SerialHandle implements Runnable { private static final String TAG = "串列埠處理類"; private String path = "";//串列埠地址 private SerialPort mSerialPort;//串列埠物件 private InputStream mInputStream;//串列埠的輸入流物件 private BufferedInputStream mBuffInputStream;//用於監聽硬體返回的資訊 private OutputStream mOutputStream;//串列埠的輸出流物件 用於傳送指令 private SerialInter serialInter;//串列埠回撥介面 private ScheduledFuture readTask;//串列埠讀取任務 /** * 新增串列埠回撥 * * @param serialInter */ public void addSerialInter(SerialInter serialInter) { this.serialInter = serialInter; } /** * 開啟串列埠 * * @param devicePath 串列埠地址(根據平板的說明說填寫) * @param baudrate 波特率(根據對接的硬體填寫 - 硬體說明書上"通訊"中會有標註) * @param isRead 是否持續監聽串列埠返回的資料 * @return 是否開啟成功 */ public boolean open(String devicePath, int baudrate, boolean isRead) { return open(devicePath, baudrate, 7, 1, 2, isRead); } /** * 開啟串列埠 * * @param devicePath 串列埠地址(根據平板的說明說填寫) * @param baudrate 波特率(根據對接的硬體填寫 - 硬體說明書上"通訊"中會有標註) * @param dataBits 資料位(根據對接的硬體填寫 - 硬體說明書上"通訊"中會有標註) * @param stopBits 停止位(根據對接的硬體填寫 - 硬體說明書上"通訊"中會有標註) * @param parity 校驗位(根據對接的硬體填寫 - 硬體說明書上"通訊"中會有標註) * @param isRead 是否持續監聽串列埠返回的資料 * @return 是否開啟成功 */ public boolean open(String devicePath, int baudrate, int dataBits, int stopBits, int parity, boolean isRead) { boolean isSucc = false; try { if (mSerialPort != null) close(); File device = new File(devicePath); mSerialPort = SerialPort // 串列埠物件 .newBuilder(device, baudrate) // 串列埠地址地址,波特率 .dataBits(dataBits) // 資料位,預設8;可選值為5~8 .stopBits(stopBits) // 停止位,預設1;1:1位停止位;2:2位停止位 .parity(parity) // 校驗位;0:無校驗位(NONE,預設);1:奇校驗位(ODD);2:偶校驗位(EVEN) .build(); // 開啟串列埠並返回 mInputStream = mSerialPort.getInputStream(); mBuffInputStream = new BufferedInputStream(mInputStream); mOutputStream = mSerialPort.getOutputStream(); isSucc = true; path = devicePath; if (isRead) readData();//開啟識別 } catch (Throwable tr) { close(); isSucc = false; } finally { return isSucc; } } // 讀取資料 private void readData() { if (readTask != null) { readTask.cancel(true); try { Thread.sleep(160); } catch (InterruptedException e) { e.printStackTrace(); } //此處睡眠:當取消任務時 執行緒池已經執行任務,無法取消,所以等待執行緒池的任務執行完畢 readTask = null; } readTask = SerialManage .getInstance() .getScheduledExecutor()//獲取執行緒池 .scheduleAtFixedRate(this, 0, 150, TimeUnit.MILLISECONDS);//執行一個迴圈任務 } @Override//每隔 150 毫秒會觸發一次run public void run() { if (Thread.currentThread().isInterrupted()) return; try { int available = mBuffInputStream.available(); if (available == 0) return; byte[] received = new byte[1024]; int size = mBuffInputStream.read(received);//讀取以下串列埠是否有新的資料 if (size > 0 && serialInter != null) serialInter.readData(path, received, size); } catch (IOException e) { Log.e(TAG, "串列埠讀取資料異常:" + e.toString()); } } /** * 關閉串列埠 */ public void close(){ try{ if (mInputStream != null) mInputStream.close(); }catch (Exception e){ Log.e(TAG,"串列埠輸入流物件關閉異常:" +e.toString()); } try{ if (mOutputStream != null) mOutputStream.close(); }catch (Exception e){ Log.e(TAG,"串列埠輸出流物件關閉異常:" +e.toString()); } try{ if (mSerialPort != null) mSerialPort.close(); mSerialPort = null; }catch (Exception e){ Log.e(TAG,"串列埠物件關閉異常:" +e.toString()); } } /** * 向串列埠傳送指令 */ public void send(final String msg) { byte[] bytes = hexStr2bytes(msg);//字元轉成byte陣列 try { mOutputStream.write(bytes);//通過輸出流寫入資料 } catch (Exception e) { e.printStackTrace(); } } /** * 把十六進位製表示的位元組陣列字串,轉換成十六進位制位元組陣列 * * @param * @return byte[] */ private byte[] hexStr2bytes(String hex) { int len = (hex.length() / 2); byte[] result = new byte[len]; char[] achar = hex.toUpperCase().toCharArray(); for (int i = 0; i < len; i++) { int pos = i * 2; result[i] = (byte) (hexChar2byte(achar[pos]) << 4 | hexChar2byte(achar[pos + 1])); } return result; } /** * 把16進位制字元[0123456789abcde](含大小寫)轉成位元組 * @param c * @return */ private static int hexChar2byte(char c) { switch (c) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'a': case 'A': return 10; case 'b': case 'B': return 11; case 'c': case 'C': return 12; case 'd': case 'D': return 13; case 'e': case 'E': return 14; case 'f': case 'F': return 15; default: return -1; } }
2.)串列埠回撥SerialInter;簡單概括一下這個類,就是將SerialHandle類中產生的結果,返回給上一層的業務程式碼,解偶合
package com.chj233.serialmode.serialUtil; /** * 串列埠回撥 */ public interface SerialInter { /** * 連線結果回撥 * @param path 串列埠地址(當有多個串列埠需要統一處理時,可以用地址來區分) * @param isSucc 連線是否成功 */ void connectMsg(String path,boolean isSucc); /** * 讀取到的資料回撥 * @param path 串列埠地址(當有多個串列埠需要統一處理時,可以用地址來區分) * @param bytes 讀取到的資料 * @param size 資料長度 */ void readData(String path,byte[] bytes,int size); }
3.)串列埠統一管理SerialManage;簡單概括一下這個類,用於管理串列埠的連線以及傳送等功能,尤其是傳送指令,極短時間內傳送多個指令(例如:1毫秒內傳送10個指令),多個指令之間會相互干擾。可能執行了第一個指令,可能一個都沒執行。這個類不是必須的,如果有更好的方法可以自己定義。
package com.chj233.serialmode.serialUtil; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; /** * 串列埠管理類 */ public class SerialManage { private static SerialManage instance; private ScheduledExecutorService scheduledExecutor;//執行緒池 同一管理保證只有一個 private SerialHandle serialHandle;//串列埠連線 傳送 讀取處理物件 private Queue<String> queueMsg = new ConcurrentLinkedQueue<String>();//執行緒安全到佇列 private ScheduledFuture sendStrTask;//迴圈傳送任務 private boolean isConnect = false;//串列埠是否連線 private SerialManage() { scheduledExecutor = Executors.newScheduledThreadPool(8);//初始化8個執行緒 } public static SerialManage getInstance() { if (instance == null) { synchronized (SerialManage.class) { if (instance == null) { instance = new SerialManage(); } } } return instance; } /** * 獲取執行緒池 * * @return */ public ScheduledExecutorService getScheduledExecutor() { return scheduledExecutor; } /** * 串列埠初始化 * * @param serialInter */ public void init(SerialInter serialInter) { if (serialHandle == null) { serialHandle = new SerialHandle(); startSendTask(); } serialHandle.addSerialInter(serialInter); } /** * 開啟串列埠 */ public void open() { isConnect = serialHandle.open("/dev/ttyS1", 9600, true);//設定地址,波特率,開啟讀取串列埠資料 } /** * 傳送指令 * * @param msg */ public void send(String msg) { /* 此處沒有直接使用 serialHandle.send(msg); 方法去傳送指令 因為 某些硬體在極短時間內只能響應一個指令,232通訊一次傳送多個指令會有物理干擾, 讓硬體接收到指令不準確;所以 此處將指令新增到佇列中,排隊執行,確保每個指令一定執行. 若不相信可以試試用serialHandle.send(msg)方法迴圈傳送10個不同的指令,看看10個指令 的執行結果。 */ queueMsg.offer(msg);//向佇列新增指令 } /** * 關閉串列埠 */ public void colse() { serialHandle.close();//關閉串列埠 } //啟動傳送傳送任務 private void startSendTask() { cancelSendTask();//先檢查是否已經啟動了任務 ? 若有則取消 //每隔100毫秒檢查一次 佇列中是否有新的指令需要執行 sendStrTask = scheduledExecutor.scheduleAtFixedRate(new Runnable() { @Override public void run() { if (!isConnect) return;//串列埠未連線 退出 if (serialHandle == null) return;//串列埠未初始化 退出 String msg = queueMsg.poll();//取出指令 if (msg == null || "".equals(msg)) return;//無效指令 退出 serialHandle.send(msg);//傳送指令 } }, 0, 100, TimeUnit.MILLISECONDS); } //取消傳送任務 private void cancelSendTask() { if (sendStrTask == null) return; sendStrTask.cancel(true); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } sendStrTask = null; } }
package com.chj233.serialmode; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import com.chj233.serialmode.serialUtil.SerialInter; import com.chj233.serialmode.serialUtil.SerialManage; public class MainActivity extends AppCompatActivity implements SerialInter { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); SerialManage.getInstance().init(this);//串列埠初始化 SerialManage.getInstance().open();//開啟串列埠 findViewById(R.id.send_but).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { SerialManage.getInstance().send("Z");//傳送指令 Z } }); } @Override public void connectMsg(String path, boolean isSucc) { String msg = isSucc ? "成功" : "失敗"; Log.e("串列埠連線回撥", "串列埠 "+ path + " -連線" + msg); } @Override//若在串列埠開啟的方法中 傳入false 此處不會返回資料 public void readData(String path, byte[] bytes, int size) { // Log.e("串列埠資料回撥","串列埠 "+ path + " -獲取資料" + bytes); } }
串列埠通訊對於Android開發者來說,僅需關注如何連線、操作(傳送指令)、讀取資料;無論是232、485還是422,對於開發者來說連線、操作、讀取程式碼都是一樣的
到此這篇關於Android串列埠通訊SerialPort的使用詳情的文章就介紹到這了,更多相關Android SerialPort內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45