Android 串口通信开发总结和实例解析
文章目录
- 前言
- 一、串口通信是什么?
- 1.概念
- 2.通讯方式
- 3.接口外观
- 二、使用步骤
- 1.准备
- 2.使用
- 2.解析案例
- 总结
前言
之前遇到的关于硬件需求的厂家一般会提供jar包调用。一直没搞过直接和硬件通信的这种直接用二进制十六进制通讯的需求,最近有空了记录一下。一方面记录和总结一下自己的学习成果,另一方面整理好了自己参考的各位大佬的一部分有用的知识,希望可以帮当有需要的人
其实这东西一开始不会的时候感觉一看就摸不着头脑,弄清楚之后基本道理也就那样,没什么复杂的,只不过就是像解析JSON一样 道理都是一样的。
一般这种硬件通信的也就是两种:
1 串口通信
2 USB通信(传送门)
提示:以下是本篇文章正文内容,下面案例可供参考
一、串口通信是什么?
1.概念
先来看一下百度百科的介绍
串口即串行接口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口。串行接口 (Serial Interface) 是指数据一位一位地顺序传送,其特点是通信线路简单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成本,特别适用于远距离通信,但传送速度较慢。
其实就是:数据是意味一位顺序传输,总是以“起始位”开始,以“停止位”结束,字符之间没有固定的时间间隔要求,而且进行传输之前,双方一定要使用同一个波特率。
2.通讯方式
通讯方式一般有三种:
单工模式:一根线只用于发送或者接收数据
双工模式:一根线既能发送也能接收数据,但是不能同时进行
全双工模式:相当于两个单工模式,两根线,一个发送一个接收,同样不能同时发送接收。这种传输效率比较高。比如RS-232通讯就是采用这种模式
接口外观
3.接口外观
串口设备的外观有很多种,下面是其中一个。
这里引用一位博主的照片
这篇博文写的也不错
对于不同的厂家,其外形接口可能不一致,但是对于我们来说,并无大碍,因为不管它怎么变化,只是针对硬件接线的问题,相对我们做上层应用,没什么影响的。我们只需要关注数据的发送和收到数据如何解析就可以了。
链接在这里
https://blog.csdn.net/qq_36270361/article/details/105405075
二、使用步骤
1.准备
在Android中,我们可以调用Unix的动态连接库(.so扩展名文件)来集成串口通信,这种调用的方式称为JNI(Java Native Interface,即Java本地接口)。
Google安卓官方已经提供了android-serialport-api 官方API
有兴趣的可以去了解一下,不过不推荐直接用这个,虽然是硬件的东西不怎么变但是都是九年前的代码了,再去集成也很麻烦。
大家用的基本都是另一个库,Android-Serialport,看一下介绍
移植谷歌官方串口库android-serialport-api,仅支持串口名称及波特率,该项目添加支持校验位、数据位、停止位、流控配置项
支持粘包处理
所以,放心用就是了,只是对谷歌的api进行的封装
用的时候自己去Github去拿最新版
Github地址
implementation 'tp.xmaihh:serialport:2.1'
对了有一个很少人提到的但是新手不知道的
搞串口的前提是要有ROOT权限!!
搞串口的前提是要有ROOT权限!!
搞串口的前提是要有ROOT权限!!
或者找厂家要要系统签名作为系统应用
可以参考我的另一个文章
Android 生成系统签名keystore 并添加到已有keystore 方便Gradle命令多渠道打包
2.使用
首先你需要两个参数,找你的硬件厂家要
1波特率
2串口地址
因为java和kotlin的项目都用到了我都贴出了
Java:
private SerialHelper serialHelper;private void initQrCodeSerialPort() {//参数:1。串口地址2波特开车serialHelper = new SerialHelper("/dev/ttyS1", 9600) {@Overrideprotected void onDataReceived(ComBean paramComBean) {//子线程操作 解析数据//返回数据byte[] bRec = paramComBean.bRec;//解析方法设备不同所以逻辑不同,具体根据厂家沟通和说明文档来写下面有例子};try {serialHelper.open();} catch (IOException e) {Logger.e(e, "二维码串口打开失败");}}
在Activcity/Fragment/Services销毁的对应的方法里去关闭,否则内存泄漏
@Overridepublic void onFinish() {super.onFinish();if (serialHelper != null) {serialHelper.close();}}
Kotlin
lateinit var serialHelper: SerialHelperprivate fun initScanner() {serialHelper = object : SerialHelper("/dev/ttyS1", 9600) {override fun onDataReceived(paramComBean: ComBean) {//子线程操作 解析数据//返回的数据val list = paramComBean.bRec//解析方法设备不同所以逻辑不同,具体根据厂家沟通和说明文档来写下面有例子 }}try {serialHelper.open()} catch (e: IOException) {XLog.e("扫码器串口打开失败", e)}}//销毁方法override fun release() {super.release()if (::connection.isInitialized) {connection.close()}}
收到这个方法回调的前提是要先发,才会收到
如果你没收到回调,如果你ROOT权限有了,要么你没打开成功,要么你没发送或者发送的不对,如果没有就看上面
发送数据
Java
serialHelper.send(new byte[]{0x00, 0x63, 0x06, 0x03, 0x6C});
Kotlin
balanceSerialPort.send(byteArrayOf(0x00, 0x63, 0x06, 0x03, 0x6C))
2.解析案例
这里用自己项目里的一个需求作为例子吧
这是一个电子秤的串口解析,看文档对发送和接收数据格式的说明
这个文档的通讯协议是厂家自己取的,可以看做一个简化版的ModeBus通讯协议,不过原理都是一样的,看这个更方便理解一些。看懂这个了以后够用看都其他的协议了
图1
这里得知,数据采用的是十六进制
收,发的数据的格式都是相同的,都是可以分为五部分的十六进制数组,
第一部分一个字节的地址码
第二部分第三部分根据需求不同 值不同 但是都是一个字节的十六进制数
从第四部分开始就是我们需要的数据,所以整个数组长度不固定
最后一位是垂直校验码
垂直校验码的格式=前面的所有数相加
这里就可以看出这个校验码的作用可以用来验证拿到的这个数据是不是完整的
图2
这是关于发送R类型的消息,和W类型消息返回的数据的说明
和上面说的相同,按结构仍然可以分为五部分 信息码可以理解为数据域的另一个称呼
所以还是那五个部分
1发送消息的时候不论是哪一种命令第一位地址码都是固定的,地址码是用来验证过滤是不是我们要收到的,只有发出的和收到的相同的才是我们需要的,这个设备的地址码是0
我只是要称重,因此发送的消息类型是读 R
得知发出的数组[0x00,0x05,寄存器地址暂时不知道,0x05,前面的相加]
收到的数组应该是[0x00(相同),0x06(上面的+1),寄存器地址暂时不知道,0x05,前面的相加]
继续向下果然看到 这里的分度就是重量
寄存器地址就是02
因此发出称重命令的数组如下
balanceSerialPort.send(byteArrayOf(0x00, 0x05, 0x02, 0x05, 0x0C))
最后一位0x0C 是垂直校验码,前面的图1说了 他的值等于0x00+0x05+0x02+0x05的和
看上图返回的收到的数据果然不出所料也是[0x00,0x06,0x02,数据域,校验码]
这里贴出一个ASCLL码表供大家参考 或者自己去网上搜了十六进制在线转十进制相加
https://blog.csdn.net/ttmice/article/details/50978054?spm=1001.2014.3001.5506
处理数据就是就是看数据域的这五位St X4,X3 C2 X1
St为状态
X4是分度值代号 就是 精度
定义一个map去取值相乘就是了
X3 X2 X1是重量的三位 不过是二进制的 可以理解为十位百位千位
然后是需要判断状态是不是对的, 文档没有说明。和厂家沟通得知St转为二进制数后,第六位如果是1,则为有效称重
接下来就很容易了 上完整代码
balanceSerialPort = object : SerialHelper(("/dev/ttyS4"), 19200) {override fun onDataReceived(paramComBean: ComBean) {runOnUiThread {logContent.append("收到返回数据\n")if (!isResetWeight) {//把原始返的byte[]变int[]//那为什么要转十进制再移位计算呢?因为厂家返回的[5][6][7]位置是这样的// 不如重量121,下面三行对应的是[5][6][7]位置// 0000000010000000000000000// 0000000000000000200000000// 0000000000000000000000001val list = paramComBean.bRec.map { it.toInt().and(0xFF) }//过滤是功能码05和寄存器02返回的才是我要的//0是地址码1号位是功能码2是寄存器3是状态St4分度值代号(就是精度)if (list[1] == 0x05 + 1 && list[2] == 0x02) {//状态转二进制val state = list[3].toString(2).padStart(8, '0')//分度值代号 val divisionCode = list[4]//根据代号取定义好的Map取精度val division = divisionMap.getValue(divisionCode)//S1 S2 S3计算相加乘以精度 endval weight =(list[5].shl(8 * 2) + list[6].shl(8 * 1) + list[7].shl(8 * 0)) * division * 1000//状态第六位是1为有效数据 计算if (state[6] == '1') {logContent.append("当前重量:$weight g\n")} else {logContent.append("未能获取重量!\n")}} else {logContent.append("未能获取重量\n")}}refreshLog(logContent);}}
}
总结
其实上面的关于数据域的解析根据业务需求是变的,但是道理都是一样的。这个协议也是同样的道理,主流的ModBus协议是在数据域有开始和结束符,用来更精准的解决粘包问题的,校验符也是两个字节,功能码也不只是两种,需要按需求选,数据也不一定是十六进制,可以是ASCII码。
到时基本都是换汤不换药原理都一样,一个懂了就都懂了!
Android 串口通信开发总结和实例解析相关推荐
- Android串口通信实例分析【附源码】
Android 串口通信实例分析,用的时开源的android-serialport-api 这个是用android ndk实现的串口通信,我把他做了一个简化,适合于一般的程序的串口通信移植,欢迎拍砖- ...
- delphi android 蓝牙,Android实例-Delphi开发蓝牙官方实例解析(XE10+小米2+小米5)
[实例简介] 2.保证无毒 3.简单,方便,实用 4.实例可以自行改用 5.如有非法,本人无法律责任,由改动代码人负责! 6.需要更多本人作品,查找标签"朱建强" 7.请下载,杀毒 ...
- android串口通信——电子扫描枪
android串口通信--电子扫描枪 我们这里开始介绍电子扫描枪(串口的),在开发中我们可能用到电子扫描枪这么一个玩意.比如,我们在做一个可以说扫描条码的app的时候,就会用到,这种情况一般都是运行 ...
- CH340与Android串口通信
CH340与Android串口通信 为何要将CH340的ATD+Eclipse上的安卓工程移植到AndroidStudio 移植的具体步骤 CH340串口通信驱动函数 通信过程中重难点 还存在的问题 ...
- android串口通信——身份证识别器
android串口通信身份证识别器 一身份证识别器基础 调用身份证识别器的步骤 波特率 基本指令 身份证信息结构 文字结构说明 民族代码对照表 性别代码对照表 二身份证的读取 读取的方法调用 身份证的 ...
- modbus协议使用【android串口通信】
modbus协议使用[android串口通信] 本文的目的是android端与上位机之间使用modbus协议进行串口通信.通过串口与其他设备进行通信,传递数据.可以理解为电脑和键盘.鼠标通信. 关于m ...
- Android串口通信apk源码
1.SerialPortHelper「Android串口通信」介绍 原项目地址 https://github.com/freyskill/SerialPortHelper Android串口通讯助手可 ...
- 串口通信工具android,Android串口通信工具
Android串口通信简单封装,可以用于和连接串口的硬件通信或者进行硬件调试 集成方法: Step 1. Add the JitPack repository to your build file / ...
- Android 蓝牙通信开发
Android 蓝牙通信开发 Receiver的设置 一.Receiver1(蓝牙状态的改变通过广播接收) 二.Receiver2(蓝牙搜索到设备.绑定设备(配对)通过广播接收) 服务端代码 客户端代 ...
最新文章
- 谈谈弹性Web托管的“弹性”
- python增量赋值是什么_python学习记录20190122_增量赋值
- 25个出众的Web表单范例
- nutch开发(六)
- 解决opencv在pycharm中无代码自动提示的bug
- 太原理工微型计算机控制试卷,太原理工大学微机原理考试(13届葬仪落整理).docx...
- python中函数startswith的用法_Python中用startswith()函数判断字符串开头的教程
- (83)建立时间与保持时间时序分析技巧
- 功夫小子实践开发-游戏设置功能的实现
- 加速求解两个矩阵任意两行之间的pearson相关性
- 天津麒麟收购中标软件,国产操作系统新旗舰扬帆起航!
- 新元宇宙奇科幻小说每周连载《地球人奇游天球记》第十二回金星挖矿
- Sqoop 使用详解
- 数据中心机房有哪些等级,国内外的评级标准?
- Oracle关于分组小计再合计
- Codeforces Round #784 (Div. 4)#蒻枸题解
- JavaScript|JavaScript 高级语法——详细汇总
- 理解sklearn.processing.scale中使用有偏总体标准差
- 2.8w即可拥有仿拼多多商城APP
- 百度云非 VIP如何作弊加速?