两种串口实现方法总结,请看:

http://blog.csdn.net/fengyuwuzu0519/article/details/73928618

  最近在做android串口的开发,找到一个开源的串口类android-serialport-api。其主页在这里http://code.google.com/p/android-serialport-api/  ,这里可以下到APK及对源码。

    但是下载源码之后发现源码不能直接使用,而且源码结构较为复杂。关于串口的操作不外乎几步:

   1.打开串口(及配置串口);

   2.读串口;

   3.写串口;

   4.关闭串口。

android-serialport-api的代码使用了继承等复杂的行为,不容易使初学者很快掌握关于串口的上述4步,所以我特别自己写了一个demo,只有一个activity,其中包含了打开串口,写串口,读串口的操作,对于关闭串口,大家一开就会不明白怎么写了。

这篇文章主要参考http://blog.csdn.net/tangcheng_ok/article/details/7021470

还有http://blog.csdn.net/jerome_home/article/details/8452305

 

下面言归正传:

 

第一:

  说道android 串口,就不得不提JNI技术,它使得java中可以调用c语言写成的库。为可在android中使用串口,android-serialport-api的作者自己写了一个c语言的动态链接库serial_port.so(自动命名成libserial_port.so),并把它放在了libs/aemeabi 里,其c源文件在JNI中,大家在下载了android-serialport-api的源代码后,将这两个文件夹copy到自己新建的工程中即可。

 

第二:

然后将调用c语言写成的动态链接库的java类放入到src文件夹下的android.serialport包下,这里一定要将包名命名成这个,因为对JNI有一定了解的人就会知道,在写c语言链接库时候,函数的命名是和调用它的类所在的包名相关的,一旦包名与链接库中函数的命名不相符,就不能调用链接库的函数。这里可以打开jni中的.c文件(他就是动态链接库的源文件),可以看到源码:

[cpp] view plaincopy

 

  1.   

[cpp] view plaincopy

 

  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.apache.org/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. #include   
  18. #include   
  19. #include   
  20. #include   
  21. #include   
  22. #include   
  23. #include   
  24.   
  25. #include "android/log.h"  
  26. static const char *TAG="serial_port";  
  27. #define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO,  TAG, fmt, ##args)  
  28. #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)  
  29. #define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)  
  30.   
  31. static speed_t getBaudrate(jint baudrate)  
  32. {  
  33.     switch(baudrate) {  
  34.     case 0: return B0;  
  35.     case 50: return B50;  
  36.     case 75: return B75;  
  37.     case 110: return B110;  
  38.     case 134: return B134;  
  39.     case 150: return B150;  
  40.     case 200: return B200;  
  41.     case 300: return B300;  
  42.     case 600: return B600;  
  43.     case 1200: return B1200;  
  44.     case 1800: return B1800;  
  45.     case 2400: return B2400;  
  46.     case 4800: return B4800;  
  47.     case 9600: return B9600;  
  48.     case 19200: return B19200;  
  49.     case 38400: return B38400;  
  50.     case 57600: return B57600;  
  51.     case 115200: return B115200;  
  52.     case 230400: return B230400;  
  53.     case 460800: return B460800;  
  54.     case 500000: return B500000;  
  55.     case 576000: return B576000;  
  56.     case 921600: return B921600;  
  57.     case 1000000: return B1000000;  
  58.     case 1152000: return B1152000;  
  59.     case 1500000: return B1500000;  
  60.     case 2000000: return B2000000;  
  61.     case 2500000: return B2500000;  
  62.     case 3000000: return B3000000;  
  63.     case 3500000: return B3500000;  
  64.     case 4000000: return B4000000;  
  65.     default: return -1;  
  66.     }  
  67. }  
  68.   
  69. /* 
  70.  * Class:     cedric_serial_SerialPort 
  71.  * Method:    open 
  72.  * Signature: (Ljava/lang/String;)V 
  73.  */  
  74. JNIEXPORT jobject JNICALL Java_android_serialport_SerialPort_open  
  75.   (JNIEnv *env, jobject thiz, jstring path, jint baudrate)  
  76. {  
  77.     int fd;  
  78.     speed_t speed;  
  79.     jobject mFileDescriptor;  
  80.   
  81.     /* Check arguments */  
  82.     {  
  83.         speed = getBaudrate(baudrate);  
  84.         if (speed == -1) {  
  85.             /* TODO: throw an exception */  
  86.             LOGE("Invalid baudrate");  
  87.             return NULL;  
  88.         }  
  89.     }  
  90.   
  91.     /* Opening device */  
  92.     {  
  93.         jboolean iscopy;  
  94.         const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);  
  95.         LOGD("Opening serial port %s", path_utf);  
  96.         fd = open(path_utf, O_RDWR | O_DIRECT | O_SYNC);  
  97.         LOGD("open() fd = %d", fd);  
  98.         (*env)->ReleaseStringUTFChars(env, path, path_utf);  
  99.         if (fd == -1)  
  100.         {  
  101.             /* Throw an exception */  
  102.             LOGE("Cannot open port");  
  103.             /* TODO: throw an exception */  
  104.             return NULL;  
  105.         }  
  106.     }  
  107.   
  108.     /* Configure device */  
  109.     {  
  110.         struct termios cfg;  
  111.         LOGD("Configuring serial port");  
  112.         if (tcgetattr(fd, &cfg))  
  113.         {  
  114.             LOGE("tcgetattr() failed");  
  115.             close(fd);  
  116.             /* TODO: throw an exception */  
  117.             return NULL;  
  118.         }  
  119.   
  120.         cfmakeraw(&cfg);  
  121.         cfsetispeed(&cfg, speed);  
  122.         cfsetospeed(&cfg, speed);  
  123.   
  124.         if (tcsetattr(fd, TCSANOW, &cfg))  
  125.         {  
  126.             LOGE("tcsetattr() failed");  
  127.             close(fd);  
  128.             /* TODO: throw an exception */  
  129.             return NULL;  
  130.         }  
  131.     }  
  132.   
  133.     /* Create a corresponding file descriptor */  
  134.     {  
  135.         jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");  
  136.         jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "", "()V");  
  137.         jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I");  
  138.         mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);  
  139.         (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)fd);  
  140.     }  
  141.   
  142.     return mFileDescriptor;  
  143. }  
  144.   
  145. /* 
  146.  * Class:     cedric_serial_SerialPort 
  147.  * Method:    close 
  148.  * Signature: ()V 
  149.  */  
  150. JNIEXPORT void JNICALL Java_android_serialport_SerialPort_close  
  151.   (JNIEnv *env, jobject thiz)  
  152. {  
  153.     jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);  
  154.     jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");  
  155.   
  156.     jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");  
  157.     jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I");  
  158.   
  159.     jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);  
  160.     jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);  
  161.   
  162.     LOGD("close(fd = %d)", descriptor);  
  163.     close(descriptor);  
  164. }  


可以看到,函数的命名规则直接和包名有关。

 

 

第三:

android.serialport包下,有两个类,分别是SerialPort.java 和SerialPortFinder.java。

其中,SerialPort.java,这个类主要用来加载SO文件,通过JNI的方式打开关闭串口。

[java] view plaincopy

 

  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.apache.org/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 android.serialport;  
  18.   
  19. import java.io.File;  
  20. import java.io.FileDescriptor;  
  21. import java.io.FileInputStream;  
  22. import java.io.FileOutputStream;  
  23. import java.io.IOException;  
  24. import java.io.InputStream;  
  25. import java.io.OutputStream;  
  26.   
  27. import android.util.Log;  
  28.   
  29. public class SerialPort {  
  30.   
  31.     private static final String TAG = "SerialPort";  
  32.   
  33.     /* 
  34.      * Do not remove or rename the field mFd: it is used by native method close(); 
  35.      */  
  36.     private FileDescriptor mFd;  
  37.     private FileInputStream mFileInputStream;  
  38.     private FileOutputStream mFileOutputStream;  
  39.   
  40.     public SerialPort(File device, int baudrate) throws SecurityException, IOException {  
  41.   
  42.         /* Check access permission */  
  43.         if (!device.canRead() || !device.canWrite()) {  
  44.             try {  
  45.                 /* Missing read/write permission, trying to chmod the file */  
  46.                 Process su;  
  47.                 su = Runtime.getRuntime().exec("/system/bin/su");  
  48.                 String cmd = "chmod 777 " + device.getAbsolutePath() + "\n"  
  49.                         + "exit\n";  
  50.                 /*String cmd = "chmod 777 /dev/s3c_serial0" + "\n" 
  51.                 + "exit\n";*/  
  52.                 su.getOutputStream().write(cmd.getBytes());  
  53.                 if ((su.waitFor() != 0) || !device.canRead()  
  54.                         || !device.canWrite()) {  
  55.                     throw new SecurityException();  
  56.                 }  
  57.             } catch (Exception e) {  
  58.                 e.printStackTrace();  
  59.                 throw new SecurityException();  
  60.             }  
  61.         }  
  62.   
  63.         mFd = open(device.getAbsolutePath(), baudrate);  
  64.         if (mFd == null) {  
  65.             Log.e(TAG, "native open returns null");  
  66.             throw new IOException();  
  67.         }  
  68.         mFileInputStream = new FileInputStream(mFd);  
  69.         mFileOutputStream = new FileOutputStream(mFd);  
  70.     }  
  71.   
  72.     // Getters and setters  
  73.     public InputStream getInputStream() {  
  74.         return mFileInputStream;  
  75.     }  
  76.   
  77.     public OutputStream getOutputStream() {  
  78.         return mFileOutputStream;  
  79.     }  
  80.   
  81.     // JNI  
  82.     private native static FileDescriptor open(String path, int baudrate);  
  83.     public native void close();  
  84.     static {  
  85.         System.loadLibrary("serial_port");  
  86.     }  
  87. }  

可以看到System.loadLibrary("serial_port");一句,这一句就是用来加载动态链接库。我们的串口操作就是要给予这个类来实现。

 

 

含有一个类SerialPortFinder.java,这个类是用来找到系统中可以用的串口的,如果你知道的android设备有什么串口,就不必使用这个类来查找串口了,一次简化我们的demo。

 

第四:加入我们自己的Activity类

  为了方便我记在android.serialport包下加入了我自己的MyserialActivity.java,大家从上面的图中也可以看见。

代码如下:

[java] view plaincopy

 

  1. package android.serialport;  
  2.   
  3.   
  4. import java.io.File;  
  5. import java.io.FileInputStream;  
  6. import java.io.FileOutputStream;  
  7. import java.io.IOException;  
  8.   
  9. import android.app.Activity;  
  10.   
  11. import android.os.Bundle;  
  12.   
  13.   
  14.   
  15. //import android.serialport.sample.R;  
  16. import android.serialport.R;  
  17.   
  18. import android.view.View;  
  19. import android.widget.Button;  
  20. import android.widget.EditText;  
  21. import android.widget.Toast;  
  22.   
  23. public class MyserialActivity extends Activity {  
  24.     /** Called when the activity is first created. */  
  25.       
  26.       
  27.      EditText mReception;  
  28.      FileOutputStream mOutputStream;  
  29.      FileInputStream mInputStream;  
  30.      SerialPort sp;  
  31.        
  32.     @Override  
  33.      
  34.     public void onCreate(Bundle savedInstanceState) {  
  35.         super.onCreate(savedInstanceState);  
  36.         setContentView(R.layout.main);  
  37.     
  38.       
  39.     final Button buttonSetup = (Button)findViewById(R.id.ButtonSetup);  
  40.     buttonSetup.setOnClickListener(new View.OnClickListener() {  
  41.         public void onClick(View v) {  
  42.             mReception = (EditText) findViewById(R.id.EditTextRec);  
  43.                 
  44.               try {  
  45.             sp=new SerialPort(new File("/dev/ttyS2"),9600);  
  46.             } catch (SecurityException e) {  
  47.                 // TODO Auto-generated catch block  
  48.                 e.printStackTrace();  
  49.             } catch (IOException e) {  
  50.                 // TODO Auto-generated catch block  
  51.                 e.printStackTrace();  
  52.             }     
  53.                 
  54.               
  55.               mOutputStream=(FileOutputStream) sp.getOutputStream();  
  56.               mInputStream=(FileInputStream) sp.getInputStream();  
  57.               
  58.                Toast.makeText(getApplicationContext(), "open",  
  59.                         Toast.LENGTH_SHORT).show();  
  60.               
  61.         }  
  62.     });  
  63.       
  64.       
  65.       
  66.     final Button buttonsend= (Button)findViewById(R.id.ButtonSent1);  
  67.     buttonsend.setOnClickListener(new View.OnClickListener() {  
  68.         public void onClick(View v) {  
  69.               
  70.             try {  
  71.                 mOutputStream.write(new String("send").getBytes());  
  72.                 mOutputStream.write('\n');  
  73.             } catch (IOException e) {  
  74.                 e.printStackTrace();  
  75.             }  
  76.                 
  77.              
  78.               Toast.makeText(getApplicationContext(), "send",  
  79.                          Toast.LENGTH_SHORT).show();  
  80.               
  81.         }  
  82.     });  
  83.       
  84.       
  85.     final Button buttonrec= (Button)findViewById(R.id.ButtonRec);  
  86.     buttonrec.setOnClickListener(new View.OnClickListener() {  
  87.         public void onClick(View v) {  
  88.             int size;  
  89.               
  90.             try {  
  91.             byte[] buffer = new byte[64];  
  92.             if (mInputStream == null) return;  
  93.             size = mInputStream.read(buffer);  
  94.             if (size > 0) {  
  95.                 onDataReceived(buffer, size);  
  96.                   
  97.             }  
  98.         } catch (IOException e) {  
  99.             e.printStackTrace();  
  100.             return;  
  101.         }  
  102.               
  103.         }  
  104.     });  
  105.     }  
  106.     void onDataReceived(final byte[] buffer, final int size) {  
  107.         runOnUiThread(new Runnable() {  
  108.             public void run() {  
  109.                 if (mReception != null) {  
  110.                     mReception.append(new String(buffer, 0, size));  
  111.                 }  
  112.             }  
  113.         });  
  114.     }  
  115.       
  116.       
  117. }  

 

可以看见,功能比较简单,只有三个按钮,分别用来打开串口(buttonsetup),写串口(buttonsend),读串口(buttonrec),一个文本框用来显示串口接收到的信息。功能已经简化到了最简。

 

下面先说说在模拟器中使用串口的方法:

应先使用-serial选项打开你的模拟器,如图(修改你模拟器的名字)

然后进入adb shell 

  cd /dev

chmod 777 ttyS2

运行后结果:

相比大家都懂得,我们的串口就是ttyS2,使用chmod命令来获取对它的操作,否则之后你的应用可能没有串口的操作权限。

然后运行程序:

其中Console就是打开串口(原谅我偷懒,忘改名字了)。

你可以把你的电脑的COM1连接到另一台电脑的串口上,并在那台电脑上打开你的串口助手之类的软件,配置好串口(参数不难从源代码里看出来)。按下模拟器中的send键,就能在那台电脑的串口助手中看到:

 

同样,从那台电脑向这台电脑发送数据也可以显示

更多相关文章

  1. Android开发——AsyncTask的使用以及源码解析
  2. Android系统服务初始化源码分析
  3. Android(安卓)HTTP GET/POST
  4. 使用 IntelliJ 查看 Android(安卓)源码
  5. android4.0.3,设置开机不自动进入锁屏状态
  6. Android设置中清除应用数据源码分析
  7. Eclipse 查看Android(安卓)程序在模拟器的CPU和内存情况
  8. Android(安卓)ubuntu10.04 源码下载和编译
  9. Android弹出式对话框AlertDialog中的EditText自动打开软键盘

随机推荐

  1. android 手机内存SD卡和cpu等信息的获取
  2. Android模拟器无法上网问题
  3. Android(安卓)Okhttp3了解及封装类使用
  4. android原生widget 电量控制(PowerSave)设
  5. Android(安卓)NotePad的简单实现
  6. 向sd写文件时权限
  7. android INSTALL_FAILED_INSUFFICIENT_ST
  8. Android实现简单断点续传和下载到本地功
  9. Android(安卓)json通信(解析)方法
  10. android studio 编译调试 错误