Android Studio : 使用 jni 实现串口通讯

Android车载开发之使用JNI实现ANDROID和串口通信详解 对串口文件进行配置(波特率等),选择串口文件,打开串口,设备不同 ,可以读写的串口也不同.读写串口 ,读串口需要开一个子线程,然后死循环读取串口发送的数据关闭串口文件其中打开,关闭串口是在jni方法执行,读写操作是android程序执行。 阅读详情

添加 SerialPort 类

在网上找到 SerialPort 的 java 类,添加到项目中。

package com.xd.serialport;

import android.util.Log;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class SerialPort {
	private static final String TAG = "SerialPort";  
	  
	/* 
	 * Do not remove or rename the field mFd: it is used by native method close(); 
	 */  
	private FileDescriptor mFd;  
	private FileInputStream mFileInputStream;  
	private FileOutputStream mFileOutputStream;  
	  
	public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException {  
	  
	    /* Check access permission */  
	    if (!device.canRead() || !device.canWrite()) {  
	        try {  
	            /* Missing read/write permission, trying to chmod the file */  
	            Process su;  
	            su = Runtime.getRuntime().exec("/system/bin/su");  
	            String cmd = "chmod 666 " + device.getAbsolutePath() + "\n"  
	                    + "exit\n";  
	            su.getOutputStream().write(cmd.getBytes());  
	            if ((su.waitFor() != 0) || !device.canRead()  
	                    || !device.canWrite()) {  
	                throw new SecurityException();  
	            }  
	        } catch (Exception e) {  
	            e.printStackTrace();  
	            throw new SecurityException();  
	        }  
	    }  
	  
	    mFd = open(device.getAbsolutePath(), baudrate, flags);  
	    if (mFd == null) {  
	        Log.e(TAG, "native open returns null");  
	        throw new IOException();  
	    }  
	    mFileInputStream = new FileInputStream(mFd);  
	    mFileOutputStream = new FileOutputStream(mFd);  
	}  
	  
	// Getters and setters  
	public InputStream getInputStream() {  
	    return mFileInputStream;  
	}  
	  
	public OutputStream getOutputStream() {  
	    return mFileOutputStream;  
	}  
	  
	// JNI  
	private native static FileDescriptor open(String path, int baudrate, int flags);  
	public native void close();  
	static {  
	    System.loadLibrary("serial_port");  
	}  
}

项目结构如下:

项目结构


生成 c 语言头文件

  • 打开 Terminal(View -> Tool Windows -> Terminal)

    Terminal

  • 输入cd app\src\main\java进入源码所在目录

    进入源码目录

  • 输入javah -jni com.xd.serialport.SerialPort生成头文件

    生成头文件

    头文件


创建 jni 文件夹,添加 .c 文件

  • 右键 Moudle,右键菜单中选择 New -> Folder -> JNI Folder,弹出的对话框,直接点击完成。

    jni文件夹

  • 将前面生成的 .h 文件移入 jni 文件夹中。

  • 右键 jni 文件夹,右键菜单中选择New -> C/C++ Source File创建与 .h 文件同名的 .c 文件。

    创建.c文件

  • 为 .c 文件添加如下内容(来源于网络)。

    注意:需要将include头文件、open、close方法中的包名修改为自己的包名。

    #include <com_xd_serialport_SerialPort.h>  
    #include <termios.h>  
    #include <unistd.h>  
    #include <sys/types.h>  
    #include <sys/stat.h>  
    #include <fcntl.h>  
    #include <string.h>  
    #include <jni.h>  
        
    #include "android/log.h"  
    static const char *TAG="serial_port";  
    #define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args)  
    #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)  
    #define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)  
      
    /* 
    * Class: android_serialport_SerialPort 
    * Method: open 
    * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; 
    */  
    static speed_t getBaudrate(jint baudrate)  
    {  
        switch(baudrate) {  
        case 0: return B0;  
        case 50: return B50;  
        case 75: return B75;  
        case 110: return B110;  
        case 134: return B134;  
        case 150: return B150;  
        case 200: return B200;  
        case 300: return B300;  
        case 600: return B600;  
        case 1200: return B1200;  
        case 1800: return B1800;  
        case 2400: return B2400;  
        case 4800: return B4800;  
        case 9600: return B9600;  
        case 19200: return B19200;  
        case 38400: return B38400;  
        case 57600: return B57600;  
        case 115200: return B115200;  
        case 230400: return B230400;  
        case 460800: return B460800;  
        case 500000: return B500000;  
        case 576000: return B576000;  
        case 921600: return B921600;  
        case 1000000: return B1000000;  
        case 1152000: return B1152000;  
        case 1500000: return B1500000;  
        case 2000000: return B2000000;  
        case 2500000: return B2500000;  
        case 3000000: return B3000000;  
        case 3500000: return B3500000;  
        case 4000000: return B4000000;  
        default: return -1;  
        }  
    }  
      
    /* 
     * Class:     android_serialport_SerialPort 
     * Method:    open 
     * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; 
     */  
    JNIEXPORT jobject JNICALL Java_com_xd_serialport_SerialPort_open  
      (JNIEnv *env, jclass thiz, jstring path, jint baudrate, jint flags)  
    {  
        int fd;  
        speed_t speed;  
        jobject mFileDescriptor;  
      
        /* Check arguments */  
        {  
            speed = getBaudrate(baudrate);  
            if (speed == -1) {  
                /* TODO: throw an exception */  
                LOGE("Invalid baudrate");  
                return NULL;  
            }  
        }  
      
        /* Opening device */  
        {  
            jboolean iscopy;  
            const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);  
            LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);  
            fd = open(path_utf, O_RDWR | flags);  
            LOGD("open() fd = %d", fd);  
            (*env)->ReleaseStringUTFChars(env, path, path_utf);  
            if (fd == -1)  
            {  
                /* Throw an exception */  
                LOGE("Cannot open port");  
                /* TODO: throw an exception */  
                return NULL;  
            }  
        }  
      
        /* Configure device */  
        {  
            struct termios cfg;  
            LOGD("Configuring serial port");  
            if (tcgetattr(fd, &cfg))  
            {  
                LOGE("tcgetattr() failed");  
                close(fd);  
                /* TODO: throw an exception */  
                return NULL;  
            }  
      
            cfmakeraw(&cfg);  
            cfsetispeed(&cfg, speed);  
            cfsetospeed(&cfg, speed);  
      
            if (tcsetattr(fd, TCSANOW, &cfg))  
            {  
                LOGE("tcsetattr() failed");  
                close(fd);  
                /* TODO: throw an exception */  
                return NULL;  
            }  
        }  
      
        /* Create a corresponding file descriptor */  
        {  
            jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");  
            jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "<init>", "()V");  
            jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I");  
            mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);  
            (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)fd);  
        }  
      
        return mFileDescriptor;  
    }  
      
    /* 
     * Class:     cedric_serial_SerialPort 
     * Method:    close 
     * Signature: ()V 
     */  
    JNIEXPORT void JNICALL Java_com_xd_serialport_SerialPort_close  
      (JNIEnv *env, jobject thiz)  
    {  
        jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);  
        jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");  
      
        jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");  
        jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I");  
      
        jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);  
        jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);  
      
        LOGD("close(fd = %d)", descriptor);  
        close(descriptor);  
    }
    

    jni文件结构


配置NDK,生成 .so 文件

  • 在 local.properties 添加 ndk 路径

    添加ndk路径

    android-ndk的版本至少要 r9d 以上的版本,如果等于或低于该版本,运行时会提示No rule to make target的错误。我使用的是 r10e 的版本。

  • 在 module 的 build.gradle 中添加 ndk 配置

    在 defaultConfig 节点下添加:

    ndk{  
    	abiFilter "armeabi"  
    	moduleName "serial_port"  // 生成so的名称
    	ldLibs "log", "z", "m", "jnigraphics", "android"  
    }
    
  • 在 gradle.properties 中添加android.useDeprecatedNdk=true,否则 sync 时会提示错误NDK integration is deprecated in the current plugin.

  • Sync Project with Gradle Files

  • 运行项目,将在目录\build\intermediates\ndk\debug\lib\armeabi下生成libserial_port.so文件。

    生成so

  • 将 so 文件拷贝到\src\main\jniLibs\armeabi目录下。

    拷贝so

至此,串口通讯可以正常使用了。


参考资料

Android 利用JNI实现串口通信 Android 通过JNI参考android-serialport-api实现 串口通信 阅读详情

相关推荐

android sudio 在项目中使用android-serialport-api 实现串口通讯,基于RK3128

安卓没有直接实现串口通讯的API,所以需要用到Google开源的代码,通过JNI的方式实现串口通讯。android-serialport-api的代码和wiki如下: android-serialport-api_code android-serialport-api_wiki Google的这个代码比较老,所以是基于eclipse实现的,我以前也写过一篇基于eclipse实现JNI库的文章,但是...

csz 2720

Android Jni 多线程 蓝牙串口收发 实例 一

在工作有一个这样的需求:在一个Android App上,通过串口对一个蓝牙进行操作,其中包括发送消息,接收消息,并进行处理。     =========================项目心得和遇上的问题总结=========================     要实现这些功能,有很多种:多线程可以放在Jni层,这样接收和消息的整理逻辑都在Jni层,这样程序就会变得复杂一些,因为你

shell812的专栏 4012

[Android Studio]的串口(serial Port)通信

Android Studio的串口(serial Port)通信 首先欢迎大家能够有缘分搜索到这篇文章,相信在优快云上应该有各种各样的关于串口通信的博客,或者调用函数啊,但是都是零零散散的,不全面,有时候还要几篇文章一起看,最后程序还报错!我自己这边调试以后,从开始到结尾都贴出来,免得自己忘记,也分享给大家。如果有什么不对的地方希望大家批评指正! 下面是我参考的一些文章: https://blo...

Limizy的博客 5286

AndroidStudio创建jinLibs文件夹

在文件中的buildTypes节点下添加 sourceSets.main { jniLibs.srcDir 'libs' } 如图 转载于:https://www.cnblogs.com/kim-liu/p/7479360.html

weixin_30954265的博客 671

jni的串口收发应用程序

此程序在eclipse环境下可直接运行,希望可以帮到要用jni写串口的人

Android串口通信(Android Studio)

Android串口通信(Android Studio) serial Port 简单的demo 好久之前整的

【转】Android Studio : 使用 jni 实现串口通讯

添加 SerialPort 类 在网上找到 SerialPort 的 java 类,添加到项目中。 package com.xd.serialport; import android.util.Log; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java...

qixin1227的博客 782

pi/4QPSK调制解调原理

文章目录1. π/4\pi/4π/4QPSK 信号的调制原理2. 匹配滤波器与成形滤波器 1. π/4\pi/4π/4QPSK 信号的调制原理 减小相位突变量的QPSK由偏置键控QPSK(OK-QPSK)和 π/4\pi/4π/4偏置的QPSK( π/4\pi/4π/4QPSK)。由于 π/4\pi/4π/4QPSK是用差分相位编码产生的(因此也叫做 π/4\pi/4π/4DQPSK),能有效地进行差分解调和鉴频器解调,在一些不易提取相干载波的场合很有用。 在常规的QPSK中,输入数据经过串/并变换后,分成

gemengxia的博客 2万+

Android Studio使用Android_Serialport_Api调试串口

因工作需求调试串口需要使用Android_Serialport_Api这个项目中的类来做调试,在查阅官方文档和各路大神的文章后终于完成了这方面的调试,为了加深记忆,就把这部分的心得记录了下来。1.下载配置Android_Serialport_Api这个工程项目被托管在Google的代码库和GitHub上,下载地址贴出来: Google https://code.google.com/p/andro

m0_38047321的博客 8159

谷粒商城篇章9 ---- P248-P261/P292-P294 ---- 消息队列【分布式高级篇六】

RabbitMQ消息队列、RabbitMQ延时队列。

weixin_48568302的博客 1550

随机子空间集成方法原理与scikit-learn实践

集成学习通过组合多个基学习器的预测结果来提升模型性能,是机器学习中的核心方法之一。随机子空间方法作为集成学习的重要变体,其核心原理是通过对特征空间进行随机子采样来增加模型多样性。这种方法特别适合处理高维数据,能有效缓解维度灾难问题,常与决策树、K近邻等对特征选择敏感的基学习器配合使用。在scikit-learn中,可以通过BaggingClassifier和BaggingRegressor实现随机子空间集成,关键参数包括max_features和n_estimators。实际应用中,该方法在金融风控、医疗诊

weixin_33773084的博客 377

android串口通讯AS项目

该项目是AS结构,不用担心jNI转过来的配置问题了,文章结尾附测试的demo。 /** * 发送命令包 */ public void sendCommand(final String command) { LogPlus.i("发送命令:" + command); byte[] bytes = ByteUtil.hexStr2bytes(command); r...

刘 争 960

下载Python3.10的相关方法及问题解决

下载Python3.10的相关方法及问题解决 报错unable to locate package python3.10-dev以及subprocess.CalledProcessError: Command ‘(‘lsb_release‘, ‘-a‘)‘ returned non-zero exit status 1问题解决

Istil 1555

Android 串口通讯 获取卡号

首先你的andoridstudio 需要配置ndk 环境 然后在去下载谷歌的的demo 下载地址 把这些直接复制到代码中 一般jniC语言调用java是指定包名调用的 所有android_serialport_api的包名不要改变 直接复制过去就行 对了 jniLibs 需要指向下,如果不想指向可以把里面的内容复制到 libs里面 我写的指向 sourc...

小牧在一直在学习,在前进的道路上大家一起学习,进步。 2031

腾讯Android开发面试指南与参考答案

腾讯深圳元宝高级Android开发工程师岗位要求3-5年Android开发经验,熟悉Kotlin和性能优化,具备架构设计能力。岗位职责包括元宝Android客户端研发、稳定性优化及跨团队协作。面试重点考察Kotlin、Jetpack Compose、多线程编程等核心技术,3轮线上面试流程较快。无AI项目经验也可应聘,需突出展示Android架构设计、性能调优等实战能力。建议准备Compose开发、算法等加分项案例。

郑伟强dev的专栏 1133

【部署】Kimi 接入OpenClaw完整步骤及关键注意事项

本文详细介绍了如何将Kimi AI接入OpenClaw系统的完整步骤。首先需确保环境满足OpenClaw版本要求和系统支持,然后通过配置向导完成本地网关设置和Kimi模型接入,包括API密钥配置。文章提供了详细的命令操作和界面截图指导,并重点说明了安全警告处理、服务状态检查、API密钥有效性验证等关键注意事项。最后还展示了Kimi流量消耗明细和问题排查方法,帮助用户顺利完成接入并解决常见问题。整个流程清晰明了,涵盖了从环境准备到最终验证的全部环节。

海兰 7189

android串口通讯

之前使用google的串口工程,在实际使用中如果串口线掉了,或者系统不稳定会造成读不到数据或者或者读取的数据不全,从而串口卡住的情况。在google的demo中,只是使用的c语音去打开串口,操作串口读取数据还是使用java 的IO流进行读取,IO流在read的时候是没有超时处理的,所有会造成串口卡住。 最新从新用jni使用c重新写了串口调用,因为是用c取里的所以串口不会卡住,可以设置超时时间。 ...

my11712的专栏 1731

【思博伦】史上最详细Spirent TestCenter测试仪使用教程精讲(一)!图解超赞超详细!!!

3. 在弹出的界面中,找到菜单栏中的“Connect/Create”,选择下拉框中的“Connect to Physical/Visual Chassis”,在弹出的对话框中输入思博伦测试仪的IP地址:192.168.6.244,点击“OK”;说明:目前我们只需要使用到Raw Stream Block,不需要用到Bound Stream Block。说明:如果要使用100G模式,由于硬件限制,必须连续3个面板端口同时配置为100G使用。打开安装包,并按照提示按照即可。

风云说通信 6479

Android串口通讯

今天在整一个项目,需要利用串口通讯在网上看了好多人的帖子才稍微整出了一点头绪。 首先串口代码就是利用谷歌自己的api,将java代码放在java/android_serialport_api目录下,如果你想改变这个报名需要用jni重新生成so文件,在这里我是直接使用这个包名来简化工作。 androidStudio的结构如下: so文件: 在gradle添加依赖: 这样就可以 虽然SerialPort是有报错的但可以不用管他 这样就可以使用串口通信了 使用串口需要手机或者模拟器有对应的口...

ElegantHedgehog的博客 768

PCL 点到面的ICP算法【2024最新版】

经典的点到面的ICP算法。博客长期更新,本文最新更新时间为:2024年10月18日。

点云侠的博客 36万+

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Android Studio的串口通讯开发

基于android-serialport-api实现 前言RS232标准接口UARTRS232与UART转接下载 NDK 和构建工具创建支持 C/C++ 的新项目编译C/C++代码串口通讯原理关于校验位HexString与Bytes的转换参考 前言 软件代码写久了,总会对嵌入式开发感兴趣,因为软件的东西写来写去看不见摸不着,而嵌入式硬件开发,可以捣鼓一些机械设备玩,电子感应灯,遥控...

weixin_33777877的博客 1137

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Android app 的串口通讯相关笔记

Framework层中并没有封装关于串口通信的类库 涉及到一些算法或者底层驱动的时候,往往需要使用JNI来开发。现在官方推荐使用CMake工具来开发JNI, CMake 是一个开源的跨平台自动化构建系统 步骤: 1.环境:android studio 配置:File-->setting-->system setting-->Android SDK-->SDK Tools-->安装CMake等 2.新建工程File-->new-->new project--

yhy08090的博客 525

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

android 串口调试助手源码,GitHub - Michelle0716/SerialPortHelper: Android 串口调试助手

SerialPortHelperAndroid 串口调试助手前言物联网开发开发是时下热门的行业。Android系统自然也能进行物联网开发。除开Android本身自带的模块还有一类通过外部链接的设备需要通过串口来进行通信。本人在做完两个相关的抓娃娃和寄存柜项目之后觉得需要总结一点东西给大家。一些预备知识关于串口串口通信指串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口...

weixin_29131709的博客 2724

Android 开发笔记 —— AndroidStudio 中使用 android-serialport-api 进行串口通讯

android-serialport-api 的下载地址:点击这里 最近有关于在 Android 上实现串口通讯的需求,肯定会牵涉到 JNI 相关,关于 JNI 相关知识请参考: Android NDK开发(一) 入门, Android NDK开发(二) 底层实现HEX的编码和解码。 一、创建 NDK 项目 这里在 AndroidStudio 中使用的是 CMark...

Bevis的博客 3587

Android studio 使用NDK 实现串口 动态库

Android Studio 详细串口 NDK 教程

gd6321374的专栏 9979
上一篇: ANDROID动态加载 使用SO库时要注意的一些问题
下一篇: Android性能优化—不建议使用枚举Enum
doris_d
博客等级 码龄12年 79粉丝 126原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值