您好,登錄后才能下訂單哦!
這篇文章給大家介紹Android中怎么實現串口讀寫,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
1、SerialPort.cpp
#include <stdlib.h> #include <stdio.h> #include <jni.h> #include <assert.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) 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: cedric_serial_SerialPort * Method: open * Signature: (Ljava/lang/String;)V */ JNIEXPORT jobject JNICALL native_open(JNIEnv *env, jobject thiz, jstring path,jint baudrate) { int fd; speed_t speed; jobject mFileDescriptor; LOGD("init native Check arguments"); /* Check arguments */ { speed = getBaudrate(baudrate); if (speed == -1) { /* TODO: throw an exception */ LOGE("Invalid baudrate"); return NULL; } } LOGD("init native Opening device!"); /* Opening device */ { jboolean iscopy; const char *path_utf = env->GetStringUTFChars(path, &iscopy); LOGD("Opening serial port %s", path_utf); // fd = open(path_utf, O_RDWR | O_DIRECT | O_SYNC); fd = open(path_utf, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY); LOGD("open() fd = %d", fd); env->ReleaseStringUTFChars(path, path_utf); if (fd == -1) { /* Throw an exception */ LOGE("Cannot open port %d",baudrate); /* TODO: throw an exception */ return NULL; } } LOGD("init native Configure device!"); /* Configure device */ { struct termios cfg; if (tcgetattr(fd, &cfg)) { LOGE("Configure device tcgetattr() failed 1"); close(fd); return NULL; } cfmakeraw(&cfg); cfsetispeed(&cfg, speed); cfsetospeed(&cfg, speed); if (tcsetattr(fd, TCSANOW, &cfg)) { LOGE("Configure device tcsetattr() failed 2"); close(fd); /* TODO: throw an exception */ return NULL; } } /* Create a corresponding file descriptor */ { jclass cFileDescriptor = env->FindClass("java/io/FileDescriptor"); jmethodID iFileDescriptor = env->GetMethodID(cFileDescriptor,"<init>", "()V"); jfieldID descriptorID = env->GetFieldID(cFileDescriptor,"descriptor", "I"); mFileDescriptor = env->NewObject(cFileDescriptor,iFileDescriptor); env->SetIntField(mFileDescriptor, descriptorID, (jint) fd); } return mFileDescriptor; } /* * Class: cedric_serial_SerialPort * Method: close * Signature: ()V */ JNIEXPORT jint JNICALL native_close(JNIEnv * env, jobject thiz) { jclass SerialPortClass = env->GetObjectClass(thiz); jclass FileDescriptorClass = env->FindClass("java/io/FileDescriptor"); jfieldID mFdID = env->GetFieldID(SerialPortClass, "mFd", "Ljava/io/FileDescriptor;"); jfieldID descriptorID = env->GetFieldID(FileDescriptorClass, "descriptor", "I"); jobject mFd = env->GetObjectField(thiz, mFdID); jint descriptor = env->GetIntField(mFd, descriptorID); LOGD("close(fd = %d)", descriptor); close(descriptor); return 1; } static JNINativeMethod gMethods[] = { { "open", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;",(void*) native_open }, { "close", "()I",(void*) native_close }, }; /* * 為某一個類注冊本地方法 */ static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods, int numMethods) { jclass clazz; clazz = env->FindClass(className); if (clazz == NULL) { return JNI_FALSE; } if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) { return JNI_FALSE; } return JNI_TRUE; } /* * 為所有類注冊本地方法 */ static int registerNatives(JNIEnv* env) { const char* kClassName = "com/jerome/serialport/SerialPort"; //指定要注冊的類 return registerNativeMethods(env, kClassName, gMethods, sizeof(gMethods) / sizeof(gMethods[0])); } /* * System.loadLibrary("lib")時調用 * 如果成功返回JNI版本, 失敗返回-1 */ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { return -1; } assert(env != NULL); if (!registerNatives(env)) { //注冊 return -1; } //成功 result = JNI_VERSION_1_4; return result; }
在編譯時注意修改const char* kClassName = "com/jerome/serialport/SerialPort";為你Java層與jni對應得包名;
2、Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) TARGET_PLATFORM := android-3 LOCAL_MODULE := serial_port LOCAL_SRC_FILES := SerialPort.cpp LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY)
如果要修改生成so文件的名稱,請修改LOCAL_MODULE := serial_port
3、SerialPort.java
package com.jerome.serialport; 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 { mFd = open(device.getAbsolutePath(), baudrate); if (mFd == null) { throw new IOException(); } mFileInputStream = new FileInputStream(mFd); mFileOutputStream = new FileOutputStream(mFd); } public InputStream getInputStream() { return mFileInputStream; } public OutputStream getOutputStream() { return mFileOutputStream; } private native FileDescriptor open(String path, int baudrate); public native int close(); static { System.loadLibrary("serial_port"); } }
4、SerialPortUtil.java
package com.jerome.serialport; import java.io.BufferedWriter; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; /** * 串口操作類 * * @author Jerome * */ public class SerialPortUtil { private String TAG = SerialPortUtil.class.getSimpleName(); private SerialPort mSerialPort; private OutputStream mOutputStream; private InputStream mInputStream; private ReadThread mReadThread; private String path = "/dev/ttyMT1"; private int baudrate = 115200; private static SerialPortUtil portUtil; private OnDataReceiveListener onDataReceiveListener = null; private boolean isStop = false; public interface OnDataReceiveListener { public void onDataReceive(byte[] buffer, int size); } public void setOnDataReceiveListener( OnDataReceiveListener dataReceiveListener) { onDataReceiveListener = dataReceiveListener; } public static SerialPortUtil getInstance() { if (null == portUtil) { portUtil = new SerialPortUtil(); portUtil.onCreate(); } return portUtil; } /** * 初始化串口信息 */ public void onCreate() { try { mSerialPort = new SerialPort(new File(path), baudrate); mOutputStream = mSerialPort.getOutputStream(); mInputStream = mSerialPort.getInputStream(); mReadThread = new ReadThread(); isStop = false; mReadThread.start(); } catch (Exception e) { e.printStackTrace(); } initBle(); } /** * 發送指令到串口 * * @param cmd * @return */ public boolean sendCmds(String cmd) { boolean result = true; byte[] mBuffer = (cmd+"\r\n").getBytes(); //注意:我得項目中需要在每次發送后面加\r\n,大家根據項目項目做修改,也可以去掉,直接發送mBuffer try { if (mOutputStream != null) { mOutputStream.write(mBuffer); } else { result = false; } } catch (IOException e) { e.printStackTrace(); result = false; } return result; } public boolean sendBuffer(byte[] mBuffer) { boolean result = true; String tail = "\r\n"; byte[] tailBuffer = tail.getBytes(); byte[] mBufferTemp = new byte[mBuffer.length+tailBuffer.length]; System.arraycopy(mBuffer, 0, mBufferTemp, 0, mBuffer.length); System.arraycopy(tailBuffer, 0, mBufferTemp, mBuffer.length, tailBuffer.length); //注意:我得項目中需要在每次發送后面加\r\n,大家根據項目項目做修改,也可以去掉,直接發送mBuffer try { if (mOutputStream != null) { mOutputStream.write(mBufferTemp); } else { result = false; } } catch (IOException e) { e.printStackTrace(); result = false; } return result; } private class ReadThread extends Thread { @Override public void run() { super.run(); while (!isStop && !isInterrupted()) { int size; try { if (mInputStream == null) return; byte[] buffer = new byte[512]; size = mInputStream.read(buffer); if (size > 0) { if(MyLog.isDyeLevel()){ MyLog.log(TAG, MyLog.DYE_LOG_LEVEL, "length is:"+size+",data is:"+new String(buffer, 0, size)); } if (null != onDataReceiveListener) { onDataReceiveListener.onDataReceive(buffer, size); } } Thread.sleep(10); } catch (Exception e) { e.printStackTrace(); return; } } } } /** * 關閉串口 */ public void closeSerialPort() { sendShellCommond1(); isStop = true; if (mReadThread != null) { mReadThread.interrupt(); } if (mSerialPort != null) { mSerialPort.close(); } } }
5、使用方法:
a、配置ndk開發環境,具體百度一下;
b、工程根目錄下新建jni文件夾,將Android.mk和SerialPort.cpp放進去;
c、ndk中進入jni目錄,編譯生成so文件,默認so生成在libs/armeabi下;
d、新建com.jerom.serialport目錄,將SerialPort和SerialPortUtil放進去;
f、在你要使用的地方初始化SerialPortUtil,實現回調接口OnDataReceiveListener即可接受數據;
關于Android中怎么實現串口讀寫就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。