Android与Arduino蓝牙通信 [英] Android bluetooth communication with Arduino
问题描述
我目前正在查看 Google 的蓝牙聊天示例.目标是基于此示例在 android 和 Arduino 之间进行通信.
I am currently looking at Google's Bluetooth Chat example. The goal is to get communication between android and and Arduino working based on this example.
虽然从智能手机到 Arduino 的通信运行良好,但另一个方向却没有:从Arduino向智能手机发送字节时,使用以下代码接收:
While communication from the smartphone to the Arduino is working great, the other direction does not: When sending bytes from the Arduino to the smartphone, the following code is used for receiving:
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(MainActivity.MESSAGE_READ, bytes, -1, buffer).sendToTarget();
这有以下问题:
- 在我的主要活动中,我得到一个字节数组,它总是 1024 字节长.无论传入的字节长度是多少.如果我知道收到了多少字节,那就太好了.
- 字节似乎无法一次全部读取.例如.上面的代码被多次调用,但缓冲区从不包含我从 Arduino 发送的所有字节.有时只有第一个字节,然后只有最后一个字节.
- 虽然此代码被多次调用,但我的主要活动只收到一次通知.怎么会这样?
这样做的正确方法是什么.是否应该实现一种收集和连接字节的机制?还是我以错误的方式使用此代码?
What is the right way to do this. Should one implement a mechanism that collects and concatenates the bytes? Or am I using this code the wrong way?
推荐答案
我总是无法一次读取大于 1 的字节缓冲区.这是因为无法保证您正确接收了所有字节.我的解决方法是一次一个字节地重复调用 read 并填充我的缓冲区.这样,如果我的任何字节没有被错误地读取,则在我的 connectedThread 的 I/O 捕获部分中捕获该字节,并且可以选择随心所欲地处理它.
I always had trouble reading a byte buffer greater than one at a time. This is because there is no way to guarantee that you received all the bytes correctly. My work around was to call read repeatedly one byte at a time and fill out my buffer. That way if any of my bytes aren't read ill catch that in the I/O catch part of my connectedThread and can choose to deal with it however I want.
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;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
// You can define this buffer to be 1024 or anything you like
buffer = new byte[3];
mmOutStream.write(253);
bytes = mmInStream.read(buffer,0,1);
mmOutStream.write(254);
bytes = mmInStream.read(buffer,1,1);
mmOutStream.write(255);
bytes = mmInStream.read(buffer,2,1);
mHandler.obtainMessage(MESSAGE_READ, buffer).sendToTarget();
}
catch (IOException e) {
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
}
}
在这种情况下,我使用了一个无符号字节数组来表示 0-255 之间的整数.此外,我使用值 255-253 作为命令告诉我的 Arduino 向我发送某些类型的信息.您不必设置任何值来表示对 arduino 的命令,而只需告诉 arduino 在每次收到信息请求时循环遍历它需要发送的值.我发现这是确认您收到的字节数(即您的 byte[] 缓冲区
的大小)的唯一方法之一.尽管在这种情况下我没有放任何东西连接线程的语句,您可以在其中放置一个读取命令以确认您收到一个字节.
In this case I used a unsigned byte array to represent integers from 0-255. Furthermore I used values 255-253 as commands to tell my Arduino to send me certain types of information. You do not have to set any value to represent a command to arduino, instead you can just tell the arduino to loop through values it needs to send each time it receives a request for information. I found out this is one of the only ways to can confirm the amounts of bytes you received(i.e the size of your byte[] buffer
).Although in this case I did not put anything in my catch statement for the connectedThread you could put a read command in there to confirm you receive a byte.
这是我如何处理 readBuffer...
Here is how I dealt with the readBuffer...
/*
* Bluetooth Handler Method
*/
ConnectedThread connectedThread;
Handler mHandler = new Handler(){
public void handleMessage(Message msg){
super.handleMessage(msg);
switch(msg.what){
case SUCCESS_CONNECT:
// Do Something;
Toast.makeText(getActivity(),"CONNECTED",Toast.LENGTH_SHORT).show();
connectedThread = new ConnectedThread((BluetoothSocket)msg.obj);
listView.setVisibility(View.GONE);
connectedThread.start();
break;
case MESSAGE_READ:
byte[] readBuf = (byte[])msg.obj;
int tempInt = byteToInt(readBuf[0]);
int speedInt = byteToInt(readBuf[1]);
int cadenceInt = byteToInt(readBuf[2]);
EditText temperatureData = (EditText)getActivity().findViewById(R.id.temperatureData);
temperatureData.setText(Integer.toString(tempInt) + " C" );
EditText cadenceData = (EditText)getActivity().findViewById(R.id.cadence);
cadenceData.setText(Integer.toString(cadenceInt) + " rpm");
EditText speedData = (EditText)getActivity().findViewById(R.id.speed_data);
speedData.setText(Integer.toString(speedInt) + " kph");
}
}
};
在这种情况下,我在手机上显示实时传感器数据.但你真的可以做任何事情.
In this case I was displaying live sensor data on my phone. But you can do anything really.
希望有所帮助.
这篇关于Android与Arduino蓝牙通信的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!