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已经给出了源码。

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

1:项目配置

首先看一下项目结构:创建了一个jni目录,jni目录用来放生成的头文件(.h文件)及Java本地方法的C代码实现类;

此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文件存放在目录里面)

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

配置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);

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

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”;还有就是数据传输的波特率要设置成一致,不然收到的数据会乱码。  

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容

  • _ 声明: 对原文格式以及内容做了细微的修改和美化, 主要为了方便阅读和理解 _ 一. 基础 Java Nativ...
    元亨利贞o阅读 5,800评论 0 34
  • 1 进程启动过程 Android应用程序框架层创建的应用程序进程具有两个特点,一是进程的入口函数是Activit...
    Kevin_Junbaozi阅读 3,798评论 0 22
  • 在不久前,接触到了物联网的开发,当时一脸懵逼了,后来问了度娘和有幸遇到大神的指导,最终实现了功能。 首先先弄懂跟硬...
    Orz013阅读 4,238评论 0 2
  • 一. Java基础部分.................................................
    wy_sure阅读 3,731评论 0 11
  • 先说我的应用场景,一块带串口的android板子跟一个外设通过串口直接通信,控制这个外设的启停。如图1(公司规定不...
    Q1an阅读 7,101评论 0 11