IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 2019级软件工程应用与实践-人工智能快递柜(代码分析9) -> 正文阅读

[移动开发]2019级软件工程应用与实践-人工智能快递柜(代码分析9)

2021SC@SDUSC
下面几篇文章主要围绕串口进行分析。
Android并没有包含串口的JNI, 需要我们自己实现。
###接受串口数据的编程逻辑
在这里插入图片描述

SerialPort.h文件

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class android_serialport_api_SerialPort */

#ifndef _Included_android_serialport_api_SerialPort
#define _Included_android_serialport_api_SerialPort

设置宏,为了防止头文件的重复引用

#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     android_serialport_api_SerialPort
 * Method:    open
 * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor;
 */

JNIEXPORT jobject JNICALL Java_sdu_cislc_lcms_cabinet_serial_api_SerialPort_open
  (JNIEnv *, jclass, jstring, jint, jint);

/*
 * Class:     android_serialport_api_SerialPort
 * Method:    close
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_sdu_cislc_lcms_cabinet_serial_api_SerialPort_close
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

头文件中主要使用了一个陌生的语法**#ifdef __cplusplus extern “C”** 其主要作用就是主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,在通过JNI调用底层C代码的时候不会出错。

SerialPort.c文件

getBaudrate函数

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;
	}

采用switch函数,设置波特率函数会用到的数
通过speed_t getBaudRate(jint baudRate)可以获取波特率 注意没有匹配的数值时返回-1.

打开串口设备

JNIEXPORT jobject JNICALL Java_android_1serialport_1api_SerialPort_open
(JNIEnv *env, jobject object, jstring deviceName, jint baudRate)

这个函数与SerialPort.java中的open(String path, int baudRate)函数相关联

 const char *device = env->GetStringUTFChars(deviceName, 0);
    LOGI("Device=%s, BaudRate= %d", device, baudRate);

获取String的字符。不能直接的用device = deviceName;最后还要释放device指针。

int fd = -1;
    do {
        fd = open(device, O_RDWR);
        if (-1 == fd) {
            LOGE("Can't Open %s[%d]: %s", device, errno, strerror(errno));
            break;
        }
 
        speed_t speed = getBaudRate(baudRate);
        if (speed == -1) {
            LOGE("Invalid baudRate");
            break;
        }

打开设备如果fd=-1则说明文件不能正常打开
若speed=-1则取得的波特率无效

struct termios Opt;
        tcgetattr(fd, &Opt);
        cfmakeraw(&Opt);
        tcflush(fd, TCIFLUSH);
        cfsetispeed(&Opt, speed);
        cfsetospeed(&Opt, speed);
 
        if (tcsetattr(fd, TCSANOW, &Opt) != 0) {
            LOGE("SetupSerial![%d]: %s", errno, strerror(errno));
            break;
}

设置串口参数:
、、、、、、要写的

 jclass cFileDescriptor = env->FindClass("java/io/FileDescriptor");
        jmethodID iFileDescriptor = env->GetMethodID(cFileDescriptor, "<init>", "()V");
        jfieldID descriptorID = env->GetFieldID(cFileDescriptor, "descriptor", "I");
        jobject fileDescriptor = env->NewObject(cFileDescriptor, iFileDescriptor);
        env->SetIntField(fileDescriptor, descriptorID, (jint)fd);

用JNI函数创建一个FileDescriptor类的实例

env->ReleaseStringUTFChars(deviceName, device);
        return fileDescriptor;

    } while(0);

使用完device指针后进行释放,这个循环时一直进行的

if(fd != -1)
        close(fd); 
    env->ReleaseStringUTFChars(deviceName, device);
    return NULL;

在fd不等于-1时,关闭设备,并释放device指针。
完整代码:

JNIEXPORT jobject JNICALL Java_android_1serialport_1api_SerialPort_open
(JNIEnv *env, jobject object, jstring deviceName, jint baudRate)
{
    const char *device = env->GetStringUTFChars(deviceName, 0);
    LOGI("Device=%s, BaudRate= %d", device, baudRate);
 
    int fd = -1;
    do {
       
        fd = open(device, O_RDWR);
        if (-1 == fd) {
            LOGE("Can't Open %s[%d]: %s", device, errno, strerror(errno));
            break;
        }
 
        speed_t speed = getBaudRate(baudRate);
        if (speed == -1) {
            LOGE("Invalid baudRate");
            break;
        }
        struct termios Opt;
        tcgetattr(fd, &Opt);
        cfmakeraw(&Opt);
        tcflush(fd, TCIFLUSH);
        cfsetispeed(&Opt, speed);
        cfsetospeed(&Opt, speed);
 
        if (tcsetattr(fd, TCSANOW, &Opt) != 0) {
            LOGE("SetupSerial![%d]: %s", errno, strerror(errno));
            break;
        }
 
        jclass cFileDescriptor = env->FindClass("java/io/FileDescriptor");
        jmethodID iFileDescriptor = env->GetMethodID(cFileDescriptor, "<init>", "()V");
        jfieldID descriptorID = env->GetFieldID(cFileDescriptor, "descriptor", "I");
        jobject fileDescriptor = env->NewObject(cFileDescriptor, iFileDescriptor);
        env->SetIntField(fileDescriptor, descriptorID, (jint)fd);
 
        env->ReleaseStringUTFChars(deviceName, device);
        return fileDescriptor;
    } while(0);
 
    if(fd != -1)
        close(fd); 
    env->ReleaseStringUTFChars(deviceName, device);
    return NULL;
}

关闭串口设备

此函数与与SerialPort.java中的close(FileDescriptor fd);函数相关联。


JNIEXPORT jboolean JNICALL Java_android_1serialport_1api_SerialPort_close
(JNIEnv *env, jobject object, jobject descriptor)
{
    if(descriptor != NULL) {
        jclass cFileDescriptor = env->FindClass("java/io/FileDescriptor");
        jfieldID descriptorID = env->GetFieldID(cFileDescriptor, "descriptor", "I");
        jint fd = env->GetIntField(descriptor, descriptorID);
        close(fd);
    }
    return 1;
    }

“descriptor”属性是在FileDescriptor类里的,要用JNI函数来得到参数descriptor里的“descriptor”属性值。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-12-06 15:23:13  更:2021-12-06 15:23:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:27:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码