android 项目开发中使用到串口通信功能,在过程中遇到了一些炕。
一、首先要安装Cmake以及 ndk工具。

二、在跟main 目录下创建cpp 文件夹,以及CMakeLists.text 、SerialPort.c 文件

三、在CMakeLists.text 文件中编写生成动态so库

# For more information about using CMake with Android Studio, read the# documentation: https://d.android.com/studio/projects/add-native-code.html# Sets the minimum version of CMake required to build the native library.cmake_minimum_required(VERSION 3.4.1)# Creates and names a library, sets it as either STATIC# or SHARED, and provides the relative paths to its source code.# You can define multiple libraries, and CMake builds them for you.# Gradle automatically packages shared libraries with your APK.add_library( # Sets the name of the library.        native-lib        # Sets the library as a shared library.        SHARED        # Provides a relative path to your source file(s).        SerialPort.c        )# Searches for a specified prebuilt library and stores the path as a# variable. Because CMake includes system libraries in the search path by# default, you only need to specify the name of the public NDK library# you want to add. CMake verifies that the library exists before# completing its build.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)# Specifies libraries CMake should link to your target library. You# can link multiple libraries, such as libraries you define in this# build script, prebuilt third-party libraries, or system libraries.target_link_libraries( # Specifies the target library.        native-lib        # Links the target library to the log library        # included in the NDK.        ${log-lib})

四、在SerialPort.c 文件中写调用jni 接口,一般都是使用android 标准串口。

/* * Copyright 2009 Cedric Priscal * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law o0r agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#include #include #include #include #include #include #include #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: return B460800;case 500000: return B500000;case 576000: return B576000;case 921600: return B921600;default: return -1;}}/* * Class:     cedric_serial_SerialPort * Method:    open * Signature: (Ljava/lang/String;)V */JNIEXPORT jobject JNICALL Java_com_serialPort_SerialPort_open  (JNIEnv *env, jobject thiz, jstring path, jint baudrate){int fd;speed_t speed;jobject mFileDescriptor;/* Check arguments */{speed = getBaudrate(baudrate);if (speed == -1) {return NULL;}}/* Opening device */{jboolean iscopy;const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);LOGD("Opening serial port %s", path_utf);fd = open(path_utf, O_RDWR | O_SYNC);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, "", "()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_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);}

五、创建Serialport文件:

 * Copyright 2009 Cedric Priscal * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */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) 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/xbin/su");///*String cmd = "chmod 777 " + device.getAbsolutePath() + "\n"//+ "exit\n";*///String cmd = "chmod 777 /dev/ttyS4" + "\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, 0);        if (mFd == null) {            Log.e(TAG, "native open returns null");            throw new IOException();        }        mFileInputStream = new FileInputStream(mFd);        mFileOutputStream = new FileOutputStream(mFd);    }        public InputStream getInputStream() {        return mFileInputStream;    }    public OutputStream getOutputStream() {        return mFileOutputStream;    }        private native static FileDescriptor open(String path, int baudrate);    public native void close();    public native static FileDescriptor open(String path, int baudrate, int flags);  }

要注意文件路径创建要跟jni调用路径一直否则调用不到,出现找不到方法的异常,特别是编译好so库之后,给第三方使用要注明
六、读取线程

  class ReadThread extends Thread{        @Override        public void run() {            super.run();            byte[] bytes = new byte[1024];            while (!isInterrupted()){                int size = 0;                    try {                      if (mInputStream != null) {                          if (mInputStream.available() > 0 ) {                              SystemClock.sleep(2);                            try {                                size = mInputStream.read(bytes);                                if (size > 0) {                                     Log.i("SerialPort_test","==== " + bytes );                                }                            } catch (IOException e) {                                e.printStackTrace();                            }                        }                      }                    } catch (Exception e) {                        e.printStackTrace();                    }            }        }    }

**在通信过程中如数据比较大,可以会遇到数据读取不完整,感觉有掉帧一样,执行mInputStream.available(),这时可以在读取之前先延时一段时间,再一次文件流读取数据,
避免数据的错乱,接着过滤协议数据。
**读线程所在的类实例最好是一个单列模式,以避免多线程操作创建不同的对象,否则会读取到数据也跟掉帧一样,多线程并发还是要注意的!!!

更多相关文章

  1. [读书笔记]intent.putExtra的使用与原理分析
  2. android工程字符串多语言翻译遗漏查找工具
  3. Adapter软件设计模式在Android的应用
  4. Android(安卓)studio出现Error:Unable to tunnel through proxy.
  5. android模拟器SD卡使用
  6. Android(安卓)NDK移植libiconv和libxml2
  7. mybatisplus的坑 insert标签insert into select无参数问题的解决
  8. python起点网月票榜字体反爬案例
  9. NPM 和webpack 的基础使用

随机推荐

  1. Android(安卓)逐帧动画isRunning 一直返
  2. android用户界面之GridView教程实例汇总
  3. CSS字体随键盘弹出而改变
  4. android换皮肤
  5. 【Android studio安装】最新Android stud
  6. 试用NativeScript
  7. ReactNative调用Android原生方法
  8. 菜鸟带你Hook技术实战
  9. Android 获取屏幕高度,虚拟导航键检测
  10. Android智能定位手表开发-目录