
串口通讯
引言
对于安卓开发的小伙伴来说,很少用到串口通信开发。主要用来外接一些硬件设备,例如扫码器,读卡器,体温枪等一些硬件设备。这些设备与安卓之间通过串口来交换数据。如果有安卓串口开发这方面的需求,本文将会对你有所帮助。
1.基本概念
串口的概念: 用串行通信方式的扩展接口,指数据一位一位地顺序传送。
串口操作相关参数:
- 1.设备名(串口地址):安卓是基于Linux系统,所以通常的串口地址为:/dev/ttyS0,/dev/ttyS1… 等。可通过linux命令查看对应的串口状态。
- 2.波特率:串口传输速率,用来衡量数据传输的快慢,即单位时间内载波参数变化的次数。波特率与距离成反比,波特率越大传输距离相应的就越短。
- 3.数据位:衡量通信中实际数据位的参数。当计算机发送一个信息包,实际的数据往往不会是8位的,标准的值是6、7和8位。如何设置取决于你想传送的信息。
- 4.停止位:用于表示单个包的最后一位。
- 5.校验位:在串口通信中一种简单的检错方式。有四种检错方式:偶、奇、高和低。
注意:
在 google 官方提供的 demo 代码基本上能够应付很多在Android设备使用串口的场景,该demo中不支持设置N,8,1。N对应校验位,8对应数据位,1对应停止位。在安卓串口操作中,不需要这三个参数。
2.串口通信 lib 准备
网上提供的代码都是通过 ndk 来编译 jni 文件生成对应的.so库。通过编写 jni 文件来打开串口,获取串口的数据流,来进行相应的读写操作。
本文通过CMake来编译 jni 文件生成对应的 so 库文件。
1.创建Android-library库。
1.首先创建:seriallibrary库
通常一些独立的功能模块,可能出现复用的情况,通常建议提取到 library 中,这样整个工程架构更加清晰明了,非常建议这样做。

2.配置CMake支持
在seriallibrary库的 build.gradle 中添加依赖:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FFA6XM5a-1633935046145)(image-20210317190054115.png)]](/https://i-blog.csdnimg.cn/blog_migrate/7e24e06047f7d96af8277b9fac3858bf.png)
3.创建 jni 文件
在 main 文件夹下创建 jni 文件夹,并创建对应的文件:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yaYkZaHs-1633935046147)(image-20210317190236684.png)]](/https://i-blog.csdnimg.cn/blog_migrate/3bc02d364b1c58b98e30933b0a328c6c.png)
4.编写 CMakeLists.txt 文件
这里涉及到 jni 和 cmake 编译相关知识,可以自行查阅 cmake 使用教程。
CMakeLists.txt 文件配置 如下:
cmake_minimum_required(VERSION 3.10.2)
# Declares and names the project.
project("serial_port2")
add_library( # Sets the name of the library.
serial
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
SerialPort.c)
include_directories(src/main/jni/)
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
target_link_libraries( # Specifies the target library.
serial
# Links the target library to the log library
# included in the NDK.
${
log-lib} )
在编写 jni 接口时,首先需要创建对应的 java 类及对应的 native 方法,创建 SerialPort.java文件。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vXL5FH4U-1633935046148)(image-20210317191826314.png)]](/https://i-blog.csdnimg.cn/blog_migrate/222b1fae9179873a6578bdb3bc2b32ab.png)
SerialPort.java 类有 open 和 close 方法,用来打开和关闭串口:
package com.android.library;
import java.io.FileDescriptor;
public class SerialPort {
/**
* 打开串口
* @param path 串口名称
* @param porterRate 波特率
* @param flags
* @return
*/
private native static FileDescriptor open(String path, int porterRate, int flags);
/**
* 关闭串口
*/
private native void close();
/**
* 加载 so 库,该库名称与在 CMakeLists.txt 配置的库名相同
*/
static {
System.loadLibrary("serial");
}
}
open 方法对应的全路径名称为:com.android.library.SerialPort#open
close 方法对应的全路径名称为:com.android.library.SerialPort#close
编写对应的 SerialPort.h 文件:注意 JNICALL 后的方法名不要写错,open 方法路径中的 . 对应__
com.android.library.SerialPort#open -> Java_com_android_library_SerialPort_open
com.android.library.SerialPort#close -> Java_com_android_library_SerialPort_close
SerialPort.h 文件如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com.android.library.SerialPort */
#ifndef _Included_com_android_libary_SerialPort
#ifdef __cplusplus
extern "C" {
#endif
/*
*
* Method: open
* Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor;
*/
/**
* Class: com.android.library.SerialPort
* Method: open
* 对应的jni接口为: com_android_library_SerialPort_open
*/
JNIEXPORT jobject JNICALL Java_com_android_library_SerialPort_open
(JNIEnv *, jclass, jstring, jint, jint);
/**
* Class: com.android.library.SerialPort
* Method: open
* 对应的jni接口为: com_android_library_SerialPort_close
*/
JNIEXPORT void JNICALL Java_com_android_library_SerialPort_close
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
SerialPort.c 文件如下:除了 JNICALL 方法名不同,其它都一样,来自 google 提供的串口工具 demo
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <jni.h>
#include "SerialPort.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)
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:

本文详细介绍了如何在Android平台上进行串口通信的开发,包括基本概念如波特率、数据位、停止位和校验位,以及如何使用CMake编译JNI文件生成.so库,通过Java调用 native 方法进行串口的打开、关闭操作。此外,还提供了串口读写数据的封装以及线程池管理,使得串口操作更加便捷。

3714

被折叠的 条评论
为什么被折叠?



