Android - 串口通讯(SerialPort)
最早的博客Android 模拟串口通信过程_launch virtual serial port driver pro-CSDN博客里就是用过 Google 提供的 demo,最近想再写个其他的demo发现用起来有点麻烦,还需要导入其他 module,因此在网上找到了Android-SerialPort-API: https://github.com/licheedev/Android-SerialPort-API.git 也是Fork自Google开源的Android串口通信Demo。
话不多说,直接开搞。
目录
一、简单说明
1、添加依赖
2、创建串口通讯工具类 SerialPortUtil
3、示例 MainActivity
4、通过logcat验证app
二、注意
三、总结
四、demo地址
一、简单说明
1、添加依赖
dependencies {...//添加依赖implementation ("com.licheedev:android-serialport:2.1.3")}
2、创建串口通讯工具类 SerialPortUtil
class SerialPortUtil {companion object {private const val TAG = "SerialPortUtil"val sInstances by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {SerialPortUtil()}}private lateinit var mIOpenSerialPortListener: IOpenSerialPortListenerprivate lateinit var mISerialPortDataListener: ISerialPortDataListenerprivate lateinit var mSendingHandlerThread: HandlerThreadprivate lateinit var mSendingHandler: Handlerprivate lateinit var mSerialPortReceivedThread: SerialPortReceivedThreadprivate lateinit var mFileInputStream: FileInputStreamprivate lateinit var mFileOutputStream: FileOutputStreamprivate lateinit var serialPort: SerialPort/*** 打开串口方法*/fun open(path: File) {try {serialPort = SerialPort.newBuilder(path, 9600) // 校验位;0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN).build()mFileInputStream = serialPort.inputStream as FileInputStreammFileOutputStream = serialPort.outputStream as FileOutputStream} catch (e: SecurityException) {mIOpenSerialPortListener.onFail(path, Status.NO_READ_WRITE_PERMISSION)return} catch (e: Exception) {mIOpenSerialPortListener.onFail(path, Status.OPEN_FAIL)return}mIOpenSerialPortListener.onSuccess(path)startSendThread()startReceivedThread()}/*** 发送数据*/fun sendBytes(bytes: ByteArray?): Boolean {try {Runnable {val message = Message.obtain()message.obj = bytesmSendingHandler.sendMessage(message)Thread.sleep(100)}.run()} catch (e: Exception) {Log.e(TAG, "sendBytes: 发送数据失败 " + e.message)return false}return true}/*** 开启发送消息线程*/private fun startSendThread() {Log.d(TAG, "startSendThread: 开启发送消息线程")mSendingHandlerThread = HandlerThread("mSendingHandlerThread")mSendingHandlerThread.start()mSendingHandler = object : Handler(mSendingHandlerThread.looper) {override fun handleMessage(msg: Message) {val sendBytes: ByteArray? = msg.obj as ByteArray?if ((null != sendBytes) && (sendBytes.isNotEmpty())) {try {mFileOutputStream.write(sendBytes)mISerialPortDataListener.onDataSend(sendBytes)} catch (e: java.io.IOException) {e.printStackTrace()}}}}}/*** 停止发送消息线程*/fun stopSendThread() {Log.d(TAG, "stopSendThread: 停止发送消息线程")mSendingHandlerThread.interrupt()mSendingHandlerThread.quit()}/*** 开启接收消息的线程*/private fun startReceivedThread() {Log.d(TAG, "startReceivedThread: 开启接受消息线程")mSerialPortReceivedThread = object : SerialPortReceivedThread(mFileInputStream) {override fun onDataReceived(bytes: ByteArray?) {mISerialPortDataListener.onDataReceived(bytes)}}mSerialPortReceivedThread.start()}/*** 停止接收消息的线程*/fun stopReceivedThread() {Log.d(TAG, "stopReceivedThread: 停止接收消息的线程")mSerialPortReceivedThread.release()serialPort.tryClose()}/*** 设置串口打开的监听*/fun setIOpenSerialPortListener(iOpenSerialPortListener: IOpenSerialPortListener) {mIOpenSerialPortListener = iOpenSerialPortListener}/*** 设置串口数据收发的监听*/fun setISerialPortDataListener(iSerialPortDataListener: ISerialPortDataListener) {mISerialPortDataListener = iSerialPortDataListener}}
在这里简单介绍些,在开启串口通讯后开启两个线程,分别处理send及received步骤。
3、示例 MainActivity
class MainActivity : Activity(), IOpenSerialPortListener, ISerialPortDataListener {companion object {private const val TAG = "MainActivity"private val FIND_CARD =byteArrayOf(0x20, 0x00, 0x80.toByte(), 0x04, 0x03, 0x03, 0x01, 0x00, 0x7a, 0x03)}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)CrashHandler.sInstance.init(this)//0、设置su位置SerialPort.setSuPath("/system/xbin/su")//1、首先设置open监听SerialPortUtil.sInstances.setIOpenSerialPortListener(this)//2、设置串口监听SerialPortUtil.sInstances.setISerialPortDataListener(this)//3、open串口SerialPortUtil.sInstances.open(File("/dev/ttyS3"))//4、模拟发送命令SerialPortUtil.sInstances.sendBytes(FIND_CARD)}override fun onDestroy() {super.onDestroy()SerialPortUtil.sInstances.stopSendThread()SerialPortUtil.sInstances.stopReceivedThread()}override fun onSuccess(device: File?) {Log.d(TAG, "onSuccess: open成功")}override fun onFail(device: File?, status: Status?) {Log.d(TAG, "onFail: open失败,原因: $status")}override fun onDataReceived(bytes: ByteArray?) {Log.d(TAG, "onDataReceived: 接受数据: " + Arrays.toString(bytes))}override fun onDataSend(bytes: ByteArray?) {Log.d(TAG, "onDataSend: 发送数据: " + Arrays.toString(bytes))}}
4、通过logcat验证app
09:52:48.349 serial_port D Opening serial port /dev/ttyS3 with flags 0x2
09:52:48.349 serial_port D open() fd = 45
09:52:48.349 serial_port D Configuring serial port
09:52:48.359 MainActivity D onSuccess: open成功
09:52:48.359 SerialPortUtil D startSendThread: 开启发送消息线程
09:52:48.359 SerialPortUtil D startReceivedThread: 开启接受消息线程
09:52:48.359 SerialPortReceivedThread I run: available = 0
09:52:48.359 MainActivity D onDataSend: 发送数据: [32, 0, -128, 4, 3, 3, 1, 0, 122, 3]
09:52:48.529 BufferQueue E [com.lichang.source/com.lichang.source.MainActivity] connect: already connected (cur=1, req=1)
09:52:48.529 mali_winsys D EGLint new_window_surface(egl_winsys_display*, void*, EGLSurface, EGLConfig, egl_winsys_surface**, egl_color_buffer_format*, EGLBoolean) returns 0x3000
09:52:48.529 OpenGLRenderer D Enabling debug mode 0
09:52:51.609 SerialPortReceivedThread I run: size = 14
09:52:51.609 SerialPortReceivedThread I run: bytes = [32, 0, 0, 8, 4, 0, 8, 4, 28, 37, -117, -5, -74, 3]
09:52:51.609 MainActivity D onDataReceived: 接受数据: [32, 0, 0, 8, 4, 0, 8, 4, 28, 37, -117, -5, -74, 3]
09:52:51.609 SerialPortReceivedThread I run: available = 0
09:52:53.729 SerialPortReceivedThread I run: size = 22
09:52:53.729 SerialPortReceivedThread I run: bytes = [32, 0, 0, 16, 32, 17, 35, 69, 103, -113, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, 3]
09:52:53.729 MainActivity D onDataReceived: 接受数据: [32, 0, 0, 16, 32, 17, 35, 69, 103, -113, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, 3]
09:52:53.729 SerialPortReceivedThread I run: available = 0
09:53:03.239 dalvikvm D Debugger has detached; object registry had 1 entries
09:53:03.249 dalvikvm D GC_CONCURRENT freed 222K, 15% free 2334K/2744K, paused 1ms+1ms, total 12ms
09:53:12.419 SerialPortUtil D stopSendThread: 停止发送消息线程
09:53:12.419 SerialPortUtil D stopReceivedThread: 停止接收消息的线程
09:53:12.419 serial_port D close(fd = 45)
二、注意
为了在Android上读/写串行端口,你需要在设备上安装su binary(这可以通过root设备来完成)。通常,具有串口通信能力的Android设备已将su安装在默认路径下。
默认的 su 路径使用的是 “/system/bin/su”
三、总结
在新项目中快速应用,可以先导入依赖,然后copy示例中的 com/lichang/source/serialport文件夹,即可按照 3、示例 MainActivity 钓箱串口工具类。
四、demo地址
serialport-demo_kt: 使用 implementation ("com.licheedev:android-serialport:2.1.3")
相关文章:
Android - 串口通讯(SerialPort)
最早的博客Android 模拟串口通信过程_launch virtual serial port driver pro-CSDN博客里就是用过 Google 提供的 demo,最近想再写个其他的demo发现用起来有点麻烦,还需要导入其他 module,因此在网上找到了Android-SerialPort-API: https://g…...
如何使用設置靜態住宅IP
靜態住宅IP就是一種靜態的、分配給住宅用戶的IP地址。與動態IP地址不同,靜態住宅IP一旦分配給用戶,就會一直保持不變,除非ISP(Internet Service Provider,互聯網服務提供商)進行手動更改。那麼,…...
在学习爬虫前的准备
1. 写一个爬虫程序需要分几步 获取网页内容。 我们会通过代码给一个网站服务器发送请求,它会返回给我们网页上的内容。 在我们平时使用浏览器访问服务器内容是,本质上也是向服务器发送一个请求,然后服务器返回网页上的内容。只不过浏览器还会…...
windows下安装oracle-win-64-11g超详细图文步骤
官方下载地址:点这里 1.根据自己电脑情况,解压64或者32位客户端,以及database压缩包 2.解压后双击执行database文件夹下的setup.exe 3.详细的安装步骤 (1)数据库安装 一、配置安全更新 电子邮件可写可不写…...
Go模板后端渲染时vue单页面冲突处理
go后端模版语法是通过 {{}} ,vue也是通过双花括号来渲染的,如果使用go渲染vue的html页面的时候就会报错,因为分别不出来哪个是vue的,哪个是go的,既可以修改go的模板语法 template.New("output").Delims(&qu…...
笔记本摄像头模拟监控推送RTSP流
使用笔记本摄像头模拟监控推送RTSP流 一、基础安装软件准备 本文使用软件下载链接:下载地址 FFmpeg软件: Download ffmpeg 选择Windows builds by BtbN 一个完整的跨平台解决方案,用于录制、转换和流式传输音频和视频。 EasyDarwin软件:Download Easy…...
鸿蒙开发已解决-ArkTS编译时遇到arkts-no-obj-literals-as-types错误
文章目录 项目场景:问题描述原因分析:解决方案:解决方案1解决方案2此Bug解决方案总结项目场景: 在开发鸿蒙项目过程中,遇到了arkts-no-obj-literals-as-types,总结了自己和网上人的解决方案,故写下这篇文章。 遇到问题: rkTS编译时遇到arkts-no-obj-literals-as-type…...
实现目标检测中的数据格式自由(labelme json、voc、coco、yolo格式的相互转换)
在进行目标检测任务中,存在labelme json、voc、coco、yolo等格式。labelme json是由anylabeling、labelme等软件生成的标注格式、voc是通用目标检测框(mmdetection、paddledetection)所支持的格式,coco是通用目标检测框࿰…...
一文读懂JVS逻辑引擎如何调用规则引擎:含详细步骤与场景示例
在当今的数字化时代,业务逻辑和规则的复杂性不断增加,这使得逻辑引擎和规则引擎在处理业务需求时显得尤为重要。逻辑引擎和规则引擎通过定义、解析和管理业务逻辑和规则,能够帮助企业提高工作效率、降低运营成本,并增强决策的科学…...
苹果应用上架是否需要软件著作权?
苹果应用上架是否需要软件著作权? 摘要 随着移动互联网的发展,苹果应用在市场上占据了很大份额。但是,很多开发者在上传苹果应用到App Store时,都会遇到一个问题,即是否需要进行软著申请?本文将深入探讨这…...
LDD学习笔记 -- Linux字符设备驱动
LDD学习笔记 -- Linux字符设备驱动 虚拟文件系统 VFS设备号相关Kernel APIs动态申请设备号动态创建设备文件内核空间和用户空间的数据交换系统调用方法readwritelseek 写一个伪字符设备驱动在主机上测试pcd(HOST)在目标板上测试pcd(TARGET) 字符驱动程序用于与Linux内核中的设备…...
杰理AC63串口收发实例
在event.h文件中预定义串口消息 #define DEVICE_EVENT_FROM_MY_UART ((M << 24) | (Y << 16) | (U << 8) | \0)在app_spp_and_le.c文件里对SYS_DEVICE_EVENT做处理,添加收到DEVICE_EVENT_FROM_MY_UART消息时的处理函数my_rx_handler(); cas…...
麦芯(MachCore)开发教程1 --- 设备软件中间件
黄国强 2024/1/10 acloud163.com 对任何公司来说,在短时间内开发一款高质量设备专用软件,是一件不太容易做到的事情。麦芯是笔者发明的一款设备软件中间件产品。麦芯致力于给设备厂商提供一个开发工具和平台,让客户快速高效的开发自己的设备专…...
reset命令
作用:将当前 HEAD 重置为指定状态 Git 的四个区域 Workspace:工作区,就是你平时存放项目代码的地方;Index / Stage:暂存区,用于临时存放你的改动,事实上它只是一个文件,保存即将提交到文件列表…...
Linux内核--进程管理(十二)LinuxIO基础知识与概念
目录 一、引言 二、IO基本概念 ------>2.1、内存空间划分 ------>2.2、读写操作 ------>2.3、用户态切换到内核态的3种方式 三、PIO&DMA ------>3.1、PIO 工作原理 ------>3.2、DMA 工作原理 四、缓冲IO和直接IO ------>4.1、缓冲 IO ------&…...
gem5学习(11):将缓存添加到配置脚本中——Adding cache to the configuration script
目录 一、Creating cache objects 1、Classic caches and Ruby 二、Cache 1、导入SimObject(s) 2、创建L1Cache 3、创建L1Cache子类 4、创建L2Cache 5、L1Cache添加连接函数 6、为L1ICache和L1DCache添加连接函数 7、为L2Cache添加内存侧和CPU侧的连接函数 完整代码…...
上海雏鸟科技无人机灯光秀跨年表演点亮三国五地夜空
2023年12月31日晚,五场别开生面的无人机灯光秀跨年表演在新加坡圣淘沙、印尼雅加达、中国江苏无锡、浙江衢州、陕西西安等五地同步举行。据悉,这5场表演背后均出自上海的一家无人机企业之手——上海雏鸟科技。 在新加坡圣淘沙西乐索海滩,500架…...
学生备考护眼台灯怎么样选择?2024五款好用台灯安利
随着现代人生活水平的提高,人们对保护视力和眼健康的重视也日益提高。然而,长时间使用电子设备和不合适的光线环境却成为了我们眼健康的潜在威胁。所以,为了有效地保护我们的眼睛,护眼台灯成为了许多人的选择。 护眼台灯作为一种能…...
Java学习,一文掌握Java之SpringBoot框架学习文集(6)
🏆作者简介,普修罗双战士,一直追求不断学习和成长,在技术的道路上持续探索和实践。 🏆多年互联网行业从业经验,历任核心研发工程师,项目技术负责人。 🎉欢迎 👍点赞✍评论…...
美团点评秋招前端测评分享
一. 选择题 1. 甲乙二人各自加工一批同样数量的零件,甲完成一半时,乙完成150个,甲全部完成时,乙完成全部的5/6,求这批零件一共有(C)个 A. 320 B. 400 C. 360 D. 420 2. 分析如…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
【深尚想】TPS54618CQRTERQ1汽车级同步降压转换器电源芯片全面解析
1. 元器件定义与技术特点 TPS54618CQRTERQ1 是德州仪器(TI)推出的一款 汽车级同步降压转换器(DC-DC开关稳压器),属于高性能电源管理芯片。核心特性包括: 输入电压范围:2.95V–6V,输…...
深入解析光敏传感技术:嵌入式仿真平台如何重塑电子工程教学
一、光敏传感技术的物理本质与系统级实现挑战 光敏电阻作为经典的光电传感器件,其工作原理根植于半导体材料的光电导效应。当入射光子能量超过材料带隙宽度时,价带电子受激发跃迁至导带,形成电子-空穴对,导致材料电导率显著提升。…...
手动给中文分词和 直接用神经网络RNN做有什么区别
手动分词和基于神经网络(如 RNN)的自动分词在原理、实现方式和效果上有显著差异,以下是核心对比: 1. 实现原理对比 对比维度手动分词(规则 / 词典驱动)神经网络 RNN 分词(数据驱动)…...
Axure Rp 11 安装、汉化、授权
Axure Rp 11 安装、汉化、授权 1、前言2、汉化2.1、汉化文件下载2.2、windows汉化流程2.3、 macOs汉化流程 3、授权 1、前言 Axure Rp 11官方下载链接:https://www.axure.com/downloadthanks 2、汉化 2.1、汉化文件下载 链接: https://pan.baidu.com/s/18Clf…...
