在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)来连接和访问设备终端:
adb shell ls /dev/tty*
二、确定波特率
波特率是串口通信的速率,单位是波特(baud)。常见的波特率有 9600、19200、38400、57600、115200 等。波特率的选择通常由串口设备的规格或协议决定。你需要查阅设备手册或与设备供应商确认。
三、读取串口数据
在选择正确的串口号和波特率后,可以通过输入流读取串口数据。以下是一个读取线程的示例代码:
private class readthread extends thread { @override public void run() { super.run(); while(!isinterrupted()) { try { if (minputstream == null) return; int size = minputstream.read(tempbuff); if (size > 0){ ondatareceived(arrays.copyofrange(tempbuff, 0, size)); } try { thread.sleep(10);//延时10ms } catch (interruptedexception e) { e.printstacktrace(); } } catch (throwable e) { e.printstacktrace(); return; } } } }
四、数据包处理
以某品牌的电子秤为例,其数据协议如下:
取重 1、主动/被动模式的数据格式相同。 2、上位机指令(hex): 1b 01 02 3、数据格式:(总共 24 字节) 01 02 000.000kg 000.000kg sta x 03 04 数据头 净重 皮重 状态 校验 数据尾 shead1 soh(01h) 1 字节,标题开始 shead2 stx(02h) 1 字节,正文开始 weight 1 xxx.xxx 7 字节,净重。 weight units u1u0 2 字节,重量单位。如“kg” weight2 xxx.xxx 7 字节,皮重。 weight units u1u0 2 字节,重量单位。如“kg” status sta 1 字节,状态 check sum bcc 1 字节,使用 bcc 算法,除 soh stx etx eot 及本字节外所有字符的 bcc 校验。 tail1 etx(03h) 1 字节,标题结束 tail2 eot(04h) 1 字节,传输结束 重量格式(净重/皮重),例如: 123.456kg 23.456kg 12.3456kg 0.012kg -12.345kg -1.234kg -0.0001kg (前面无数据则用空格填充。如果小数点后面有四位,则为精确到 0.1g) 状态: bit7:1 重量溢出;0 重量正常 bit6:1 开机后未归零(开机时秤盘上有重物);0 开机后已归零 bit5:1 当前在去皮模式;0 当前不是 去皮模式 bit4:1 当前重量为 0;0 当前重量不为 0 bit3:1 重量稳定;0 重量不稳定 bit2~bit0 0
在串口通信中,处理数据包并确保数据的完整性是一项重要的任务。在这篇博客中,我们将探讨如何使用 java 通过串口读取数据,并确保每条读到的数据都是完整的。我们将介绍如何设计一个系统来处理数据包,包括数据包解析和验证的逻辑。
五、数据包解析类
定义一个抽象数据包类 packet:
public abstract class packet { protected byte[] data; public packet(byte[] data) { this.data = data; } public byte[] getdata() { return data; } public abstract string getnetweight(); public abstract string gettareweight(); public abstract byte getstatus(); }
实现具体的数据解析类 defaultpacket:
public class defaultpacket extends packet { public defaultpacket(byte[] data) { super(data); } @override public string getnetweight() { return new string(data, 2, 7); } @override public string gettareweight() { return new string(data, 11, 7); } @override public byte getstatus() { return data[20]; } public static string parsestatus(byte status) { stringbuilder sb = new stringbuilder(); sb.append("weight overflow: ").append((status & 0x80) != 0).append("\n"); sb.append("not zeroed on power-up: ").append((status & 0x40) != 0).append("\n"); sb.append("tare mode: ").append((status & 0x20) != 0).append("\n"); sb.append("weight is zero: ").append((status & 0x10) != 0).append("\n"); sb.append("weight stable: ").append((status & 0x08) != 0).append("\n"); return sb.tostring(); } }
六、数据包解析接口和实现类
定义数据包解析接口 packetparser:
public interface packetparser { int getdatalength(); boolean isvalid(byte[] data); boolean checkchecksum(byte[] data); packet parse(byte[] data); }
具体数据包解析类
defaultpacketparser 实现了具体的数据包解析和验证逻辑:
public class defaultpacketparser implements packetparser { @override public int getdatalength() { return 24; } @override public boolean isvalid(byte[] data) { return data[0] == 0x01 && data[1] == 0x02 && data[22] == 0x03 && data[23] == 0x04; } @override public boolean checkchecksum(byte[] data) { byte checksum = 0; for (int i = 2; i < 21; i++) { checksum ^= data[i]; } return checksum == data[21]; } @override public packet parse(byte[] data) { return new defaultpacket(data); } }
七、数据包输入流类
packetinputstream 类使用 packetparser 来处理数据包的解析和验证,并累积无效数据:
import java.io.bytearrayoutputstream; import java.io.filterinputstream; import java.io.ioexception; import java.io.inputstream; import java.util.arrays; public class packetinputstream extends filterinputstream { private packetparser parser; private byte[] buffer; private int bufferpos = 0; private bytearrayoutputstream bytearraybuffer = new bytearrayoutputstream(); public packetinputstream(inputstream in, packetparser parser) { super(in); this.parser = parser; this.buffer = new byte[parser.getdatalength()]; } public packet readpacket() throws ioexception { // 将上次剩余的无效数据写入缓冲区 if (bytearraybuffer.size() > 0) { byte[] invaliddata = bytearraybuffer.tobytearray(); system.arraycopy(invaliddata, 0, buffer, 0, invaliddata.length); bufferpos = invaliddata.length; bytearraybuffer.reset(); } while (bufferpos < parser.getdatalength()) { int read = in.read(buffer, bufferpos, parser.getdatalength() - bufferpos); if (read == -1) { return null; // eof reached } bufferpos += read; } int start = findpacketstart(buffer); while (start == -1 && bufferpos >= 2) { system.arraycopy(buffer, 1, buffer, 0, bufferpos - 1); bufferpos--; int read = in.read(buffer, bufferpos, 1); if (read == -1) { return null; // eof reached } bufferpos += read; start = findpacketstart(buffer); } if (start != 0) { byte[] remainingdata = arrays.copyofrange(buffer, start, bufferpos); system.arraycopy(remainingdata, 0, buffer, 0, remainingdata.length); bufferpos = remainingdata.length; return null; } if (!parser.isvalid(buffer)) { bytearraybuffer.write(buffer, 0, bufferpos); bufferpos = 0; return null; // 返回 null 表示无效数据包 } if (!parser.checkchecksum(buffer)) { bytearraybuffer.write(buffer, 0, bufferpos); bufferpos = 0; return null; // 返回 null 表示校验失败 } packet packet = parser.parse(arrays.copyof(buffer, parser.getdatalength())); bufferpos = 0; return packet; } private int findpacketstart(byte[] data) { for (int i = 0; i < data.length - 1; i++) { if (data[i] == 0x01 && data[i + 1] == 0x02) { return i; } } return -1; } }
八、读取线程类
readthread 使用 packetinputstream 和 packetparser 来读取和处理数据包:
import java.io.inputstream; private class readthread extends thread { private packetinputstream packetinputstream; public readthread(inputstream inputstream, packetparser parser) { this.packetinputstream = new packetinputstream(inputstream, parser); } @override public void run() { super.run(); while (!isinterrupted()) { try { packet packet = packetinputstream.readpacket(); if (packet != null) { if (packet instanceof defaultpacket) { ondatareceived((defaultpacket) packet); } } } catch (ioexception e) { e.printstacktrace(); return; } } } private void ondatareceived(defaultpacket packet) { system.out.println("net weight: " + packet.getnetweight()); system.out.println("tare weight: " + packet.gettareweight()); system.out.println("status: " + defaultpacket.parsestatus(packet.getstatus())); } }
总结
通过抽象数据包解析逻辑,我们可以更好地处理串口数据包的完整性问题。我们定义了数据包类 packet 和 defaultpacket,并使用 packetparser 接口来实现数据包的解析和验证。packetinputstream 类负责处理数据包的读取和无效数据的累积,而 readthread 负责读取和处理有效数据包。这种设计使代码更加模块化、易于维护和扩展,可以很容易地适应不同格式的数据包。
以上就是android读取串口数据的操作指南的详细内容,更多关于android读取串口数据的资料请关注代码网其它相关文章!
发表评论