BLE 安卓APP控制LED灯的实现(转)
//注:参考AmoMcu源代码修改。
打开APP,检查蓝牙是否打开
BluetoothAdapter mBluetoothAdapter; final BluetoothManager bluetoothManager =(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); // 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); }
蓝牙扫描
private void scanLeDevice(final boolean enable) { if (enable) { // Stops scanning after a pre-defined scan period. mHandler.postDelayed(new Runnable() { @Override public void run() { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); } }, SCAN_PERIOD); mScanning = true; mBluetoothAdapter.startLeScan(mLeScanCallback); } else { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); } }
连接GATT服务
绑定一个服务
Intent gattServiceIntent = new Intent(this, BluetoothLeService.class); bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE); 注:BluetoothLeService.java,属于安卓源代码,可以到网上下载回来。 // Code to manage Service lifecycle. private final ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder service) { mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService(); if (!mBluetoothLeService.initialize()) { Log.e(TAG, "Unable to initialize Bluetooth"); finish(); } // Automatically connects to the device upon successful start-up initialization. mBluetoothLeService.connect(mDeviceAddress); } @Override public void onServiceDisconnected(ComponentName componentName) { mBluetoothLeService = null; } };
点击某个特征值的响应:
获取前面的数据,不用再次扫描,由扫描页面得到的数据,传过来的
b=getIntent().getExtras(); tv_addr.setText(b.getString(EXTRAS_DEVICE_ADDRESS)); mDeviceAddress=b.getString(EXTRAS_DEVICE_ADDRESS); tv_name.setText(b.getString(EXTRAS_DEVICE_NAME)); mDeviceName=b.getString(EXTRAS_DEVICE_NAME); tv_rssi.setText(b.getString(EXTRAS_DEVICE_RSSI)); lv=(ExpandableListView)this.findViewById(R.id.expandableListView1); lv.setOnChildClickListener(servicesListClickListner); private final ExpandableListView.OnChildClickListener servicesListClickListner = new ExpandableListView.OnChildClickListener() { @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { if (mGattCharacteristics != null) { final BluetoothGattCharacteristic characteristic = mGattCharacteristics.get(groupPosition).get(childPosition); //当前目标特征值 target_chara=characteristic; final int charaProp = characteristic.getProperties(); if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) { mNotifyCharacteristic = characteristic; mBluetoothLeService.setCharacteristicNotification( characteristic, true); } tv_uuid.setText(characteristic.getUuid().toString()); Intent intent=new Intent(); b.putString("CONNET_SATE", status); b.putString("UUID", characteristic.getUuid().toString()); intent.putExtras(b); intent.setClass(MyGattDetail.this, LEDControl.class); startActivity(intent); return true; } return false; } };
读写特征值的数据
读数据:
private static BluetoothGattCharacteristic myCharacteristic=null; private static BluetoothLeService mBluetoothLeService; mBluetoothLeService.readCharacteristic(myCharacteristic);
注释:readCharacteristic该函数会调用BluetoothGatt.readCharacteristic(BluetoothGattCharacteristic characteristic)
写数据:
mBluetoothLeService.writeCharacteristic(myCharacteristic);
注释:writeCharacteristic该函数会调用BluetoothGatt.writeCharacteristic(BluetoothGattCharacteristic characteristic)
示例代码:
private char[] buffer =new char [] {0x6F,0x0F,0x0F,0x0F,0x0F,0x0F}; private void send() { MyGattDetail.write(ConvertString(buffer)); } private String ConvertString(char buffer[]){ String nRcvString; StringBuffer tStringBuf=new StringBuffer (); tStringBuf.append(buffer); nRcvString=tStringBuf.toString(); return nRcvString; } device_name = (TextView) findViewById(R.id.ledpage_devname); ledButton1 = (ToggleButton) findViewById(R.id.ledpage_led1); ledButton1.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if(isChecked){ buffer[1]=0x01; }else{ buffer[1]=0x00; } send(); } }); ledButton2 = (ToggleButton) findViewById(R.id.ledpage_led2); ledButton2.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if(isChecked){ buffer[2]=0x01; }else{ buffer[2]=0x00; } send(); } }); ledButton3 = (ToggleButton) findViewById(R.id.ledpage_led3); ledButton3.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { // TODO Auto-generated method stub if(isChecked){ buffer[3]=0x01; }else{ buffer[3]=0x00; } send(); } }); ledButton4 = (ToggleButton) findViewById(R.id.ledpage_led4); ledButton4.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { // TODO Auto-generated method stub if(isChecked){ buffer[4]=0x01; }else{ buffer[4]=0x00; } send(); } });
使用ToggleButton控件控制LED:
问题:
使用TI的demo会发现打开一个LED会比较慢,偶尔还会失效。也就是说会掉帧,考虑大之前的所写的关于延时值的设置,如下:
Connection Interval(GAPROLE_MIN_CONN_INTERVAL && GAPROLE_MAX_CONN_INTERVAL)- 连接间隔,在BLE的两个设备的连接中使用跳频机制。两个设备使用特定的信道发送和接收数据,然后过一段时间后再使用新的信道(BLE协议栈的链路层处理信道的切换)。两个设备在切换信道后发送和接收数据称为一个连接事件。尽管没有应用数据被发送和接收,两个设备仍旧会交换链路层数据来维持连接。这个连接间隔就是这个两个连接事件的之间的时间间隔。间隔以1.25ms为单元,连接间隔的范围的6-3200既7.5ms-4s(4000ms)之间。
由此可以看出:间隔小,适用于那些需要快速反应的任务。LED灯需要快速的反应,所以经过设置如下:
// Minimum connection interval (units of 1.25ms, 80=100ms) if automatic parameter update request is enabled
#define DEFAULT_DESIRED_MIN_CONN_INTERVAL 6//80
// Maximum connection interval (units of 1.25ms, 800=1000ms) if automatic parameter update request is enabled
#define DEFAULT_DESIRED_MAX_CONN_INTERVAL 80//800
这样子实时体验就有大大的提升。