分享

android串口通信实例分析

 arm_embed 2012-07-26

置顶] android串口通信实例分析

分类: android 118人阅读 评论(4) 收藏 举报

android 串口通信实例分析,用的时开源的android-serialport-api

这个是用android ndk实现的串口通信,我把他做了一个简化,适合于一般的程序的串口通信移植,欢迎拍砖~~~~~~~~~

先说jni接口吧,原本文件太多,其实只需要SerialPort.c和Android.mk就可以实现

Serialport.c

  1. #include     <stdio.h>  
  2. #include     <stdlib.h>  
  3. #include     <unistd.h>  
  4. #include     <sys/types.h>  
  5. #include     <sys/stat.h>  
  6. #include     <fcntl.h>  
  7. #include     <termios.h>  
  8. #include     <errno.h>  
  9. #include     <jni.h>  
  10. #include     <android/log.h>  
  11.   
  12. #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "", __VA_ARGS__))//在logcat上打印信息用  
  13. //#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)  
  14. //#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)  
  15.   
  16. static speed_t getBaudrate(jint baudrate)  
  17. {  
  18.     switch(baudrate) {  
  19.     case 0return B0;  
  20.     case 50return B50;  
  21.     case 75return B75;  
  22.     case 110return B110;  
  23.     case 134return B134;  
  24.     case 150return B150;  
  25.     case 200return B200;  
  26.     case 300return B300;  
  27.     case 600return B600;  
  28.     case 1200return B1200;  
  29.     case 1800return B1800;  
  30.     case 2400return B2400;  
  31.     case 4800return B4800;  
  32.     case 9600return B9600;  
  33.     case 19200return B19200;  
  34.     case 38400return B38400;  
  35.     case 57600return B57600;  
  36.     case 115200return B115200;  
  37.     case 230400return B230400;  
  38.     case 460800return B460800;  
  39.     case 500000return B500000;  
  40.     case 576000return B576000;  
  41.     case 921600return B921600;  
  42.     case 1000000return B1000000;  
  43.     case 1152000return B1152000;  
  44.     case 1500000return B1500000;  
  45.     case 2000000return B2000000;  
  46.     case 2500000return B2500000;  
  47.     case 3000000return B3000000;  
  48.     case 3500000return B3500000;  
  49.     case 4000000return B4000000;  
  50.     defaultreturn -1;  
  51.     }  
  52. }  
  53.   
  54. /* 
  55.  * Class:     com.huangcheng.serial.SerialPort 
  56.  * Method:    open 
  57.  * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; 
  58.  * 
  59.  * 用于打开串口,配置串口参数,包括的参数有path(需要打开的串口设备文件路径),baudrate(波特率),flags(打开串口的参数,如O_NONBLOCK之类的,可以随不同情况设置) 
  60.  * 其串口数据的读取是用FileDescriptor来实现的 
  61.  * 
  62.  */  
  63. JNIEXPORT jobject JNICALL Java_com_huangcheng_serial_SerialPort_open  
  64.   (JNIEnv *env, jclass thiz, jstring path, jint baudrate, jint flags)  
  65. {  
  66.     int fd;  
  67.     speed_t speed;  
  68.     jobject mFileDescriptor;  
  69.   
  70.     /* Check arguments */  
  71.     {  
  72.         speed = getBaudrate(baudrate);  
  73.         if (speed == -1) {  
  74.             /* TODO: throw an exception */  
  75.             LOGI("Invalid baudrate");  
  76.             return NULL;  
  77.         }  
  78.     }  
  79.   
  80.     /* Opening device */  
  81.     {  
  82.         jboolean iscopy;  
  83.         const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);  
  84.         LOGI("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);  
  85.         fd = open(path_utf, O_RDWR | flags);  
  86.         LOGI("open() fd = %d", fd);  
  87.         (*env)->ReleaseStringUTFChars(env, path, path_utf);  
  88.         if (fd == -1)  
  89.         {  
  90.             /* Throw an exception */  
  91.             LOGI("Cannot open port");  
  92.             /* TODO: throw an exception */  
  93.             return NULL;  
  94.         }  
  95.     }  
  96.   
  97.     /* Configure device */  
  98.     {  
  99.         struct termios cfg;  
  100.         LOGI("Configuring serial port");  
  101.         if (tcgetattr(fd, &cfg))  
  102.         {  
  103.             LOGI("tcgetattr() failed");  
  104.             close(fd);  
  105.             /* TODO: throw an exception */  
  106.             return NULL;  
  107.         }  
  108.   
  109.         cfmakeraw(&cfg);  
  110.         cfsetispeed(&cfg, speed);  
  111.         cfsetospeed(&cfg, speed);  
  112.   
  113.         if (tcsetattr(fd, TCSANOW, &cfg))  
  114.         {  
  115.             LOGI("tcsetattr() failed");  
  116.             close(fd);  
  117.             /* TODO: throw an exception */  
  118.             return NULL;  
  119.         }  
  120.     }  
  121.   
  122.     /* Create a corresponding file descriptor */  
  123.     {  
  124.         jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");  
  125.         jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "<init>""()V");  
  126.         jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor""I");  
  127.         mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);  
  128.         (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)fd);  
  129.     }  
  130.   
  131.     return mFileDescriptor;  
  132. }  
  133.   
  134. /* 
  135.  * Class:     com.huangcheng.serial.SerialPort 
  136.  * Method:    close 
  137.  * Signature: ()V 
  138.  * 
  139.  * 用于串口关闭 
  140.  */  
  141. JNIEXPORT void JNICALL Java_com_huangcheng_serial_SerialPort_close  
  142.   (JNIEnv *env, jobject thiz)  
  143. {  
  144.     jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);  
  145.     jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");  
  146.   
  147.     jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd""Ljava/io/FileDescriptor;");  
  148.     jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor""I");  
  149.   
  150.     jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);  
  151.     jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);  
  152.   
  153.     LOGI("close(fd = %d)", descriptor);  
  154.     close(descriptor);  
  155. }  
Android.mk

  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4.   
  5. LOCAL_MODULE    := serial_port  
  6. LOCAL_SRC_FILES := SerialPort.c  
  7.   
  8. LOCAL_LDLIBS    := -llog  
  9. include $(BUILD_SHARED_LIBRARY)  

然后,直接在目录下ndk-build一下,便可得到我们需要的lib库文件。看看怎么调用吧,首先在SerialPort.java中实现打开和关闭串口,引用了lib 库

  1. package com.huangcheng.serial;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileDescriptor;  
  5. import java.io.FileInputStream;  
  6. import java.io.FileOutputStream;  
  7. import java.io.IOException;  
  8. import java.io.InputStream;  
  9. import java.io.OutputStream;  
  10.   
  11. import android.util.Log;  
  12.   
  13. public class SerialPort {  
  14.     private static final String TAG = "SerialPort";  
  15.   
  16.     /* 
  17.      * Do not remove or rename the field mFd: it is used by native method close(); 
  18.      */  
  19.     private FileDescriptor mFd;  
  20.     private FileInputStream mFileInputStream;  
  21.     private FileOutputStream mFileOutputStream;  
  22.   
  23.     public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException {  
  24.   
  25.         /* Check access permission */  
  26.         if (!device.canRead() || !device.canWrite()) {  
  27.             try {  
  28.                 /* Missing read/write permission, trying to chmod the file */  
  29.                 Process su;  
  30.                 su = Runtime.getRuntime().exec("/system/bin/su");  
  31.                 String cmd = "chmod 666 " + device.getAbsolutePath() + "\n"  
  32.                         + "exit\n";  
  33.                 su.getOutputStream().write(cmd.getBytes());  
  34.                 if ((su.waitFor() != 0) || !device.canRead()  
  35.                         || !device.canWrite()) {  
  36.                     throw new SecurityException();  
  37.                 }  
  38.             } catch (Exception e) {  
  39.                 e.printStackTrace();  
  40.                 throw new SecurityException();  
  41.             }  
  42.         }  
  43.   
  44.         mFd = open(device.getAbsolutePath(), baudrate, flags);  
  45.         if (mFd == null) {  
  46.             Log.e(TAG, "native open returns null");  
  47.             throw new IOException();  
  48.         }  
  49.         mFileInputStream = new FileInputStream(mFd);  
  50.         mFileOutputStream = new FileOutputStream(mFd);  
  51.     }  
  52.   
  53.     // Getters and setters  
  54.     public InputStream getInputStream() {  
  55.         return mFileInputStream;  
  56.     }  
  57.   
  58.     public OutputStream getOutputStream() {  
  59.         return mFileOutputStream;  
  60.     }  
  61.   
  62.     // JNI  
  63.     private native static FileDescriptor open(String path, int baudrate, int flags);  
  64.     public native void close();  
  65.     static {  
  66.         System.loadLibrary("serial_port");  
  67.     }  
  68. }  
然后他做了一个很聪明的控制串口打开和关闭的类Application.java,继承自android.app.Application 这样,他便可以在所有的Activity类中调用实现串口打开和关闭。
  1. /* 
  2.  * Copyright 2009 Cedric Priscal 
  3.  *  
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  *  
  8.  * http://www./licenses/LICENSE-2.0 
  9.  *  
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License.  
  15.  */  
  16.   
  17. package com.huangcheng.serial;  
  18.   
  19. import java.io.File;  
  20. import java.io.IOException;  
  21. import java.security.InvalidParameterException;  
  22.   
  23. public class Application extends android.app.Application {  
  24.   
  25.     private SerialPort mSerialPort = null;  
  26.   
  27.     public SerialPort getSerialPort() throws SecurityException, IOException, InvalidParameterException {  
  28.         if (mSerialPort == null) {  
  29.             /* Open the serial port */  
  30.             mSerialPort = new SerialPort(new File("/dev/ttyUSB0"),192000);  
  31.         }  
  32.         return mSerialPort;  
  33.     }  
  34.   
  35.     public void closeSerialPort() {  
  36.         if (mSerialPort != null) {  
  37.             mSerialPort.close();  
  38.             mSerialPort = null;  
  39.         }  
  40.     }  
  41. }  
最后写了一个类SerialPortActivity.java实现串口打开和关闭,串口数据通过Input/OutputStrean流来读取和发送,所有继承这个类的Activiy就可以实现串口读取或者发送。

  1. /* 
  2.  * Copyright 2009 Cedric Priscal 
  3.  *  
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  *  
  8.  * http://www./licenses/LICENSE-2.0 
  9.  *  
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License.  
  15.  */  
  16.   
  17. package com.huangcheng.serial;  
  18.   
  19. import java.io.IOException;  
  20. import java.io.InputStream;  
  21. import java.io.OutputStream;  
  22. import java.security.InvalidParameterException;  
  23.   
  24. import com.huangcheng.zigbeeview.R;  
  25.   
  26. import android.app.Activity;  
  27. import android.app.AlertDialog;  
  28. import android.content.DialogInterface;  
  29. import android.content.DialogInterface.OnClickListener;  
  30. import android.os.Bundle;  
  31. public abstract class SerialPortActivity extends Activity {  
  32.   
  33.     protected Application mApplication;  
  34.     protected SerialPort mSerialPort;  
  35.     protected OutputStream mOutputStream;  
  36.     private InputStream mInputStream;  
  37.     private ReadThread mReadThread;  
  38.   
  39.     private class ReadThread extends Thread {  
  40.   
  41.         @Override  
  42.         public void run() {  
  43.             super.run();  
  44.             while(!isInterrupted()) {  
  45.                 int size;  
  46.                 try {  
  47.                     byte[] buffer = new byte[64];  
  48.                     if (mInputStream == nullreturn;  
  49.                     size = mInputStream.read(buffer);  
  50.                     if (size > 0) {  
  51.                         onDataReceived(buffer, size);  
  52.                     }  
  53.                 } catch (IOException e) {  
  54.                     e.printStackTrace();  
  55.                     return;  
  56.                 }  
  57.             }  
  58.         }  
  59.     }  
  60.   
  61.     private void DisplayError(int resourceId) {  
  62.         AlertDialog.Builder b = new AlertDialog.Builder(this);  
  63.         b.setTitle("Error");  
  64.         b.setMessage(resourceId);  
  65.         b.setPositiveButton("OK"new OnClickListener() {  
  66.             public void onClick(DialogInterface dialog, int which) {  
  67.                 SerialPortActivity.this.finish();  
  68.             }  
  69.         });  
  70.         b.show();  
  71.     }  
  72.   
  73.     @Override  
  74.     protected void onCreate(Bundle savedInstanceState) {  
  75.         super.onCreate(savedInstanceState);  
  76.         mApplication = (Application) getApplication();  
  77.         try {  
  78.             mSerialPort = mApplication.getSerialPort();  
  79.             mOutputStream = mSerialPort.getOutputStream();  
  80.             mInputStream = mSerialPort.getInputStream();  
  81.   
  82.             /* Create a receiving thread */  
  83.             mReadThread = new ReadThread();  
  84.             mReadThread.start();  
  85.         } catch (SecurityException e) {  
  86.             DisplayError(R.string.error_security);  
  87.         } catch (IOException e) {  
  88.             DisplayError(R.string.error_unknown);  
  89.         } catch (InvalidParameterException e) {  
  90.             DisplayError(R.string.error_configuration);  
  91.         }  
  92.     }  
  93.   
  94.     protected abstract void onDataReceived(final byte[] buffer, final int size);  
  95.   
  96.     @Override  
  97.     protected void onDestroy() {  
  98.         if (mReadThread != null)  
  99.             mReadThread.interrupt();  
  100.         mApplication.closeSerialPort();  
  101.         mSerialPort = null;  
  102.         super.onDestroy();  
  103.     }  
  104. }  

最后,是一个测试Activity实现串口收发,ConsoleActivity.java
  1. /* 
  2.  * Copyright 2009 Cedric Priscal 
  3.  *  
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  *  
  8.  * http://www./licenses/LICENSE-2.0 
  9.  *  
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License.  
  15.  */  
  16.   
  17. package com.huangcheng.serial;  
  18.   
  19. import java.io.IOException;  
  20.   
  21. import com.huangcheng.zigbeeview.R;  
  22.   
  23. import android.os.Bundle;  
  24. import android.view.KeyEvent;  
  25. import android.widget.EditText;  
  26. import android.widget.TextView;  
  27. import android.widget.TextView.OnEditorActionListener;  
  28.   
  29. public class ConsoleActivity extends SerialPortActivity {  
  30.   
  31.     EditText mReception;  
  32.   
  33.     @Override  
  34.     protected void onCreate(Bundle savedInstanceState) {  
  35.         super.onCreate(savedInstanceState);  
  36.         setContentView(R.layout.console);  
  37.   
  38. //      setTitle("Loopback test");  
  39.         mReception = (EditText) findViewById(R.id.EditTextReception);  
  40.   
  41.         EditText Emission = (EditText) findViewById(R.id.EditTextEmission);  
  42.         Emission.setOnEditorActionListener(new OnEditorActionListener() {  
  43.             public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {  
  44.                 int i;  
  45.                 CharSequence t = v.getText();  
  46.                 char[] text = new char[t.length()];  
  47.                 for (i=0; i<t.length(); i++) {  
  48.                     text[i] = t.charAt(i);  
  49.                 }  
  50.                 try {  
  51.                     mOutputStream.write(new String(text).getBytes());  
  52.                     mOutputStream.write('\n');  
  53.                 } catch (IOException e) {  
  54.                     e.printStackTrace();  
  55.                 }  
  56.                 return false;  
  57.             }  
  58.         });  
  59.     }  
  60.   
  61.     @Override  
  62.     protected void onDataReceived(final byte[] buffer, final int size) {  
  63.         runOnUiThread(new Runnable() {  
  64.             public void run() {  
  65.                 if (mReception != null) {  
  66.                     mReception.append(new String(buffer, 0, size));  
  67.                 }  
  68.             }  
  69.         });  
  70.     }  
  71. }  
我会把android-serialport-api源码上传,大家可以根据我的这个博客自己简化一下,就可以直接移植到需要到程序上去了,绝对可用!

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多