串口通信
2018-11-06 本文已影响0人
其实很简单oo
关于android单片机串口通信
网上有很多关于android串口读写的结果,但是搜出来的都不太让我满意 ,下面贴出我写的SerialPortUtils类的代码:
public class SerialPortUtils {
private static SerialPortUtils serialPortUtils = null;
private SerialPort serialPort;
private InputStream inputStream;
private OutputStream outputStream;
private SCMDataReceiveListener SCMDataReceiveListener;
private ReadThread readThread;
private byte[] mData = null;
private TimerThread timerThread;
//超时时间(超时检测线程是每次休眠固定时间,通过休眠次数来判断超时)
private int TimeOut=3000;
private int timeOutCount = 0;//timeOutCount=TimeOut/sleepTime
//超时线程睡眠时间
private int sleepTime=50;
//休眠次数
private int sleepCount = 0;
public static SerialPortUtils getInstance() {
if (serialPortUtils == null) {
serialPortUtils = new SerialPortUtils();
}
return serialPortUtils;
}
public void setSCMDataReceiveListener(SCMDataReceiveListener SCMDataReceiveListener) {
this.SCMDataReceiveListener = SCMDataReceiveListener;
}
public void openSerialPort() {
try {
String PORT_PATH = "/dev/ttyUSB0";
int BAUD_RATE = 9600;
serialPort = new SerialPort(new File(PORT_PATH), BAUD_RATE, 0);
inputStream = serialPort.getInputStream();
outputStream = serialPort.getOutputStream();
if (timerThread == null) {
MyApp.getInstance().isReceived=true;
timerThread = new TimerThread();
timerThread.setName("TIMER THREAD");
timerThread.setPriority(1);
timerThread.start();
}
setTomeOut(TimeOut);
} catch (IOException e) {
Log.e("open serial log",e.getMessage());
e.printStackTrace();
}
}
public void setThreadStatus(boolean status){
if(status){
}
}
public void closeSerialPort() {
try {
try {
inputStream.close();
outputStream.close();
} catch (NullPointerException e) {
e.printStackTrace();
}
serialPort.close();
} catch (IOException e) {
Log.e("close log",e.getMessage());
e.printStackTrace();
}
}
/**
* 启动线程接收数据
*/
public void readReceivedData() {
if (inputStream == null) {
return;
}
Log.i("zy", "线程进行中" + inputStream.toString());
if (readThread == null) {
readThread = new ReadThread();
readThread.setName("READ THREAD");
readThread.setPriority(1);
readThread.start();
}
}
public void sendDataToSerialPort(byte[] data) {
mData = data;
if (serialPort == null) {
openSerialPort();
}
try {
if (data != null) {
int dataLength = data.length;
Log.e("DATASIZE", String.valueOf(dataLength));
if (dataLength > 0) {
outputStream.write(data);
outputStream.flush();
sleepCount=0;
MyApp.getInstance().isReceived = false;
Log.e("timerThred status",timerThread.isAlive()?"isAlive":"noAlive");
Log.e("readThread status",readThread.isAlive()?"isAlive":"noAlive");
}
}
} catch (IOException e) {
Log.e("send log",e.getMessage());
e.printStackTrace();
}
}
//设置超时时间
private void setTomeOut(long mesc) {
//超时检测线程是每次休眠固定时间,通过休眠次数来判断超时
timeOutCount = (int) (mesc / sleepTime);
}
/**
* 判断是否超时的线程
*/
private class TimerThread extends Thread {
@Override
public void run() {
while (MyApp.getInstance().isStart) {
try {
sleep(sleepTime);
if (!MyApp.getInstance().isReceived && MyApp.getInstance().sendDataCount <= 10) {
if (sleepCount > timeOutCount) {//超时
ParseProtocolUtils.setStatusData("重发第"+MyApp.getInstance().sendDataCount+"次");
Log.e("test data resend","重发第"+MyApp.getInstance().sendDataCount+"次");
Log.e("status",(timerThread.isInterrupted() ?"true":"false")+","+(readThread.isInterrupted() ?"true":"false"));
MyApp.getInstance().sendDataCount++;
sendDataToSerialPort(mData);
} else {
sleepCount++;
}
}else {
sleepCount=0;
if(MyApp.getInstance().sendDataCount>10){
}
}
} catch (Exception e) {
Log.e("timer log",e.getMessage());
e.printStackTrace();
}
}
}
}
private class ReadThread extends Thread {
@Override
public void run() {
super.run();
// 定义一个包的最大长度
int maxLength = 215;
byte[] buffer = new byte[maxLength];
// 每次收到实际长度
int available = 0;
// 当前已经收到包的总长度
int currentLength = 0;
// 协议头长度(帧头、命令字、数据长度)
int headerLength = 5;
//校验位
int checkBitLength=1;
while (!isInterrupted()) {
try {
available = inputStream.available();
if (available > 0) {
// 防止超出数组最大长度导致溢出
if (available > maxLength - currentLength) {
available = maxLength - currentLength;
}
inputStream.read(buffer, currentLength, available);
currentLength += available;
}
}
catch (Exception e) {
e.printStackTrace();
}
int cursor = 0;
// 如果当前收到包大于头的长度,则解析当前包
while (currentLength >= headerLength) {
// 取到头部第一个字节
if (buffer[cursor] != intToByte(0xaa)&&buffer[cursor] != intToByte(0x55)) {
if(buffer[cursor+1]!=intToByte(0x75)){
--currentLength;
++cursor;
continue;
}
}
int contentLenght = parseLen(buffer, cursor, headerLength);
// 如果内容包的长度大于最大内容长度或者小于等于0,则说明这个包有问题,丢弃
if (contentLenght <= 0 || contentLenght > maxLength - headerLength-checkBitLength) {
currentLength = 0;
break;
}
// 如果当前获取到长度小于整个包的长度,则跳出循环等待继续接收数据
int factPackLen = contentLenght + headerLength+checkBitLength;
if (currentLength < contentLenght + headerLength+checkBitLength) {
break;
}
// 一个完整包即产生
MyApp.getInstance().isStart=true;
MyApp.getInstance().isReceived = true;
MyApp.getInstance().sendDataCount = 1;
SCMDataReceiveListener.dataRecevie(buffer, cursor, factPackLen);
currentLength -= factPackLen;
cursor += factPackLen;
}
// 残留字节移到缓冲区首
if (currentLength > 0 && cursor > 0) {
System.arraycopy(buffer, cursor, buffer, 0, currentLength);
}
}
}
}
public byte intToByte(int x) {
return (byte) x;
}
/**
* 获取协议内容长度
*/
public int parseLen(byte buffer[], int index, int headerLength) {
int rlt=buffer[3]*200+buffer[4];
return rlt;
}
public interface SCMDataReceiveListener {
void dataRecevie(byte[] str,int cursor, int size);
}
}
我这里做的有超时重发的功能,但是总感觉这样做不怎么好,因为线程一直在运行太消耗性能了,但是又不知道其他方法做出来超时重发的效果,希望广大网友可以提出宝贵的意见,谢谢。
恭喜IG夺冠 哈哈哈哈
后记:
忘了说了,上面接收数据的byte数组在接收到超过127的数字的时候会变成负数,至于原因随便百度就知道了,转换的时候需要特别注意下