Android开发BLE,找到标志service怎么消除后,写入CCCD后无反馈。

您所在位置: &
&nbsp&&nbsp&nbsp&&nbsp
rf51822创建一个简单ble例程.pdf 29页
本文档一共被下载:
次 ,您可全文免费在线阅读后下载本文档。
下载提示
1.本站不保证该用户上传的文档完整性,不预览、不比对内容而直接下载产生的反悔问题本站不予受理。
2.该文档所得收入(下载+内容+预览三)归上传者、原创者。
3.登录后可充值,立即自动返金币,充值渠道很便利
你可能关注的文档:
··········
··········
本文介绍了在 nRF51822 上如何开始编写低功耗蓝牙(BLE)应用程序,包括对 BLE 的特性进
行了概要的介绍,并且详细描述了构建一个定制服务的简单例程,这个简单的例程叫做 LED
Button 服务。
本文的目的是教你如何一步步创建自己的 BLE 应用程序,包括使用 nRF51822 芯片创建一个
定制的服务。
1.1 最低要求
需要有嵌入式 C 语言编程经验,以便完全理解本应用手册。
需要的工具
需要一个 nRF51822 Evaluation Kit 的开发板,另外还需要下载和安装以下软件工具:
o S110 SoftDevice
o nRFgo Studio
o nRF51 SDK
o Keil MDK‐ARM
o SEGGER’s J‐Link tools
如何把协议栈固件 S110 SoftDevice 烧录到 nRF51822 芯片中请参考: 《nRF51822 Evaluation Kit
User Guide》。
注意:当编写本文档时参考了最新版本的 nRF51
和最新版本的协议栈 S110
SoftDevice 6.0.0 。
1.2 文档说明
下面的文档是重要的参考资料。
使用 Evaluation
Kit 开发板的介绍和配置,包括 Keil 和
nRF51822 Evaluation Kit User Guide
SoftDevice 的配置。
这个文件在 SDK 安装的文件夹之下的子文件夹中,包含
nRF51 SDK documentation
了SDK 中所有功能API 的文档。
介绍了协议栈 S110 SoftDevice,包括资源的用法和高级
S110 nRF51822 SoftDevice Specification
的功能函数。
nRF51822 Product Specification
描述了 nRF51 的硬件、模块和电气特性。
介绍了 nRF51 芯片系列所有功能模块的描述和芯片所有
nRF51 Series Reference Manual
的外围资源。
这个应用手册包含使用 Keil μVision
的信息,它为
nAN‐15: Creating Applications with the Keil
nRF24LE1 芯片而写,但是 3.3 节“Including files”和 3.4 节
C51 Compiler
““Debug your project”同样适用于 nRF51822 芯片。
Bluetooth Core Specification, version 4.0
这个文档由蓝牙技术联盟组织提供,包含了关于蓝牙服
卷 1,3,4,6
务和 profiles 的信息。
1.3 蓝牙技术资源
所有蓝牙技术联盟的服务、特性和描述都是根据蓝牙开发网站来定义,可以参考规范的不同
部分找到 UUID 或者是数据格式的定义。
nRF51822 和 S110 SoftDevice
S110 SoftDevice 是 BLE 外围设备协议栈的解决方案,它集成了低功耗控制器、主机,并提供
了一个完整和灵活的 API
用于在一个片
正在加载中,请稍后...您所在位置: &
&nbsp&&nbsp&nbsp&&nbsp
nrf51822创建一个简单ble例程nrf51822创建一个简单ble例程.pdf 29页
本文档一共被下载:
次 ,您可全文免费在线阅读后下载本文档。
下载提示
1.本站不保证该用户上传的文档完整性,不预览、不比对内容而直接下载产生的反悔问题本站不予受理。
2.该文档所得收入(下载+内容+预览三)归上传者、原创者。
3.登录后可充值,立即自动返金币,充值渠道很便利
nrf51822创建一个简单ble例程nrf51822创建一个简单ble例程
你可能关注的文档:
··········
··········
本文介绍了在 nRF51822 上如何开始编写低功耗蓝牙(BLE)应用程序,包括对 BLE 的特性进
行了概要的介绍,并且详细描述了构建一个定制服务的简单例程,这个简单的例程叫做 LED
Button 服务。
本文的目的是教你如何一步步创建自己的 BLE 应用程序,包括使用 nRF51822 芯片创建一个
定制的服务。
1.1 最低要求
需要有嵌入式 C 语言编程经验,以便完全理解本应用手册。
需要的工具
需要一个 nRF51822 Evaluation Kit 的开发板,另外还需要下载和安装以下软件工具:
o S110 SoftDevice
o nRFgo Studio
o nRF51 SDK
o Keil MDK‐ARM
o SEGGER’s J‐Link tools
如何把协议栈固件 S110 SoftDevice 烧录到 nRF51822 芯片中请参考: 《nRF51822 Evaluation Kit
User Guide》。
注意:当编写本文档时参考了最新版本的 nRF51
和最新版本的协议栈 S110
SoftDevice 6.0.0 。
1.2 文档说明
下面的文档是重要的参考资料。
使用 Evaluation
Kit 开发板的介绍和配置,包括 Keil 和
nRF51822 Evaluation Kit User Guide
SoftDevice 的配置。
这个文件在 SDK 安装的文件夹之下的子文件夹中,包含
nRF51 SDK documentation
了SDK 中所有功能API 的文档。
介绍了协议栈 S110 SoftDevice,包括资源的用法和高级
S110 nRF51822 SoftDevice Specification
的功能函数。
nRF51822 Product Specification
描述了 nRF51 的硬件、模块和电气特性。
介绍了 nRF51 芯片系列所有功能模块的描述和芯片所有
nRF51 Series Reference Manual
的外围资源。
这个应用手册包含使用 Keil μVision
的信息,它为
nAN‐15: Creating Applications with the Keil
nRF24LE1 芯片而写,但是 3.3 节“Including files”和 3.4 节
C51 Compiler
““Debug your project”同样适用于 nRF51822 芯片。
Bluetooth Core Specification, version 4.0
这个文档由蓝牙技术联盟组织提供,包含了关于蓝牙服
卷 1,3,4,6
务和 profiles 的信息。
1.3 蓝牙技术资源
所有蓝牙技术联盟的服务、特性和描述都是根据蓝牙开发网站来定义,可以参考规范的不同
部分找到 UUID 或者是数据格式的定义。
nRF51822 和 S110 SoftDevice
S110 SoftDevice 是 BLE 外围设备协议栈的解决方案,它集成了低功耗控制器、主机,并提供
了一个完整和灵活的 API
用于在一个片
正在加载中,请稍后...开发你的第一个BLE应用程序—Blinky
时间: 22:15:45
&&&& 阅读:101
&&&& 评论:
&&&& 收藏:0
标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&本文将和大家一起编写我们的第一个BLE应用程序:Blinky(闪灯程序),哪怕你之前没有任何BLE开发经验,也不用担心,只要跟着文中所述步骤,你就可以一步步搭建自己的第一个BLE应用程序。通过这个Blinky程序的搭建,你将体会到BLE的一些基本概念,对BLE将会有一个非常直观的认识,为后续自己的BLE应用程序开发打下一个坚实的基础。&
1. 开发准备
1)&&&& nRF52或者nRF51开发板1块。请参考“”,购买相应开发板(DK)。
2)&&&& 开发环境搭建。简述如下(详细说明请参考“”):
安装Keil5 MDK
安装SDK。如果你使用的是nRF52开发板,请安装nRF5 SDK15.0.0,下载链接:。如果你手上是nRF51开发板,请下载nRF5 SDK12.3.0: (nRF51最高SDK版本只能到12.3.0,后续SDK就不再支持nRF51了)
安装ARM CMSIS4.5.0,下载链接:。
安装Keil5 Device Family Pack,下载链接:。
安装nRF5 Command Line Tools,下载链接(Windows版):。
安装安卓版或者iOS版nRF connect。iOS版nRF connect请到苹果app store下载,搜索“nRF”即可以找到。安卓版nRF connect可以到Nordic Github官网上下载,下载链接为:
安装PC版nRF connect或者nRFgo studio。PC版nRF connect下载链接(Windows版):。
注:如果你使用的是Linux系统/Mac系统,或者你使用的不是Keil5-MDK,请参考“”来搭建你的开发环境。
2. 运行Blinky程序
请按照如下步骤运行SDK自带的Blinky程序
1)&&&& 确认自己的芯片型号或者开发板。如果采用Nordic官方开发板的话,芯片型号和开发板编号对应关系如下:
nRF51系列对应开发板编号为PCA10028
nRF52832和nRF52810对应开发板编号为PCA10040
nRF52840对应开发板编号为PCA10056
这里我会以nRF52832开发板PCA10040为例阐述整个开发过程,其他开发板与之类似,大家自己可以举一反三来开始自己的开发之旅。
2)&&&& 将开发板与PC机通过USB线相连,同时打开开发板电源(将左下角的拨位开关打到“ON”位置),打开桌面版nRF Connect,选择启动“Programmer”应用,由于驱动之前已经安装好了,设备可以立即识别成功。执行“full erase”操作,以擦除芯片原始内容。
3)&&&& 打开SDK中的Blinky程序。对于blinky程序,如果是52832开发板,请打开:nRF5_SDK_15.0.0_a53641a\examples\ble_peripheral\ble_app_blinky\pca10040\s132\arm5_no_packs;如果是51822开发板,请打开:nRF5_SDK_12.3.0_d7731ad\examples\ble_peripheral\experimental_ble_app_blinky\pca1\arm5_no_packs
后续将以52832开发板为例来阐述,51822与之类似就不再阐述了。
注:Nordic SDK例程目录结构为:SDK版本/ examples /协议角色/例子名称/开发板型号/协议栈型号/工具链类型/具体工程,比如下面例子:
Nordic每一个例子都支持5种工具链:Keil5/Keil4/IAR/GCC/SES,如下所示:
4)&&&& 编译上面的blinky程序。如果你已经按照之前的说明配置好了开发环境,那么这里编译是不会报任何错的。(如果你遇到了编译错误,请重新按照前面说明去搭建你的开发环境,不要怀疑SDK例子代码有问题哦)
5)&&&& 程序下载。程序下载包括2步:先下载softdevice,再下载应用。Softdevice是Nordic蓝牙协议栈的名称,整个开发过程中只需下载一次。应用就是我们这里的blinky程序。
蓝牙协议栈下载(整个开发周期只下载一次)。在Keil ‘select target’下拉列表中,默认选择的是Keil工程对应的Target,即‘nrf52832_xxaa’。我们还可以选择另一个target ‘flash_s132_nrf52_6.0.0_softdevice’,即softdevice对应的target,然后点击“下载download”(不需要编译哦!),此时会把softdevice下载到开发板中。
应用下载。重新选择Target:‘nrf52832_xxaa’,点击“下载Download”,此时会把Blinky程序下载到开发板中。此时开发板的LED1常亮,表示程序运行正常。
6)&&&& 打开手机蓝牙和手机版nRF connect。在nRF connect中,你将看到一个广播设备:Nordic_Blinky,这个就是我们的开发板。
7)&&&& 连接设备。点击“CONNECT”,手机将与设备建立连接,并开始服务发现过程,连接成功后,LED1熄灭,LED2点亮,最后将得到如下界面。
由上图可见,Blinky程序包含三个service:Generic Access(GAP),Generic Attribute(GATT),以及Nordic LED Button Service,GAP和GATT都是标准的蓝牙service,Nordic LED Button Service是Blinky程序自定义的service,它又具体包括两个characteristic:Button和LED。
8)&&&& 测试Blinky程序。点击右上角的“Enable CCCDs”以使能notification,如下:
&&& 按下开发板上的Button1按键,你会发现nRF connect中的Button characteristic Value会实时显示按键状态:pressed或者released。
点击nRF connect中的LED characteristic右边的向上箭头,选择“ON”并“SEND”,你会发现开发板的LED3将点亮;选择“OFF”并“SEND”,LED3又将熄灭。
3. 定制你的Blinky程序
3.1 修改广播名称
如前所述,Blinky程序默认的广播名字是:Nordic_Blinky,我们现在将其修改为“My_Blinky”,怎么做呢?我们在Keil中全文搜索“Nordic_Blinky”,发现有如下宏定义:
#define DEVICE_NAME
"Nordic_Blinky"
我们只需将这里的Nordic_Blinky换成My_Blinky,即
#define DEVICE_NAME
"My_Blinky"
就可以实现我们的目标了。重新编译下载blinky程序,在nRF connect中,你将看到:
你再全文搜索一下“DEVICE_NAME”,你会发现广播名字其实是通过如下API来完成修改的:
err_code = sd_ble_gap_device_name_set(&sec_mode,
(const uint8_t *)DEVICE_NAME,
strlen(DEVICE_NAME));
注:Keil的搜索功能非常好用,很多问题都可以通过它来解决
3.2 修改广播间隔
如nRF connect界面所示,blinky程序的广播间隔大概为40ms左右,现在为了节省功耗,我们将其改为200ms,通过搜索,我们可以看到如下宏定义:
#define APP_ADV_INTERVAL
/**& The advertising interval (in units of 0.625 this value corresponds to 40 ms). */
因此为了将广播间隔改为200ms,只需将APP_ADV_INTERVAL改成200/0.625 = 320,即
#define APP_ADV_INTERVAL
重新编译下载blinky程序,在nRF connect中,你将发现广播间隔已改为200ms了:
3.3 修改Button characteristic行为 (设备发数据给手机)
现在的Blinky程序,只有按下开发板的Button1时,nRF connect的Button characteristic 值才会更新。我们现在新增一个功能:当按下开发板的Button 2时,让Button characteristic value更新为5(注: nRF connect把1当成按键按下,把0当成按键释放,为了更直观,我们没有选择0或者1,而是随便选择一个值:5)。我们先找到Button1按下的回调函数,如下所示:&
case LEDBUTTON_BUTTON:
NRF_LOG_INFO("Send button state change.");
err_code = ble_lbs_on_button_change(m_conn_handle, &m_lbs, button_action);
if (err_code != NRF_SUCCESS &&
err_code != BLE_ERROR_INVALID_CONN_HANDLE &&
err_code != NRF_ERROR_INVALID_STATE &&
err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
APP_ERROR_CHECK(err_code);
可以看出,我们是通过ble_lbs_on_button_change来更新Button characteristic的值的,ble_lbs_on_button_change具体函数实现如下所示:
uint32_t ble_lbs_on_button_change(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t button_state)
ble_gatts_hvx_params_t params;
uint16_t len = sizeof(button_state);
memset(&params, <span style="color: #, sizeof(params));
params.type
= BLE_GATT_HVX_NOTIFICATION;
params.handle = p_lbs-&button_char_handles.value_
params.p_data = &button_
params.p_len
return sd_ble_gatts_hvx(conn_handle, &params);
我们可以仿照Button1的做法,来添加Button2的代码。首先初始化app_button模块,让button2按下事件可以被button_event_handler捕获,如下:
static app_button_cfg_t buttons[] =
{LEDBUTTON_BUTTON, false, BUTTON_PULL, button_event_handler},
{BSP_BUTTON_1, false, BUTTON_PULL, button_event_handler}
然后在button_event_handler调用ble_button2_send(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t val),以更新Button characteristic的值,代码如下所示:
case BSP_BUTTON_1:
NRF_LOG_INFO("Button2 pressed.");
ble_button2_send(m_conn_handle, &m_lbs, <span style="color: #);
ble_button2_send(m_conn_handle, &m_lbs, 5)实现代码如下所示:
uint32_t ble_button2_send(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t val)
ble_gatts_hvx_params_t params;
uint16_t len = sizeof(val);
memset(&params, <span style="color: #, sizeof(params));
params.type
= BLE_GATT_HVX_NOTIFICATION;
params.handle = p_lbs-&button_char_handles.value_
//Button characteristic value handle
params.p_data = &
params.p_len
return sd_ble_gatts_hvx(conn_handle, &params);
重新编译下载blinky程序,连接设备,使能cccd,按下Button2,你会看到Button characteristic的值变为5:
3.4 修改LED characteristic行为(手机发数据给设备)
由于nRF connect把LED characteristic的值写死了,只能发送“ON”或者“OFF”,前面也测试过,发送“ON”之后,LED3将点亮,其实这里的“ON”,就是数值1。我们现在增加一个新的功能:在收到“ON”命令后,把LED4 toggle一下。
这个实现起来比较简单,我们只需在led_write_handler中添加bsp_board_led_invert(BSP_BOARD_LED_3),整体代码如下所示:
static void led_write_handler(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t led_state)
if (led_state)
bsp_board_led_on(LEDBUTTON_LED);
NRF_LOG_INFO("Received LED ON!");
bsp_board_led_invert(BSP_BOARD_LED_3);
bsp_board_led_off(LEDBUTTON_LED);
NRF_LOG_INFO("Received LED OFF!");
重新编译下载blinky程序,连接设备,你会发现第一次发送“ON”,LED4点亮,第二次发送“ON”,LED4又将熄灭。
通过全文搜索“led_write_handler”,你会发现这个函数是被ble_lbs.c中的on_write调用,而on_write又被ble_lbs_on_ble_evt调用,而ble_lbs_on_ble_evt就是我们的BLE事件回调函数,每当softdevice收到LED characteristic的写操作时,都会调用它,这就是通过nRF connect操作设备的过程和原理。
这篇文章主要让大家对BLE有个大概的认识,后面我会专门写一篇文章来介绍上面提到的BLE service,characteristic,write,notify以及CCCD等,以帮助大家深刻理解这些概念。标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&原文地址:https://www.cnblogs.com/iini/p/8996025.html
&&国之画&&&& &&&&chrome插件
版权所有 京ICP备号-2
迷上了代码!Android 蓝牙开发 —— BLE
蓝牙——BLE
1.BLE 是 Bluetooth Low Energy 的缩写,意思为低功耗蓝牙。由蓝牙技术联盟(Bluetooth SIG)设计的无线通讯技术,主要用于医疗,健身,安全和家庭娱乐行业。 与传统蓝牙相比,蓝牙低功耗旨在大幅降低功耗和成本,同时也能够达到相同的通讯效果。
支持多个平台,包括 IOS,Android,Windows Phone 和 BlackBerry 以及 macOS,Linux,Windows 8 和 Windows 10 在内的移动操作系统本身支持蓝牙低功耗。 蓝牙 SIG 预测,到 2018 年,超过 90% 的蓝牙智能手机将支持蓝牙低功耗。
在安卓平台,
在 Android 4.3 (API level 18) 以后引进来的,通过这些 API 可以扫描蓝牙设备、连接设备,查询 services、读写设备的 characteristics(属性特征),然后通过属性进行数据传输。
低功耗,使用 BLE 与周围设备进行通讯时,其峰值功耗为传统蓝牙的一半
传输距离提升到 100 米
低延时,最短可在3 ms内完成连接并开始进行数据传输
传输数据量较小,最大 512 个字节,超过 20 个字节需要分包处理
应用领域:
主要用于智能硬件,像健康护理、运动和健身、设备电源管理等
对于BLE单设备来讲常见的蓝牙模块的工作模有四种:
主设备模式
从设备模式
Mesh组网模式
主设备模式
可以与一个从设备进行连接。在此模式下可以对周围设备进行搜索并选择需要连接的从设备进行连接。同时可以设置默认连接从设备的MAC地址,这样模块上电之后就可以查找此模块并进行连接。
从设备模式
BLE支持从设备模式,在此模式下完全符合BLE4.1协议,用户可以根据协议自己开发APP。此模式下包含一个串口收发的Service,用户可以通过UUID找到它,里面有两个通道,分别是读和写。用户可以操作这两个通道进行数据的传输。
在这种模式下模块可以一对多进行广播。用户可以通过AT指令设置模块广播的数据,模块可以在低功耗的模式下持续的进行广播,应用于极低功耗,小数据量,单向传输的应用场合,比如无线抄表,室内定位等功能。
Mesh组网模式
在这种模式下模块可以实现简单的自组网络,每个模块只需要设置相同的通讯密码就可以加入到同一网络当中,每一个模块都可以发起数据,每个模块可以收到数据并且进行回复。并且不需要网关,即使某一个设备出现故障也会跳过并选择最近的设备进行传输。
GATT generic Attributes的缩写,中文是通用属性,是低功耗蓝牙设备之间进行通信的协议。
GATT定义了一种多层的数据结构,已连接的低功耗蓝牙设备用它来进行通信,GATT层是传输真正数据所在的层。一个GATT服务器通过一个称为属性表的表格组织数据,这些数据就是用于真正发送的数据。
GATT定义的多层数据结构简要概括起来就是服务(service)可以包含多个特征(characteristic),每个特征包含属性(properties)和值(value),还可以包含多个描述(descriptor)。它形象的结构如下图:
profile(数据配置文件)
一个profile文件可以包含一个或者多个服务,一个profile文件包含需要的服务的信息或者为对等设备如何交互的配置文件的选项信息。设备的GAP和GATT的角色都可能在数据的交换过程中改变,因此,这个文件应该包含广播的种类、所使用的连接间隔、所需的安全等级等信息。
需要注意的是: 一个profile中的属性表不能包含另一个属性表。
一个属性包含句柄、UUID(类型)、值,句柄是属性在GATT表中的索引,在一个设备中每一个属性的句柄都是唯一的。UUID包含属性表中数据类型的信息,它是理解属性表中的值的每一个字节的意义的关键信息。在一个GATT表中可能有许多属性,这些属性能可能有相同的UUID。
个人理解,属性指的是 Service、Characteristic 这样的对象
一个低功耗蓝牙设备可以定义许多 Service, Service 可以理解为一个功能的集合。设备中每一个不同的 Service 都有一个 128 bit 的 UUID 作为这个 Service 的独立标志。蓝牙核心规范制定了两种不同的UUID,一种是基本的UUID,一种是代替基本UUID的16位UUID。所有的蓝牙技术联盟定义UUID共用了一个基本的UUID:
0x0000xxxx-00-FB
为了进一步简化基本UUID,每一个蓝牙技术联盟定义的属性有一个唯一的16位UUID,以代替上面的基本UUID的‘x’部分。例如,心率测量特性使用0X2A37作为它的16位UUID,因此它完整的128位UUID为:
0x0-805F9B34FB
Characteristic
在 Service 下面,又包括了许多的独立数据项,我们把这些独立的数据项称作 Characteristic。同样的,每一个 Characteristic 也有一个唯一的 UUID 作为标识符。在 Android 开发中,建立蓝牙连接后,我们说的通过蓝牙发送数据给外围设备就是往这些 Characteristic 中的 Value 字段写入数据;外围设备发送数据给手机就是监听这些 Charateristic 中的 Value 字段有没有变化,如果发生了变化,手机的 BLE API 就会收到一个监听的回调。
DesCriptor
任何在特性中的属性不是定义为属性值就是为描述符。描述符是一个额外的属性以提供更多特性的信息,它提供一个人类可识别的特性描述的实例。然而,有一个特别的描述符值得特别地提起:客户端特性配置描述符(Client Characteristic Configuration Descriptor,CCCD),这个描述符是给任何支持通知或指示功能的特性额外增加的。在CCCD中写入“1”使能通知功能,写入“2”使能指示功能,写入“0”同时禁止通知和指示功能。
常采用的模式是主机模式,然后扫描客户端硬件,然后连接,获取相关服务和特性,然后进行数据传输。
&uses-permission android:name="android.permission.BLUETOOTH"/& 使用蓝牙所需要的权限
&uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/& 使用扫描和设置蓝牙的权限(申明这一个权限必须申明上面一个权限)
在Android5.0之前,是默认申请GPS硬件功能的。而在Android 5.0 之后,需要在manifest 中申明GPS硬件模块功能的使用。
&!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --&
&uses-feature android:name="android.hardware.location.gps" /&
在 Android 6.0 及以上,还需要打开位置权限。如果应用没有位置权限,蓝牙扫描功能不能使用(其它蓝牙操作例如连接蓝牙设备和写入数据不受影响)。
&uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/&
除了上面的设置之外,如果想设置设备只支持 BLE,可以加上下面这句话
&uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/&
同样,如果不想添加 BLE 的支持,那么可以设置 required="false"
然后可以在运行时判断设备是否支持 BLE,
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
判断 BLE 在设备上是否支持,如果不支持的话,那么可以不用继续后面的操作了;如果支持,但是有可能蓝牙被禁掉了,因为开着蓝牙比较好点,用户一般都会关闭蓝牙,这时候可以发送请求,来打开蓝牙,可以通过两个步骤来完成。
获取 BluetoothAdapter
BluetoothAdapter 对于一个设备来说唯一的,整个系统或者应用,对蓝牙进行操作时都是需要这个的适配器。它的获取需要通过系统服务来获取。
private BluetoothAdapter mBluetoothA
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
2.打开蓝牙
一般对于用户来说,在手机上蓝牙是关闭,当开启你的应用时就需要开启蓝牙,有两种方式,一种是跳转到设置界面,由用户自己开启蓝牙;
另外一种时,直接在应用开启蓝牙,不需要用户打开,而是直接帮用户开启手机上的蓝牙。
跳转到设置界面
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
直接开启蓝牙
if (!mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.enable();
扫描蓝牙设备可以通过startLeScan(),其中有一个参数是 ScanCallback,通过它返回扫描结果,因为扫描过程是很耗电的,所以在扫描过程需要保证
1.一旦找到目标设备,需要停止扫描
2.扫描不要设置循环,而且需要设置一个时间
private ScanCallback mScanCallback = new ScanCallback() {
public void onScanResult(int callbackType, final ScanResult result) {
runOnUiThread(new Runnable() {
public void run() {
MDevice mDev = new MDevice(result.getDevice(), result.getRssi());
if (!mList.contains(mDev)) {
mList.add(mDev);
if (mList.size() & 0) {
mScanner.stopScan(mScanCallback);
Toast.makeText(MainActivity.this, "扫描结束,设备数 " + mList.size()
, Toast.LENGTH_SHORT).show();
private BluetoothAdapter mBluetoothA
private boolean mS
private Handler mH
private static final long SCAN_PERIOD = 10000;
private void scanLeDevice(final boolean enable) {
if (enable) {
mHandler.postDelayed(new Runnable() {
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
这里遇到一个坑,就是实际中手机与一些智能硬件连接时,也就是需要连接指定的硬件,设备有一个UUID,所以可以通过如下方法连接
startLeScan(UUID[], BluetoothAdapter.LeScanCallback)
但是实际中使用时,连接时会出错,仍需要再次验证。
我当时的做法是采用了另外一种方法,当时这种方法,要求 API 高于 21。
private void scanLeDevice() {
mHander.postDelayed(stopScanRunnable, 50000);
List&ScanFilter& filters = new ArrayList&&();
ScanFilter filter = new ScanFilter.Builder()
.setDeviceAddress("D8:B0:4C:E2:45:2A")
filters.add(filter);
mScanner.startScan(filters, new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(), mScanCallback);
扫描结束后需要停止扫描
boolean startLeScan(BluetoothAdapter.LeScanCallback callback)
通过扫描能够获得设备 BluetoothDevice,包含地址和名字
通过设备连接并获取 BluetoothGatt,后面通过 BluetoothGatt 的实例来进行client的操作,如使用该实例去发现服务,获取读、写、通知等属性
public static BluetoothGatt mBluetoothG
mBluetoothGatt = device.connectGatt(context, false, mGattCallback);
通过连接回调来监听连接的状态,包含三种状态,连接、断开、正在连接,根据状态可以发送广播,
在接收广播的位置进行做相应的处理
private final static BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
String intentA
if (newState == BluetoothProfile.STATE_CONNECTED) {
System.out.println("----------------------------&已经连接");
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastConnectionUpdate(intentAction);
else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
System.out.println("----------------------------&连接断开");
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
broadcastConnectionUpdate(intentAction);
else if (newState == BluetoothProfile.STATE_DISCONNECTING) {
System.out.println("----------------------------&正在连接");
当操作完成后,需要关闭连接,必须调用 BluetoothGatt#close 方法释放连接资源
由于有了 mBluetoothGatt,就可以去发现服务,再通过服务去获取可以操作的属性
mBluetoothGatt.discoverServices();
发现服务以及获取其他属性,如write和read,notify,Descriptor相关的属性,均是在 BluetoothGattCallback 中有回调,在回调中就可以通过发送广播,然后在其他位置做处理,
如接收数据就会有回调,然后将数据传递出去,对数据解析等
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
System.out.println("----------------------------&发现服务");
broadcastConnectionUpdate(ACTION_GATT_SERVICES_DISCOVERED);
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
int status) {
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
int status) {
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic
characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
System.out.println("onCharacteristicWrite -------------------&write success");
Intent intent = new Intent(ACTION_GATT_CHARACTERISTIC_WRITE_SUCCESS);
mContext.sendBroadcast(intent);
Intent intent = new Intent(ACTION_GATT_CHARACTERISTIC_ERROR);
intent.putExtra(Constants.EXTRA_CHARACTERISTIC_ERROR_MESSAGE, "" + status);
mContext.sendBroadcast(intent);
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
broadcastNotifyUpdate(characteristic);
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
super.onMtuChanged(gatt, mtu, status);
这里有两个方法:
方法一: 一般数据读取的话,想到的是用 read 属性,所以需要获取特定通道的 BluetoothGattCharactristic。
1)BluetoothGatt#getService 得到服务
2)BluetoothGattService#getCharactristic 获取 BluetoothGattCharactristic,这里获取的 BluetoothGattCharactristic 是有指定 UUID 的,也就是说不同的 Charactristic的 UUID 是不同的,读和写的通道不同,根据不同的操作,然后通过UUID获取相应的通道
3)BluetoothGattCharactristic#readCharacteristic 方法可以通知系统去读取特定的数据
4)BluetoothGattCallback#onCharacteristicRead 方法。通过 BluetoothGattCharacteristic#getValue 可以读取到蓝牙设备的数据
方法二:采用 notify 属性,客户端发送数据,服务端监听属性变化,然后根据 属性的 UUID 判断是否是 notify 的属性,如果是的话,说确实是由远程设备发过来的数据。
1)BluetoothGatt#getService 得到服务
2)BluetoothGattService#getCharactristic 获取 BluetoothGattCharactristic,这里的这个属性是 notify 属性
3)获得属性后需要进行判断设备是否支持notify操作,然后再设备打开notify通知
void prepareBroadcastDataNotify(
BluetoothGattCharacteristic characteristic) {
final int charaProp = characteristic.getProperties();
Toast.makeText(this, " " + charaProp, Toast.LENGTH_SHORT).show();
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) & 0) {
BluetoothLeService.setCharacteristicNotification(characteristic, true);
4) 设置属性时,也要通知远程设备端也要开启 notify 属性
public static void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
if (characteristic.getDescriptor(UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG)) != null) {
if (enabled == true) {
BluetoothGattDescriptor descriptor = characteristic
.getDescriptor(UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
BluetoothGattDescriptor descriptor = characteristic
.getDescriptor(UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
对于 BLE 方式的数据传输来说,数据的大小是有限制的,一次性最多可以传输512个字节,这也是BLE小数据量传输的特点,另外,对于每次传输,也有限制,每个数据包大小不超过20个字节,超过20个字节的话,需要分包处理。写的步骤和读取类似。
1)BluetoothGatt#getService 得到服务
2)BluetoothGattService#getCharactristic 获取 BluetoothGattCharactristic,这里的这个属性是 write 属性
3)写入字节数据
public static void writeCharacteristicGattDb(
BluetoothGattCharacteristic characteristic, byte[] byteArray) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
byte[] valueByte = byteA
characteristic.setValue(valueByte);
mBluetoothGatt.writeCharacteristic(characteristic);
4)对于手机端,写入数据后,远程端会接受,同时回调中也会能够接收,也可以在回调中做一下数据判断,看是否是自己发出的数据
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic
characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
System.out.println("onCharacteristicWrite -------------------&write success");
Intent intent = new Intent(ACTION_GATT_CHARACTERISTIC_WRITE_SUCCESS);
characteristic.getValue();
mContext.sendBroadcast(intent);
Intent intent = new Intent(ACTION_GATT_CHARACTERISTIC_ERROR);
intent.putExtra(Constants.EXTRA_CHARACTERISTIC_ERROR_MESSAGE, "" + status);
mContext.sendBroadcast(intent);
一般在通讯过程中,需要有连接的心跳包,来检测是否仍处于连接状态,可以通过设置定时器,主机端定时 write 数据,客户端定时 notify 数据
操作完成,需要断开蓝牙并释放资源,通过 BluetoothGatt#disconnect 断开连接,然后回调中会收到断开的监听,可以根据状态释放资源。BluetoothGattCallback#onConnectionStateChange回调中通过这个方法的 newState 参数可以判断是连接成功还是断开成功的回调,断开成功的话,然后调用 BluetoothGatt#close 方法释放资源
Android蓝牙BLE的详细讲解
Android蓝牙开发GATT协议
Android蓝牙开发全面总结
Android BLE蓝牙详细解读
Android蓝牙BLE开发(一)-基本原理
Android-低功耗蓝牙(BLE)-客户端(主机/中心设备)和服务端(从机/外围设备)
android 蓝牙ACL通讯详解
Android 手机搜发蓝牙广播测试
Android蓝牙开发(二) BLE4.0低功耗蓝牙
没有更多推荐了,}

我要回帖

更多关于 apushservice是什么 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信