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

前言:

最近在總是看見有人在群里面問(wèn)一些串口通信相關(guān)的問(wèn)題,特別是對(duì)于我們這些做APP出生的程序員來(lái)說(shuō),初次接觸串口通信的確是會(huì)遇到各種Bug,各種摸不著頭腦。串口通信偏向嵌入式一點(diǎn),是Android設(shè)備通過(guò)串口與其他設(shè)備進(jìn)行通信的一種方式,本文介紹的Android純串口的通信,并不是手機(jī)上的USB串口通信。

簡(jiǎn)介:

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

一、什么是串口?

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

常見的串口有25針和9針(遵循RS-232標(biāo)準(zhǔn))

二、串口通信原理

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

串口用于ASCII碼字符的傳輸。通信使用3根線完成,分別是地線(GND)、發(fā)送(TX)、接收(RX)。由于串口通信是異步的,端口能夠在一根線上發(fā)送數(shù)據(jù)同時(shí)在另一根線上接收數(shù)據(jù)。其他線用于握手,但不是必須的。串口通信最重要的參數(shù)是波特率、數(shù)據(jù)位、停止位和奇偶校驗(yàn)。對(duì)于兩個(gè)進(jìn)行通信的端口,這些參數(shù)必須匹配。

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

Android SDK并沒(méi)有在Framework層實(shí)現(xiàn)封裝關(guān)于串口通信的類庫(kù)。但是,Android是基于Linux kernel 2.6上的,所以我們可以像在Linux系統(tǒng)上一樣來(lái)使用串口。因?yàn)镕ramework層中并沒(méi)有封裝關(guān)于串口通信的類庫(kù),所以我們需要通過(guò)Android NDK來(lái)實(shí)現(xiàn)打開、讀寫串口,然后提供接口供JAVA本地調(diào)用。

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

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

1:項(xiàng)目配置

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

此Demo支持多串口通信

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

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

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

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

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

第三步:實(shí)現(xiàn)SerialPort.java類中的本地方法,這里直接拷貝Google寫好的C實(shí)現(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)化錯(cuò)誤... ");

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();

}

}

}

```

本文沒(méi)有介紹關(guān)于jni、NDK的內(nèi)容,因?yàn)樯暇W(wǎng)有很講這方面知識(shí)講解。如有不了解的請(qǐng)自行百度、google。

注意:

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。

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

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