快速开发和使用Android串口

news2024/12/23 20:26:42

一、什么是串口

        串口叫做串行接口,也称串行通信接口,也可以叫做COM口,按电气标准及协议来分包括RS-232-C、RS-422、RS485、USB等。串行接口是指数据一位一位地顺序传送,其特点是通信线路简单,只要一对传输线就可以实现双向通信,从而大大降低了成本,特别适用于远距离通信,但传送速度较慢。

二、串口通讯方式

  • 单工模式:只支持数据在一个方向上传输;在同一时间只有一方能接收或发送信息,不能实现双向通信。一般用在只向一个方向传输数据的场合,比如跟打印机通讯。
  • 半双工模式:如果只有一条通讯线,那么它既可以发送数据也可以接收数据,但不能同时进行发送和接收。如果使用两条通讯线,数据可以在两个方向传输,但是在同一时间只可以有一方接受或发送信息,实际上是一种切换方向的单工通讯。比如RS485-2W通讯就是采用这种模式。
  • 全双工模式:数据可以同时往两个方向传输,相当于两个单工通讯的结合,它要求发送设备和接收设备都有独立的发送和接收能力,在同一时间可以同时进行发送和接收数据,实现双向通信,数据传输效率比较高。比如RS-232通讯就是采用这种模式。

串口通讯是一个字符一个字符地传输,每个字符一位一位地传输,总是以“起始位”开始,以“停止位”结束,字符之间没有固定的时间间隔要求。
实际传输时每一位的信号宽度与波特率有关,波特率越高,宽度越小,在进行传输之前,双方一定要使用同一个波特率。 

三、Android串口开发

        通过使用serialport库,直接上代码 :

第一步导包:

// 在项目根目录的build.gradle文件中添加:
allprojects {
    repositories {
        ...
        mavenCentral()
    }
}
// 在项目Module下的build.gradle文件中添加:
dependencies {
    implementation 'io.github.xmaihh:serialport:2.1.1'
}

第二步代码:


import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.RadioGroup;
import android.widget.Toast;

import com.alibaba.fastjson.JSONObject;

import java.io.IOException;
import java.io.InputStream;

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 RadioGroup.OnCheckedChangeListener {

    @BindView(R.id.rg_type)
    RadioGroup mRgType;
    @BindView(R.id.et_read_content)
    EditText mEtReadContent;
    @BindView(R.id.et_send_content)
    EditText mEtSendContent;

    private SerialHelper serialHelper;
    private boolean isHexType = false;
    private String text = "";

    private Handler mHandler = new Handler(new Handler.Callback() {
        @Override
        public 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;
        }
    });

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ButterKnife.bind(this);

        mRgType.setOnCheckedChangeListener(this);

        initSerialConfig();
    }

    private void initSerialConfig() {
        //初始化SerialHelper对象,设定串口名称和波特率(此处为接收扫码数据)
        serialHelper = new SerialHelper("/dev/ttyACM0", 9600) {
            @Override
            protected void onDataReceived(ComBean paramComBean) {
                Message message = mHandler.obtainMessage();
                message.obj = paramComBean;
                Log.e("TAG", "onDataReceived: " + JSONObject.toJSONString(message.obj));
                mHandler.sendMessage(message);
            }
        };

        /*
         * 默认的BaseStickPackageHelper将接收的数据扩展成64位,一般用不到这么多位
         * 我这里重新设定一个自适应数据位数的
         */

        serialHelper.setStickPackageHelper(new AbsStickPackageHelper() {
            @Override
            public 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;
            }
        });
    }

    @OnClick({R.id.bt_open, R.id.bt_close, R.id.bt_send, R.id.bt_clear_content})
    public void onButtonClicked(View view){
        switch (view.getId()) {
            case R.id.bt_open:
                if (serialHelper.isOpen()) {
                    Toast.makeText(this, Const.SPORT_NAME + "串口已经打开", Toast.LENGTH_SHORT).show();
                    return;
                }
                try {
                    serialHelper.open();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                Toast.makeText(this, Const.SPORT_NAME + "串口打开成功", Toast.LENGTH_SHORT).show();
                break;

            case R.id.bt_close:
                if (serialHelper.isOpen()) {
                    serialHelper.close();
                    Toast.makeText(this, Const.SPORT_NAME + "串口已经关闭", Toast.LENGTH_SHORT).show();
                }
                break;

            case R.id.bt_clear_content:
                text = "";
                mEtReadContent.setText(text);
                break;

            case R.id.bt_send:
                if (!serialHelper.isOpen()) {
                    Toast.makeText(this, Const.SPORT_NAME + "串口没打开 发送失败", Toast.LENGTH_SHORT).show();
                    return;
                }
                String sendContent = mEtSendContent.getText().toString();
                if (isHexType) {
                    serialHelper.sendHex(sendContent);
                } else {
                    serialHelper.sendTxt(sendContent);
                }
                break;
        }
    }

    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
        switch (checkedId) {
            case R.id.rb_txt:
                isHexType = false;
                mEtSendContent.setText(Const.TXT_TYPE_SEND);
                break;

            case R.id.rb_hex:
                isHexType = true;
                mEtSendContent.setText(Const.HEX_TYPE_SEND);
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        serialHelper.close();
        serialHelper = null;
    }
}
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <!--串口操作部分-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toTopOf="@id/ll_read_data"
        android:layout_marginBottom="@dimen/dp_10"
        android:orientation="horizontal">

        <Button
            android:id="@+id/bt_open"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="@string/open_serial"
            android:layout_marginStart="@dimen/dp_10"
            android:layout_gravity="center_vertical"/>

        <TextView
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:textSize="@dimen/edit_text_size"
            android:text="@string/data_type"
            android:layout_marginStart="@dimen/dp_10"
            android:layout_gravity="center_vertical"/>

        <RadioGroup
            android:id="@+id/rg_type"
            android:layout_width="0dp"
            android:layout_weight="2"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginStart="@dimen/dp_10"
            android:orientation="horizontal">


            <RadioButton
                android:id="@+id/rb_txt"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="wrap_content"
                android:checked="true"
                android:text="@string/data_type_txt"/>

            <RadioButton
                android:id="@+id/rb_hex"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="wrap_content"
                android:layout_marginStart="@dimen/dp_10"
                android:text="@string/data_type_hex"/>

        </RadioGroup>

        <Button
            android:id="@+id/bt_close"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="@string/close_serial"
            android:layout_marginStart="@dimen/dp_10"
            android:layout_marginEnd="@dimen/dp_10"
            android:layout_gravity="center_vertical"/>

    </LinearLayout>

    <!--数据接收部分-->
    <LinearLayout
        android:id="@+id/ll_read_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:orientation="horizontal">


        <!--数据接收显示-->
        <EditText
            android:id="@+id/et_read_content"
            android:layout_width="0dp"
            android:layout_height="200dp"
            android:layout_marginStart="@dimen/dp_10"
            android:layout_weight="6"
            android:background="@drawable/edit_bg"
            android:cursorVisible="false"
            android:focusable="false"
            android:focusableInTouchMode="false"
            android:gravity="top"
            android:padding="@dimen/dp_5"
            android:textSize="@dimen/edit_text_size" />

        <Button
            android:id="@+id/bt_clear_content"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="@string/clear_all_data"
            android:layout_marginStart="@dimen/dp_10"
            android:layout_marginEnd="@dimen/dp_10"
            android:layout_gravity="center_vertical"/>


    </LinearLayout>

    <View
        android:id="@+id/view_line"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_2"
        android:layout_marginTop="@dimen/dp_10"
        android:layout_marginStart="@dimen/dp_10"
        android:layout_marginEnd="@dimen/dp_10"
        android:background="@color/colorAccent"
        app:layout_constraintTop_toBottomOf="@id/ll_read_data"/>

    <!--数据发送部分-->
    <LinearLayout
        android:id="@+id/ll_send_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@id/view_line"
        android:layout_marginTop="@dimen/dp_10"
        android:orientation="horizontal">


        <!--数据接收显示-->
        <EditText
            android:id="@+id/et_send_content"
            android:layout_width="0dp"
            android:layout_height="200dp"
            android:layout_marginStart="@dimen/dp_10"
            android:layout_weight="6"
            android:singleLine="false"
            android:background="@drawable/edit_bg"
            android:gravity="top"
            android:padding="@dimen/dp_5"
            android:inputType="text"
            android:textSize="@dimen/edit_text_size"
            android:text="@string/txt_data"/>

        <Button
            android:id="@+id/bt_send"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="@string/send_data"
            android:layout_marginStart="@dimen/dp_10"
            android:layout_marginEnd="@dimen/dp_10"
            android:layout_gravity="center_vertical"/>


    </LinearLayout>

</android.support.constraint.ConstraintLayout>

 第三步说明:

        上面代码,在创建serialHelper之时,就已经传入了一个onDataReceived()方法,用来监听串口数据接收,但是如要打开串口才能开启监听。

SerialHelper创建完成,打开串口

serialHelper.open();

如果需要设置其他的属性,比如设置奇偶检验,需要在执行open()之前设定。

serialHelper.setPort(String sPort);      //设置串口
serialHelper.setBaudRate(int iBaud);     //设置波特率
serialHelper.setStopBits(int stopBits);  //设置停止位
serialHelper.setDataBits(int dataBits);  //设置数据位
serialHelper.setParity(int parity);      //设置校验位
serialHelper.setFlowCon(int flowcon);    //设置流控

发送数据

serialHelper.send(byte[] bOutArray); // 发送byte[]
serialHelper.sendHex(String sHex);  // 发送Hex
serialHelper.sendTxt(String sTxt);  // 发送ASCII

关闭串口

serialHelper.close(); 

效果图 

 四、参考文章

Android串口使用2之使用Google官方库android-serialport-api_android-serialport-api使用_Steven Jon的博客-CSDN博客

mirrors / xmaihh / Android-Serialport · GitCode 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/600392.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机视觉—YOLO V4

计算机视觉—YOLO V4 1、YOLO V41.1、网络结构1.1.1、BackBone&#xff1a;CSPDarknet531.1.2、Neck&#xff1a;SPP结构1.1.3、Neck&#xff1a;PAN结构1.1.4、YOLO v4整体结构 1.2、优化策略 1、YOLO V4 原论文下载地址&#xff1a;https://arxiv.org/abs/2004.10934 1.1、…

Windows中安装GCC教程

GCC的安装教程 GCC简介 GCC编译器通常在Linux系统下使用&#xff0c;一般来说大部分发行的系统会默认安装&#xff0c;GCC编译器使用gcc指令在终端进行shell操作。 对于新接触Linux的朋友来说&#xff0c;简单的在Windows中练习过渡一下应该就足够了。&#xff08;我就是因为…

Apache IoTDB 荣获国家网信办 2022 年中国开源创新大赛决赛一等奖,三位核心研发荣获表彰!...

项目获得权威认可&#xff01; 2023 年 5 月 15 日&#xff0c;2022 年中国开源创新大赛组委会对外公布“2022 中国互联网发展创新与投资大赛公益项目暨2022年中国开源创新大赛”决赛获奖名单&#xff0c;并于 2023 年 5 月 31 日在北京举办“2022年中国开源创新大赛总结发布活…

chatgpt赋能python:用Python编写FizzBuzz——解析最简单的编程题

用Python编写FizzBuzz——解析最简单的编程题 作为每个程序员的入门题目&#xff0c;FizzBuzz是一个简单但常见的问题。FizzBuzz要求我们用数字1到100来打印输出&#xff0c;但是当数字是3的倍数时&#xff0c;需要输出Fizz&#xff1b;当数字是5的倍数时&#xff0c;需要输出…

力扣高频SQL50题(基础版)——第三天

力扣高频SQL50题(基础版)——第三天 1 产品销售分析Ⅰ 1.1 题目内容 1.1.1 基本题目信息1 1.1.2 基本题目信息2 1.1.3 示例输入输出 1.2 示例sql语句 # Write your MySQL query statement below SELECT p.product_name,s.year,s.price FROM Sales s INNER JOIN Product p …

chatgpt赋能python:Python几次方函数介绍

Python几次方函数介绍 Python作为一门高级编程语言&#xff0c;具有丰富的数学函数库。其中&#xff0c;几次方函数在许多数值计算、数据分析和科学计算中都得到广泛应用。Python中的几次方函数有多种实现方式&#xff0c;包括内置函数pow()、运算符**、NumPy库的numpy.power(…

(3)NUC 980 kenerl编译

解压 用到的配置文件位置&#xff1a; /NUC980-linux-4.4.y-master/arch/arm/configs/nuc980_defconfig 执行&#xff1a; 编译linux内核源码。了解其 配置文件在 arch/arm/configs/nuc980_defconfig (1) make nuc980_defconfig 载入配置文件 (2) make menuconfig --->Devi…

机器龙的制作

1. 功能说明 本文示例将实现R326样机机器龙边张合嘴巴、边煽动翅膀、边摆动尾巴运动的功能。 2. 结构说明 本项目使用的机器龙样机是用可以用探索者零件或者探索者兼容零件制作。样机主要由头部模块、翅膀模块、尾巴模块、四足行走模块四部分组成。其中头部模块由2自由度并联关…

从元宇宙到生成式AI:炒作、现实和未来前景

不久前&#xff0c;科技界充斥着一种被称为元宇宙的未来主义概念。这个相互关联的虚拟现实空间宇宙&#xff0c;个人可以在模拟环境中进行交互&#xff0c;被誉为技术的未来。如今围绕元宇宙的炒作已经彻底失败了。技术重点现在已经转向生成AI&#xff0c;重点是像GPT-4和谷歌的…

一文搞懂Flutter的手势事件——事件分发与冲突处理详解

本文字数&#xff1a;43617字 预计阅读时间&#xff1a;110分钟 前言 之前有两篇文章都围绕着runApp()进行展开&#xff0c;讲解了布局绘制的详细过程。 https://www.jianshu.com/p/2ef749ff4d40/https://www.jianshu.com/p/f37f8da235ec 那么接下来我们想详细的说一说Flutter是…

哔哩哔哩视频云画质与窄带高清AI落地实践

视频赛道卷到下半场&#xff0c;一定会面临体验与成本的对抗&#xff0c;尤其是在行业大环境“过冬”的背景下&#xff0c;想要在有限带宽下获得最佳的画质观感变得异常具备挑战性。从视频云业务场景的视角来看&#xff0c;如何有效解决cross-domain问题、如何突破低业务延迟下…

留学生用ChatGPT写论文?真的会被开除!!!

转眼进入6月&#xff0c;大家的论文完成的怎么样了&#xff1f;很多留学生都有这样的疑问&#xff0c;用ChatGPT写论文靠谱吗&#xff1f; 其实在最近&#xff0c;&#xff0c;ChatGPT被学生用来辅助写论文&#xff0c;已经不是什么新鲜事了。它作为新型人工智能&#xff0c;搜…

二十三种设计模式:状态模式

状态模式&#xff0c;就是把所有的状态抽象成一个个具体的类&#xff0c;然后继承一个抽象状态类&#xff0c;在每一个状态类内封装对应状态的行为&#xff0c;符合开放封闭原则&#xff0c;当增加新的状态或减少状态时&#xff0c;只需修改关联的类即可。很适合多分支行为方法…

SpringBoot使用flywaydb实现数据库版本管理【附源码】

一、项目背景 本文主要是配合SpringBoot使用用户输入的自定义数据源启动一文附带产出。前文主要介绍了SpringBoot无数据源启动&#xff0c;然后通过用户录入自定义数据库配置后&#xff0c;连接数据库的操作。但是当整个项目交给用户使用时&#xff0c;谁使用都不知道情况下&a…

JetBrains的.NET和ASP.NET集成开发环境Rider 2023版本在Linux系统的下载与安装配置教程

目录 前言一、Rider 安装二、使用配置总结 前言 Rider是一款专为.NET和ASP.NET开发人员设计的集成开发环境&#xff08;IDE&#xff09;。它提供了丰富的功能和工具&#xff0c;可以帮助开发人员更高效地编写、调试和部署.NET和ASP.NET应用程序。注&#xff1a;已在CentOS7.9和…

Java课程设计之购物车管理系统

一、项目准备 1、开发工具&#xff1a;JDK、Eclipse 2、需求分析&#xff1a; 包括商品管理和购物车管理。 1&#xff09;商品管理主要功能 商品信息导入 显示所有商品信息 2&#xff09;购物车主要功能 添加商品到购物车 修改购物车中的商品数量 显示购物车中的所有商…

运维小白必学篇之基础篇第六集:权限实验

权限实验 实验作业&#xff1a; 1、创建1.txt文件&#xff0c;修改1.txt文件权限为属主最大&#xff0c;属组读写&#xff0c;其他人无权限 2、单独为1.txt文件的属组赋予执行权限 3、修改1.txt的属组为a1 4、修改用户a2的登录shell为/bin/bash 5、创建a1用户&#xff0c;设置…

chatgpt赋能python:Python内置函数求和

Python内置函数求和 Python是一种易学易用的编程语言&#xff0c;是许多开发人员和数据分析师的首选语言。Python提供了多种内置函数来处理不同的任务&#xff0c;其中包括求和函数。本文将介绍Python中的内置求和函数以及如何使用它们。 Python内置求和函数 在Python中&…

【51单片机】AT24C20数据帧(I2C总线)

&#x1f38a;专栏【51单片机】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【Love Story】 &#x1f970;大一同学小吉&#xff0c;欢迎并且感谢大家指出我的问题&#x1f970; 小吉先向大家道个歉&#xff0c;因为最近在期末…

“微商城”项目(4首页)

1.显示轮播图 首页和商品详情页都有图片轮播图展示&#xff0c;考虑到Vue组件代码的复用性&#xff0c;把轮播图相关代码单独放置在src\components\swiper.vue文件中。 在src\pages\Home.vue文件中&#xff0c;编写HTML结构代码&#xff0c;示例代码如下。 <template>…