2016-03-01 202 views
1

我很努力從定製藍牙低功耗設備讀取/發送數據。我正在使用Microchip RN4020藍牙模塊。Android和低功耗藍牙(BLE)

我發現的每個教程或示例都解釋瞭如何將移動應用程序連接到設備,但我沒有找到如何實際與其進行交互。 因此,我正是可以做和不能做我的應用程序。

每一個特徵目前我做了以下內容:

gatt.readCharacteristic(services.get(i).getCharacteristics().get(j));

這是結果,當我打印的價值觀:

getStringValue= Mobi_F934�� 
getStringValue= null 
getStringValue= ����d��� 

getStringValue= 001EC030F934 
getStringValue= 2.1 
getStringValue= 1.10 
getStringValue= 1.10 
getStringValue= Microchip 
getStringValue= RN4020 

getStringValue= 
getStringValue= 

我不知道這是重要的或者不...

如何讀取從BLE設備發送的數據?

編輯:我的Android代碼

@TargetApi(21) 
public class MainActivity extends ActionBarActivity { 
    private BluetoothAdapter mBluetoothAdapter; 
    private int REQUEST_ENABLE_BT = 1; 
    private Handler mHandler; 
    private static final long SCAN_PERIOD = 10000; 
    private BluetoothLeScanner mLEScanner; 
    private ScanSettings settings; 
    private List<ScanFilter> filters; 
    private BluetoothGatt mGatt; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     mHandler = new Handler(); 
     if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { 
      Toast.makeText(this, "BLE Not Supported", 
        Toast.LENGTH_SHORT).show(); 
      finish(); 
     } 

     // Initializes Bluetooth adapter 
     final BluetoothManager bluetoothManager = 
       (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); 
     mBluetoothAdapter = bluetoothManager.getAdapter(); 

    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 
     // Ensures Bluetooth is available on the device and it is enabled. If not, 
     // displays a dialog requesting user permission to enable Bluetooth. 

     if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { 
      Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); 
      startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); 
     } else { 
      if (Build.VERSION.SDK_INT >= 21) { 
       mLEScanner = mBluetoothAdapter.getBluetoothLeScanner(); 
       settings = new ScanSettings.Builder() 
         .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) 
         .build(); 
       filters = new ArrayList<ScanFilter>(); 
      } 
      scanLeDevice(true); 
     } 
    } 

    @Override 
    protected void onPause() { 
     super.onPause(); 
     if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) { 
      scanLeDevice(false); 
     } 
    } 

    @Override 
    protected void onDestroy() { 
     if (mGatt == null) { 
      return; 
     } 
     mGatt.close(); 
     mGatt = null; 
     super.onDestroy(); 
    } 

    @Override 
    protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
     if (requestCode == REQUEST_ENABLE_BT) { 
      if (resultCode == Activity.RESULT_CANCELED) { 
       //Bluetooth not enabled. 
       finish(); 
       return; 
      } 
     } 
     super.onActivityResult(requestCode, resultCode, data); 
    } 

    private void scanLeDevice(final boolean enable) { 
     if (enable) { 
      mHandler.postDelayed(new Runnable() { 
       @Override 
       public void run() { 
        if (Build.VERSION.SDK_INT < 21) { 
         mBluetoothAdapter.stopLeScan(mLeScanCallback); 
        } else { 
         mLEScanner.stopScan(mScanCallback); 

        } 
       } 
      }, SCAN_PERIOD); 
      if (Build.VERSION.SDK_INT < 21) { 
       mBluetoothAdapter.startLeScan(mLeScanCallback); 
      } else { 
       mLEScanner.startScan(filters, settings, mScanCallback); 
      } 
     } else { 
      if (Build.VERSION.SDK_INT < 21) { 
       mBluetoothAdapter.stopLeScan(mLeScanCallback); 
      } else { 
       mLEScanner.stopScan(mScanCallback); 
      } 
     } 
    } 


    private ScanCallback mScanCallback = new ScanCallback() { 
     @Override 
     public void onScanResult(int callbackType, ScanResult result) { 
      Log.e("callbackType", "MAX " + String.valueOf(callbackType)); 
      Log.e("result", "MAX " + result.toString()); 
      BluetoothDevice btDevice = result.getDevice(); 
      connectToDevice(btDevice); 
     } 

     @Override 
     public void onBatchScanResults(List<ScanResult> results) { 
      for (ScanResult sr : results) { 
       Log.e("ScanResult - Results", "MAX " + sr.toString()); 
      } 
     } 

     @Override 
     public void onScanFailed(int errorCode) { 
      Log.e("Scan Failed", "MAX " + "Error Code: " + errorCode); 
     } 
    }; 

    private BluetoothAdapter.LeScanCallback mLeScanCallback = 
      new BluetoothAdapter.LeScanCallback() { 
       @Override 
       public void onLeScan(final BluetoothDevice device, int rssi, 
            byte[] scanRecord) { 
        runOnUiThread(new Runnable() { 
         @Override 
         public void run() { 
          Log.e("onLeScan", "MAX " + device.toString()); 
          connectToDevice(device); 
         } 
        }); 
       } 
      }; 

    public void connectToDevice(BluetoothDevice device) { 
     if (mGatt == null) { 
      mGatt = device.connectGatt(this, false, gattCallback); 
      scanLeDevice(false);// will stop after first device detection 
     } 
    } 

    private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() { 
     @Override 
     public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { 
      Log.e("onConnectionStateChange", "MAX " + "Status: " + status); 
      switch (newState) { 
       case BluetoothProfile.STATE_CONNECTED: 
        Log.e("gattCallback", "MAX " + "STATE_CONNECTED"); 
        gatt.discoverServices(); 
        break; 
       case BluetoothProfile.STATE_DISCONNECTED: 
        Log.e("gattCallback", "MAX " + "STATE_DISCONNECTED"); 
        break; 
       default: 
        Log.e("gattCallback", "MAX " + "STATE_OTHER"); 
      } 

     } 

     @Override 
     public void onServicesDiscovered(BluetoothGatt gatt, int status) { 
      List<BluetoothGattService> services = gatt.getServices(); 
      Log.e("onServicesDiscovered", "MAX " + services.toString()); 

      /* 
      for(int i = 0; i < services.size(); i++){ 
       for (int j = 0; j < services.get(i).getCharacteristics().size(); j++){ 
        Log.e("MAX", "i= " + i + " j= " + j); 
        gatt.readCharacteristic(services.get(i).getCharacteristics().get 
          (j)); 
       } 
      } 
      */ 

      gatt.readCharacteristic(services.get(0).getCharacteristics().get(0)); 
     } 

     @Override 
     public void onCharacteristicRead(BluetoothGatt gatt, 
             BluetoothGattCharacteristic 
               characteristic, int status) { 
      Log.e("onCharacteristicRead", "MAX " + characteristic.toString()); 
      Log.e("onCharacteristicRead", "MAX " +characteristic.getStringValue(0)); 
      //gatt.disconnect(); 
     } 
    }; 
    } 

編輯2:我的Arduino代碼

#include <SoftwareSerial.h> 

/* Set up BT to arduino uno 
BT RN4020 Arduino Uno 
------------------------------------------------ 
Red   3.3V 
Green  GND 
Yellow(RX) TX (digital pin 1) 
Orange(TX) RX (digital pin 0) 
White  PIN 8 (!) This is not GND (!) 
Blue   3.3V (Ioref can also be used) 
*/ 

/* 
----------------------------------------------------------------------------- 
-----EXPLANATION PROGRAM----------------------------------------------------- 
---------------------------- 
Eerst wordt de BT module geïnitialiseerd door verschillende commando's door te 
sturen. Bij elk commando wordt gecheckt of de BT module het juiste antwoord 
heeft teruggestuurd. 
De initialisatie moet gebeuren in CMD mode, de CMD/MLDP pin moet laag zijn. Na 
de initialisatie checken we tot de BT module is geconnecteerd met het device. 
Als de BT module geconnecteerd is zetten we deze uit CMD mode en in MLDP mode 
om het verzenden en ontvangen van data te ondersteunen. Daarna zenden we om de 
seconde de string 'test' door. 
Dit gebeurt zolang het device geconnecteerd is met de BT module. 
------------------------------------------------------------------------------ 
------------------------------------------------------------------------------ 
----------------------------- 
*/ 

int CMD_MLD_pin = 8; // IO pin for CMD/MLDP pin (LOW --> CMD, HIGH --> MLDP) 

void setup() // Initialising BT RN4020 
{ 
    pinMode(CMD_MLD_pin, OUTPUT); 
    digitalWrite(CMD_MLD_pin, LOW); // put CMD/MLDP pin LOW for CMD mode 
    delay(5000); 
    /* Initialize Bluetooth */ 
    Serial.begin(115200); // Set up serial connection with required baud rate of 
         // 115200 
    delay(1500); 
    Serial.println("R,1"); //Reboot 
    while(!Serial.find("Reboot")){} // Waiting until BT RN4020 responds the 
    required string 
    while(!Serial.find("CMD")){} 
    //delay(2000); 
    Serial.println("SF,1"); // Factory reset 
    while(!Serial.find("AOK")){} 
    //delay(1500); 
    Serial.println("SR,32000000"); // Set device as peripheral 
    while(!Serial.find("AOK")){} 
    Serial.println("S-, Mobi"); // Change name of BT 
    while(!Serial.find("AOK")){} 
    //delay(1500); 
    Serial.println("R,1"); // Reboot to make changes effective 
    while(!Serial.find("Reboot")){} 
    while(!Serial.find("CMD")){} 
    //delay(2000); 
} 

void loop() 
{ 
    // Wait until the device responds it is connected 
    // If the device is connected we will send every second the string 'test' 
    while(!Serial.find("Connected")){} // Wait until BT RN4020 is connected to a 
            // device 
    digitalWrite(CMD_MLD_pin, HIGH); // Go to MLDP to support data stream 
    while(!Serial.find("MLDP")){} // Wait until BT RN4020 is effectively in MLDP 
           // mode 
    delay(500); 
    while (!Serial.find("Connection End")) // Send string to BTRN4020 while the 
             // BT RN4020 is conected to a device 
    { 
    Serial.println("test"); 
    delay(1000); 
    } 
} 
+0

BLE設備發送數據時,無論是通過通知服務。或者您可以閱讀該服務,其中大部分數據都是十六進制格式,因此您必須將其轉換。所以代碼更具體的答案 – AAnkit

回答

1

問了幾個月後,我設法解決了我的問題。那時我忘了分享我的解決方案。無論如何,遲到比從未更好!

這是我在BLE上測試android-TI sensortag通信時編寫的一些代碼。

完整的例子可在https://github.com/maxhelskens/SmergyBicycle

package com.example.max.smergy; 

import android.annotation.TargetApi; 
import android.app.Activity; 
import android.app.ProgressDialog; 
import android.bluetooth.BluetoothAdapter; 
import android.bluetooth.BluetoothDevice; 
import android.bluetooth.BluetoothGatt; 
import android.bluetooth.BluetoothGattCallback; 
import android.bluetooth.BluetoothGattCharacteristic; 
import android.bluetooth.BluetoothGattDescriptor; 
import android.bluetooth.BluetoothGattService; 
import android.bluetooth.BluetoothManager; 
import android.bluetooth.BluetoothProfile; 
import android.bluetooth.le.BluetoothLeScanner; 
import android.bluetooth.le.ScanCallback; 
import android.bluetooth.le.ScanFilter; 
import android.bluetooth.le.ScanResult; 
import android.bluetooth.le.ScanSettings; 
import android.content.Context; 
import android.content.Intent; 
import android.content.pm.PackageManager; 
import android.os.Build; 
import android.os.Bundle; 
import android.os.Handler; 
import android.os.Message; 
import android.support.v7.app.AppCompatActivity; 
import android.support.v7.widget.Toolbar; 
import android.util.Log; 
import android.util.SparseArray; 
import android.view.Menu; 
import android.view.MenuItem; 
import android.widget.TextView; 
import android.widget.Toast; 

import java.util.ArrayList; 
import java.util.List; 
import java.util.UUID; 

@TargetApi(21) 
public class MainActivity extends AppCompatActivity { 

    private static final String TAG = "MainActivity"; 

    private static final String DEVICE_NAME = "SensorTag"; 

    /* Humidity Service */ 
    private static final UUID HUMIDITY_SERVICE = UUID.fromString("F000AA20-0451-4000-B000-000000000000"); 
    private static final UUID HUMIDITY_DATA_CHAR = UUID.fromString("f000aa21-0451-4000-b000-000000000000"); 
    private static final UUID HUMIDITY_CONFIG_CHAR = UUID.fromString("f000aa22-0451-4000-b000-000000000000"); 
    /* magneto Service */ 
    private static final UUID MAGNETO_SERVICE = UUID.fromString("F000AA80-0451-4000-B000-000000000000"); 
    private static final UUID MAGNETO_DATA_CHAR = UUID.fromString("f000aa81-0451-4000-b000-000000000000"); 
    private static final UUID MAGNETO_CONFIG_CHAR = UUID.fromString("f000aa82-0451-4000-b000-000000000000"); 
    /* Barometric Pressure Service */ 
    private static final UUID PRESSURE_SERVICE = UUID.fromString("f000aa40-0451-4000-b000-000000000000"); 
    private static final UUID PRESSURE_DATA_CHAR = UUID.fromString("f000aa41-0451-4000-b000-000000000000"); 
    private static final UUID PRESSURE_CONFIG_CHAR = UUID.fromString("f000aa42-0451-4000-b000-000000000000"); 
    private static final UUID PRESSURE_CAL_CHAR = UUID.fromString("f000aa43-0451-4000-b000-000000000000"); 
    /* Client Configuration Descriptor */ 
    private static final UUID CONFIG_DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); 


    private BluetoothAdapter mBluetoothAdapter; 
    private SparseArray<BluetoothDevice> mDevices; 

    private BluetoothGatt mGatt; 

    private TextView mTemperature, mHumidity, mPressure; 

    private ProgressDialog mProgress; 

    private int REQUEST_ENABLE_BT = 1; 
    private BluetoothLeScanner mLEScanner; 
    private ScanSettings settings; 
    private List<ScanFilter> filters; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     setProgressBarIndeterminate(true); 

     // Find the toolbar view inside the activity layout 
     Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 
     // Sets the Toolbar to act as the ActionBar for this Activity window. 
     // Make sure the toolbar exists in the activity and is not null 
     setSupportActionBar(toolbar); 


     /* 
     * We are going to display the results in some text fields 
     */ 
     mTemperature = (TextView) findViewById(R.id.text_temperature); 
     mHumidity = (TextView) findViewById(R.id.text_humidity); 
     mPressure = (TextView) findViewById(R.id.text_pressure); 

     //Check if BLE is supported 
     if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { 
      Toast.makeText(this, "BLE Not Supported", 
        Toast.LENGTH_SHORT).show(); 
      finish(); 
     } 
     final BluetoothManager bluetoothManager = 
       (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); 
     mBluetoothAdapter = bluetoothManager.getAdapter(); 

     mDevices = new SparseArray<BluetoothDevice>(); 


     /* 
     * A progress dialog will be needed while the connection process is 
     * taking place 
     */ 
     mProgress = new ProgressDialog(this); 
     mProgress.setIndeterminate(true); 
     mProgress.setCancelable(false); 

    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 
     if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { 
      Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); 
      startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); 
     } else { 
      if (Build.VERSION.SDK_INT >= 21) { 
       mLEScanner = mBluetoothAdapter.getBluetoothLeScanner(); 
       settings = new ScanSettings.Builder() 
         .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) 
         .build(); 
       filters = new ArrayList<ScanFilter>(); 
      } 
     } 

     clearDisplayValues(); 
    } 

    @Override 
    protected void onPause() { 
     super.onPause(); 

     //Make sure dialog is hidden 
     mProgress.dismiss(); 
     //Cancel any scans in progress 
     mHandler.removeCallbacks(mStopRunnable); 
     mHandler.removeCallbacks(mStartRunnable); 

     if (Build.VERSION.SDK_INT < 21) { 
      mBluetoothAdapter.stopLeScan(mLeScanCallback); 
     } else { 
      mLEScanner.stopScan(mScanCallback); 

     } 
    } 

    @Override 
    protected void onStop() { 
     super.onStop(); 
     //Disconnect from any active tag connection 
     if (mGatt != null) { 
      mGatt.close(); 
      mGatt = null; 
     } 
    } 

    @Override 
    protected void onDestroy() { 
     if (mGatt == null) { 
      return; 
     } 
     mGatt.close(); 
     mGatt = null; 
     super.onDestroy(); 
    } 

    @Override 
    protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
     if (requestCode == REQUEST_ENABLE_BT) { 
      if (resultCode == Activity.RESULT_CANCELED) { 
       //Bluetooth not enabled. 
       finish(); 
       return; 
      } 
     } 
     super.onActivityResult(requestCode, resultCode, data); 
    } 

    // Menu icons are inflated just as they were with actionbar 
    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.menu_main, menu); 

     //Add any device elements we've discovered to the overflow menu 
     for (int i=0; i < mDevices.size(); i++) { 
      BluetoothDevice device = mDevices.valueAt(i); 
      menu.add(0, mDevices.keyAt(i), 0, device.getName()); 
     } 

     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     switch (item.getItemId()) { 
      case R.id.bluetoothSearch: 
       mDevices.clear(); 
       startScan(); 
       //scanLeDevice(true); 

       return true; 
      default: 
       //Obtain the discovered device to connect with 
       BluetoothDevice device = mDevices.get(item.getItemId()); 
       Log.i(TAG, "Connecting to " + device.getName()); 
       /* 
       * Make a connection with the device 
       */ 

       connectToDevice(device); 
       //Display progress UI 
       mHandler.sendMessage(Message.obtain(null, MSG_PROGRESS, "Connecting to " + device.getName() + "...")); 
       return super.onOptionsItemSelected(item); 
     } 
    } 

    private void clearDisplayValues() { 
     mTemperature.setText("---"); 
     mHumidity.setText("---"); 
     mPressure.setText("---"); 
    } 

    private Runnable mStopRunnable = new Runnable() { 
     @Override 
     public void run() { 
      stopScan(); 
     } 
    }; 
    private Runnable mStartRunnable = new Runnable() { 
     @Override 
     public void run() { 
      startScan(); 
     } 
    }; 

    private void startScan() { 
     if (Build.VERSION.SDK_INT < 21) { 
      mBluetoothAdapter.startLeScan(mLeScanCallback); 
     } else { 
      mLEScanner.startScan(filters, settings, mScanCallback); 
     } 
     setProgressBarIndeterminateVisibility(true); 

     mHandler.postDelayed(mStopRunnable, 2500); 
    } 

    private void stopScan() { 
     if (Build.VERSION.SDK_INT < 21) { 
      mBluetoothAdapter.stopLeScan(mLeScanCallback); 
     } else { 
      mLEScanner.stopScan(mScanCallback); 

     } 
     setProgressBarIndeterminateVisibility(false); 
    } 

    private BluetoothAdapter.LeScanCallback mLeScanCallback = 
      new BluetoothAdapter.LeScanCallback() { 
       @Override 
       public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { 
        Log.i("onLeScan", device.toString()); 

        mDevices.put(device.hashCode(), device); 
        //Update the overflow menu 
        invalidateOptionsMenu(); 
       } 
      }; 

/* 

    private void scanLeDevice(final boolean enable) { 
     if (enable) { 
      mHandler.postDelayed(new Runnable() { 
       @Override 
       public void run() { 
        if (Build.VERSION.SDK_INT < 21) { 
         mBluetoothAdapter.stopLeScan(mLeScanCallback); 
        } else { 
         mLEScanner.stopScan(mScanCallback); 

        } 
       } 
      }, SCAN_PERIOD); 
      if (Build.VERSION.SDK_INT < 21) { 
       mBluetoothAdapter.startLeScan(mLeScanCallback); 
      } else { 
       mLEScanner.startScan(filters, settings, mScanCallback); 
      } 
     } else { 
      if (Build.VERSION.SDK_INT < 21) { 
       mBluetoothAdapter.stopLeScan(mLeScanCallback); 
      } else { 
       mLEScanner.stopScan(mScanCallback); 
      } 
     } 
    } 

*/ 

    private ScanCallback mScanCallback = new ScanCallback() { 
     @Override 
     public void onScanResult(int callbackType, ScanResult result) { 
      Log.i("callbackType", String.valueOf(callbackType)); 
      Log.i("result", result.toString()); 
      BluetoothDevice btDevice = result.getDevice(); 

      mDevices.put(btDevice.hashCode(), btDevice); 
      //Update the overflow menu 
      invalidateOptionsMenu(); 
     } 

     @Override 
     public void onBatchScanResults(List<ScanResult> results) { 
      for (ScanResult sr : results) { 
       Log.i("ScanResult - Results", sr.toString()); 
      } 
     } 

     @Override 
     public void onScanFailed(int errorCode) { 
      Log.e("Scan Failed", "Error Code: " + errorCode); 
     } 
    }; 


    public void connectToDevice(BluetoothDevice device) { 
     if (mGatt == null) { 
      mGatt = device.connectGatt(this, false, gattCallback); 
      stopScan(); 
     } 
    } 


    /* 
    * In this callback, we've created a bit of a state machine to enforce that only 
    * one characteristic be read or written at a time until all of our sensors 
    * are enabled and we are registered to get notifications. 
    */ 
    private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() { 
     /* State Machine Tracking */ 
     private int mState = 0; 

     private void reset() { mState = 0; } 

     private void advance() { mState++; } 

     /* 
     * Send an enable command to each sensor by writing a configuration 
     * characteristic. This is specific to the SensorTag to keep power 
     * low by disabling sensors you aren't using. 
     */ 
     private void enableNextSensor(BluetoothGatt gatt) { 
      BluetoothGattCharacteristic characteristic; 
      switch (mState) { 
       /* 
       case 0: 
        Log.d(TAG, "Enabling pressure cal"); 
        characteristic = gatt.getService(PRESSURE_SERVICE) 
          .getCharacteristic(PRESSURE_CONFIG_CHAR); 
        characteristic.setValue(new byte[] {0x02}); 
        break; 
       case 1: 
        Log.d(TAG, "Enabling pressure"); 
        characteristic = gatt.getService(PRESSURE_SERVICE) 
          .getCharacteristic(PRESSURE_CONFIG_CHAR); 
        characteristic.setValue(new byte[] {0x01}); 
        break; */ 
       case 0: 
        Log.d(TAG, "Enabling humidity"); 
        characteristic = gatt.getService(HUMIDITY_SERVICE) 
          .getCharacteristic(HUMIDITY_CONFIG_CHAR); 
        characteristic.setValue(new byte[] {0x01}); 
        break; 
       case 1: 
        Log.d(TAG, "Enabling magneto"); 
        characteristic = gatt.getService(MAGNETO_SERVICE) 
          .getCharacteristic(MAGNETO_CONFIG_CHAR); 
        characteristic.setValue(new byte[] {(byte)0x7F, (byte)0x00}); 
        break; 
       default: 
        mHandler.sendEmptyMessage(MSG_DISMISS); 
        Log.i(TAG, "All Sensors Enabled"); 
        return; 
      } 

      gatt.writeCharacteristic(characteristic); 
     } 

     /* 
     * Read the data characteristic's value for each sensor explicitly 
     */ 
     private void readNextSensor(BluetoothGatt gatt) { 
      BluetoothGattCharacteristic characteristic; 
      switch (mState) { 
       /* 
       case 0: 
        Log.d(TAG, "Reading pressure cal"); 
        characteristic = gatt.getService(PRESSURE_SERVICE) 
          .getCharacteristic(PRESSURE_CAL_CHAR); 
        break; 
       case 1: 
        Log.d(TAG, "Reading pressure"); 
        characteristic = gatt.getService(PRESSURE_SERVICE) 
          .getCharacteristic(PRESSURE_DATA_CHAR); 
        break;*/ 
       case 0: 
        Log.d(TAG, "Reading humidity"); 
        characteristic = gatt.getService(HUMIDITY_SERVICE) 
          .getCharacteristic(HUMIDITY_DATA_CHAR); 
        break; 
       case 1: 
        Log.d(TAG, "Reading magneto"); 
        characteristic = gatt.getService(MAGNETO_SERVICE) 
          .getCharacteristic(MAGNETO_DATA_CHAR); 
        break; 
       default: 
        mHandler.sendEmptyMessage(MSG_DISMISS); 
        Log.i(TAG, "All Sensors Enabled"); 
        return; 
      } 

      gatt.readCharacteristic(characteristic); 
     } 


     /* 
     * Enable notification of changes on the data characteristic for each sensor 
     * by writing the ENABLE_NOTIFICATION_VALUE flag to that characteristic's 
     * configuration descriptor. 
     */ 
     private void setNotifyNextSensor(BluetoothGatt gatt) { 
      BluetoothGattCharacteristic characteristic; 
      switch (mState) { 
       /* 
       case 0: 
        Log.d(TAG, "Set notify pressure cal"); 
        characteristic = gatt.getService(PRESSURE_SERVICE) 
          .getCharacteristic(PRESSURE_CAL_CHAR); 
        break; 
       case 1: 
        Log.d(TAG, "Set notify pressure"); 
        characteristic = gatt.getService(PRESSURE_SERVICE) 
          .getCharacteristic(PRESSURE_DATA_CHAR); 
        break;*/ 
       case 0: 
        Log.d(TAG, "Set notify humidity"); 
        characteristic = gatt.getService(HUMIDITY_SERVICE) 
          .getCharacteristic(HUMIDITY_DATA_CHAR); 
        break; 
       case 1: 
        Log.d(TAG, "Set notify magneto"); 
        characteristic = gatt.getService(MAGNETO_SERVICE) 
          .getCharacteristic(MAGNETO_DATA_CHAR); 
        break; 
       default: 
        mHandler.sendEmptyMessage(MSG_DISMISS); 
        Log.i(TAG, "All Sensors Enabled"); 
        return; 
      } 

      //Enable local notifications 
      gatt.setCharacteristicNotification(characteristic, true); 
      //Enabled remote notifications 
      BluetoothGattDescriptor desc = characteristic.getDescriptor(CONFIG_DESCRIPTOR); 
      desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); 
      gatt.writeDescriptor(desc); 
     } 


     @Override 
     public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { 
      Log.i("onConnectionStateChange", "Status: " + status); 
      if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) { 
       /* 
       * Once successfully connected, we must next discover all the services on the 
       * device before we can read and write their characteristics. 
       */ 
       gatt.discoverServices(); 
       mHandler.sendMessage(Message.obtain(null, MSG_PROGRESS, "Discovering Services...")); 
      } else if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_DISCONNECTED) { 
       /* 
       * If at any point we disconnect, send a message to clear the weather values 
       * out of the UI 
       */ 
       mHandler.sendEmptyMessage(MSG_CLEAR); 
      } else if (status != BluetoothGatt.GATT_SUCCESS) { 
       /* 
       * If there is a failure at any stage, simply disconnect 
       */ 
       gatt.close(); 
      } 

     } 

     @Override 
     public void onServicesDiscovered(BluetoothGatt gatt, int status) { 
      List<BluetoothGattService> services = gatt.getServices(); 
      Log.i("onServicesDiscovered", services.toString()); 

      mHandler.sendMessage(Message.obtain(null, MSG_PROGRESS, "Enabling Sensors...")); 
      /* 
      * With services discovered, we are going to reset our state machine and start 
      * working through the sensors we need to enable 
      */ 
      reset(); 
      enableNextSensor(gatt); 
     } 

     @Override 
     public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { 
      Log.i("onCharacteristicRead", characteristic.toString()); 
      //For each read, pass the data up to the UI thread to update the display 
      if (HUMIDITY_DATA_CHAR.equals(characteristic.getUuid())) { 
       mHandler.sendMessage(Message.obtain(null, MSG_HUMIDITY, characteristic)); 
      } 
      if (MAGNETO_DATA_CHAR.equals(characteristic.getUuid())) { 
       mHandler.sendMessage(Message.obtain(null, MSG_MAGNETO, characteristic)); 
      } 
      if (PRESSURE_DATA_CHAR.equals(characteristic.getUuid())) { 
       mHandler.sendMessage(Message.obtain(null, MSG_PRESSURE, characteristic)); 
      } 
      if (PRESSURE_CAL_CHAR.equals(characteristic.getUuid())) { 
       mHandler.sendMessage(Message.obtain(null, MSG_PRESSURE_CAL, characteristic)); 
      } 

      //After reading the initial value, next we enable notifications 
      setNotifyNextSensor(gatt); 
     } 

     @Override 
     public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { 
      //After writing the enable flag, next we read the initial value 
      readNextSensor(gatt); 
     } 

     @Override 
     public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { 
      /* 
      * After notifications are enabled, all updates from the device on characteristic 
      * value changes will be posted here. Similar to read, we hand these up to the 
      * UI thread to update the display. 
      */ 
      if (HUMIDITY_DATA_CHAR.equals(characteristic.getUuid())) { 
       mHandler.sendMessage(Message.obtain(null, MSG_HUMIDITY, characteristic)); 
      } 
      if (MAGNETO_DATA_CHAR.equals(characteristic.getUuid())) { 
       mHandler.sendMessage(Message.obtain(null, MSG_MAGNETO, characteristic)); 
      } 
      if (PRESSURE_DATA_CHAR.equals(characteristic.getUuid())) { 
       mHandler.sendMessage(Message.obtain(null, MSG_PRESSURE, characteristic)); 
      } 
      if (PRESSURE_CAL_CHAR.equals(characteristic.getUuid())) { 
       mHandler.sendMessage(Message.obtain(null, MSG_PRESSURE_CAL, characteristic)); 
      } 
     } 

     @Override 
     public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { 
      //Once notifications are enabled, we move to the next sensor and start over with enable 
      advance(); 
      enableNextSensor(gatt); 
     } 

     @Override 
     public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { 
      Log.d(TAG, "Remote RSSI: " + rssi); 
     } 

     private String connectionState(int status) { 
      switch (status) { 
       case BluetoothProfile.STATE_CONNECTED: 
        return "Connected"; 
       case BluetoothProfile.STATE_DISCONNECTED: 
        return "Disconnected"; 
       case BluetoothProfile.STATE_CONNECTING: 
        return "Connecting"; 
       case BluetoothProfile.STATE_DISCONNECTING: 
        return "Disconnecting"; 
       default: 
        return String.valueOf(status); 
      } 
     } 
    }; 


    /* 
    * We have a Handler to process event results on the main thread 
    */ 
    private static final int MSG_HUMIDITY = 101; 
    private static final int MSG_PRESSURE = 102; 
    private static final int MSG_PRESSURE_CAL = 103; 
    private static final int MSG_MAGNETO = 104; 
    private static final int MSG_PROGRESS = 201; 
    private static final int MSG_DISMISS = 202; 
    private static final int MSG_CLEAR = 301; 
    private Handler mHandler = new Handler() { 
     @Override 
     public void handleMessage(Message msg) { 
      BluetoothGattCharacteristic characteristic; 
      switch (msg.what) { 
       case MSG_HUMIDITY: 
        characteristic = (BluetoothGattCharacteristic) msg.obj; 
        if (characteristic.getValue() == null) { 
         Log.w(TAG, "Error obtaining humidity value"); 
         return; 
        } 
        updateHumidityValues(characteristic); 
        break; 
       case MSG_MAGNETO: 
        characteristic = (BluetoothGattCharacteristic) msg.obj; 
        if (characteristic.getValue() == null) { 
         Log.w(TAG, "Error obtaining magneto value"); 
         return; 
        } 
        updateMagnetoValues(characteristic); 
        break; 
       case MSG_PRESSURE: 
        characteristic = (BluetoothGattCharacteristic) msg.obj; 
        if (characteristic.getValue() == null) { 
         Log.w(TAG, "Error obtaining pressure value"); 
         return; 
        } 
        updatePressureValue(characteristic); 
        break; 
       case MSG_PRESSURE_CAL: 
        characteristic = (BluetoothGattCharacteristic) msg.obj; 
        if (characteristic.getValue() == null) { 
         Log.w(TAG, "Error obtaining cal value"); 
         return; 
        } 
        updatePressureCals(characteristic); 
        break; 
       case MSG_PROGRESS: 
        mProgress.setMessage((String) msg.obj); 
        if (!mProgress.isShowing()) { 
         mProgress.show(); 
        } 
        break; 
       case MSG_DISMISS: 
        mProgress.hide(); 
        break; 
       case MSG_CLEAR: 
        clearDisplayValues(); 
        break; 
      } 
     } 
    }; 

    /* Methods to extract sensor data and update the UI */ 

    private void updateHumidityValues(BluetoothGattCharacteristic characteristic) { 
     double humidity = SensorTagData.extractHumidity(characteristic); 

     mHumidity.setText(String.format("%.0f%%", humidity)); 
    } 

    ArrayList<Double> magnets = new ArrayList<>(); 
    double average = 0; 
    int count = -1; 
    int wait5 = 0; 

    private void updateMagnetoValues(BluetoothGattCharacteristic characteristic) { 
     double magnet = SensorTagData.extractMagnetoX(characteristic); 
     Log.e("MAGNETO", "" + magnet); 
     magnet = Math.abs(magnet); 

     if (wait5 == 0) { 

      if (magnet > average + 300 || magnet < average - 300) { 
       wait5 = 6; 

       count ++; 
       mPressure.setText("" + count); 
      } 
     } 
     else { 
      wait5 --; 
     } 

     if (magnets.size() >= 5) { 
      magnets.remove(0); 
     } 
     magnets.add(magnet); 
     double sum = 0; 
     for (int i = 0; i < magnets.size(); i++) { 
      sum += magnets.get(i); 
     } 
     average = sum/magnets.size(); 
     average = magnets.get(2); 

     //mHumidity.setText(String.format("%.0f%%", humidity)); 

    } 

    private int[] mPressureCals; 
    private void updatePressureCals(BluetoothGattCharacteristic characteristic) { 
     mPressureCals = SensorTagData.extractCalibrationCoefficients(characteristic); 
    } 

    private void updatePressureValue(BluetoothGattCharacteristic characteristic) { 
     if (mPressureCals == null) return; 
     double pressure = SensorTagData.extractBarometer(characteristic, mPressureCals); 
     double temp = SensorTagData.extractBarTemperature(characteristic, mPressureCals); 

     mTemperature.setText(String.format("%.1f\u00B0C", temp)); 
     mPressure.setText(String.format("%.2f", pressure)); 
    } 
} 
1

嗯,我認爲你應該做如何使用的特點更多的閱讀。你的芯片在默認情況下有很多特徵,主要包含來自芯片的信息。爲了發送和接收數據,您必須首先對芯片進行編程,以便通過特定的特性發送數據,並通過其他特定的特性接收數據。

某些芯片具有默認的Rx和Tx特性,您應該使用它們來發送和接收數據。這些特性充當BLE與芯片上Tx和Rx引腳之間的流水線,並將簡單回顯所有數據。

或者,您可以在BLE服務上創建自己的特徵,並編寫自己的發送和接收協議。

讓我給你舉一個簡單的例子:

假設您正在使用芯片的默認特性發送數據。這些數據必須以小塊發送,例如20個字節。要在Android上讀取此數據,您必須首先獲取該特徵的描述符並啓用通知。這將告訴Android聽取該特徵並監控變化。

characteristic = gatt.getService(UUID.fromString(SERVICE_UUID)).getCharacteristic(UUID.fromString(CHARACTERISTIC_UUID)); //Find you characteristic 
    mGatt.setCharacteristicNotification(characteristic, true); //Tell you gatt client that you want to listen to that characteristic 
    List<BluetoothGattDescriptor> descriptors = characteristic.getDescriptors(); //find the descriptors on the characteristic 
    BluetoothGattDescriptor descriptor = descriptors.get(1); //get the right descriptor for setting notifications 
    descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); 
    mGatt.writeDescriptor(descriptor); //apply these changes to the ble chip to tell it we are ready for the data 

這樣做了以後,你就可以使用onCharacteristicChanged方法來讀取數據:

@Override 
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { 
    super.onCharacteristicChanged(gatt, characteristic); 
    String data = characteristic.getStringValue(0); 
} 

發送的數據將是一個有點簡單。一旦你找到的特徵,你就必須以塊的形式寫入數據到特點:

byte[] value = new byte[1]; 
value[0] = (byte) (21 & 0xFF); //your data 
characteristic.setValue(value); //assign the new data value to the characteristic 
boolean success = mBluetoothGatt.writeCharacteristic(charac); //write to the chip 

一旦寫入,該芯片將刷新特性,將數據發送到芯片的TX腳上。

編輯:

通過the user manual for RN4020去,你可以看到,該芯片具有默認的電池服務和型號,軟件版本等一些特點,但沒有默認Rx和Tx的特性。

在這種情況下,您在代碼中找到的特徵僅僅是設備信息,實際上是無用的。你必須首先在芯片上定義你自己的私人服務和特性。請參閱manual中的示例3-1。一旦您使用唯一的UUID定義私有服務和特性,您可以將數據寫入該數據,並使用相同的UUID在Android上閱讀。

+0

我想感謝您的快速回復。但是我有一個問題,如果我使用微芯片的應用程序,我可以讀取數據(它是一個終端),如果芯片上沒有定義Rx和Tx,那該怎麼做? –

+0

很難說沒有看到你的代碼。但我猜你可能有一個預定義的特徵。嘗試使用它,看看它是否工作。無論如何,最好使用特有的UUID在Android中讀取它,而不是遍歷所有這些。 – SoroushA

+0

你在正確的軌道上。我的建議是代替服務和特性的.get(0),使用gatt.getService(UUID.fromString(SERVICE_UUID))。getCharacteristic(UUID.fromString(CHARACTERISTIC_UUID)); 然後在您的芯片端代碼上,將您的數據寫入具有該UUID和voila的特性中! – SoroushA

-1

我得到RN4020在processing.org與arduino平臺結合使用。如果你仍然有興趣,讓我知道。

您是否將SW喚醒和硬件喚醒引腳連接到vcc 3.3v? 你不必去開始你的CMD everythime。

我只是將CDM直接連接到VCC。一旦你給重啓命令,它直接進入MLDP。

+2

您應該修復語法/拼寫錯誤。這真的會損害你的答案的可讀性。 – Laurel