Android蓝牙输入流实时读取
我正在开发一个Android应用程序,它通过蓝牙接收实时数据并在屏幕上绘图 数据是陀螺传感器位置信息。我从定制的飞思卡尔Kinetis K10微控制器板(由我自己设计和测试)发送。对于蓝牙通信,我使用HC-05蓝牙模块 数据格式如下: 字节_1:位置标识字节,始终等于-128 字节2:轴1的位置 字节_3:轴2的位置 字节4:轴3的位置 我以特定的顺序连续发送这4个字节。我每5毫秒发送4字节的数据包,发送数据包大约需要4.7毫秒(9600波特率)。 从微控制器输出的数据在准确性和定时方面是完美的(用逻辑分析仪检查) 问题是,当从手机接收数据时,一些字节似乎丢失了。下面是代码的一部分,我正在读取InputStream:Android蓝牙输入流实时读取,android,bluetooth,inputstream,Android,Bluetooth,Inputstream,我正在开发一个Android应用程序,它通过蓝牙接收实时数据并在屏幕上绘图 数据是陀螺传感器位置信息。我从定制的飞思卡尔Kinetis K10微控制器板(由我自己设计和测试)发送。对于蓝牙通信,我使用HC-05蓝牙模块 数据格式如下: 字节_1:位置标识字节,始终等于-128 字节2:轴1的位置 字节_3:轴2的位置 字节4:轴3的位置 我以特定的顺序连续发送这4个字节。我每5毫秒发送4字节的数据包,发送数据包大约需要4.7毫秒(9600波特率)。 从微控制器输出的数据在准确性和定时方面是完美的
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e("Printer Service", "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
@Override
public void run() {
Log.i("BluetoothService", "BEGIN mConnectedThread");
byte[] buffer = new byte[4];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
int position = 0;
if(buffer[0] == -128) {
if(bytes >= 2) {
sendArray.errorTilt = buffer[1];
}
if(bytes >= 3) {
sendArray.errorRoll = buffer[2];
}
if(bytes == 4) {
sendArray.errorPan = buffer[3];
}
}
else if(buffer[1] == -128) {
position = 1;
if(bytes >= 3) {
sendArray.errorTilt = buffer[2];
}
if(bytes == 4) {
sendArray.errorRoll = buffer[3];
}
if(bytes >= 2) {
sendArray.errorPan = buffer[0];
}
}
else if(buffer[2] == -128 && bytes >= 3) {
position = 2;
sendArray.errorRoll = buffer[0];
sendArray.errorPan = buffer[1];
if(bytes == 4) {
sendArray.errorTilt = buffer[3];
}
}
else if(buffer[3] == -128 && bytes == 4) {
position = 3;
sendArray.errorTilt = buffer[0];
sendArray.errorRoll = buffer[1];
sendArray.errorPan = buffer[2];
}
if(position <= bytes && bytes > 1) {
sendArray.errorUpdate = true;
}
} catch (Exception e) {
e.printStackTrace();
connectionLost();
BluetoothService.this.stop();
break;
}
}
}
public void write(int oneByte) {
try {
mmOutStream.write(oneByte);
} catch (IOException e) {
Log.e("BluetoothService", "Exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e("BluetoothService", "close() of connect socket failed", e);
}
}
}
私有类ConnectedThread扩展线程{
私人最终蓝牙插座mmSocket;
私有最终输入流mmInStream;
私有最终输出流mmOutStream;
公共连接线程(BluetoothSocket){
mmSocket=插座;
InputStream tmpIn=null;
OutputStream tmpOut=null;
试一试{
tmpIn=socket.getInputStream();
tmpOut=socket.getOutputStream();
}捕获(IOE异常){
Log.e(“打印机服务”,“未创建临时套接字”,e);
}
mmInStream=tmpIn;
mmOutStream=tmpOut;
}
@凌驾
公开募捐{
Log.i(“BluetoothService”、“BEGIN McConnectedThread”);
字节[]缓冲区=新字节[4];
整数字节;
while(true){
试一试{
字节=mmInStream.read(缓冲区);
int位置=0;
如果(缓冲区[0]==-128){
如果(字节>=2){
sendArray.errorTilt=缓冲区[1];
}
如果(字节>=3){
sendArray.errorRoll=缓冲区[2];
}
如果(字节==4){
sendArray.errorPan=缓冲区[3];
}
}
else if(缓冲区[1]=-128){
位置=1;
如果(字节>=3){
sendArray.errorTilt=缓冲区[2];
}
如果(字节==4){
sendArray.errorRoll=缓冲区[3];
}
如果(字节>=2){
sendArray.errorPan=缓冲区[0];
}
}
else if(缓冲区[2]=-128&&bytes>=3){
位置=2;
sendArray.errorRoll=缓冲区[0];
sendArray.errorPan=缓冲区[1];
如果(字节==4){
sendArray.errorTilt=缓冲区[3];
}
}
else if(缓冲区[3]=-128&&字节==4){
位置=3;
sendArray.errorTilt=缓冲区[0];
sendArray.errorRoll=缓冲区[1];
sendArray.errorPan=缓冲区[2];
}
如果(位置1){
sendArray.errorUpdate=true;
}
}捕获(例外e){
e、 printStackTrace();
connectionLost();
BluetoothService.this.stop();
打破
}
}
}
公共无效写入(整数字节){
试一试{
mmOutStream.write(一个字节);
}捕获(IOE异常){
Log.e(“蓝牙服务”,“写入期间异常”,e);
}
}
公开作废取消(){
试一试{
mmSocket.close();
}捕获(IOE异常){
Log.e(“BluetoothService”,“连接套接字关闭()失败”,e);
}
}
}
sendArray是一个保持许多不同变量的单例
errorTilt、errorRoll和errorPan是从接收缓冲区更新的轴的当前值
“位置”保持位置标识字节的位置。它用于检查是否有任何变量已更新
很多时候,输入缓冲区只接收到一个字节,因为我不知道它应该是哪个轴,因为我没有关于它相对于位置字节的相对位置的信息,这个特定的字节是无用的,并且丢失了
我已经通过以下方法测试了接收的准确性。我让MCU在其中一个轴上输出一个三角波,而不是轴数据。在手机上,三角波的线条并不像人们想象的那样笔直,而是随机弯曲的,并含有人工制品
为了绘制数据,我使用GraphView,并从一个单独的线程以相等的间隔更新图形
我曾尝试使用更长的接收缓冲区(使用修改后的接收算法),但这没有帮助,因为一次只接收几个字节
我尝试过实现InputStream.available(),但它总是提供127个可用字节,这似乎不是真的
我读过很多关于类似问题的文章,在过去的5天里我一直在研究,但是我找不到一个好的解决方案
总之,我需要实现所有字节的准确、实时(或接近实时)接收
具有类似问题的线程:
多谢各位
更新:
我刚试过把信息发送出去
public void run() {
byte[] bytes = new byte[38];
int iterator = 0;
while (true) {
try {
int bytesAvailable = mmInStream.available();
if (bytesAvailable > 0) {
byte[] curBuf = new byte[bytesAvailable];
mmInStream.read(curBuf);
for (byte b : curBuf) {
if (b == (byte) 0xAA && iterator == 38) {
mHandler.obtainMessage(MainActivity.DATA_READ, bytes.length, -1, bytes).sendToTarget();
iterator = 0;
bytes[iterator] = b;
} else {
bytes[iterator] = b;
}
iterator++;
}
}
} catch (IOException ex) {
Log.e(TAG, "disconnected", ex);
connectionLost();
break;
}
}
}