用Java读取串行信息
我正在移植一个已经用Python开发的Android应用程序。在Python程序中,有一行我正试图完全理解:用Java读取串行信息,java,android,python,Java,Android,Python,我正在移植一个已经用Python开发的Android应用程序。在Python程序中,有一行我正试图完全理解: self.comfd = Serial(...) # from the pySerial API .... self.buffer = list(struct.unpack('192H', self.comfd.read(384))) 据我所知,self.comfd.read(384)正在读取384字节,unpack('192H')正在从该数据中解压192个未签名的短消息。这是否正确
self.comfd = Serial(...) # from the pySerial API
....
self.buffer = list(struct.unpack('192H', self.comfd.read(384)))
据我所知,self.comfd.read(384)
正在读取384字节,unpack('192H')
正在从该数据中解压192个未签名的短消息。这是否正确
现在在Java中,我已经能够使用
SerialPort device = SerialPort(file, baud, flags);
InputStream in = device.getInputStream();
我的问题是,现在我有了输入流,如何像Python程序那样创建无符号的短裤
我尝试过的(没有产生正确的值):
byte[]buffer=新字节[384];
in.read(缓冲区);
ByteBuffer bb=ByteBuffer.allocate(2);
对于(int i=0;i
我做错了什么?谢谢你的帮助
编辑:我合并了Jason C的答案,而且我循环错误。通过将其更改为
for(int i=0;i
解决了我的问题。您可以使用字符(在Java中是一个16位无符号值),例如:
使用bb.order()设置big-vs.little-endian
您也可以不使用ByteBuffer将2个字节打包成一个int(假定为小endian)。字节在Java中是有符号的,因此您必须在移位之前将字节转换为无符号值,您可以通过将其临时存储在一个短值(或int或任何足以容纳0-255的大值)中来实现:
short b0=(缓冲区[0]&255);//技巧转换为无符号
短b1=(缓冲区[1]&255);
int val=b0 |(b1Java没有无符号的数字(char
是16位无符号的,但它不是一个数字,char
的数学运算将始终导致对int
的隐式强制转换)
如果将2个字节的无符号数据读入short
,并希望看到0-65535(而不是-32768-32767)范围内的值,则必须使用可以包含该范围内值的类型
对于16位short
的情况,下一个较大的值是32位int
short signed = ...;
int unsigned = signed & 0xFFFF;
假设signed
的值为0xFFFF
,则会发生以下情况:
short signed = -1; // FFFF on byte level
表达式signed&0xFFFF
包含一个short
和一个int
0xFFFF
是一个文本整数类型的数字,当在Java源代码中找到它时,它被认为是int
。您可以通过将其更改为0xFFFF
来将其设置为long
(如果要将无符号的int
转换为long
,则需要该参数)
由于&
运算符在一个公共类型中需要两边,因此Java将静默地转换较小的类型
int stillSigned = (int) signed; // hidden step
它仍将具有完全相同的值-1,因为在查看它时,这是以前的无符号值,但它在bytelevel上更改为0xFFFFFFFF
现在应用位操作以删除所有添加的FF
s
int unsigned = stillSigned & 0xFFFF;
最后在字节级上得到0x0000FFFF
,最后可以看到65535的值
由于正好有16位值,所以可以使用char
并将其强制转换为int
char value = ...;
int unsigned = value;
但上述方法适用于任何无符号转换:byteValue&0xFF
,shortValue&0xFFFF
,intValue&0xffffff
接下来应该做的事情是不要使用简单的InputStream
来执行
SerialPort device = SerialPort(file, baud, flags);
InputStream in = device.getInputStream();
byte[] buffer = new byte[384];
in.read(buffer);
原因是不能保证读取缓冲区中所需的所有字节。如果流已完成,它将返回已读取的字节数或-1
。手动编写确保缓冲区已满的代码很麻烦,但有一个简单的解决方案:
DataInputStream
具有非常好的功能,您可以使用:
SerialPort device = SerialPort(file, baud, flags);
DataInputStream in = new DataInputStream(device.getInputStream());
int unsignedShort = in.readUnsignedShort();
从字节[]
数据中获取不同数字的另一种方法是使用ByteBuffer
,因为它提供了类似.getShort()
我已经更新了这个答案,我以前的答案不是最好的。请注意,DataInputStream假设大端字节顺序,并且这是不能更改的。这是正确的。例如,这样做会有所帮助。或者使用字节缓冲
方式并指定正确的字节顺序
。
char value = ...;
int unsigned = value;
SerialPort device = SerialPort(file, baud, flags);
InputStream in = device.getInputStream();
byte[] buffer = new byte[384];
in.read(buffer);
SerialPort device = SerialPort(file, baud, flags);
DataInputStream in = new DataInputStream(device.getInputStream());
byte[] buffer = new byte[384];
in.readFully(buffer);
SerialPort device = SerialPort(file, baud, flags);
DataInputStream in = new DataInputStream(device.getInputStream());
int unsignedShort = in.readUnsignedShort();
SerialPort device = SerialPort(file, baud, flags);
DataInputStream in = new DataInputStream(device.getInputStream());
byte[] buffer = new byte[384];
in.readFully(buffer);
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
while (byteBuffer.hasRemaining()) {
int unsigned = byteBuffer.getChar();
System.out.println(unsigned);
}