【问题标题】:Android bluetooth communication with Arduino与 Arduino 的 Android 蓝牙通信
【发布时间】:2014-03-15 10:53:15
【问题描述】:

我目前正在查看 Google 的蓝牙聊天示例。目标是让 android 和 Arduino 之间的通信基于此示例工作。

虽然从智能手机到 Arduino 的通信运行良好,但另一个方向却没有: 从 Arduino 向智能手机发送字节时,使用以下代码进行接收:

// 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 发送的所有字节。有时只有第一个字节,然后只有最后一个字节。
  • 虽然此代码被多次调用,但我的主要活动只收到一次通知。怎么可能?

这样做的正确方法是什么。是否应该实现一种收集和连接字节的机制?还是我用错了这段代码?

【问题讨论】:

  • 首先,您不应该期望所有字节都立即显示 - 当您异步采用一个字节的接口(例如 Arduino 的串行输出)时,根本不会发生这种情况,并且将其通过分组接口,如蓝牙(或以太网或 USB 等)。接下来,在您的 read() 调用之后立即记录 read() 调用返回的 bytes 的值,看看它是否合理。如果你走到了这一步,你的问题在于通知 UI 或那里的代码做了什么。
  • 如果您的 Arduino 中的数据是文本数据并且换行符终止,您可以考虑将 InputStream 包装在 InputStreamReader 中,然后使用 BufferedReader 提供可能适合您需要的 readLine() 方法。
  • 同时使用 Arduino 确保您的波特率设置正确,因为 Arduino 无法像您的蓝牙以最大速度运行一样快。

标签: java android bluetooth serial-port arduino


【解决方案1】:

我每次读取大于一个的字节缓冲区时总是遇到问题。这是因为无法保证您正确接收到所有字节。我的解决方法是一次一个字节地重复调用 read 并填写我的缓冲区。这样,如果我的任何字节没有被读取,就会在我的 connectedThread 的 I/O 捕获部分中捕获它,并且可以选择按照我的意愿处理它。

连接线程示例

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[] buffer 的大小)。尽管在这种情况下,我没有在 connectedThread 的 catch 语句中添加任何内容,但您可以添加在那里读取命令以确认您收到一个字节。

消息处理程序

这是我如何处理 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");
                    
            }
        }       
    };

在这种情况下,我在手机上显示实时传感器数据。但是你真的可以做任何事情。

希望有所帮助。

【讨论】:

  • 我应该添加 java 没有无符号字节数组。所以我创建了自己的函数 byteToInt(byte b) 来为我进行转换。
  • 您能在此处发布您如何从 Arduino 发送数据吗?作为一个字符串每个循环?我的示例发送“T:30.39H:33.98PPM:2943”,我需要在 Arduino 上对其进行解析并在单独的文本元素中显示
猜你喜欢
  • 1970-01-01
  • 2016-07-29
  • 2013-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多