Android開發(fā)板串口(SerialPort)通信

前言:

最近在總是看見有人在群里面問一些串口通信相關(guān)的問題墨技,特別是對于我們這些做APP出生的程序員來說谷朝,初次接觸串口通信的確是會遇到各種Bug,各種摸不著頭腦寄摆。串口通信偏向嵌入式一點喇闸,是Android設(shè)備通過串口與其他設(shè)備進行通信的一種方式逝她,本文介紹的Android純串口的通信浇坐,并不是手機上的USB串口通信。

簡介:

首先簡述一下此項目應(yīng)用黔宛,它是一個簡單的物聯(lián)網(wǎng)智能盒子近刘,主要工作:是通過Android開發(fā)板上的串口進行數(shù)據(jù)讀寫操作。一塊Android開發(fā)板外接一個單片機臀晃,Android上面跑有MQTT服務(wù)與后臺服務(wù)器通信觉渴,Android機收到MQTT發(fā)布的不同信息后,將信息轉(zhuǎn)換成不同的串口指令發(fā)給單片機徽惋,Android板收到對應(yīng)的MQTT消息就做相應(yīng)的界面處理并將MQTT消息轉(zhuǎn)換成不同的串口指令發(fā)給單片機案淋,然后單片機直接控制硬件設(shè)備工作。

一险绘、什么是串口踢京?

串行端口 (SerialPort)簡稱:串口誉碴,主要用于數(shù)據(jù)被逐位按順序傳送的通訊方式稱為串口通訊(簡單來講就是按順序一位一位地傳輸數(shù)據(jù))。

常見的串口有25針和9針(遵循RS-232標準)

二瓣距、串口通信原理

串口通信(Serial Communications)的概念非常簡單黔帕,串口按位(bit)發(fā)送和接收字節(jié)。

串口用于ASCII碼字符的傳輸蹈丸。通信使用3根線完成成黄,分別是地線(GND)、發(fā)送(TX)逻杖、接收(RX)奋岁。由于串口通信是異步的,端口能夠在一根線上發(fā)送數(shù)據(jù)同時在另一根線上接收數(shù)據(jù)荸百。其他線用于握手闻伶,但不是必須的。串口通信最重要的參數(shù)是波特率够话、數(shù)據(jù)位虾攻、停止位和奇偶校驗。對于兩個進行通信的端口更鲁,這些參數(shù)必須匹配。

三奇钞、Android應(yīng)用串口通信的實現(xiàn)

Android SDK并沒有在Framework層實現(xiàn)封裝關(guān)于串口通信的類庫澡为。但是,Android是基于Linux kernel 2.6上的景埃,所以我們可以像在Linux系統(tǒng)上一樣來使用串口媒至。因為Framework層中并沒有封裝關(guān)于串口通信的類庫,所以我們需要通過Android NDK來實現(xiàn)打開谷徙、讀寫串口拒啰,然后提供接口供JAVA本地調(diào)用。

這里可以參照Google已經(jīng)給出了源碼完慧。

這是12年的代碼谋旦,還是Eclipse工程,本文主要介紹如何在Android Studio中使用屈尼。這里先得配置好NDK環(huán)境

1:項目配置

首先看一下項目結(jié)構(gòu):創(chuàng)建了一個jni目錄册着,jni目錄用來放生成的頭文件(.h文件)及Java本地方法的C代碼實現(xiàn)類;

此Demo支持多串口通信

Java層的代碼脾歧,Google已經(jīng)給封裝好了甲捏,主要的都在SerialPort.java

第一步:拷貝創(chuàng)建 native方法的java類 SerialPort.java 到自己的項目中;

第二步:生成.h頭文件; 生成方法有多種鞭执,這里使用 cd \app\src\main\java 進入到j(luò)ava目錄下司顿;

方式1: javah -classpath . -jni? +全限定類名芒粹;

方式2:javah -d ../jni? +全限定類名;(此方式會直接創(chuàng)建一個jni目錄大溜,然后把生成的.h文件存放在目錄里面)

第三步:實現(xiàn)SerialPort.java類中的本地方法化漆,這里直接拷貝Google寫好的C實現(xiàn),將c代碼中的函數(shù)名與生成的頭文件中的函數(shù)名保持一致

配置build.gradle

需要封裝好的aar或jar包猎提,加扣扣


使用

串口作操都封裝到SerialPortUtil類中

```

/**

* Created by 631934797 on 2017/6/18.

*

*串口工具類

*/

public classSerialPortUtil {

private static finalStringTAG= SerialPortUtil.class.getSimpleName();

public staticSerialPortserialPort=null;

public staticInputStreammInputStream=null;

public staticOutputStreammOutputStream=null;

public static booleanflag=false;

private staticBufferedReaderbr;

/**

* 打開串口

*/

public static voidopenSrialPort(String port, intbaudrate){

Log.i(TAG,"打開串口");

try{

serialPort=newSerialPort(newFile("/dev/"+ port),baudrate,0);

//獲取打開的串口中的輸入輸出流获三,以便于串口數(shù)據(jù)的收發(fā)

mInputStream=serialPort.getInputStream();

mOutputStream=serialPort.getOutputStream();

flag=true;

//接收串口數(shù)據(jù)

receiveSerialPort();

}catch(IOException e) {

e.printStackTrace();

}

}

/**

* 接收串口數(shù)據(jù)

*/

public static voidreceiveSerialPort(){

newThread(newRunnable() {

@Override

public voidrun() {

//循環(huán)接收串口數(shù)據(jù)

while(flag) {

try{

if(mInputStream==null)return;

br=newBufferedReader(newInputStreamReader(mInputStream));

String str;

while((str =br.readLine()) !=null)

{

if(TextUtils.isEmpty(str))continue;

Log.i(TAG,"接收串口數(shù)據(jù):"+ str);

if(String.valueOf(str.charAt(0)).equals("{") && str.substring(str.length() -1).equals("}")){

acceptAndNotify(str);

}

}

}catch(Exception e) {

e.printStackTrace();

}

}

}

}).start();

}

/**

* 區(qū)分收到的指令數(shù)據(jù)并分類分發(fā)

*

*@paramjsonBack收到的JSON指令

*/

private static voidacceptAndNotify(String jsonBack) {

if(jsonBack ==null||"".equals(jsonBack.trim()))

throw newIllegalArgumentException("JsonBack is illegal, please check args ... ");

JsonParser jsonParser =newJsonParser();

JsonObject json = (JsonObject) jsonParser.parse(jsonBack);

if(json ==null)

throw newJsonParseException("Json Parse error, please check args ... ");

String protocolResult = json.getAsJsonPrimitive("protocol").getAsString();

if(protocolResult ==null||"".equals(protocolResult))

throw newNumberFormatException("轉(zhuǎn)化錯誤... ");

switch(protocolResult) {

case"coin_in":

//? ? ? ? ? ? ? ? EventBus.getDefault().post(new SerialPortEvent(GsonUtil.parse(jsonBack, CoinAndRemoteCoinBean.class)));

break;

case"remote_coin_in":

//? ? ? ? ? ? ? ? EventBus.getDefault().post(new SerialPortEvent(GsonUtil.parse(jsonBack, CoinAndRemoteCoinBean.class)));

break;

case"key_event":

//? ? ? ? ? ? ? ? EventBus.getDefault().post(new SerialPortEvent(GsonUtil.parse(jsonBack, OrientationAndKeyBean.class)));

break;

}

}

/**

* 發(fā)送串口數(shù)據(jù)

*@paramdata要發(fā)送的數(shù)據(jù)

*/

public static voidsendSerialPort(String data){

Log.i(TAG,"發(fā)送串口數(shù)據(jù):"+ data);

try{

byte[] sendData = data.getBytes();

mOutputStream.write(sendData);

mOutputStream.flush();

Log.i(TAG,"發(fā)送串口數(shù)據(jù)成功!");

}catch(IOException e) {

e.printStackTrace();

Log.i(TAG,"發(fā)送串口數(shù)據(jù)失斚撬铡疙教!");

}

}

/**

*關(guān)閉串口

*關(guān)閉串口中的輸入輸出流

*然后將flag的值設(shè)為flag,終止接收數(shù)據(jù)線程

*/

public static voidcloseSerialPort(){

Log.i(TAG,"關(guān)閉串口");

try{

if(serialPort!=null) {

serialPort.close();

}

if(mInputStream!=null) {

mInputStream.close();

}

if(mOutputStream!=null){

mOutputStream.close();

}

if(br!=null){

br.close();

}

flag=false;

}catch(IOException e) {

e.printStackTrace();

}

}

}

```

本文沒有介紹關(guān)于jni伞租、NDK的內(nèi)容贞谓,因為上網(wǎng)有很講這方面知識講解。如有不了解的請自行百度葵诈、google裸弦。

注意:

不同的開發(fā)板操作的串口路徑是不同的,比如我的開發(fā)板上的串口路徑是“/dev/ttyS5”作喘;還有就是數(shù)據(jù)傳輸?shù)牟ㄌ芈室O(shè)置成一致理疙,不然收到的數(shù)據(jù)會亂碼。??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載泞坦,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者窖贤。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市贰锁,隨后出現(xiàn)的幾起案子赃梧,更是在濱河造成了極大的恐慌,老刑警劉巖豌熄,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件授嘀,死亡現(xiàn)場離奇詭異,居然都是意外死亡锣险,警方通過查閱死者的電腦和手機蹄皱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芯肤,“玉大人夯接,你說我怎么就攤上這事》鬃保” “怎么了盔几?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長掩幢。 經(jīng)常有香客問我逊拍,道長上鞠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任芯丧,我火速辦了婚禮芍阎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘缨恒。我一直安慰自己谴咸,他們只是感情好,可當我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布骗露。 她就那樣靜靜地躺著岭佳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪萧锉。 梳的紋絲不亂的頭發(fā)上珊随,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天,我揣著相機與錄音柿隙,去河邊找鬼叶洞。 笑死,一個胖子當著我的面吹牛禀崖,可吹牛的內(nèi)容都是我干的衩辟。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼波附,長吁一口氣:“原來是場噩夢啊……” “哼惭婿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起叶雹,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎换吧,沒想到半個月后折晦,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡沾瓦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年满着,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贯莺。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡风喇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缕探,到底是詐尸還是另有隱情魂莫,我是刑警寧澤,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布爹耗,位于F島的核電站耙考,受9級特大地震影響谜喊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜倦始,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一斗遏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鞋邑,春花似錦诵次、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至视译,卻和暖如春嬉荆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背酷含。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工鄙早, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人椅亚。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓限番,卻偏偏與公主長得像,于是被迫代替她去往敵國和親呀舔。 傳聞我的和親對象是個殘疾皇子弥虐,可洞房花燭夜當晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容

  • _ 聲明: 對原文格式以及內(nèi)容做了細微的修改和美化, 主要為了方便閱讀和理解 _ 一. 基礎(chǔ) Java Nativ...
    元亨利貞o閱讀 5,916評論 0 34
  • 1 進程啟動過程 Android應(yīng)用程序框架層創(chuàng)建的應(yīng)用程序進程具有兩個特點,一是進程的入口函數(shù)是Activit...
    Kevin_Junbaozi閱讀 3,848評論 0 23
  • 在不久前媚赖,接觸到了物聯(lián)網(wǎng)的開發(fā)霜瘪,當時一臉懵逼了,后來問了度娘和有幸遇到大神的指導(dǎo)惧磺,最終實現(xiàn)了功能颖对。 首先先弄懂跟硬...
    Orz013閱讀 4,473評論 0 2
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 3,810評論 0 11
  • 先說我的應(yīng)用場景,一塊帶串口的android板子跟一個外設(shè)通過串口直接通信磨隘,控制這個外設(shè)的啟停缤底。如圖1(公司規(guī)定不...
    Q1an閱讀 7,281評論 0 11