蓝牙ble外围设备如何向中心设备发送数据_【TB-02模组专题④】如何在Android开发低功耗蓝牙ble控制 TB-02 ,代码全部开源!...

3355375f5dd79af59ae20a7cf4139252.png

模组TB-02模组专题>系列博客学习由安信可科技-开源团队潜心所力所写。如有不对之处,请留言,我们及时更改。

  • 1、【TB-02模组专题①】BLE MESH开发环境linux版搭建
  • 2、【TB-02模组专题②】学习如何通过蓝牙mesh对接天猫精灵实现语音控制
  • 3、【TB-02模组专题③】微信小程序蓝牙通讯 Ble 蓝牙Mesh TB02模组;

acabb119117b96433477dc4f70f142bc.png


前言
今天就给大家我最近做的一个《安信可Android蓝牙APP控制TB02》的过程分享吧!
最后共勉大家一句话: 生命意义在于折腾,生命价值在于奉献;

7070bd3835101cff7cbd566d1db21f0a.png


一、材料准备


这里务必声明一下,硬件对接需要一点成本请自行出资,并不像纯软件就可以搞的!下面推荐的蓝牙模块自行某宝购买哈!

53dea975b3a7e4b6cb127124e638c2f8.png
  1. ble蓝牙模块一个,可从某宝购买!我使用的是安信可TB02模块开发版
  2. Android Java开发,用的是 AndroidStudio工具!请自行入门Android开发哦!

085bcd35677771281321560b1ece3898.png

这里不涉及到单片机编程,直接用串口助手模拟单片机;

  1. 蓝牙模块开启 从机模式,等待连接;
  2. 安卓APP开始搜索设备,之后成功连接;
  3. 之后读取设备服务service列表,再读取指定服务的特征列表 characters;
  4. 根据硬件厂商指定通讯的特征通道来做数据的收、发和通知特性;

注意:一个ble蓝牙设备可拥有多个服务和特征,涉及到读取设备的服务和特征,都是需要需要设备厂商指定的!如果未能列出,那么此特征的权限是 可读可写可通知,一般为一个特征拥有此三个权限;如果不是,那需要具体问设备厂商啦!!


二、蓝牙模块初始化


如果您的板子并没烧录AT固件,请按照第一篇文章,编译 example/at 工程,烧录到板子即可!
默认波特率等设置,上电后会有信息打印,如下图所示:

e574de18cc5679acf11132115f67ecfe.png


下面为大家列下主要指令:

01abeab1eb38158a47b2b43322b51d11.png

三、App开发过程


Android开发的蓝牙ble API文档还是很齐全的!为了减少开发工作量,我使用了第三方库,实现 动态授权和 ble连接发现以及设备通讯;
APP源码已经在底部贴出,请知悉!

3.1 搜索设备
搜索前务必要开启 蓝牙权限,而在安卓 6.0(包括6.0) 系统以上,务必开启定位权限,否则也是无法搜索到蓝牙设备的呢!

//动态授权
PermissonUtil.checkPermission(this, new PermissionListener() {
            @Override
            public void havePermission() {
                initBleScan();
            }

            @Override
            public void requestPermissionFail() {
                Toast.makeText(mContext, "您拒绝了开启权限", Toast.LENGTH_SHORT).show();
                finish();
            }
        }, Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.ACCESS_FINE_LOCATION);

第一步肯定是搜索设备,通过 调用 object.scanBle() 来发现设备,入参可以指定 UUID,注意设备列表的回调是通过 onSuccess() 方法回调。

mBleController.scanBle(0, new ScanCallback() {
            @Override
            public void onSuccess() {
               
                //判断获取到的设备蓝牙列表是否大于0
                if (bluetoothDevices.size() > 0) {
                    mDeviceList.setAdapter(new DeviceListAdapter(MainActivity.this, bluetoothDevices));
                    mDeviceList.setOnItemClickListener(MainActivity.this);
                } else {
                    Toast.makeText(MainActivity.this, "Search Device Lists empty!", Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onScanning(BluetoothDevice device, int rssi, byte[] scanRecord) {
                //过滤是否含有 Ai-Thinker 名字的蓝牙设备
                if (device.getName() != null && device.getName().contains("Ai-Thinker"))
                    if (!bluetoothDevices.contains(device)) {
                        bluetoothDevices.add(device);
                    }
            }
        });

3.2 连接设备
上步我们已经拿到了周围的蓝牙设备列表,那么如何判断哪个是我们想要的呢?一般为名字,TB02的广播名字一般为 Ai-Thinker,于是乎,调用 connect() ,入参为搜索到的设备的 mac地址!

  //连接设备
  mBleController.connect(0, address, new ConnectCallback() {
            @Override
            public void onConnSuccess() {
                Toast.makeText(MainActivity.this, "connected!", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onConnFailed() {
                Toast.makeText(MainActivity.this, "connect fail!", Toast.LENGTH_SHORT).show();
            }
        });


3.3 获取服务列表和其特征列表
上面说了,一个设备可拥有多个服务service,我们在获取时候,是在已连接成功的情况下再获取哦!
下面获取到了服务列表,并通过判断其 uuid 是否和我们一致,从而判断是否Tb01设备,否则,就是连接了其他设备。
也许你会问,如何获取这个uuid是否一致。参考uuid一般是厂商提供的,如下:

  //TODO 这里是TB02开发板提供的各种UUID,请勿修改
    private static final String BLUETOOTH_S = "00010203-0405-0607-0809-0a0b0c0d1910";
    private static final String BLUETOOTH_NOTIFY_C = "00010203-0405-0607-0809-0a0b0c0d2b10";
    private static final String BLUETOOTH_WRITE_C = "00010203-0405-0607-0809-0a0b0c0d2b10";


如果获取了服务,那么我们下一步就是要获此这个服务下的特征列表;
同样道理,也是要获取到其特征的uuid,在 TB01模块里面的这个服务,只有一个特征好吧。所以只取元素第一个即可!
下面是代码,其实这些早已经封装在另外一个库了,如有兴趣可以去翻阅看看品读;

    //服务被发现了
        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (null != mBluetoothGatt && status == BluetoothGatt.GATT_SUCCESS) {
                List<BluetoothGattService> services = mBluetoothGatt.getServices();
                int serviceSize = services.size();
                for (int i = 0; i < serviceSize; i++) {
                    HashMap<String, BluetoothGattCharacteristic> charMap = new HashMap<>();
                    BluetoothGattService bluetoothGattService = services.get(i);
                    String serviceUuid = bluetoothGattService.getUuid().toString();
                    List<BluetoothGattCharacteristic> characteristics = bluetoothGattService.getCharacteristics();
                    int characteristicSize = characteristics.size();

                    for (int j = 0; j < characteristicSize; j++) {
                        charMap.put(characteristics.get(j).getUuid().toString(), characteristics.get(j));
                        if (characteristics.get(j).getUuid().toString().equals(BLUETOOTH_NOTIFY_C)) {
                            if (enableNotification(true, characteristics.get(j))) {
                                isConnectResponse = true;
                                connSuccess();
                            } else {
                                reConnect();
                            }
                        }
                    }
                    servicesMap.put(serviceUuid, charMap);
                }
            }
        }

3.4 主动订阅通知
下面程序中的调用 wx.notifyBLECharacteristicValueChange()方法目的是 主动监听此通道的数值变化,通俗来说就是:设备一旦发送数据在此通道,就会立刻收到通知;

if (!mBluetoothGatt.setCharacteristicNotification(characteristic, enable))
            return false;

3.5 如何接受设备发来的数据
上一点已经主动监听到了某通道的数值变化,这点必须要做的;
然后,就可以调用下面方法,接收到数据打印出来。注意:接收到的是十六进制格式,还需要转下!

  // TODO 接收数据的监听
        mBleController.registReciveListener(REQUESTKEY_SENDANDRECIVEACTIVITY, new OnReceiverCallback() {
            @Override
            public void onRecive(byte[] value) {
                // 这里为了演示方便,把 byte数组转字符串显示
                String string = new String(value);
                mReciveString.append(string + "rn");
                mReciveText.setText(mReciveString.toString());
            }
        });

3.6 如何发送数据到设备
发送数据时候,必须确定所在的通道是否可写 write ;发送数据时候,务必把字符串转为byte数组,再传进去;

                String sendText = mSendEdit.getText().toString().trim();
                if (TextUtils.isEmpty(sendText)) {
                    Toast.makeText(this, "send text cannot be null" , Toast.LENGTH_SHORT).show();
                    return;
                } else {
                    //这里把字符串格式转byte数组
                    byte[] bytes = sendText.getBytes();
                    mBleController.writeBuffer(bytes, new OnWriteCallback() {
                        @Override
                        public void onSuccess() {
                            Toast.makeText(SendAndReciveActivity.this, "send OK!", Toast.LENGTH_SHORT).show();
                        }
                        @Override
                        public void onFailed(int state) {
                            Toast.makeText(SendAndReciveActivity.this, "send Fail!", Toast.LENGTH_SHORT).show();
                        }
                    });
                }

  • 最后共勉,源码地址:github.com/Ai-Thinker-…
  • 编译后可直接安装的APK:docs.ai-thinker.com/_media/ble/…

本文作者:安信可开源团队
转载请留言告知,并标明出处。
技术咨询:xuhongv@aithinker.com,support@aithinker.com 有问必回复!

商务咨询:marketing@aithinker.com

官网地址:wwww.ai-thinker.com/home

研发中心:深圳市宝安区西乡固戍华丰智慧创新港C座410室

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值