Android开发板串口(SerialPort)通信

前言:

最近在总是看见有人在群里面问一些串口通信相关的问题,特别是对于我们这些做APP出生的程序员来说,初次接触串口通信的确是会遇到各种Bug,各种摸不着头脑。串口通信偏向嵌入式一点,是Android设备通过串口与其他设备进行通信的一种方式,本文介绍的Android纯串口的通信,并不是手机上的USB串口通信。

简介:

首先简述一下此项目应用,它是一个简单的物联网智能盒子,主要工作:是通过Android开发板上的串口进行数据读写操作。一块Android开发板外接一个单片机,Android上面跑有MQTT服务与后台服务器通信,Android机收到MQTT发布的不同信息后,将信息转换成不同的串口指令发给单片机,Android板收到对应的MQTT消息就做相应的界面处理并将MQTT消息转换成不同的串口指令发给单片机,然后单片机直接控制硬件设备工作。

一、什么是串口?

串行端口 (SerialPort)简称:串口,主要用于数据被逐位按顺序传送的通讯方式称为串口通讯(简单来讲就是按顺序一位一位地传输数据)。

常见的串口有25针和9针(遵循RS-232标准)

二、串口通信原理

串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节。

串口用于ASCII码字符的传输。通信使用3根线完成,分别是地线(GND)、发送(TX)、接收(RX)。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。其他线用于握手,但不是必须的。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通信的端口,这些参数必须匹配。

三、Android应用串口通信的实现

Android SDK并没有在Framework层实现封装关于串口通信的类库。但是,Android是基于Linux kernel 2.6上的,所以我们可以像在Linux系统上一样来使用串口。因为Framework层中并没有封装关于串口通信的类库,所以我们需要通过Android NDK来实现打开、读写串口,然后提供接口供JAVA本地调用。

这里可以参照Google已经给出了源码,地址在GitHub android-serialport-api 

这是12年的代码,还是Eclipse工程,本文主要介绍如何在Android Studio中使用。这里先得配置好NDK环境 

1:项目配置

首先看一下项目结构:创建了一个jni和jniLibs两个包,jni包用来放生成的头文件(.h文件)及Java本地方法的C代码实现类;jniLibs包用来放不同abi体系的so库

《Android开发板串口(SerialPort)通信》

Java层的代码,Google已经给封装好了,主要的都在 SerialPort.java

第一步:拷贝创建 native方法的java类 SerialPort.java 到自己的项目中;

第二步:生成.h头文件; 生成方法有多种,这里使用 cd \app\src\main\java 进入到java目录下,然后 javah -classpath . -jni  +全限定类名

《Android开发板串口(SerialPort)通信》

第三步:实现SerialPort.java类中的本地方法,这里直接拷贝Google写好的C实现,将c代码中的函数名与生成的头文件中的函数名保持一致

《Android开发板串口(SerialPort)通信》

配置build.gradle

《Android开发板串口(SerialPort)通信》

如需帮助请加QQ:631934797   与我联系

使用

串口作操都封装到SerialPortUtil类中

/**

* Created by Roy88 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);

//获取打开的串口中的输入输出流,以便于串口数据的收发

mInputStream=serialPort.getInputStream();

mOutputStream=serialPort.getOutputStream();

flag=true;

//接收串口数据

receiveSerialPort();

}catch(IOException e) {

e.printStackTrace();

}

}

/**

* 接收串口数据

*/

public static voidreceiveSerialPort(){

newThread(newRunnable() {

@Override

public voidrun() {

//循环接收串口数据

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,”接收串口数据:”+ str);

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

acceptAndNotify(str);

}

}

}catch(Exception e) {

e.printStackTrace();

}

}

}

}).start();

}

/**

* 区分收到的指令数据并分类分发

*

*@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(“转化错误… “);

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;

}

}

/**

* 发送串口数据

*@paramdata要发送的数据

*/

public static voidsendSerialPort(String data){

Log.i(TAG,”发送串口数据:”+ data);

try{

byte[] sendData = data.getBytes();

mOutputStream.write(sendData);

mOutputStream.flush();

Log.i(TAG,”发送串口数据成功!”);

}catch(IOException e) {

e.printStackTrace();

Log.i(TAG,”发送串口数据失败!”);

}

}

/**

*关闭串口

*关闭串口中的输入输出流

*然后将flag的值设为flag,终止接收数据线程

*/

public static voidcloseSerialPort(){

Log.i(TAG,”关闭串口”);

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

}

}

}

本文没有介绍关于jni、NDK的内容,因为上网有很讲这方面知识讲解。如有不了解的请自行百度、google。

注意:

不同的开发板操作的串口路径是不同的,比如我的开发板上的串口路径是“/dev/ttyS5”;还有就是数据传输的波特率要设置成一致,不然收到的数据会乱码。

如需帮助请加QQ:631934797   与我联系

《Android开发板串口(SerialPort)通信》 觉得有帮助,可以给作者发红包

    原文作者:Roy88
    原文地址: https://www.jianshu.com/p/8394d2b3384f
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞