当前位置:   article > 正文

Android - 串口通讯(SerialPort)_android串口通讯

android串口通讯

最早的博客Android 模拟串口通信过程_launch virtual serial port driver pro-CSDN博客里就是用过 Google 提供的 demo,最近想再写个其他的demo发现用起来有点麻烦,还需要导入其他 module,因此在网上找到了Android-SerialPort-API: https://github.com/licheedev/Android-SerialPort-API.git 也是Fork自Google开源的Android串口通信Demo。

话不多说,直接开搞。

目录

一、简单说明

1、添加依赖

2、创建串口通讯工具类 SerialPortUtil

3、示例 MainActivity

4、通过logcat验证app

二、注意

三、总结

四、demo地址


一、简单说明

1、添加依赖
  1. dependencies {
  2. ...
  3. //添加依赖
  4. implementation ("com.licheedev:android-serialport:2.1.3")
  5. }
2、创建串口通讯工具类 SerialPortUtil
  1. class SerialPortUtil {
  2. companion object {
  3. private const val TAG = "SerialPortUtil"
  4. val sInstances by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
  5. SerialPortUtil()
  6. }
  7. }
  8. private lateinit var mIOpenSerialPortListener: IOpenSerialPortListener
  9. private lateinit var mISerialPortDataListener: ISerialPortDataListener
  10. private lateinit var mSendingHandlerThread: HandlerThread
  11. private lateinit var mSendingHandler: Handler
  12. private lateinit var mSerialPortReceivedThread: SerialPortReceivedThread
  13. private lateinit var mFileInputStream: FileInputStream
  14. private lateinit var mFileOutputStream: FileOutputStream
  15. private lateinit var serialPort: SerialPort
  16. /**
  17. * 打开串口方法
  18. */
  19. fun open(path: File) {
  20. try {
  21. serialPort = SerialPort
  22. .newBuilder(path, 9600) // 校验位;0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN)
  23. .build()
  24. mFileInputStream = serialPort.inputStream as FileInputStream
  25. mFileOutputStream = serialPort.outputStream as FileOutputStream
  26. } catch (e: SecurityException) {
  27. mIOpenSerialPortListener.onFail(path, Status.NO_READ_WRITE_PERMISSION)
  28. return
  29. } catch (e: Exception) {
  30. mIOpenSerialPortListener.onFail(path, Status.OPEN_FAIL)
  31. return
  32. }
  33. mIOpenSerialPortListener.onSuccess(path)
  34. startSendThread()
  35. startReceivedThread()
  36. }
  37. /**
  38. * 发送数据
  39. */
  40. fun sendBytes(bytes: ByteArray?): Boolean {
  41. try {
  42. Runnable {
  43. val message = Message.obtain()
  44. message.obj = bytes
  45. mSendingHandler.sendMessage(message)
  46. Thread.sleep(100)
  47. }.run()
  48. } catch (e: Exception) {
  49. Log.e(TAG, "sendBytes: 发送数据失败 " + e.message)
  50. return false
  51. }
  52. return true
  53. }
  54. /**
  55. * 开启发送消息线程
  56. */
  57. private fun startSendThread() {
  58. Log.d(TAG, "startSendThread: 开启发送消息线程")
  59. mSendingHandlerThread = HandlerThread("mSendingHandlerThread")
  60. mSendingHandlerThread.start()
  61. mSendingHandler = object : Handler(mSendingHandlerThread.looper) {
  62. override fun handleMessage(msg: Message) {
  63. val sendBytes: ByteArray? = msg.obj as ByteArray?
  64. if ((null != sendBytes) && (sendBytes.isNotEmpty())) {
  65. try {
  66. mFileOutputStream.write(sendBytes)
  67. mISerialPortDataListener.onDataSend(sendBytes)
  68. } catch (e: java.io.IOException) {
  69. e.printStackTrace()
  70. }
  71. }
  72. }
  73. }
  74. }
  75. /**
  76. * 停止发送消息线程
  77. */
  78. fun stopSendThread() {
  79. Log.d(TAG, "stopSendThread: 停止发送消息线程")
  80. mSendingHandlerThread.interrupt()
  81. mSendingHandlerThread.quit()
  82. }
  83. /**
  84. * 开启接收消息的线程
  85. */
  86. private fun startReceivedThread() {
  87. Log.d(TAG, "startReceivedThread: 开启接受消息线程")
  88. mSerialPortReceivedThread = object : SerialPortReceivedThread(mFileInputStream) {
  89. override fun onDataReceived(bytes: ByteArray?) {
  90. mISerialPortDataListener.onDataReceived(bytes)
  91. }
  92. }
  93. mSerialPortReceivedThread.start()
  94. }
  95. /**
  96. * 停止接收消息的线程
  97. */
  98. fun stopReceivedThread() {
  99. Log.d(TAG, "stopReceivedThread: 停止接收消息的线程")
  100. mSerialPortReceivedThread.release()
  101. serialPort.tryClose()
  102. }
  103. /**
  104. * 设置串口打开的监听
  105. */
  106. fun setIOpenSerialPortListener(iOpenSerialPortListener: IOpenSerialPortListener) {
  107. mIOpenSerialPortListener = iOpenSerialPortListener
  108. }
  109. /**
  110. * 设置串口数据收发的监听
  111. */
  112. fun setISerialPortDataListener(iSerialPortDataListener: ISerialPortDataListener) {
  113. mISerialPortDataListener = iSerialPortDataListener
  114. }
  115. }

 在这里简单介绍些,在开启串口通讯后开启两个线程,分别处理send及received步骤。

3、示例 MainActivity
  1. class MainActivity : Activity(), IOpenSerialPortListener, ISerialPortDataListener {
  2. companion object {
  3. private const val TAG = "MainActivity"
  4. private val FIND_CARD =
  5. byteArrayOf(0x20, 0x00, 0x80.toByte(), 0x04, 0x03, 0x03, 0x01, 0x00, 0x7a, 0x03)
  6. }
  7. override fun onCreate(savedInstanceState: Bundle?) {
  8. super.onCreate(savedInstanceState)
  9. setContentView(R.layout.activity_main)
  10. CrashHandler.sInstance.init(this)
  11. //0、设置su位置
  12. SerialPort.setSuPath("/system/xbin/su")
  13. //1、首先设置open监听
  14. SerialPortUtil.sInstances.setIOpenSerialPortListener(this)
  15. //2、设置串口监听
  16. SerialPortUtil.sInstances.setISerialPortDataListener(this)
  17. //3、open串口
  18. SerialPortUtil.sInstances.open(File("/dev/ttyS3"))
  19. //4、模拟发送命令
  20. SerialPortUtil.sInstances.sendBytes(FIND_CARD)
  21. }
  22. override fun onDestroy() {
  23. super.onDestroy()
  24. SerialPortUtil.sInstances.stopSendThread()
  25. SerialPortUtil.sInstances.stopReceivedThread()
  26. }
  27. override fun onSuccess(device: File?) {
  28. Log.d(TAG, "onSuccess: open成功")
  29. }
  30. override fun onFail(device: File?, status: Status?) {
  31. Log.d(TAG, "onFail: open失败,原因: $status")
  32. }
  33. override fun onDataReceived(bytes: ByteArray?) {
  34. Log.d(TAG, "onDataReceived: 接受数据: " + Arrays.toString(bytes))
  35. }
  36. override fun onDataSend(bytes: ByteArray?) {
  37. Log.d(TAG, "onDataSend: 发送数据: " + Arrays.toString(bytes))
  38. }
  39. }
4、通过logcat验证app
  1. 09:52:48.349 serial_port D Opening serial port /dev/ttyS3 with flags 0x2
  2. 09:52:48.349 serial_port D open() fd = 45
  3. 09:52:48.349 serial_port D Configuring serial port
  4. 09:52:48.359 MainActivity D onSuccess: open成功
  5. 09:52:48.359 SerialPortUtil D startSendThread: 开启发送消息线程
  6. 09:52:48.359 SerialPortUtil D startReceivedThread: 开启接受消息线程
  7. 09:52:48.359 SerialPortReceivedThread I run: available = 0
  8. 09:52:48.359 MainActivity D onDataSend: 发送数据: [32, 0, -128, 4, 3, 3, 1, 0, 122, 3]
  9. 09:52:48.529 BufferQueue E [com.lichang.source/com.lichang.source.MainActivity] connect: already connected (cur=1, req=1)
  10. 09:52:48.529 mali_winsys D EGLint new_window_surface(egl_winsys_display*, void*, EGLSurface, EGLConfig, egl_winsys_surface**, egl_color_buffer_format*, EGLBoolean) returns 0x3000
  11. 09:52:48.529 OpenGLRenderer D Enabling debug mode 0
  12. 09:52:51.609 SerialPortReceivedThread I run: size = 14
  13. 09:52:51.609 SerialPortReceivedThread I run: bytes = [32, 0, 0, 8, 4, 0, 8, 4, 28, 37, -117, -5, -74, 3]
  14. 09:52:51.609 MainActivity D onDataReceived: 接受数据: [32, 0, 0, 8, 4, 0, 8, 4, 28, 37, -117, -5, -74, 3]
  15. 09:52:51.609 SerialPortReceivedThread I run: available = 0
  16. 09:52:53.729 SerialPortReceivedThread I run: size = 22
  17. 09:52:53.729 SerialPortReceivedThread I run: bytes = [32, 0, 0, 16, 32, 17, 35, 69, 103, -113, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, 3]
  18. 09:52:53.729 MainActivity D onDataReceived: 接受数据: [32, 0, 0, 16, 32, 17, 35, 69, 103, -113, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, 3]
  19. 09:52:53.729 SerialPortReceivedThread I run: available = 0
  20. 09:53:03.239 dalvikvm D Debugger has detached; object registry had 1 entries
  21. 09:53:03.249 dalvikvm D GC_CONCURRENT freed 222K, 15% free 2334K/2744K, paused 1ms+1ms, total 12ms
  22. 09:53:12.419 SerialPortUtil D stopSendThread: 停止发送消息线程
  23. 09:53:12.419 SerialPortUtil D stopReceivedThread: 停止接收消息的线程
  24. 09:53:12.419 serial_port D close(fd = 45)

二、注意

为了在Android上读/写串行端口,你需要在设备上安装su binary(这可以通过root设备来完成)。通常,具有串口通信能力的Android设备已将su安装在默认路径下。

默认的 su 路径使用的是 “/system/bin/su”

三、总结

在新项目中快速应用,可以先导入依赖,然后copy示例中的 com/lichang/source/serialport文件夹,即可按照 3、示例 MainActivity 钓箱串口工具类。

四、demo地址

serialport-demo_kt: 使用 implementation ("com.licheedev:android-serialport:2.1.3")

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/638971
推荐阅读
相关标签
  

闽ICP备14008679号