Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android串口操作,簡化android-serialport-api的demo

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

編輯:關於Android編程

最近在做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文件(他就是動態鏈接庫的源文件),可以看到源碼:

  1. /*
  2. *Copyright2009CedricPriscal
  3. *
  4. *LicensedundertheApacheLicense,Version2.0(the"License");
  5. *youmaynotusethisfileexceptincompliancewiththeLicense.
  6. *YoumayobtainacopyoftheLicenseat
  7. *
  8. *http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
  11. *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
  12. *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
  13. *SeetheLicenseforthespecificlanguagegoverningpermissionsand
  14. *limitationsundertheLicense.
  15. */
  16.  
  17. #include
  18. #include
  19. #include
  20. #include
  21. #include
  22. #include
  23. #include
  24.  
  25. #include"android/log.h"
  26. staticconstchar*TAG="serial_port";
  27. #defineLOGI(fmt,args...)__android_log_print(ANDROID_LOG_INFO,TAG,fmt,##args)
  28. #defineLOGD(fmt,args...)__android_log_print(ANDROID_LOG_DEBUG,TAG,fmt,##args)
  29. #defineLOGE(fmt,args...)__android_log_print(ANDROID_LOG_ERROR,TAG,fmt,##args)
  30.  
  31. staticspeed_tgetBaudrate(jintbaudrate)
  32. {
  33. switch(baudrate){
  34. case0:returnB0;
  35. case50:returnB50;
  36. case75:returnB75;
  37. case110:returnB110;
  38. case134:returnB134;
  39. case150:returnB150;
  40. case200:returnB200;
  41. case300:returnB300;
  42. case600:returnB600;
  43. case1200:returnB1200;
  44. case1800:returnB1800;
  45. case2400:returnB2400;
  46. case4800:returnB4800;
  47. case9600:returnB9600;
  48. case19200:returnB19200;
  49. case38400:returnB38400;
  50. case57600:returnB57600;
  51. case115200:returnB115200;
  52. case230400:returnB230400;
  53. case460800:returnB460800;
  54. case500000:returnB500000;
  55. case576000:returnB576000;
  56. case921600:returnB921600;
  57. case1000000:returnB1000000;
  58. case1152000:returnB1152000;
  59. case1500000:returnB1500000;
  60. case2000000:returnB2000000;
  61. case2500000:returnB2500000;
  62. case3000000:returnB3000000;
  63. case3500000:returnB3500000;
  64. case4000000:returnB4000000;
  65. default:return-1;
  66. }
  67. }
  68.  
  69. /*
  70. *Class:cedric_serial_SerialPort
  71. *Method:open
  72. *Signature:(Ljava/lang/String;)V
  73. */
  74. JNIEXPORTjobjectJNICALLJava_android_serialport_SerialPort_open
  75. (JNIEnv*env,jobjectthiz,jstringpath,jintbaudrate)
  76. {
  77. intfd;
  78. speed_tspeed;
  79. jobjectmFileDescriptor;
  80.  
  81. /*Checkarguments*/
  82. {
  83. speed=getBaudrate(baudrate);
  84. if(speed==-1){
  85. /*TODO:throwanexception*/
  86. LOGE("Invalidbaudrate");
  87. returnNULL;
  88. }
  89. }
  90.  
  91. /*Openingdevice*/
  92. {
  93. jbooleaniscopy;
  94. constchar*path_utf=(*env)->GetStringUTFChars(env,path,&iscopy);
  95. LOGD("Openingserialport%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. /*Throwanexception*/
  102. LOGE("Cannotopenport");
  103. /*TODO:throwanexception*/
  104. returnNULL;
  105. }
  106. }
  107.  
  108. /*Configuredevice*/
  109. {
  110. structtermioscfg;
  111. LOGD("Configuringserialport");
  112. if(tcgetattr(fd,&cfg))
  113. {
  114. LOGE("tcgetattr()failed");
  115. close(fd);
  116. /*TODO:throwanexception*/
  117. returnNULL;
  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:throwanexception*/
  129. returnNULL;
  130. }
  131. }
  132.  
  133. /*Createacorrespondingfiledescriptor*/
  134. {
  135. jclasscFileDescriptor=(*env)->FindClass(env,"java/io/FileDescriptor");
  136. jmethodIDiFileDescriptor=(*env)->GetMethodID(env,cFileDescriptor,"","()V");
  137. jfieldIDdescriptorID=(*env)->GetFieldID(env,cFileDescriptor,"descriptor","I");
  138. mFileDescriptor=(*env)->NewObject(env,cFileDescriptor,iFileDescriptor);
  139. (*env)->SetIntField(env,mFileDescriptor,descriptorID,(jint)fd);
  140. }
  141.  
  142. returnmFileDescriptor;
  143. }
  144.  
  145. /*
  146. *Class:cedric_serial_SerialPort
  147. *Method:close
  148. *Signature:()V
  149. */
  150. JNIEXPORTvoidJNICALLJava_android_serialport_SerialPort_close
  151. (JNIEnv*env,jobjectthiz)
  152. {
  153. jclassSerialPortClass=(*env)->GetObjectClass(env,thiz);
  154. jclassFileDescriptorClass=(*env)->FindClass(env,"java/io/FileDescriptor");
  155.  
  156. jfieldIDmFdID=(*env)->GetFieldID(env,SerialPortClass,"mFd","Ljava/io/FileDescriptor;");
  157. jfieldIDdescriptorID=(*env)->GetFieldID(env,FileDescriptorClass,"descriptor","I");
  158.  
  159. jobjectmFd=(*env)->GetObjectField(env,thiz,mFdID);
  160. jintdescriptor=(*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的方式打開關閉串口。

  1. /*
  2. *Copyright2009CedricPriscal
  3. *
  4. *LicensedundertheApacheLicense,Version2.0(the"License");
  5. *youmaynotusethisfileexceptincompliancewiththeLicense.
  6. *YoumayobtainacopyoftheLicenseat
  7. *
  8. *http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
  11. *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
  12. *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
  13. *SeetheLicenseforthespecificlanguagegoverningpermissionsand
  14. *limitationsundertheLicense.
  15. */
  16.  
  17. packageandroid.serialport;
  18.  
  19. importjava.io.File;
  20. importjava.io.FileDescriptor;
  21. importjava.io.FileInputStream;
  22. importjava.io.FileOutputStream;
  23. importjava.io.IOException;
  24. importjava.io.InputStream;
  25. importjava.io.OutputStream;
  26.  
  27. importandroid.util.Log;
  28.  
  29. publicclassSerialPort{
  30.  
  31. privatestaticfinalStringTAG="SerialPort";
  32.  
  33. /*
  34. *DonotremoveorrenamethefieldmFd:itisusedbynativemethodclose();
  35. */
  36. privateFileDescriptormFd;
  37. privateFileInputStreammFileInputStream;
  38. privateFileOutputStreammFileOutputStream;
  39.  
  40. publicSerialPort(Filedevice,intbaudrate)throwsSecurityException,IOException{
  41.  
  42. /*Checkaccesspermission*/
  43. if(!device.canRead()||!device.canWrite()){
  44. try{
  45. /*Missingread/writepermission,tryingtochmodthefile*/
  46. Processsu;
  47. su=Runtime.getRuntime().exec("/system/bin/su");
  48. Stringcmd="chmod777"+device.getAbsolutePath()+"\n"
  49. +"exit\n";
  50. /*Stringcmd="chmod777/dev/s3c_serial0"+"\n"
  51. +"exit\n";*/
  52. su.getOutputStream().write(cmd.getBytes());
  53. if((su.waitFor()!=0)||!device.canRead()
  54. ||!device.canWrite()){
  55. thrownewSecurityException();
  56. }
  57. }catch(Exceptione){
  58. e.printStackTrace();
  59. thrownewSecurityException();
  60. }
  61. }
  62.  
  63. mFd=open(device.getAbsolutePath(),baudrate);
  64. if(mFd==null){
  65. Log.e(TAG,"nativeopenreturnsnull");
  66. thrownewIOException();
  67. }
  68. mFileInputStream=newFileInputStream(mFd);
  69. mFileOutputStream=newFileOutputStream(mFd);
  70. }
  71.  
  72. //Gettersandsetters
  73. publicInputStreamgetInputStream(){
  74. returnmFileInputStream;
  75. }
  76.  
  77. publicOutputStreamgetOutputStream(){
  78. returnmFileOutputStream;
  79. }
  80.  
  81. //JNI
  82. privatenativestaticFileDescriptoropen(Stringpath,intbaudrate);
  83. publicnativevoidclose();
  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. packageandroid.serialport;
  2.  
  3.  
  4. importjava.io.File;
  5. importjava.io.FileInputStream;
  6. importjava.io.FileOutputStream;
  7. importjava.io.IOException;
  8.  
  9. importandroid.app.Activity;
  10.  
  11. importandroid.os.Bundle;
  12.  
  13.  
  14.  
  15. //importandroid.serialport.sample.R;
  16. importandroid.serialport.R;
  17.  
  18. importandroid.view.View;
  19. importandroid.widget.Button;
  20. importandroid.widget.EditText;
  21. importandroid.widget.Toast;
  22.  
  23. publicclassMyserialActivityextendsActivity{
  24. /**Calledwhentheactivityisfirstcreated.*/
  25.  
  26.  
  27. EditTextmReception;
  28. FileOutputStreammOutputStream;
  29. FileInputStreammInputStream;
  30. SerialPortsp;
  31.  
  32. @Override
  33.  
  34. publicvoidonCreate(BundlesavedInstanceState){
  35. super.onCreate(savedInstanceState);
  36. setContentView(R.layout.main);
  37.  
  38.  
  39. finalButtonbuttonSetup=(Button)findViewById(R.id.ButtonSetup);
  40. buttonSetup.setOnClickListener(newView.OnClickListener(){
  41. publicvoidonClick(Viewv){
  42. mReception=(EditText)findViewById(R.id.EditTextRec);
  43.  
  44. try{
  45. sp=newSerialPort(newFile("/dev/ttyS2"),9600);
  46. }catch(SecurityExceptione){
  47. //TODOAuto-generatedcatchblock
  48. e.printStackTrace();
  49. }catch(IOExceptione){
  50. //TODOAuto-generatedcatchblock
  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. finalButtonbuttonsend=(Button)findViewById(R.id.ButtonSent1);
  67. buttonsend.setOnClickListener(newView.OnClickListener(){
  68. publicvoidonClick(Viewv){
  69.  
  70. try{
  71. mOutputStream.write(newString("send").getBytes());
  72. mOutputStream.write('\n');
  73. }catch(IOExceptione){
  74. e.printStackTrace();
  75. }
  76.  
  77.  
  78. Toast.makeText(getApplicationContext(),"send",
  79. Toast.LENGTH_SHORT).show();
  80.  
  81. }
  82. });
  83.  
  84.  
  85. finalButtonbuttonrec=(Button)findViewById(R.id.ButtonRec);
  86. buttonrec.setOnClickListener(newView.OnClickListener(){
  87. publicvoidonClick(Viewv){
  88. intsize;
  89.  
  90. try{
  91. byte[]buffer=newbyte[64];
  92. if(mInputStream==null)return;
  93. size=mInputStream.read(buffer);
  94. if(size>0){
  95. onDataReceived(buffer,size);
  96.  
  97. }
  98. }catch(IOExceptione){
  99. e.printStackTrace();
  100. return;
  101. }
  102.  
  103. }
  104. });
  105. }
  106. voidonDataReceived(finalbyte[]buffer,finalintsize){
  107. runOnUiThread(newRunnable(){
  108. publicvoidrun(){
  109. if(mReception!=null){
  110. mReception.append(newString(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. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved