1.一般自定义的串口协议
串口传输接口底层是按位(bit)发送的,上层是按byte发送和接收的,但协议为了方便描述,每个byte用十六进制数(0x00~0xFF)表示,范相当于十进制的0~255,而byte为八位且是有符号类型,相当于十进制的-128~127,明显0x8F~0xFF(128~255)是不能准确转换为byte的,咋办?
byte b = 0xFF;
编译器会提示出错,因为0xFF被当作255整数处理,255超过了byte(-128~127)的范围,不能直接赋值,那咋办?强转啊!
byte b = (byte) 0xFF;
这样就没问题了,但此时你会不会觉得这样写就和协议想发送0xFF的想法不匹配了呢,我明明想发个255来着,那我告诉你,你一个一个字节的发,每个字节就只能是-128~127,不能在其他范围,所以强转的目的是你可以发送这个0xFF的前提,发送的值肯定不是255,具体是啥:
public class Main {
public static void main(String[] args) {
byte c1 = (byte) 0xFF;
int c2 = c1 & 0xFF;
System.out.println(""+c1);
System.out.println(""+c2);
}
}
-1
255
Process finished with exit code 0
可见,实际上是一个-1,但接受端为了表达这是个发送端发送给我的是0xFF(255)而不是-1,你可以通过取到该字节值后 “ 该值 & 0xFF”转为无符号值即255.
通常自定义协议的格式:
一.接收到数据是不固定的长度,协议是起始是AA AA 结束是DE D0
接收到的数据有可能是AA AA 08 56 82 44 DE DO
二.接受到数据是不固定的长度,协议的起始A0 55 第三个字节为协议长度,结束字节是发送数据的异或校验值,
列如:A0 55 04 51 00 00 55 A0 55 04 53 00 01 56
结束字节是前面各个字节异或后的值:
/**
* 异或校验和
* @param data
* @return
*/
public static byte getXor(byte[] data){
byte temp=data[0];
for (int i = 1; i <data.length; i++) {
temp ^=data[i];
}
return temp;
}
2.分段接收数据不好解析
在读取串口数据时,通常在线程中读取输入流中的数据,这时接受的字节数是不固定的,一条指令被分成若干段,接受到的散乱字节不好处理,看到网上有做延时接受处理,也就是输入流可用的时候就延时一会儿,等接受完了再一次性读出来,效果不错:
/**
* 4.接收串口数据的线程
*/
private class ReceiveThread extends Thread {
@Override
public void run() {
//条件判断,只要条件为true,则一直执行这个线程
while (isStart) {
if (inputStream == null) {
return;
}
byte[] readData = new byte[1024*4];
try {
String receiveCmd = "";
String HEAD = "A055";
StringBuilder sb = new StringBuilder();
// 为了一次性读完,做了延迟读取
if (inputStream.available() > 0 ) {
SystemClock.sleep(200);
int size = inputStream.read(readData);
if (size > 0) {
String readString = DataUtils.ByteArrToHex(readData, 0, size);
LogUtils.d(readString);
if(!TextUtils.isEmpty(readString)){
String[] split = readString.split(HEAD);
for (int i = 1; i < split.length; i++) {
receiveCmd = HEAD+split[i];
sb.append(receiveCmd+"\n");
LogUtils.e(receiveCmd);
}
}
EventBus.getDefault().post(sb.toString());
sb.setLength(0);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}