Ble4.0 APP开发

Android蓝牙4.0 BLE开发坑总结 onServicesDiscovered 回调里不能直接执行 write /readDataFromCharacteristic() 或者 enableNotificationOfCharacteristic之类的,而要放到主线程里执行,如 handler.post( … ); 如果发现连接上了,service也discover到了,但是始终不能触发onCharacteristicChanged的, 阅读详情
这是哥们目前搜到最给力的!绝对干货!
Android ble开发和IOS ble开发基本差不多,有点小区别。IOS 表现是特别稳定特别好用,重连飞快,需要操心的少。 Android目前坑还是比较多,各种错误,蓝牙奔溃等等。但,细心调理,Android也还是可以用的。

本篇文章主讲 Android, IOS的简单点,可以下次讲。

先来介绍几个类 :BluetoothGatt,BluetoothGattService,BluetoothGattCharacteristic,BluetoothGattCallback   


  官方介绍网址是   https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html.有兴趣的童鞋可以翻墙去看。以下是我尽可能形象的通 俗表达
BluetoothGatt
       BluetoothGatt 是开发里最重要最常用到的东西了,我把它理解为 手机与 设备通信的管道。有了这个管道,收发数据就容易了。
         BluetoothGatt 是通过蓝牙设备连接获得:  bluetoothDevice.connectGatt(this.context, false, gattCallback);
                                 先来谈一下这个方法:
                         BluetoothGatt android.bluetooth.BluetoothDevice.connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)


                          public BluetoothGatt connectGatt (Context context, boolean autoConnect, BluetoothGattCallback callback)
                          Added in API level 18

                          Connect to GATT Server hosted by this device. Caller acts as GATT client. The callback is used to deliver results to Caller,           
                            such as connection status as well as any further GATT client operations. The method returns a BluetoothGatt instance.
                             You   can use BluetoothGatt to conduct GATT client operations.

                               Parameters
                             autoConnectWhether to directly connect to the remote device (false) or to automatically connect as soon as the remote device becomes available (true).
                                callbackGATT callback handler that will receive asynchronous callbacks.

                                Throws
                           IllegalArgumentExceptionif callback is null
                         --------------------------------------------------------------------------------------
                          autoConnect  为false  立刻发起一次连接
为true  自动连接,只要蓝牙设备变得可用



                           实测发现,用false连接比较好,比较快, true会等个十几秒甚至几分钟才会连接上。  开发过程中一般都是用false,扫描到bluetoothdevice之后,直接用false连接即可。
                           BluetoothGattCallback   是非常重要的回调函数,手机与蓝牙设备的一切通信结果都在这里体现。待会细讲。


BluetoothGattService
           蓝牙设备所拥有的服务。在这里比喻成 班级 吧。bluetoothdevice就比喻成学校吧。 一个学校可以有很多个班级。班级 根据UUID来区别。
BluetoothGattCharacteristic
           蓝牙设备所拥有的特征。比喻成 学生。 一个班级里也可以有很多个学生。学生也是根据UUID 来区别
                当你需要用手机来和蓝牙设备通信的时候,就相当于 你想 和一个学生交流,你得先知道 这个学生的学号,所在班级号,就是开发中的所说的CharacUUID, ServiceUUID
BluetoothGattCallback   
      所有操作的回调函数。
           private BluetoothGattCallback gattCallback = new BluetoothGattCallback() {

                @Override
                public void onCharacteristicChanged(BluetoothGatt gatt,
                                BluetoothGattCharacteristic characteristic) {

                        super.onCharacteristicChanged(gatt, characteristic);
                       //收到设备notify值 (设备上报值)
                }

                @Override
                public void onCharacteristicRead(BluetoothGatt gatt,
                                BluetoothGattCharacteristic characteristic, int status) {
                        super.onCharacteristicRead(gatt, characteristic, status);
                        //读取到值

                }

                @Override
                public void onCharacteristicWrite(BluetoothGatt gatt,
                                BluetoothGattCharacteristic characteristic, int status) {
                        super.onCharacteristicWrite(gatt, characteristic, status);
                                if (status == BluetoothGatt.GATT_SUCCESS) {
                                         //write成功(发送值成功)
                                }
                         
                }

                @Override
                public void onConnectionStateChange(BluetoothGatt gatt, int status,
                                int newState) {
                        super.onConnectionStateChange(gatt, status, newState);
                        if (status == BluetoothGatt.GATT_SUCCESS) {
                                if (newState == BluetoothGatt.STATE_CONNECTED) {
                                     // 连接成功
                                 
                                } else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
                                      // 断开连接
                                         
                                }
                        }
                }

                @Override
                public void onDescriptorRead(BluetoothGatt gatt,
                                BluetoothGattDescriptor descriptor, int status) {
                        super.onDescriptorRead(gatt, descriptor, status);
                }

                @Override
                public void onDescriptorWrite(BluetoothGatt gatt,
                                BluetoothGattDescriptor descriptor, int status) {
                        super.onDescriptorWrite(gatt, descriptor, status);

                }

                @Override
                public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
                        super.onReadRemoteRssi(gatt, rssi, status);
                        if (status == BluetoothGatt.GATT_SUCCESS) {
                                  //获取到RSSI,  RSSI 正常情况下 是 一个 负值,如 -33 ; 这个值的绝对值越小,代表设备离手机越近
                                 //通过mBluetoothGatt.readRemoteRssi();来获取
                        }
                }

                @Override
                public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
                        super.onReliableWriteCompleted(gatt, status);
                }

                @Override
                public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                        super.onServicesDiscovered(gatt, status);

                        if (status == BluetoothGatt.GATT_SUCCESS) {
                                       //寻找到服务
                        }
                }
        };
       ---------------------------------------------------------------------------------------------------------------------------------------
       当调用了连接函数 mBluetoothGatt =  bluetoothDevice.connectGatt(this.context, false, gattCallback);之后,
       如果连接成功就会 走到 连接状态回调:
                    @Override
                public void onConnectionStateChange(BluetoothGatt gatt, int status,
                                int newState) {
                                if (status == BluetoothGatt.GATT_SUCCESS) {
                                        //首先判断这个status   如果等于 BluetoothGatt.GATT_SUCCESS(value=0)代表这个回调是正常的,
                                       //如果不等于 0,那边就代表没有成功,也不需要进行其他操作了,
                                       // 连接成功和断开连接都会走到这里
                                         if (newState == BluetoothGatt.STATE_CONNECTED) {
                                                   // 连接成功


                                                   //连接成功之后,我们应该立刻去寻找服务(上面提到的BluetoothGattService),只有寻找到服务之后,才可以和设备进行通信
                                                   gatt.discoverServices();// 寻找服务
                                          } else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
                                                // 断开连接
                                          }

                               }
                }
         当判断到连接成功之后,会去寻找服务, 这个过程是异步的,会耗点时间,当寻找到服务之后,会走到回调:
                @Override
                public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                        super.onServicesDiscovered(gatt, status);

                        if (status == BluetoothGatt.GATT_SUCCESS) {
                                       //寻找到服务
                                      //寻找服务之后,我们就可以和设备进行通信,比如下发配置值,获取设备电量什么的
                                    
                                      readBatrery();  //读取电量操作
                                     sendSetting(); //下发配置值

                        }
                }
           /***读操作***/
             void   readBatrery(){
                         //如上面所说,想要和一个学生通信,先知道他的班级(ServiceUUID)和学号(CharacUUID)
                         BluetoothGattService batteryService=mBluetoothGatt.getService(UUID.fromString("0000180f-0000-1000-8000-00805f9b34fb")); //此处的0000180f...是举例,实际开发需要询问硬件那边
                         if(batteryService!=null){
                        BluetoothGattCharacteristic batteryCharacteristic=batteryService.getCharacteristic(UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb"));//此处的00002a19...是举例,实际开发需要询问硬件那边
                        if(batteryCharacteristic!=null){
                                mBluetoothGatt.readCharacteristic(batteryCharacteristic); //读取电量, 这是读取batteryCharacteristic值的方法,读取其他的值也是如此,只是它们的ServiceUUID 和CharacUUID不一样
                        }
                }
              }
            如果读取电量(或者读取其他值)成功之后 ,会来到 回调:
                @Override
                public void onCharacteristicRead(BluetoothGatt gatt,
                                BluetoothGattCharacteristic characteristic, int status) {
                        super.onCharacteristicRead(gatt, characteristic, status);
                        //读取到值,根据UUID来判断读到的是什么值
                     if (characteristic.getUuid().toString()
                                        .equals("00002a19-0000-1000-8000-00805f9b34fb")) {// 获取到电量
                             int battery = characteristic.getValue()[0];
                     }

                }
         /***写操作***/
         void   sendSetting(){
                BluetoothGattService sendService=mBluetoothGatt.getService(UUID.fromString("00001805-0000-1000-8000-00805f9b34fb"));//此处的00001805...是举例,实际开发需要询问硬件那边
                if(sendService!=null){
                        BluetoothGattCharacteristic sendCharacteristic=sendService.getCharacteristic(UUID.fromString("00002a08-0000-1000-8000-00805f9b34fb"));//此处的00002a08...是举例,实际开发需要询问硬件那边
                        if(sendCharacteristic!=null){
                                sendCharacteristic.setValue(new byte[] { 0x01,0x20,0x03  });//随便举个数据

                                mBluetoothGatt.writeCharacteristic(sendCharacteristic);//写命令到设备,
                        }
                }
         }


          如果下发配置成功之后,会来到回调:
               @Override
                public void onCharacteristicWrite(BluetoothGatt gatt,
                                BluetoothGattCharacteristic characteristic, int status) {
                        super.onCharacteristicWrite(gatt, characteristic, status);
                                if (status == BluetoothGatt.GATT_SUCCESS) {
                                         //write成功(发送值成功),可以根据 characteristic.getValue()来判断是哪个值发送成功了,比如 连接上设备之后你有一大串命令需要下发,你调用多次写命令, 这样你需要判断是不是所有命令都成功了,因为android不太稳定,有必要来check命令是否成功,否则你会发现你明明调用 写命令,但是设备那边不响应
                                         
                                         
                                }
                         
                }


       讲解完读写操作,还有一个重要操作 就是  Notify(通知)
        notify 就是让设备 可以发送通知给你,也可以说上报值给你(发送命令给你)
              首先你得打开设备的通知功能:    //参数 enable 就是打开还是关闭, characteristic就是你想让具有通知功能的BluetoothGattCharacteristic
                private boolean enableNotification(boolean enable,
                        BluetoothGattCharacteristic characteristic) {
                if (mBluetoothGatt == null || characteristic == null)
                        return false;
                if (!mBluetoothGatt.setCharacteristicNotification(characteristic,
                                enable))
                        return false;
                BluetoothGattDescriptor clientConfig = characteristic
                                .getDescriptor(UUIDUtils.CCC);
                if (clientConfig == null)
                        return false;

                if (enable) {
                        clientConfig
                                        .setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                } else {
                        clientConfig
                                        .setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
                }
                return mBluetoothGatt.writeDescriptor(clientConfig);
           }
           一旦设备那边notify 数据给你,你会在回调里收到:
                @Override
                public void onCharacteristicChanged(BluetoothGatt gatt,
                                BluetoothGattCharacteristic characteristic) {

                        super.onCharacteristicChanged(gatt, characteristic);
                       //收到设备notify值 (设备上报值),根据 characteristic.getUUID()来判断是谁发送值给你,根据 characteristic.getValue()来获取这个值
                }





=========================以上属于BLE基本的操作,下面是进阶========================================


1. 关于发送命令, 比如刚连接上设备,你会把很多配置都发送给设备,此时可能会调用多次 write操作,这个时候你应该需要在 write操作之间 加点间隔 例如开启线程,用 Thread.sleep(150), 因为只有收到onCharacteristicWrite回调之后才代表你的值成功了,如果
     不加间隔,你会发现可能只会成功一个值。目前测试下来,我才用的是间隔150毫秒比较好,不会太慢,成功率也会高, 可自己实践慢慢调试,这个数值还与设备端update速率有关
           
    在Write 操作的时候,还有个办法可以增快下发速度,且不需要加sleep
     就是设置characteristic .setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);  Wrtite characteristic without requiring a response by the remote device, 就是不需        要回复,这样速度会快,测试下来连续发送9个数据,设备端那边打印数据都收到且是正确的,但回调值有点奇怪:
        图1 是我的发送指令 ,连续无间隔发送9个命令:
               
       图2,3是 onCharacteristicWrite 回调打印信息:
                  
          从图片看出,有的值没有收到 onCharacteristicWrite 回调,如第一个值 { 1, 0x08, 3 }   ,有的值回调了2次 如 { 1, 0x04, 3 },可能会觉得有的值没有发送成功吧?
     以下是 设备端收到值的打印信息:(0x00FF是用做分隔符,可忽略)
              
         
           可以发现,9个值均接收正常, 所以说 这种快速发值,还是有点可靠的。测试的不多,各位可斟酌使用


2.关于重连     
  提到ble,估计想的最多的就是重连了。重连当然得是自动重连。可能有人想到的的就是 断开之后再来一次bluetoothDevice.connectGatt(this.context, false, gattCallback)行不行?


先看看官方的说法 :
          
       官方说  mbluetoothGatt.connect()方法就是用来重连的, 只要你断线之后 调用此方法就好了。
       测试下来 确实可以,但不同手机体验不一样, 但大家知道 android 碎片化现象很严重,什么 flyme,什么MIUI,emotion之类的。所以需要做什么适配。
      只调用 mbluetoothGatt.connect()来重连,我归类为2种  三星 手机  和 非三星手机。
      三星手机现象:
             重连非常迅速 ,断开之后,只要一回到有效范围内。立马重连成功。 就算隔一天你回来 靠近设备,立马连接成功。这简直就是太棒了。
     非三星手机现象:
            也会重连成功,但这时间无法保证,有可能1分钟,有可能5分钟,10分钟,甚至就连不上了。体验非常不好。

     说一下解决办法:
           判断手机是否为三星手机:
              private boolean checkIsSamsung() { //此方法是我自行使用众多三星手机总结出来,不一定很准确
                String brand = android.os.Build.BRAND;
                Log.e("", " brand:" + brand);
                if (brand.toLowerCase().equals("samsung")) {
                        return true;
                }
                return false;
              }
         在设备断线之后, 我们需要进入重连流程:




              if(isSamsung){
                   //这里最好 Sleep 300毫秒,测试发现有时候三星手机断线之后立马调用connect会容易蓝牙奔溃
                   mbluetoothGatt.connect();
              }else{
                   connectGatt();
                   handler.removeCallbacks(runnableReconnect  );
                  handler.postDelayed(runnableReconnect  , 30*1000);
              }
             流程就是断线之后 三星手机 调用官方的connect()函数,而非三星手机 使用 connectGatt() ,相当于重新建立连接,并且每30s去循环询问是否需要重新建立连接,如果已经连接好,取消这个循环。这样能保证过一天回来你也有机会重连上,非三星手机通过这个方法重连体验特别好,也可以达到回来之后瞬间连接的效果

               
               这样的方案目前是比较好的,手机APP也可以很省电。,像很多其他的防丢器类APP,比如nut.研究过这个app,这个软件总是在扫描,一直scan,不管你连上还是不连上。 android的scan是很耗电的,app功能完善之后同时也要考虑电量优化。
               这里测试过 手机的耗电量,用示波器来接手机测试的,
                三星断线之后 重连的阶段,耗电量大概在20ma-30ma(锁屏电量 3ma),
                魅族MX2 在30s循环期间,耗电量大概在15ma(锁屏电量 15ma),
                    这里推测三星的connect()期间它系统自己在后台使用低频率的扫描,这样可以使他重连是很快的。scan就要耗电,所以它电量会比锁屏上升一点。
                   魅族MX2采用每30s重新建立连接,没有scan,基本没有额外耗电。
               这种 重连流程 用身边的手机 三星S3,S4,note2,MX2,M3,Nexus5测试过都很好用。亲们也可以用其他测试一下。




        public void connectGatt() {


                if (bluetoothDevice != null) {
                        if (mBluetoothGatt != null) {
                                mBluetoothGatt.close();
                                mBluetoothGatt.disconnect();


                                mBluetoothGatt = null;
                        }
                        mBluetoothGatt = bluetoothDevice.connectGatt(this.context, false,
                                        gattCallback);


                } else {
                        Log.e(tagString,
                                        "the bluetoothDevice is null, please reset the bluetoothDevice");
                }
        }



            Runnable runnableReconnect = new Runnable() {


                        @Override
                        public void run() {
                                if (! isConnected() ) {
                                        handler.postDelayed(this, 30 * 1000);
                                         connectGatt();
                                }
                        }
                };



flutter 操作ble Flutter 是一个跨平台的移动应用开发框架,可以帮助开发者使用一套代码来构建安卓和 iOS 的应用。 要在 Flutter 中操作 BLE(蓝牙低功耗),可以使用 flutter_blue 插件。这个插件是由 Flutter 官方团队开发的,支持在 Flutter 应用中扫描、连接、读写 BLE 设备。 使用 flutter_blue 插件的步骤如下: 在 pubspec.yaml 文件中添... 阅读详情

相关推荐

APP Invertor 蓝牙BLE 个人案例分享 快速开发自己的蓝牙APP

APP Invertor 2 蓝牙BLE 个人案例分享 快速开发自己的蓝牙APP 经过几天的学习,期间查找了许多的文章资料。经过研究和总结加实践,终于做出了一个实现简单的接收和发送的Demo。下面将分享个人制作的过程。 在此之前需要声明的是所用不同版本的APP Invertor 2,其中的组件的信息以及用法都会稍有不同,本文讲解使用到的版本是 App Inventor 2 WxBit 汉化增强版。...

Luminuos_的博客 1万+

android ble和ios ble 对比,低功耗蓝牙的坑对比,低功耗蓝牙的总结

1.设备的蓝牙广播   蓝牙是固定定时发送31个字节的广播。(最多31个字节,可以小于,根据公司自身需要有硬件研发烧录进去)。手机端打开蓝牙扫描,扫描到了设备的mac地址,但是这个mac地址是不能判断身份的,因为ios端每次开关蓝牙搜索到的设备mac可能都不一样。所以就需要统一固定31个字节里边的某些字节代表设备的id,当手机端搜索到了该字段就请求后台的数据判断这个设备的身份。2. 手机端的扫描 ...

云梦九章~ 2万+

IPhone MFI蓝牙认证分析

故事背景: 为什么要研究IOS的蓝牙呢? 答:当然是工作需要啦,公司有个项目是做心电测量的,主要就是通过手持嵌入式设备测量心电,通过蓝牙将数据传送到手机(安卓,IOS),然后手机端解析数据包并绘制曲线,最后上传到服务器保存。目前已经完成了安卓设备的APP开发工作,支持大多数的主流安卓设备(主要安卓各厂商的蓝牙不同,完全兼容希望不大),然后Boss就打算继续开发IOS的版本了,遂让我这个做QT的

u012056558的专栏 5445

ios连接蓝牙设备的兼容问题

蓝牙设备在安卓系统中的MAC与deviceId属性的值相同,然后在ios系统中的MAC并不等于deviceId,deviceId只是一个UUID。当已知deviceId、serviceId、特征值时,在安卓系统中可以跳过获取serviceId与特征值的步骤,但是ios系统中需要按顺序此次执行完成函数后,才能执行发送指令。因此,在ios系统中需要。为避免小程序搜索不到附近蓝牙设备,建议在开启蓝牙前,先向用户发起精确位置授权,确保可以正常连接蓝牙设备。现有代码在安卓系统中连接蓝牙设备正常,在。

烤奶要加冰的博客 1667

Android BLE4.+ 蓝牙开发国产手机兼容性解决方案

算是做了n年的智能穿戴BLE开发了, 首先对国内的安卓开发者提醒下 , BLE开发是真的很坑, 特别是安卓, ios端也坑, 但没安卓坑 因为国产有很多手机 各种奇葩兼容都有, 其实这些方案我很早就写到云笔记里了,一直没公开, 这里的解决方案大部分都是网上搜不到 或者网上搜到类似的问题, 但回复基本上是回答[无法解决] 或 [重启手机解决]等 没意义的解决办法,让我很无语… 以下内...

没错, 我是东芝 1万+

智慧养殖蓝牙监控方案与App开发实战

蓝牙低功耗(BLE)技术作为物联网关键通信协议,通过2.4GHz频段实现设备间短距离数据传输,其核心优势在于低功耗设计(仅需纽扣电池供电)与自适应跳频抗干扰能力。在智慧农业场景中,基于BLE的环境监测方案能有效解决养殖场布线困难、供电受限等痛点,典型应用包括温湿度传感、气体浓度检测等实时数据采集。通过手机App或网关设备,养殖场管理者可远程监控氨气浓度等关键指标,结合4G/GPS模块还能实现位置追踪与云端同步。开发时需注意蓝牙协议栈的MTU设置、数据分包处理及重连机制,现场部署则要考虑金属结构对信号的衰减影

weixin_33925615的博客 286

Ble4.0 APP开发总结

Ble4.0 APP开发总结最近自学了一个多礼拜的蓝牙ble开发,对这方面有些粗略的理解,及时做个总结,不对的地方希望大家帮忙揪出来。首先介绍几个类 :BluetoothGatt,BluetoothGattService,BluetoothGattCharacteristic,BluetoothGattCallbackBluetoothGatt这个类是开发里最重要最常用到的东西了,我把它理解为 手机

z957250254的博客 990

第一百一十九回 如何通过蓝牙设备读写数据

本章回主要介绍了通过蓝牙设备读写数据的概念以及实现方法,并且通过文字结合代码的方式进行了演示。最后分享了自己总结的经验。

talk_8的专栏 1118

[Android实例] 细谈Ble4.0 APP开发

转载:http://www.aiuxian.com/article/p-2836861.html Android ble开发和IOS ble开发基本差不多,有点小区别。IOS 表现是特别稳定特别好用,重连飞快,需要操心的少。 Android目前坑还是比较多,各种错误,蓝牙奔溃等等。但,细心调理,Android也还是可以用的。 本篇文章主讲 Android, IOS的简单点,可以下次

987

手把手教你用MATLAB/Simulink模拟微电网潮流方向(附代码下载)

本文提供了一份详细的MATLAB/Simulink微电网潮流仿真实战指南。通过手把手教学,指导读者从零搭建包含光伏、储能和负荷的微电网模型,并模拟并网、孤岛等多种运行场景下的潮流方向变化。文章核心在于利用Simulink实现微电网的动态潮流分析与可视化,帮助工程师深入理解分布式能源系统中的功率平衡与控制策略。

weixin_28314575的博客 106

Blender入门教程-3D视图界面介绍

3D视图用于与3D场景交互,可用于各种目的,例如建模、动画、纹理绘制等。在关闭 启动画面 后,启动场景会显示在3D视口中(如果没有加载其他blend文件)。01 标题栏标题栏包含了基于当前 模式 的各种菜单和控制。

weixin_52345129的博客 2287

Android BLE4.0 从小白到理解的过程

学习蓝牙低功耗的开发过程,要达到的效果是——利用两台Android手机,通过BLE4.0进行通信,可以发送和接收数据。 其中一台Android手机T模拟发出广播,作为BLE设备(周边设备),这个BLE设备在生产环境中就是我们用到的气体检测传感器、智能手环、体重秤、血压计等等; 另一台Android手机B,作为中央设备,搜索手机T发出的广播并连接; 手机B可以接收手机T的数据,也可以发送数据给...

让学习编程变得生动有趣~ 1359

scGPT实战指南:如何用生成式AI加速你的单细胞多组学研究?

本文提供了scGPT在单细胞多组学研究中的实战指南。详细介绍了从环境部署、数据预处理到细胞类型注释与扰动预测等核心任务的操作流程。通过利用生成式AI和Transformer基础模型,scGPT能够显著加速分析,并提升细胞注释的准确性及基因调控网络推断的深度,为研究人员提供了强大的AI分析引擎。

weixin_29215815的博客 402

android ble 蓝牙4.0 cc2540 开发(一)

1、概述 公司做了两个蓝牙4.0的app项目,对于蓝牙4.0 ble的理解也从阅读官方的代码,各种到吗到有自己的见解。 很多手机早前就有蓝牙4.0,但是android官方是在sdk 4.3以上才开始支持蓝牙4.0 一般app开发的现在都建议用户自行升级到android系统到4.3以上 才能使用开发的app。早前三星,摩托罗拉,lg,博通是有提供自己的蓝牙库的,因为大家使用的库不能统一,所以现

8227

深入解析SerDes系统中的时钟数据恢复电路(CDR)——基于Cadence的PLL/Bang-Bang/PS-PI架构实现与仿真

本文深入解析SerDes系统中的时钟数据恢复电路(CDR),重点探讨基于Cadence平台的PLL、Bang-Bang和PS-PI三种架构的实现与仿真。通过详细的技术对比和工程实践案例,揭示CDR在高速串行通信中的关键作用,并提供TSMC 28nm工艺下的优化策略与故障排查经验,助力工程师应对10Gbps以上SerDes设计挑战。

weixin_29202687的博客 249

YOLOv8 | 损失函数改进,最新提出的Shape-IoU,有效涨点

作为检测器定位分支的重要组成,边框回归损失在目标检测任务中发挥巨大作用。现有的边框回归方法,通常考虑了GT框与预测框之间的几何关系,通过使用边框间的相对位置与相对形状等计算损失,而忽略了边框其自身的形状与尺度等固有属性对边框回归的影响。为了弥补现有研究的不足,本文提出聚焦边框自身形状与尺度的边框回归方法。首先我们对边框回归特性进行分析,得出边框自身形状因素与尺度因素会对回归结果产生影响。

kay_545 1913

Android Ble4.0开发

最近在做一个蓝牙的项目,是Blu4.0,Android系统知识 http://blog.csdn.net/hellogv/article/details/6036849 http://blog.csdn.net/hellogv/article/details/6042091

流水不腐小夏 4042

工业相机的检测原理课件(建议收藏)

本课件为各位工程师详细介绍了工业相机的视觉检测原理 ,旨在为工程师调试工业相机的视觉检测原理时提供理论性指导。

Bamboo265925的博客 498

蓝牙ble学习开发资料

1、蓝牙核心规范 这个是蓝牙官方的文档,也是最权威的文档,所有开源的、闭源的蓝牙协议栈都是根据这个展开的,为了对比学习,我收集了从v4.0到v5.3的文档,ble也是从v4.0开始支持的。 2、蓝牙核心规范补充协议 可以认为是补丁,这里是最新的v10。 3、蓝牙官方标准Profile与service 这里面的文档也是来自蓝牙官方,官方规定了一些常见的profile和serivice文档,如心率、电池、设备信息等。 4、几款ble调试手机app 个别需要科学上网,才能下载。 使用教程:几款常用的ble.

freemote的博客 1322

探索CompletableFuture:高效异步编程的利器

随着现代软件系统的复杂性和用户需求的多样化,异步编程成为了提升系统性能和响应速度的重要手段。在Java领域,CompletableFuture作为Java 8引入的新特性,提供了强大的异步编程能力,极大地简化了多线程和并发任务的处理。本文将深入探讨CompletableFuture的基本功能和使用方法,介绍如何利用其提升程序的并发性能和代码的可维护性。

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 170万+

智能工厂评估模型研究

摘要:通过对国内外现有智能制造评估模型的研究,结合重庆制造业行业领跑者与落后者之间差距大的现状,以实现全要素全连接的数字化工厂为出发点,融合工业互联网标识,构建实践可行的智能工厂评估模型推动中小型企业参与智能制造转型,缓和两极分化问题。本评估模型包含工厂体系架构的3个层级,提供用于推动智能制造转型的参考,包括设计、生产、管理的全过程评估。关键词:智能制造评估模型;智能制造转型;全连接工厂;工业互联网标识0 引言受行业需求与技术创新的影响,全球制造业在历经了工业1.0机械化、工业2.0电气化和工业3.0自动

罗伯特技术屋 677

基于BLE 4.0的低功耗室外温度计:从硬件设计到App上架全流程解析

蓝牙低功耗(BLE)技术是物联网设备实现超长续航和手机直连的关键。其核心原理在于深度睡眠模式下的微安级待机电流,通过事件驱动架构,设备仅在广播、连接或数据采集时短暂唤醒,从而大幅降低平均功耗。这一技术价值在于为电池供电的传感器节点提供了可行的无线通信方案,使其能够部署在难以取电的室外环境,并稳定运行数月甚至数年。在应用场景上,BLE广泛用于智能家居、健康监测、资产追踪等领域,实现环境数据的实时采集与监控。本文以室外温度计为例,深入剖析了如何围绕BL600芯片进行硬件选型、PCB设计优化以控制功耗,并详细介绍

weixin_30873847的博客 292

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

【BLE开发】nRF51822:建立基于SDK的独立工程(IAR)

一、简介 本文以ble_app_template工程为例,介绍如何建立基于SDK的独立工程。 二、开发平台 硬件平台:E77-2G4M04S(nRF51822) 软件平台:IAR Embedded Workbench for ARM Version 8.32.1.18361 协议栈: nRF5_SDK_12.3.0 调试工具:nRF Connect Version 4.19...

EEsdream的博客 1196

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

测试技术之APP蓝牙连接测试

目前APP与硬件模块之间的通信有几种模式:蓝牙连接模式、WiFi连接模式(Socket或HTTP服务器)、DLNA音视频共享(iOS上也可以使用AirPlay)。最近在项目中,测试了APP通过蓝牙与外设硬件连接的功能,整理了一些相关的开发、实现和测试方法,在这里与大家分享。蓝牙基础知识1. iOS台下蓝牙开发可以使用 MFI(ExternalAccessory 框架) 或 BLE (CoreBluetooth 框架) 进行,但实际开发中基本都使用 CoreBluetooth 框架,因为它功能更强大,支持蓝牙

okcross0的博客 1670

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

上一篇: BLE 安卓APP控制LED灯的实现
下一篇: 蓝牙协议分析_基本概念
xiaoxiandroid
博客等级 码龄12年 12粉丝 3原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值