前言:

最近在总是看见有人在群里面问一些串口通信相关的问题,特别是对于我们这些做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目录,jni目录用来放生成的头文件(.h文件)及Java本地方法的C代码实现类;

Android开发板串口(SerialPort)通信_第1张图片 此Demo支持多串口通信

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

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

第二步:生成.h头文件; 生成方法有多种,这里使用 cd \app\src\main\java 进入到java目录下;

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

方式2:javah -d ../jni  +全限定类名;(此方式会直接创建一个jni目录,然后把生成的.h文件存放在目录里面)

Android开发板串口(SerialPort)通信_第2张图片

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

Android开发板串口(SerialPort)通信_第3张图片

配置build.gradle

Android开发板串口(SerialPort)通信_第4张图片

如需帮助请 + 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)通信_第5张图片 觉得有帮助,可以给作者发红包

更多相关文章

  1. Android中的Http通信(三)之get、post传递参数到服务器
  2. Android Studio利用异步任务AsyncTask发送post请求获取json数据
  3. Android通过JSON数据格式和java服务后台进行数据交互
  4. Android (安卓数据的五种存储方式)

随机推荐

  1. Android,谁动了我的内存(1)
  2. Android组件及UI框架大全
  3. Activity and Task(二)
  4. 图解Android中的Binder机制
  5. Android图像处理简介の使用内置Camera应
  6. 关于Scroller ,scrollTo,scrollBy
  7. Android(安卓)RSA与Java RSA加密不同标准
  8. 玩Android的第一天
  9. android中定时开关机的实现
  10. Android学习心得之二——Android系统架构