Android 中的串口开发
一:背景
本文着重讲安卓下的串口。
由于开源的Android在各种智能设备上的使用越来越多,如车载系统等。在我们的认识中,Android OS的物理接口一般只有usb host接口和耳机接口,但其实安卓支持各种各样的工业接口,如HDMI、usb、网口、串口等等。
下图就是一块Android工业板,标圈的DB9(也叫RS232串口)就是串口中的一种形态。
二、什么是串口?
串行端口 ,即:SerialPort,简称串口,主要用于数据被逐位按顺序传送的通讯方式称为串口通讯(简单来讲就是按顺序一位一位地传输数据)。
三、串口的一般形态
串口一般有RS232和RS485之分,485串口可以使用RS-232转RS-485串口的转换器转换。
RS232:
232协议的串口是全双工 的,它允许数据同时接收和发送,但RS232的理论传输距离只有10米。
RS-485:
485是半双工的,半双工意味着同一时间只能收/发,就像是独木桥,同时只能有一个方向的人流通过,如果对向有来人则会造成数据丢失,RS485的理论距离是1200峭,通常如果要远距离使用的话会使用485串口,短距离则可以使用232。
四、串口的使用
无论是Android、windows还是Linux,串口的使用都要以下几步:
-
打开串口
-
串口配置(一般为:波特率、数据位、停止位和奇偶校验)
-
串口操作(读/写,无非就是输入输出流的操作罢了)
-
关闭串口
五、代码实践
package com.xz.andfasterserialport;import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import tp.xmaihh.serialport.SerialHelper;
import tp.xmaihh.serialport.bean.ComBean;
import tp.xmaihh.serialport.stick.AbsStickPackageHelper;
import tp.xmaihh.serialport.utils.ByteUtil;public class MainActivity extends AppCompatActivity implements View.OnClickListener{private Button leftReduce;private Button leftAdd;private Button buyWine;private TextView wine_number;private String yellowWineType = "01";@BindView(R.id.rg_type)RadioGroup mRgType;private SerialHelper serialHelper;private boolean isHexType = false;private String text = "";private Handler mHandler = new Handler(new Handler.Callback() {@Overridepublic boolean handleMessage(Message msg) {ComBean comBean = (ComBean) msg.obj;String time = comBean.sRecTime;String rxText;rxText = new String(comBean.bRec);if (isHexType) {//转成十六进制数据rxText = ByteUtil.ByteArrToHex(comBean.bRec);}text += "Rx-> " + time + ": " + rxText + "\r" + "\n";//mEtReadContent.setText(text);return false;}});private RadioButton radioButton1;private RadioButton radioButton2;private RadioButton radioButton3;private RadioButton radioButton4;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ButterKnife.bind(this);initSerialConfig();//下面的两行设置全屏,隐藏系统状态栏getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);leftReduce = findViewById(R.id.left_reduce);leftAdd = findViewById(R.id.left_add);buyWine = findViewById(R.id.buy_wine);wine_number = findViewById(R.id.wine_number);radioButton1 = findViewById(R.id.rb_mk);radioButton2 = findViewById(R.id.rb_ls);radioButton3 = findViewById(R.id.rb_lx);radioButton4 = findViewById(R.id.rb_fzz);leftReduce.setOnClickListener(this);leftAdd.setOnClickListener(this);buyWine.setOnClickListener(this);radioButton1.setOnClickListener(this);radioButton2.setOnClickListener(this);radioButton3.setOnClickListener(this);radioButton4.setOnClickListener(this);}private void initSerialConfig() {//初始化SerialHelper对象,设定串口名称和波特率serialHelper = new SerialHelper(Const.SPORT_NAME, Const.BAUD_RATE) {@Overrideprotected void onDataReceived(ComBean paramComBean) {Message message = mHandler.obtainMessage();message.obj = paramComBean;mHandler.sendMessage(message);}};/** 默认的BaseStickPackageHelper将接收的数据扩展成64位,一般用不到这么多位* 我这里重新设定一个自适应数据位数的*/serialHelper.setStickPackageHelper(new AbsStickPackageHelper() {@Overridepublic byte[] execute(InputStream is) {try {int available = is.available();if (available > 0) {byte[] buffer = new byte[available];int size = is.read(buffer);if (size > 0) {return buffer;}} else {SystemClock.sleep(50);}} catch (IOException e) {e.printStackTrace();}return null;}});}//设置数据格式为十六进制还是其他,我们希望isHexType = true@Overrideprotected void onDestroy() {super.onDestroy();serialHelper.close();serialHelper = null;}//打开串口方法public void openSerialPort() {if (serialHelper.isOpen()) {Toast.makeText(this, Const.SPORT_NAME + "串口已经打开", Toast.LENGTH_SHORT).show();return;}try {serialHelper.open();} catch (Exception e) {e.printStackTrace();}Toast.makeText(this, Const.SPORT_NAME + "串口打开成功", Toast.LENGTH_SHORT).show();}//关闭串口方法public void closeSerialPort() {if (serialHelper.isOpen()) {serialHelper.close();Toast.makeText(this, Const.SPORT_NAME + "串口已经关闭", Toast.LENGTH_SHORT).show();}}@Overridepublic void onClick(View v) {int id = v.getId();switch (id) {case R.id.left_reduce:String stringValue1 = wine_number.getText().toString();//Log.d("XTQXTQXTQ",stringValue1);int value1 = Integer.parseInt(stringValue1);//Log.d("XTQXTQXTQ",value1+"");if ((value1 > 50)) {int newValue1 = value1 - 10;wine_number.setText(newValue1 + "");}break;case R.id.left_add:String stringValue2 = wine_number.getText().toString();//Log.d("XTQXTQXTQ",stringValue2);int value2 = Integer.parseInt(stringValue2);//Log.d("XTQXTQXTQ",value2+"");if ((value2 < 150)) {int newValue2 = value2 + 10;wine_number.setText(newValue2 + "");}break;case R.id.buy_wine:Toast.makeText(this,"开始发送串口数据",Toast.LENGTH_LONG).show();openSerialPort();if (!serialHelper.isOpen()) {Toast.makeText(this, Const.SPORT_NAME + "串口没打开 发送失败", Toast.LENGTH_SHORT).show();return;}int sendContentInt = Integer.parseInt(wine_number.getText().toString());//Log.d("100转十六进制" ,String.format("%02x", 100));String sendContent = "FB01"+yellowWineType+"00"+String.format("%x", sendContentInt)+"00"+"00"+"FE";Log.d("100转十六进制内容" ,sendContent);isHexType = true;//String sendContent = "FB010200960000FE";if (isHexType) {serialHelper.sendHex(sendContent);} else {serialHelper.sendTxt(sendContent);}case R.id.rb_mk:yellowWineType = "01";break;case R.id.rb_ls:yellowWineType = "02";break;case R.id.rb_lx:yellowWineType = "03";break;case R.id.rb_fzz:yellowWineType = "04";break;default:break;}}//十六进制校验位checkSum
}
package com.xz.andfasterserialport;public class Const {//串口 波特率public static final String SPORT_NAME = "/dev/ttyS1";public static final int BAUD_RATE = 9600;public static final String TXT_TYPE_SEND = "hello";public static final String HEX_TYPE_SEND = "123ABC";
}
主要思路:
添加依赖
首先,你需要在你的Android项目中添加依赖。确保项目build.gradle(Module级别)文件中有以下配置:
allprojects {repositories {maven { url 'https://jitpack.io' } // 或者使用作者推荐的仓库地址}
}dependencies {implementation 'com.github.xiaozhuang799:AndFasterSerialPort:latest.version'
}
初始化并使用串口
接下来,在你的Activity或Service中,初始化SerialHelper对象,并配置必要的串口参数:
import com.example.andfasterserialport.SerialHelper;// 假设已经定义了串口名和波特率
final String SERIAL_PORT_NAME = "/dev/ttyS0"; // 根据实际情况更改
final int BAUD_RATE = 9600; // 设置波特率SerialHelper serialHelper = new SerialHelper(SERIAL_PORT_NAME, BAUD_RATE) {@Overrideprotected void onDataReceived(ComBean paramComBean) {// 处理接收到的数据byte[] data = paramComBean.getData();// 你的逻辑代码}
};// 打开串口
serialHelper.open();// 发送数据示例
byte[] sendBuffer = "Hello, Serial Port!".getBytes();
serialHelper.send(sendBuffer);// 不要忘记在适当的时候关闭串口
serialHelper.close();
确保在使用串口前,已添加必要的权限到AndroidManifest.xml:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- 对于Android 6.0及以上,还需要在运行时请求这些权限 -->
参考项目地址:
GitCode - 全球开发者的开源社区,开源代码托管平台
相关文章:
Android 中的串口开发
一:背景 本文着重讲安卓下的串口。 由于开源的Android在各种智能设备上的使用越来越多,如车载系统等。在我们的认识中,Android OS的物理接口一般只有usb host接口和耳机接口,但其实安卓支持各种各样的工业接口,如HDM…...
TensorRt OP
在TensorRT中,OP(Operations,操作)是指网络中的基本计算单元,类似于数学中的运算符。每个OP执行一个特定的计算任务,例如卷积、矩阵乘法、激活函数等。TensorRT通过识别和优化这些OP来提高深度学习模型的推…...
构建负责任的人工智能:数据伦理与隐私保护
构建负责任的人工智能:数据伦理与隐私保护 目录 🌟 数据伦理的重要性📊 公平性评估:实现无偏差的模型🔒 数据去标识化:保护用户隐私的必要手段🔍 透明性与问责:建立可信的数据处理…...
微信小程序live-pusher和video同时使用,video播放声音时时大时小
一、遇到的问题 微信小程序live-pusher和video同时使用,video播放声音时有时无时大时小 二、排查流程 业务是模拟面试,每道题一个推流live-pusher和一个面试题video,一次面试有多道面试题,页面就一个live-pusher和一个video,切换面试题时给live-pusher和video重新赋值u…...
MySQL 分库分表实战
在当今互联网时代,数据量的增长呈爆炸式趋势,传统的单库单表架构已经难以满足大规模数据存储和高并发访问的需求。MySQL 分库分表技术应运而生,它可以有效地提高数据库的性能、扩展性和可用性。本文将详细介绍 MySQL 分库分表的实战经验。 一…...
MySQL—CRUD—进阶—(二) (ಥ_ಥ)
文本目录: ❄️一、新增: ❄️二、查询: 1、聚合查询: 1)、聚合函数: 2)、GROUP BY子句: 3)、HAVING 子句: 2、联合查询: 1)、内连接…...
时序分解 | TTNRBO-VMD改进牛顿-拉夫逊算法优化变分模态分解
时序分解 | TTNRBO-VMD改进牛顿-拉夫逊算法优化变分模态分解 目录 时序分解 | TTNRBO-VMD改进牛顿-拉夫逊算法优化变分模态分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 (创新独家)TTNRBO-VMD改进牛顿-拉夫逊优化算优化变分模态分解TTNRBO–VMD 优化VMD分解层数K和…...
2024“源鲁杯“高校网络安全技能大赛-Misc-WP
Round 1 hide_png 题目给了一张图片,flag就在图片上,不过不太明显,写个python脚本处理一下 from PIL import Image # 打开图像并转换为RGB模式 img Image.open("./attachments.png").convert("RGB") # 获取图像…...
CSS行块标签的显示方式
块级元素 标签:h1-h6,p,div,ul,ol,li,dd,dt 特点: (1)如果块级元素不设置默认宽度,那么该元素的宽度等于其父元素的宽度。 (2)所有的块级元素独占一行显示. (3ÿ…...
Go 语言中的 for range 循环教程
在 Go 语言中,for range 循环是一个方便的语法结构,用于遍历数组、切片、映射和字符串。本教程将通过示例代码来帮助理解如何在 Go 中使用 for range 循环。 package mainimport "fmt"func main() {// 遍历切片并计算和nums : []int{2, 3, 4}…...
青训营 X 豆包MarsCode 技术训练营--小M的比赛胜场计算
问题描述 小M参加了一场n个人的比赛,比赛规则是所有选手两两对决。每个人有一个能力值,对应着他们的序号。参赛者同时被分为黄色或蓝色两种颜色。比赛胜负的规则如下: 当比赛双方颜色不同时,能力值大的选手获胜; 当比…...
海王3纯源码
海王3是一款热门的捕鱼类游戏,其纯源码为开发者提供了一个完整的游戏开发基础。该源码包括客户端和服务端的完整架构,支持多人在线竞技模式和丰富的游戏玩法。服务端采用C语言编写,并使用MySQL数据库来存储玩家数据,确保数据处理的…...
【ShuQiHere】Linux 系统中的硬盘管理详解:命令与技巧
【ShuQiHere】 💽 在 Linux 系统中,硬盘管理不仅仅是存储数据的操作,更涉及系统性能、数据安全和稳定性的优化。无论你是系统管理员、开发者还是 Linux 爱好者,掌握硬盘管理的基础操作都非常有用。本文将从硬盘健康检查、分区管理…...
数据结构之堆和二叉树的简介
1.树 1.1 树的概念与结构 如图所示,树是⼀种非线性的数据结构,它是由 n (n>0) 个有限结点组成⼀个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。 …...
微信小程序上传图片添加水印
微信小程序使用wx.chooseMedia拍摄或从手机相册中选择图片并添加水印, 代码如下: // WXML代码:<canvas canvas-id"watermarkCanvas" style"width: {{canvasWidth}}px; height: {{canvasHeight}}px;"></canvas&…...
xshell5找不到匹配的host key算法
xshell5找不到匹配的host key算法,是因为电脑客户端不支持服务器的算法,因此需要再服务器增加算法。 下面以Ubuntu系统为例,修改下面的文件 sudo vim /etc/ssh/sshd_config 增加下面算法 KexAlgorithms diffie-hellman-group-exchange-…...
Linux中安装Tomcat
文章目录 一、Tomcat介绍1.1、Tomcat是什么1.2、Tomcat的工作原理1.3、Tomcat适用的场景1.4、Tomcat与Nginx、Apache比较1.4.1、优势1.4.2、劣势1.4.3、定位功能 1.5、Tomcat 的主要组件1.6、Tomcat 的主要配置文件 二、Tomcat安装2.1、查看可用的JDK2.2、安装OpenJDK 112.3、配…...
RV1126音视频学习(二)-----VI模块
文章目录 前言2.RV1126的视频输入vi模块2.1什么是VI模块2.3RV1126VI模块主要APIRK_MPI_SYS_Init()RK_MPI_VI_SetChnAttrRK_MPI_VI_EnableChnRK_S32 RK_MPI_VI_DisableChnRK_MPI_VI_StartStreamRK_MPI_SYS_GetMediaBufferRK_MPI_MB_GetPtrRK_MPI_MB_GetSizeRK_MPI_MB_ReleaseBuf…...
「C/C++」C++17 之 std::string_view 轻量级字符串视图
✨博客主页何曾参静谧的博客📌文章专栏「C/C」C/C程序设计📚全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…...
Linux内核-内核模块内核参数
作者介绍:简历上没有一个精通的运维工程师。希望大家多多关注作者,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 我们的Linux进阶部分,到目前为止,已经讲过:硬件,日常运维,基础软…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
