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进阶部分,到目前为止,已经讲过:硬件,日常运维,基础软…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...

GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...

初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

前端开发者常用网站
Can I use网站:一个查询网页技术兼容性的网站 一个查询网页技术兼容性的网站Can I use:Can I use... Support tables for HTML5, CSS3, etc (查询浏览器对HTML5的支持情况) 权威网站:MDN JavaScript权威网站:JavaScript | MDN...