首页 > 学院 > 开发设计 > 正文

蓝牙Ble4.0通讯的步骤及实现

2019-11-06 09:41:05
字体:
来源:转载
供稿:网友

在一家偏硬件的一家公司从事穿戴式设备的开发,通过近几个月学习与研究对于蓝牙4.0的通讯还有有点自己的见解,有不足的地方大家可以一起讨论,互相学习,废话不多说,那么如何进行蓝牙4.0的通讯与数据传输呢?本demo比较简单,大家应该都可以很好理解与学习的!

有基本的几个步骤,下面是一些代码段,希望对大家有所帮助吧。

添加蓝牙权限,

<uses-permission android:name="android.permission.BLUETOOTH"/><uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/><uses-feature android:name="android.hardware.bluetooth_le"    android:required="true"/>
判断手机手机是否支持蓝牙ble
// 检查当前手机是否支持ble 蓝牙,如果不支持退出程序if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {    Toast.makeText(this, "设备不支持BLE 蓝牙", Toast.LENGTH_SHORT).show();    finish();}
//获得蓝牙适配器对象
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
对于蓝牙的搜索过程采用广播:
/** 因为蓝牙在搜索到设备和搜索完毕都是通过广播发送的,这里我们需要注册广播接收器 */IntentFilter intentFilter = new IntentFilter(        BluetoothDevice.ACTION_FOUND);registerReceiver(receiver, intentFilter);intentFilter = new IntentFilter(        BluetoothAdapter.ACTION_DISCOVERY_FINISHED);registerReceiver(receiver, intentFilter);//注册蓝牙信号强度intentFilter = new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED);registerReceiver(receiver, intentFilter);
广播的注册:
 //注册广播    PRivate final BroadcastReceiver receiver = new BroadcastReceiver() {        @Override        public void onReceive(Context arg0, Intent intent) {            String action = intent.getAction();            // 判断这个广播是否是蓝牙搜索到设备的广播            if (action.equals(BluetoothDevice.ACTION_FOUND)) {                // 获取到传递过来的设备信息                BluetoothDevice device = intent                        .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {                    //信号强度                    short rssi = intent.getExtras().getShort(                            BluetoothDevice.EXTRA_RSSI);                    String s = String.valueOf(rssi);                    mDeviceList.add(device.getName()  + "/n"                            + device.getAddress() + "/n" + "信号强度:" + s +"dbm");                    arrayAdapter.notifyDataSetChanged();                }                // 判断是否为搜索完毕的广播            } else if (action                    .equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {                /***///             setTitle("连接蓝牙设备");                bt_search.setText("搜索完毕");            }        }    };
项目创建时需要打开蓝牙,详细代码片段
// 为了确保设备上蓝牙能使用, 如果当前蓝牙设备没启用,弹出对话框向用户要求授予权限来启用if (!mBluetoothAdapter.isEnabled()) {    Intent enabletIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);    startActivityForResult(enabletIntent, REQUEST_CODE);}
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {    super.onActivityResult(requestCode, resultCode, data);    if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_CANCELED) {        finish();        return;    }}
基本工作有了这些后,我们建立一个listview来显示搜索到的蓝牙设备,
//适配器 + Listview显示arrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,mDeviceList);listView.setAdapter(arrayAdapter);
2.如何进行扫描呢?这里采用的是按钮触发:
bt_search.setText("正在搜索蓝牙设备...");if(mBluetoothAdapter.isDiscovering()){    mBluetoothAdapter.cancelDiscovery();}mBluetoothAdapter.startDiscovery();其实这个时候点击按钮,并没有任何显示,因为我们得用一个集合加载搜索到的设备,前面采用MVC的模式进行适配,将搜索到的设备加载到链表里面
//数据源存放蓝牙设备----------------获取已绑定的设备,将其存放于set集合Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();if(devices.size() > 0){    for (BluetoothDevice device:devices) {        mDeviceList.add(device.getName()  + "/n"                + device.getAddress());    }}
将搜索到的设备显示到listview上后对其item项进行进一步的连接,并进行通信、
因为要连接设备的地址,这里进行字符串的截取
        String s = mDeviceList.get(position);        String a[] = s.split("/n");        String name = a[0];        String address = a[1];        Log.i(TAG, "address =" + address);        if (mBluetoothAdapter == null || address == null) {            Log.w(TAG, "蓝牙适配器为空或者地址为空.");            return;        }        //根据地址取得设备        device = mBluetoothAdapter.getRemoteDevice(address);        //获取链接 这个时候需要实现BluetoothGattCallback        bluetoothGatt = device.connectGatt(this, false, bluetoothGattCallback);接下来执行回调方法,回调方法主要有
onConnectionStateChange, // 返回链接状态
onServicesDiscovered,   //发现服务时调用此方法
onCharacteristicRead      //字段读
onCharacteristicWrite   //字段写
onCharacteristicChanged   //蓝牙通信内容写入写出时调用此方法
onDescriptorRead       // 字段读
onDescriptorWrite    //字段写
 //回调方法    private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {        // 返回链接状态        @Override        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {            super.onConnectionStateChange(gatt, status, newState);            Log.i(TAG,"onConnectionStateChange");            if (newState == BluetoothProfile.STATE_CONNECTED) {                //连接成功  因为是异步调用的 所以刷新UI的操作要放在主线程中,当然也可以使用hanlder  Eventbus等 随便                runOnUiThread(new Runnable() {                    @Override                    public void run() {                        link = 1;                        tv_address.setText("连接成功" + device.getAddress());                    }                });                //发现服务,连接成功                gatt.discoverServices();            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {                //断开连接                link = 2;                runOnUiThread(new Runnable() {                    @Override                    public void run() {                        tv_address.setText("连接断开");                    }                });            }        }        @Override        public void onServicesDiscovered(BluetoothGatt gatt, int status) {            super.onServicesDiscovered(gatt, status);            Log.i(TAG,"onServicesDiscovered");            if (status == BluetoothGatt.GATT_SUCCESS) {                bluetoothGattServiceList = bluetoothGatt.getServices();                for (int i = 0; i < bluetoothGattServiceList.size(); i++) {                    BluetoothGattService bluetoothGattService = bluetoothGattServiceList                            .get(i);                    if (bluetoothGattService.getUuid().equals(BleConstants.TEMP_SERVICE_UUID)) {                        BleConstants.type = 1;                        break;                    } else if (bluetoothGattService.getUuid().equals(BleConstants.TEMP_SERVICE_UUID_G)) {                        BleConstants.type = 0;                        break;                    }                }                //-------------------------                for (int i = 0; i < bluetoothGattServiceList.size(); i++) {                    BluetoothGattService bluetoothGattService = bluetoothGattServiceList                            .get(i);                    Log.i(TAG,"Service UUID-" + i + ":" + bluetoothGattService.getUuid());                    List<BluetoothGattCharacteristic> bluetoothGattCharacteristicList = bluetoothGattService                            .getCharacteristics();                    for (int j = 0; j < bluetoothGattCharacteristicList.size(); j++) {                        BluetoothGattCharacteristic bluetoothGattCharacteristic = bluetoothGattCharacteristicList                                .get(j);                        Log.i(TAG,"Characteristic UUID-" + i + "-" + j + ":"                                + bluetoothGattCharacteristic.getUuid());                        if (bluetoothGattCharacteristic.getUuid().equals(BleConstants.TEMP_CHAR_UUID)) {                            Log.i(TAG, "TEMP_CHAR_UUID");                         } else if (bluetoothGattCharacteristic.getUuid().equals(BleConstants.TEMP_BATTERY_CHAR_UUID)) {                            Log.i(TAG, "BATTERY_CHAR_UUID" + bluetoothGattCharacteristic.getUuid().toString());                        } else if (bluetoothGattCharacteristic.getUuid()                                .equals(BleConstants.TEMP_UART_WRITE_CHAR_UUID)) {                        } else if (bluetoothGattCharacteristic.getUuid()                                .equals(BleConstants.TEMP_UART_READ_CHAR_UUID)) {                        }                    }                }                read();                Log.i(TAG, "BluetoothGatt.GATT_SUCCESS");            }        }        @Override        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {            super.onCharacteristicRead(gatt, characteristic, status);            Log.i(TAG,"onCharacteristicRead");        }        /**         * write成功(发送值成功) 写入Characteristic成功与否的回调 可以根据         * characteristic.getValue()来判断是哪个值发送成功了,比如 连接上设备之后你有一大串命令需要下发,你调用多次写命令,         * 这样你需要判断是不是所有命令都成功了,因为android不太稳定,有必要来check命令是否成功,否则你会发现你明明调用         * 写命令,但是设备那边不响应         */        @Override        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {            super.onCharacteristicWrite(gatt, characteristic, status);            Log.i(TAG,"onCharacteristicWrite");        }        @Override        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {            super.onCharacteristicChanged(gatt, characteristic);            Log.i(TAG,"onCharacteristicChanged");            byte[] read_data = characteristic.getValue();            String as = byteToHexString(read_data);            Log.i(TAG, "as = " + as);              float abcd = 0;               if(read_data[1] == 0x01){                //温度                       abcd = (float) ((read_data[2]) * 256 + (0x000000FF & read_data[3])) / 10;            }                      string1 = String.valueOf(abcd);            Log.i(TAG, "string1 =" + string1);        }        @Override        public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {            super.onDescriptorRead(gatt, descriptor, status);            Log.i(TAG,"onDescriptorRead");        }        @Override        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {            super.onDescriptorWrite(gatt, descriptor, status);            Log.i(TAG,"onDescriptorWrite");        }    };
read()方法如下:
public void read() {    if (BleConstants.type == 1) {        BluetoothGattService bluetoothGattServic = bluetoothGatt                .getService(BleConstants.TEMP_UART_SERVICE_UUID);        BluetoothGattCharacteristic bluetoothGattCharacteristic = bluetoothGattServic                .getCharacteristic(BleConstants.TEMP_UART_READ_CHAR_UUID);        for (int k = 0; k < bluetoothGattCharacteristic.getDescriptors().size(); k++) {            BluetoothGattDescriptor descriptor = bluetoothGattCharacteristic                    .getDescriptors().get(k);            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);            bluetoothGatt.writeDescriptor(descriptor);        }        //发送通知        bluetoothGatt.setCharacteristicNotification(                bluetoothGattCharacteristic, true);    } else if (BleConstants.type == 0) {        BluetoothGattService bluetoothGattServic = bluetoothGatt                .getService(BleConstants.TEMP_SERVICE_UUID_G);        BluetoothGattCharacteristic bluetoothGattCharacteristic = bluetoothGattServic                .getCharacteristic(BleConstants.TEMP_READ_CHAR_UUID_G);        for (int k = 0; k < bluetoothGattCharacteristic.getDescriptors().size(); k++) {            BluetoothGattDescriptor descriptor = bluetoothGattCharacteristic.getDescriptors().get(k);            //ENABLE_NOTIFICATION_VALUE            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);            bluetoothGatt.writeDescriptor(descriptor);        }        bluetoothGatt.setCharacteristicNotification(                bluetoothGattCharacteristic, true);    }}
进制转换的方法:
    public String byteToHexString(byte[] bArray) {        StringBuffer sb = new StringBuffer(bArray.length);        Log.i(TAG, "bArray.length = " + bArray.length);    //长度为5        String sTemp;        for (int i = 0; i < bArray.length; i++) {            Log.i(TAG, "bArray = " + bArray[i]);    // 5, 1, 0, -2, -6            //将整数变为字符串            // 0xff是十六进制FF的表示方法,因为一个十六进制数字转换成二进制是四位,即F=1111,            // 所以0xff占用一个字节 。也就是说是1B,1KB是1024B。            //另外你表达不太清楚,如果你问FF KB是多少,十六进制FF=15*16+15*1=255,即255KB            sTemp = Integer.toHexString(0xFF & bArray[i]);//            Log.i(TAG, "sTemp" + sTemp);            //Log: sTemp 5, sTemp 1, sTemp 0, sTemp fc, sTemp f8     ---as: 05 01 00F6 F2            if (sTemp.length() < 2)                sb.append(0);            sb.append(sTemp.toUpperCase());        }        return sb.toString();    }

蓝牙通信需要用到的UUID,关于uuid不懂的就自己百度了。

// 温度值蓝牙特征服务UUIDpublic static final UUID TEMP_SERVICE_UUID = UUID.fromString("00001809-0000-1000-8000-00805f9b34fb");// 温度值蓝牙特征值UUIDpublic static final UUID TEMP_CHAR_UUID = UUID.fromString("00002A1C-0000-1000-8000-00805f9b34fb");

那为了保证数据传输并显示,这里主要测试了温度的显示。

// handler类接收数据    Handler handler = new Handler() {        public void handleMessage(Message msg) {            if (msg.what == 1) {                tv_display.setText(string1 + "℃");            }        };    };    // 线程类    class ThreadShow implements Runnable {        @Override        public void run() {            while (true) {                try {                    Thread.sleep(300);                    Message msg = new Message();                    msg.what = 1;                    handler.sendMessage(msg);                                 } catch (Exception e) {                    e.printStackTrace();                }            }        }    }

以上就是关于蓝牙如何连接以及通信数据的自己的一点学习经验,目前还在深圳找工作,期待找到一家适合自己的工作吧!


上一篇:ListView填坑

下一篇:xcode 设置代码折叠

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表