当前位置: 首页 > 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. 分析如…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)

宇树机器人多姿态起立控制强化学习框架论文解析 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架&#xff08;一&#xff09; 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…...

基于IDIG-GAN的小样本电机轴承故障诊断

目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) ​梯度归一化(Gradient Normalization)​​ (2) ​判别器梯度间隙正则化(Discriminator Gradient Gap Regularization)​​ (3) ​自注意力机制(Self-Attention)​​ 3. 完整损失函数 二…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

Qt 事件处理中 return 的深入解析

Qt 事件处理中 return 的深入解析 在 Qt 事件处理中&#xff0c;return 语句的使用是另一个关键概念&#xff0c;它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别&#xff1a;不同层级的事件处理 方…...

c# 局部函数 定义、功能与示例

C# 局部函数&#xff1a;定义、功能与示例 1. 定义与功能 局部函数&#xff08;Local Function&#xff09;是嵌套在另一个方法内部的私有方法&#xff0c;仅在包含它的方法内可见。 • 作用&#xff1a;封装仅用于当前方法的逻辑&#xff0c;避免污染类作用域&#xff0c;提升…...

comfyui 工作流中 图生视频 如何增加视频的长度到5秒

comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗&#xff1f; 在ComfyUI中实现图生视频并延长到5秒&#xff0c;需要结合多个扩展和技巧。以下是完整解决方案&#xff1a; 核心工作流配置&#xff08;24fps下5秒120帧&#xff09; #mermaid-svg-yP…...