设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间17 现在时间17 缓存数据 这个世界上很多东西会变,很多人会走。 但你在我心里,从开始的那一天,到现在从来没有变过。 我一直在等,等你的消息。

这个世界上很多东西会变,很多人会走。 但你在我心里,从开始的那一天,到现在从来没有变过。 我一直在等,等你的消息。 -- 盛夏的果实

查看: 1309|回复: 1

Android读取串口数据的操作指南

[复制链接]

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
37
主题
23
精华
0
金钱
93
积分
60
注册时间
2023-9-29
最后登录
2025-3-13

发表于 2024-11-26 21:24:39 | 显示全部楼层 |阅读模式
目录


  • 一、确定串口号和波特率
  • 二、确定波特率
  • 三、读取串口数据
  • 四、数据包处理
  • 五、数据包解析类
  • 六、数据包解析接口和实现类
  • 七、数据包输入流类
  • 八、读取线程类
  • 总结
在Android系统上读取串口数据是一个常见的需求,特别是当我们需要与硬件设备进行通信时。通过开源项目 Crazy-MT/SerialAssistant,我们可以快速了解如何在Android上实现这一功能。以下是详细的步骤和代码示例,帮助你更好地理解和实现串口通信。

一、确定串口号和波特率

1. 查找设备文件
在Linux系统中(Android基于Linux),串口设备通常表示为 /dev/ttySx 或 /dev/ttyUSBx,其中 x 是数字。例如,/dev/ttyS0 代表第一个串口,/dev/ttyUSB0 代表第一个USB串口适配器。
2. 通过文件系统查看可用串口
你可以在Android设备的终端中使用 ls /dev/tty* 命令来查看可用的串口设备文件。使用ADB(Android Debug Bridge)来连接和访问设备终端:
  1. adb shell
  2. ls /dev/tty*
复制代码
二、确定波特率

波特率是串口通信的速率,单位是波特(baud)。常见的波特率有 9600、19200、38400、57600、115200 等。波特率的选择通常由串口设备的规格或协议决定。你需要查阅设备手册或与设备供应商确认。

三、读取串口数据

在选择正确的串口号和波特率后,可以通过输入流读取串口数据。以下是一个读取线程的示例代码:
  1. private class ReadThread extends Thread {
  2.     @Override
  3.     public void run() {
  4.         super.run();
  5.         while(!isInterrupted()) {
  6.             try
  7.             {
  8.                 if (mInputStream == null) return;
  9.                 int size = mInputStream.read(tempBuff);
  10.                 if (size > 0){
  11.                     onDataReceived(Arrays.copyOfRange(tempBuff, 0, size));
  12.                 }
  13.                 try
  14.                 {
  15.                     Thread.sleep(10);//延时10ms
  16.                 } catch (InterruptedException e)
  17.                 {
  18.                     e.printStackTrace();
  19.                 }
  20.             } catch (Throwable e)
  21.             {
  22.                 e.printStackTrace();
  23.                 return;
  24.             }
  25.         }
  26.     }
  27. }
复制代码
四、数据包处理

以某品牌的电子秤为例,其数据协议如下:
  1. 取重

  2. 1、主动/被动模式的数据格式相同。
  3. 2、上位机指令(HEX): 1b 01 02
  4. 3、数据格式:(总共 24 字节)

  5. 01 02  000.000kg 000.000kg sta  X   03 04
  6. 数据头  净重       皮重      状态 校验 数据尾

  7. SHead1        SOH(01H)   1 字节,标题开始
  8. SHead2        STX(02H)   1 字节,正文开始
  9. Weight 1      XXX.XXX    7 字节,净重。
  10. Weight Units  U1U0       2 字节,重量单位。如“kg”
  11. Weight2       XXX.XXX    7 字节,皮重。
  12. Weight Units  U1U0       2 字节,重量单位。如“kg”
  13. Status        STA        1 字节,状态
  14. Check Sum     BCC        1 字节,使用 BCC 算法,除 SOH STX ETX EOT 及本字节外所有字符的 BCC 校验。
  15. Tail1         ETX(03H)   1 字节,标题结束
  16. Tail2         EOT(04H)   1 字节,传输结束

  17. 重量格式(净重/皮重),例如:
  18. 123.456kg
  19. 23.456kg
  20. 12.3456kg
  21. 0.012kg
  22. -12.345kg
  23. -1.234kg
  24. -0.0001kg
  25. (前面无数据则用空格填充。如果小数点后面有四位,则为精确到 0.1g)

  26. 状态:
  27. bit7:1 重量溢出;0 重量正常
  28. bit6:1 开机后未归零(开机时秤盘上有重物);0 开机后已归零
  29. bit5:1 当前在去皮模式;0 当前不是    去皮模式
  30. bit4:1 当前重量为 0;0 当前重量不为 0
  31. bit3:1 重量稳定;0 重量不稳定
  32. bit2~bit0  0
复制代码
在串口通信中,处理数据包并确保数据的完整性是一项重要的任务。在这篇博客中,我们将探讨如何使用 Java 通过串口读取数据,并确保每条读到的数据都是完整的。我们将介绍如何设计一个系统来处理数据包,包括数据包解析和验证的逻辑。

五、数据包解析类

定义一个抽象数据包类 Packet:
  1. public abstract class Packet {
  2.     protected byte[] data;

  3.     public Packet(byte[] data) {
  4.         this.data = data;
  5.     }

  6.     public byte[] getData() {
  7.         return data;
  8.     }

  9.     public abstract String getNetWeight();
  10.     public abstract String getTareWeight();
  11.     public abstract byte getStatus();
  12. }
复制代码
实现具体的数据解析类 DefaultPacket:
  1. public class DefaultPacket extends Packet {

  2.     public DefaultPacket(byte[] data) {
  3.         super(data);
  4.     }

  5.     @Override
  6.     public String getNetWeight() {
  7.         return new String(data, 2, 7);
  8.     }

  9.     @Override
  10.     public String getTareWeight() {
  11.         return new String(data, 11, 7);
  12.     }

  13.     @Override
  14.     public byte getStatus() {
  15.         return data[20];
  16.     }

  17.     public static String parseStatus(byte status) {
  18.         StringBuilder sb = new StringBuilder();
  19.         sb.append("Weight Overflow: ").append((status & 0x80) != 0).append("\n");
  20.         sb.append("Not Zeroed on Power-up: ").append((status & 0x40) != 0).append("\n");
  21.         sb.append("Tare Mode: ").append((status & 0x20) != 0).append("\n");
  22.         sb.append("Weight is Zero: ").append((status & 0x10) != 0).append("\n");
  23.         sb.append("Weight Stable: ").append((status & 0x08) != 0).append("\n");
  24.         return sb.toString();
  25.     }
  26. }
复制代码
六、数据包解析接口和实现类

定义数据包解析接口 PacketParser:
  1. public interface PacketParser {
  2.     int getDataLength();
  3.     boolean isValid(byte[] data);
  4.     boolean checkChecksum(byte[] data);
  5.     Packet parse(byte[] data);
  6. }
复制代码
具体数据包解析类
DefaultPacketParser 实现了具体的数据包解析和验证逻辑:
  1. public class DefaultPacketParser implements PacketParser {
  2.     @Override
  3.     public int getDataLength() {
  4.         return 24;
  5.     }

  6.     @Override
  7.     public boolean isValid(byte[] data) {
  8.         return data[0] == 0x01 && data[1] == 0x02 && data[22] == 0x03 && data[23] == 0x04;
  9.     }

  10.     @Override
  11.     public boolean checkChecksum(byte[] data) {
  12.         byte checksum = 0;
  13.         for (int i = 2; i < 21; i++) {
  14.             checksum ^= data[i];
  15.         }
  16.         return checksum == data[21];
  17.     }

  18.     @Override
  19.     public Packet parse(byte[] data) {
  20.         return new DefaultPacket(data);
  21.     }
  22. }
复制代码
七、数据包输入流类

PacketInputStream 类使用 PacketParser 来处理数据包的解析和验证,并累积无效数据:
  1. import java.io.ByteArrayOutputStream;
  2. import java.io.FilterInputStream;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.util.Arrays;

  6. public class PacketInputStream extends FilterInputStream {
  7.     private PacketParser parser;
  8.     private byte[] buffer;
  9.     private int bufferPos = 0;
  10.     private ByteArrayOutputStream byteArrayBuffer = new ByteArrayOutputStream();

  11.     public PacketInputStream(InputStream in, PacketParser parser) {
  12.         super(in);
  13.         this.parser = parser;
  14.         this.buffer = new byte[parser.getDataLength()];
  15.     }

  16.     public Packet readPacket() throws IOException {
  17.         // 将上次剩余的无效数据写入缓冲区
  18.         if (byteArrayBuffer.size() > 0) {
  19.             byte[] invalidData = byteArrayBuffer.toByteArray();
  20.             System.arraycopy(invalidData, 0, buffer, 0, invalidData.length);
  21.             bufferPos = invalidData.length;
  22.             byteArrayBuffer.reset();
  23.         }

  24.         while (bufferPos < parser.getDataLength()) {
  25.             int read = in.read(buffer, bufferPos, parser.getDataLength() - bufferPos);
  26.             if (read == -1) {
  27.                 return null; // EOF reached
  28.             }
  29.             bufferPos += read;
  30.         }

  31.         int start = findPacketStart(buffer);
  32.         while (start == -1 && bufferPos >= 2) {
  33.             System.arraycopy(buffer, 1, buffer, 0, bufferPos - 1);
  34.             bufferPos--;
  35.             int read = in.read(buffer, bufferPos, 1);
  36.             if (read == -1) {
  37.                 return null; // EOF reached
  38.             }
  39.             bufferPos += read;
  40.             start = findPacketStart(buffer);
  41.         }

  42.         if (start != 0) {
  43.             byte[] remainingData = Arrays.copyOfRange(buffer, start, bufferPos);
  44.             System.arraycopy(remainingData, 0, buffer, 0, remainingData.length);
  45.             bufferPos = remainingData.length;
  46.             return null;
  47.         }

  48.         if (!parser.isValid(buffer)) {
  49.             byteArrayBuffer.write(buffer, 0, bufferPos);
  50.             bufferPos = 0;
  51.             return null; // 返回 null 表示无效数据包
  52.         }

  53.         if (!parser.checkChecksum(buffer)) {
  54.             byteArrayBuffer.write(buffer, 0, bufferPos);
  55.             bufferPos = 0;
  56.             return null; // 返回 null 表示校验失败
  57.         }

  58.         Packet packet = parser.parse(Arrays.copyOf(buffer, parser.getDataLength()));
  59.         bufferPos = 0;
  60.         return packet;
  61.     }

  62.     private int findPacketStart(byte[] data) {
  63.         for (int i = 0; i < data.length - 1; i++) {
  64.             if (data[i] == 0x01 && data[i + 1] == 0x02) {
  65.                 return i;
  66.             }
  67.         }
  68.         return -1;
  69.     }
  70. }
复制代码
八、读取线程类

ReadThread 使用 PacketInputStream 和 PacketParser 来读取和处理数据包:
  1. import java.io.InputStream;

  2. private class ReadThread extends Thread {
  3.     private PacketInputStream packetInputStream;

  4.     public ReadThread(InputStream inputStream, PacketParser parser) {
  5.         this.packetInputStream = new PacketInputStream(inputStream, parser);
  6.     }

  7.     @Override
  8.     public void run() {
  9.         super.run();
  10.         while (!isInterrupted()) {
  11.             try {
  12.                 Packet packet = packetInputStream.readPacket();
  13.                 if (packet != null) {
  14.                     if (packet instanceof DefaultPacket) {
  15.                         onDataReceived((DefaultPacket) packet);
  16.                     }
  17.                 }
  18.             } catch (IOException e) {
  19.                 e.printStackTrace();
  20.                 return;
  21.             }
  22.         }
  23.     }

  24.     private void onDataReceived(DefaultPacket packet) {
  25.         System.out.println("Net Weight: " + packet.getNetWeight());
  26.         System.out.println("Tare Weight: " + packet.getTareWeight());
  27.         System.out.println("Status: " + DefaultPacket.parseStatus(packet.getStatus()));
  28.     }
  29. }
复制代码
总结

通过抽象数据包解析逻辑,我们可以更好地处理串口数据包的完整性问题。我们定义了数据包类 Packet 和 DefaultPacket,并使用 PacketParser 接口来实现数据包的解析和验证。PacketInputStream 类负责处理数据包的读取和无效数据的累积,而 ReadThread 负责读取和处理有效数据包。这种设计使代码更加模块化、易于维护和扩展,可以很容易地适应不同格式的数据包。
以上就是Android读取串口数据的操作指南的详细内容,更多关于Android读取串口数据的资料请关注晓枫资讯其它相关文章!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
15
积分
10
注册时间
2022-12-28
最后登录
2022-12-28

发表于 2025-3-15 01:12:28 | 显示全部楼层
路过,支持一下
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表