Android-串口编程原理和实现方式(附源码).docx
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Android 串口 编程 原理 实现 方式 源码
- 资源描述:
-
提到串口编程,就不得不提到JNI,不得不提到JavaAPI中的文件描述符类:FileDescriptor。下面我分别对JNI、FileDescriptor以及串口的一些知识点和实现的源码进行分析说明。这里主要是参考了开源项目android-serialport-api。 串口编程需要了解的基本知识点:对于串口编程,我们只需对串口进行一系列的设置,然后打开串口,这些操作我们可以参考串口调试助手的源码进行学习。在Java中如果要实现串口的读写功能只需操作文件设备类:FileDescriptor即可,其他的事都由驱动来完成不用多管!当然,你想了解,那就得看驱动代码了。这里并不打算对驱动进行说明,只初略阐述应用层的实现方式。 (一)JNI: 关于JNI的文章网上有很多,不再多做解释,想详细了解的朋友可以查看云中漫步的技术文章,写得很好,分析也很全面,那么在这篇拙文中我强调3点: 1、如何将编译好的SO文件打包到APK中?(方法很简单,直接在工程目录下新建文件夹 libs/armeabi,将SO文件Copy到此目录即可) 2、命名要注意的地方?(在编译好的SO文件中,将文件重命名为:libfilename.so即可。其中filename.so是编译好后生成的文件) 3、MakeFile文件的编写(不用多说,可以直接参考package/apps目录下用到JNI的相关项目写法) 这是关键的代码: [cpp] view plaincopy 1. <span style="font-size:18px;"> int fd; 2. speed_t speed; 3. jobject mFileDescriptor; 4. 5. /* Check arguments */ 6. { 7. speed = getBaudrate(baudrate); 8. if (speed == -1) { 9. /* TODO: throw an exception */ 10. LOGE("Invalid baudrate"); 11. return NULL; 12. } 13. } 14. 15. /* Opening device */ 16. { 17. jboolean iscopy; 18. const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy); 19. LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags); 20. fd = open(path_utf, O_RDWR | flags); 21. LOGD("open() fd = %d", fd); 22. (*env)->ReleaseStringUTFChars(env, path, path_utf); 23. if (fd == -1) 24. { 25. /* Throw an exception */ 26. LOGE("Cannot open port"); 27. /* TODO: throw an exception */ 28. return NULL; 29. } 30. } 31. 32. /* Configure device */ 33. { 34. struct termios cfg; 35. LOGD("Configuring serial port"); 36. if (tcgetattr(fd, &cfg)) 37. { 38. LOGE("tcgetattr() failed"); 39. close(fd); 40. /* TODO: throw an exception */ 41. return NULL; 42. } 43. 44. cfmakeraw(&cfg); 45. cfsetispeed(&cfg, speed); 46. cfsetospeed(&cfg, speed); 47. 48. if (tcsetattr(fd, TCSANOW, &cfg)) 49. { 50. LOGE("tcsetattr() failed"); 51. close(fd); 52. /* TODO: throw an exception */ 53. return NULL; 54. } 55. } 56. </span> (二)FileDescritor: 文件描述符类的实例用作与基础机器有关的某种结构的不透明句柄,该结构表示开放文件、开放套接字或者字节的另一个源或接收者。文件描述符的主要实际用途是创建一个包含该结构的FileInputStream 或FileOutputStream。这是API的描述,不太好理解,其实可简单的理解为:FileDescritor就是对一个文件进行读写。 (三)实现串口通信细节 1) 建工程:SerialDemo包名:org.winplus.serial,并在工程目录下新建jni和libs两个文件夹和一个org.winplus.serial.utils,如下图: 2) 新建一个类:SerialPortFinder,添加如下代码: [java] view plaincopy 1. <span style="font-size:18px;">package org.winplus.serial.utils; 2. 3. import java.io.File; 4. import java.io.FileReader; 5. import java.io.IOException; 6. import java.io.LineNumberReader; 7. import java.util.Iterator; 8. import java.util.Vector; 9. 10. import android.util.Log; 11. 12. public class SerialPortFinder { 13. 14. private static final String TAG = "SerialPort"; 15. 16. private Vector<Driver> mDrivers = null; 17. 18. public class Driver { 19. public Driver(String name, String root) { 20. mDriverName = name; 21. mDeviceRoot = root; 22. } 23. 24. private String mDriverName; 25. private String mDeviceRoot; 26. Vector<File> mDevices = null; 27. 28. public Vector<File> getDevices() { 29. if (mDevices == null) { 30. mDevices = new Vector<File>(); 31. File dev = new File("/dev"); 32. File[] files = dev.listFiles(); 33. int i; 34. for (i = 0; i < files.length; i++) { 35. if (files[i].getAbsolutePath().startsWith(mDeviceRoot)) { 36. Log.d(TAG, "Found new device: " + files[i]); 37. mDevices.add(files[i]); 38. } 39. } 40. } 41. return mDevices; 42. } 43. 44. public String getName() { 45. return mDriverName; 46. } 47. } 48. 49. Vector<Driver> getDrivers() throws IOException { 50. if (mDrivers == null) { 51. mDrivers = new Vector<Driver>(); 52. LineNumberReader r = new LineNumberReader(new FileReader( 53. "/proc/tty/drivers")); 54. String l; 55. while ((l = r.readLine()) != null) { 56. // Issue 3: 57. // Since driver name may contain spaces, we do not extract 58. // driver name with split() 59. String drivername = l.substring(0, 0x15).trim(); 60. String[] w = l.split(" +"); 61. if ((w.length >= 5) && (w[w.length - 1].equals("serial"))) { 62. Log.d(TAG, "Found new driver " + drivername + " on " 63. + w[w.length - 4]); 64. mDrivers.add(new Driver(drivername, w[w.length - 4])); 65. } 66. } 67. r.close(); 68. } 69. return mDrivers; 70. } 71. 72. public String[] getAllDevices() { 73. Vector<String> devices = new Vector<String>(); 74. // Parse each driver 75. Iterator<Driver> itdriv; 76. try { 77. itdriv = getDrivers().iterator(); 78. while (itdriv.hasNext()) { 79. Driver driver = itdriv.next(); 80. Iterator<File> itdev = driver.getDevices().iterator(); 81. while (itdev.hasNext()) { 82. String device = itdev.next().getName(); 83. String value = String.format("%s (%s)", device, 84. driver.getName()); 85. devices.add(value); 86. } 87. } 88. } catch (IOException e) { 89. e.printStackTrace(); 90. } 91. return devices.toArray(new String[devices.size()]); 92. } 93. 94. public String[] getAllDevicesPath() { 95. Vector<String> devices = new Vector<String>(); 96. // Parse each driver 97. Iterator<Driver> itdriv; 98. try { 99. itdriv = getDrivers().iterator(); 100. while (itdriv.hasNext()) { 101. Driver driver = itdriv.next(); 102. Iterator<File> itdev = driver.getDevices().iterator(); 103. while (itdev.hasNext()) { 104. String device = itdev.next().getAbsolutePath(); 105. devices.add(device); 106. } 107. } 108. } catch (IOException e) { 109. e.printStackTrace(); 110. } 111. return devices.toArray(new String[devices.size()]); 112. } 113. } 114. </span> 上面这个类在“android-serialport-api串口工具测试随笔”中有详细的说明,我就不多说了。 3)新建SerialPort类,这个类主要用来加载SO文件,通过JNI的方式打开关闭串口 [java] view plaincopy 1. <span style="font-size:18px;">package org.winplus.serial.utils; 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 18. * close(); 19. */ 20. private FileDescriptor mFd; 21. private FileInputStream mFileInputStream; 22. private FileOutputStream mFileOutputStream; 23. 24. public SerialPort(File device, int baudrate, int flags) 25. throws SecurityException, IOException { 26. 27. /* Check access permission */ 28. if (!device.canRead() || !device.canWrite()) { 29. try { 30. /* Missing read/write permission, trying to chmod the file */ 31. Process su; 32. su = Runtime.getRuntime().exec("/system/bin/su"); 33. String cmd = "chmod 666 " + device.getAbsolutePath() + "\n" 34. + "exit\n"; 35. su.getOutputStream().write(cmd.getBytes()); 36. if ((su.waitFor() != 0) || !device.canRead() 37. || !device.canWrite()) { 38. throw new SecurityException(); 39. } 40. } catch (Exception e) { 41. e.printStackTrace(); 42. throw new SecurityException(); 43. } 44. } 45. 46. mFd = open(device.getAbsolutePath(), baudrate, flags); 47. if (mFd == null) { 48. Log.e(TAG, "native open returns null"); 49. throw new IOException(); 50. } 51. mFileInputStream = new FileInputStream(mFd); 52. mFileOutputStream = new FileOutputStream(mFd); 53. } 54. 55. // Getters and setters 56. public InputStream getInputStream() { 57. return mFileInputStream; 58. } 59. 60. public OutputStream getOutputStream() { 61. return mFileOutputStream; 62. } 63. 64. // JNI 65. private native static FileDescriptor open(String path, int baudrate, 66. int flags); 67. 68. public native void close(); 69. 70. static { 71. System.loadLibrary("serial_port"); 72. } 73. } 74. </span> 4) 新建一个Application 继承android.app.Application,用来对串口进行初始化和关闭串口 [java] view plaincopy 1. <span style="font-size:18px;">package org.winplus.serial; 2. 3. import java.io.File; 4. import java.io.IOException; 5. import java.security.InvalidParameterException; 6. 7. import org.winplus.serial.utils.SerialPort; 8. import org.winplus.serial.utils.SerialPortFinder; 9. 10. import android.content.SharedPreferences; 11. 12. public class Application extends android.app.Application { 13. public SerialPortFinder mSerialPortFinder = new SerialPortFinder(); 14. private SerialPort mSerialPort = null; 15. 16. public SerialPort getSerialPort() throws SecurityException, IOException, InvalidParameterException { 17. if (mSerialPort == null) { 18. /* Read serial port parameters */ 19. SharedPreferences sp = getSharedPreferences("android_serialport_api.sample_preferences", MODE_PRIVATE); 20. String path = sp.getString("DEVICE", ""); 21. int baudrate = Integer.decode(sp.getString("BAUDRATE", "-1")); 22. 23. /* Check parameters */ 24. if ( (path.length() == 0) || (baudrate == -1)) { 25. throw new InvalidParameterException(); 26. } 27. 28. /* Open the serial port */ 29. mSerialPort = new SerialPort(new File(path), baudrate, 0); 30. } 31. return mSerialPort; 32. } 33. 34. public void closeSerialPort() { 35. if (mSerialPort != null) { 36. mSerialPort.close(); 37. mSerialPort = null; 38. } 39. } 40. } 41. </span> 5) 新建一个继承抽象的Activity类,主要用于读取串口的信息 [java] view plaincopy 1. <span style="font-size:18px;">package org.winplus.serial; 2. 3. import java.io.IOException; 4. import java.io.InputStream; 5. import java.io.OutputStream; 6. import java.security.InvalidParameterException; 7. 8. import org.winplus.serial.utils.SerialPort; 9. 10. import android.app.Activity; 11. import android.app.AlertDialog; 12. import android.content.DialogInterface; 13. import android.content.DialogInterface.OnClickListener; 14. import android.os.Bundle; 15. 16. public abstract class SerialPortActivity extends Activity { 17. protected Application mApplication; 18. protected SerialPort mSerialPort; 19. protected OutputStream mOutputStream; 20. private InputStream mInputStream; 21. private ReadThread mReadThread; 22. 23. private class ReadThread extends Thread { 24. 25. @Override 26. public void run() { 27. super.run(); 28. while (!isInterrupted()) { 29. int size; 30. try { 31. byte[] buffer = new byte[64]; 32. if (mInputStream == null) 33. return; 34. 35. /** 36. * 这里的read要尤其注意,它会一直等待数据,等到天荒地老,海枯石烂。如果要判断是否接受完成,只有设置结束标识,或作其他特殊的处理。 37. */ 38. size = mInputStream.read(buffer); 39. if (size > 0) { 40. onDataReceived(buffer, size); 41. } 42. } catch (IOException e) { 43. e.printStackTrace(); 44. return; 45. } 46. } 47. } 48. } 49. 50. private void DisplayError(int resourceId) { 51. AlertDialog.Builder b = new AlertDialog.Builder(this); 52. b.setTitle("Error"); 53. b.setMessage(resourceId); 54. b.setPositiveButton("OK", new OnClickListener() { 55. public void onClick(DialogInterface dialog, int which) { 56. SerialPortActivity.this.finish(); 57. } 58. }); 59. b.show(); 60. } 61. 62. @Override 63. protected void onCreate(Bundle save展开阅读全文
咨信网温馨提示:1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:0574-28810668;投诉电话:18658249818。




Android-串口编程原理和实现方式(附源码).docx



实名认证













自信AI助手
















微信客服
客服QQ
发送邮件
意见反馈



链接地址:https://www.zixin.com.cn/doc/11877024.html