当前位置: 首页 > news >正文

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)数据库安装 一、配置安全更新 电子邮件可写可不写&#xf…...

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是通用目标检测框&#xff0…...

一文读懂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做处理&#xff0c;添加收到DEVICE_EVENT_FROM_MY_UART消息时的处理函数my_rx_handler(); cas…...

麦芯(MachCore)开发教程1 --- 设备软件中间件

黄国强 2024/1/10 acloud163.com 对任何公司来说&#xff0c;在短时间内开发一款高质量设备专用软件&#xff0c;是一件不太容易做到的事情。麦芯是笔者发明的一款设备软件中间件产品。麦芯致力于给设备厂商提供一个开发工具和平台&#xff0c;让客户快速高效的开发自己的设备专…...

reset命令

作用&#xff1a;将当前 HEAD 重置为指定状态 Git 的四个区域 Workspace&#xff1a;工作区&#xff0c;就是你平时存放项目代码的地方;Index / Stage&#xff1a;暂存区&#xff0c;用于临时存放你的改动&#xff0c;事实上它只是一个文件&#xff0c;保存即将提交到文件列表…...

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日晚&#xff0c;五场别开生面的无人机灯光秀跨年表演在新加坡圣淘沙、印尼雅加达、中国江苏无锡、浙江衢州、陕西西安等五地同步举行。据悉&#xff0c;这5场表演背后均出自上海的一家无人机企业之手——上海雏鸟科技。 在新加坡圣淘沙西乐索海滩&#xff0c;500架…...

学生备考护眼台灯怎么样选择?2024五款好用台灯安利

随着现代人生活水平的提高&#xff0c;人们对保护视力和眼健康的重视也日益提高。然而&#xff0c;长时间使用电子设备和不合适的光线环境却成为了我们眼健康的潜在威胁。所以&#xff0c;为了有效地保护我们的眼睛&#xff0c;护眼台灯成为了许多人的选择。 护眼台灯作为一种能…...

Java学习,一文掌握Java之SpringBoot框架学习文集(6)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…...

美团点评秋招前端测评分享

一&#xff0e; 选择题 1. 甲乙二人各自加工一批同样数量的零件&#xff0c;甲完成一半时&#xff0c;乙完成150个&#xff0c;甲全部完成时&#xff0c;乙完成全部的5/6&#xff0c;求这批零件一共有&#xff08;C&#xff09;个 A. 320 B. 400 C. 360 D. 420 2. 分析如…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖

在Vuzix M400 AR智能眼镜的助力下&#xff0c;卢森堡罗伯特舒曼医院&#xff08;the Robert Schuman Hospitals, HRS&#xff09;凭借在无菌制剂生产流程中引入增强现实技术&#xff08;AR&#xff09;创新项目&#xff0c;荣获了2024年6月7日由卢森堡医院药剂师协会&#xff0…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

第7篇:中间件全链路监控与 SQL 性能分析实践

7.1 章节导读 在构建数据库中间件的过程中&#xff0c;可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中&#xff0c;必须做到&#xff1a; &#x1f50d; 追踪每一条 SQL 的生命周期&#xff08;从入口到数据库执行&#xff09;&#…...

SQL Server 触发器调用存储过程实现发送 HTTP 请求

文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...

Pydantic + Function Calling的结合

1、Pydantic Pydantic 是一个 Python 库&#xff0c;用于数据验证和设置管理&#xff0c;通过 Python 类型注解强制执行数据类型。它广泛用于 API 开发&#xff08;如 FastAPI&#xff09;、配置管理和数据解析&#xff0c;核心功能包括&#xff1a; 数据验证&#xff1a;通过…...