需求
单片机通过Socket发送过来类似 { 0xff,0x0c ,0x80...}的byte数组,根据协议分为unsigned char 和signed char两种类型。需要将int数据转为两个byte发送给单片机,或将单片机发来的2个byte转化为int。
工具程序
/**
* 将两个byte数据转化为有符号int
* @param high : 高八位
* @param low : 低八位
* @return
*/
public static int twoByteToSignedInt(byte high,byte low){
return (high << 8) | low;
}
/**
* 将两个byte数据转化为无符号int
* @param high : 高八位
* @param low : 低八位
* @return
*/
public static int twoByteToUnsignedInt(byte high,byte low){
return ((high << 8) & 0xffff) | (low & 0x00ff);
}
/**
* 将int转换为两个byte
* @param numInt : 实际只取其中的低16位二进制数
* @return 长度为2的byte数组 ,byte[0]为高8位,byte[1]为低八位
*/
public static byte[] intToTwoByte(int numInt){
byte[] rest = new byte[2];
if(numInt < -32768 || numInt > 32767){
return null;
}
rest[0] = (byte)(numInt >> 8);//高8位
rest[1] = (byte)(numInt & 0x00ff);//低8位
return rest;
}
解释
- 单片机发送过来的数据有 unsigned char 和 signed char 之分;而 Java 中的 byte(8位)、int(32位) 都是有符号的。
- 计算机里的数字,不管正负,其底层都是以补码形式存在的!!
- Java 的二进制采用补码形式。比如 Java 里的 Integer.toBinaryString(int) 函数,如果传入负数,则只会输出其补码形式,传入正数则输出原码二进制数(正数补码=原码)。
signed char 转为 Java 的有符号 int
参见函数 twoByteToSignedInt(byte high,byte low) 。由于在单片机中signed char也是以补码形式存在,所以直接用位操作将两个byte拼接为一个int即可。unsigned char 转为 Java 的无符号 int
参见函数 twoByteToUnsignedInt(byte high,byte low) 。那为什么要按位与0xffff呢?因为byte->int会发生符号扩展,这在转为有符号int时没有影响,但在转为无符号int时,符号扩展会造成数值出现误差。
具体来说,比如对于一个byte,如果不进行& 0xff,那么当一个byte会转换成int时,由于int是32位,而byte只有8位这时会进行f符号扩展,例如补码11111111的十进制数为-1,转换为int时变为1111 1111 1111 1111 1111 1111 1111 1111(补码)即0xffffffff但是这个数是不对的,这种补位就会造成误差。和0xff相与后,高24比特就会被清0了,结果就对了。int 转为 unsigned/signed char
参见intToTwoByte(int numInt)。
直接取int里的低16位即可。因为无论正负,在单片机里都是以补码形式存在,不需要额外转换。