当前位置: 代码迷 >> Android >> Android串口操作,简单化android-serialport-api的demo
  详细解决方案

Android串口操作,简单化android-serialport-api的demo

热度:713   发布时间:2016-04-28 04:31:34.0
Android串口操作,简化android-serialport-api的demo

??最近在做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?<termios.h>??
  18. #include?<unistd.h>??
  19. #include?<sys/types.h>??
  20. #include?<sys/stat.h>??
  21. #include?<fcntl.h>??
  22. #include?<string.h>??
  23. #include?<jni.h>??
  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,?"<init>",?"()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键,就能在那台电脑的串口助手中看到:


?

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

?

至此,这个小demo就完毕了。

? 我的源码在这里: ??http://download.csdn.net/detail/akunainiannian/5202173

  相关解决方案