简介
蓝牙* 低能耗(蓝牙 LE 或 BLE)是一种低能耗、近距离无线通信技术,非常适用于物联网行业应用。 BLE 专门针对小规模数据传输而设计,可在客户端、服务器和简单用户界面之间提供快速的连接,非常适用于控制和监控应用。 Arduino 101* 包含板载蓝牙 LE,可帮助开发人员与支持蓝牙技术的设备进行交互,例如手机和平板电脑。 我们将讨论如何创建 BLEservice,以及如何与安卓设备通信。 此外,我们还搭建了一套 BLE 血压监测系统,以展示 Arduino 101* 的 BLE 功能。
硬件组件
本项目中使用的硬件组件如下:
- Arduino 101* 模块
- Grove* - Starter Kit Plus
- 一根即插即用的标准 USB 线缆
该项目将使用 Grove 套件中的旋转角度传感器,请参见图 1 及其它组件。
如欲了解安装英特尔® Curie 开发板,以及针对 Arduino 101* 平台设置软件开发环境的详情,请访问https://software.intel.com/zh-cn/articles/fun-with-the-arduino-101-genuino-101。
图 1: Arduino 101*(带旋转角度传感器)。
中央和外设设备
蓝牙 LE 支持两种主要的联网设备:中央和外围设备。
中央: 蓝牙设备,例如智能手机、平板电脑或 PC,向外围设备发出连接请求。 连接到外围设备后,中央设备便可交换数据、读取外围设备上的数值,并在外围设备上执行命令。
外设: BLE 设备在广告之后尝试连接请求。 它会收集和公布数据,以便供其他设备使用。
中央设备通过广告包(advertising package)与外围设备通信。 外围设备发出广告,中央设备则对这些广告进行扫描。
图 2: 中央和外设设备通信
通用属性配置文件 (GATT)
Arduino 101* 蓝牙 LE 以通用属性配置文件 (GATT) 架构为基础。 GATT 定义了一种分层数据结构,连接的蓝牙 LE 设备可以看到该结构。 GATT 配置文件可以指定通过 BLE 链路的小型传输数据。 这些通过 BLE 链路的小型传输数据被称为属性。 GATT 基于属性协议 (ATT) 而构建。 ATT 可传输属性,而属性则被格式化为特征和服务。 如欲了解关于蓝牙 LE 和 GATT 的更多信息,请访问 https://www.bluetooth.com/what-is-bluetooth-technology/bluetooth-technology-basics/low-energy和https://www.bluetooth.com/specifications/gatt。
外设数据结构
在 GATT 架构中,数据被组织为服务和特征。 一项服务便是一套压缩外设设备行为的特性。 特征是定义的服务属性,可提供关于服务的更多信息。 例如,血压服务的特征是血压测量、中间气囊内压力和血压特性。
图 3:蓝牙服务和特征关系。
创建血压 BLE 服务
要创建 BLE 服务,您需要知道服务编号和相应的特征编号。 在 蓝牙页面,选择 GATT Specifications -> Services ,查看完整的 GATT 服务列表。
图 4:蓝牙 GATT 规格下拉菜单。
选择血压服务,获得 BLEService 构建程序的服务编号。
图 5:蓝牙服务。
在 蓝牙页面,选择GATT Specifications -> Characteristics ,访问血压特征编号。
图 6:蓝牙特征。
接下来,添加 Arduino 101* CurieBLE 库组件,以支持与其它蓝牙* 设备的通信与交互。 您可以从以下地址找到开源 CurieBLE 库: https://github.com/01org/corelibs-arduino101。
#include <CurieBLE.h>
BLEPeripheral blePeripheral; // BLE Peripheral Device
BLEService bloodPressureService("1810"); // Blood Pressure Service
// BLE Blood Pressure Characteristic"
BLECharacteristic bloodPressureChar("2A35", // standard 16-bit characteristic UUID
BLERead | BLENotify, 2); // remote clients will be able to
// get notifications if this characteristic changes
为外设 BLE 设备设置一个本地名称。 当电话(中央设备)连接到该外设蓝牙* 设备时,电话上将会显示本地名称,从而确认连接的外设。
blePeripheral.setLocalName("BloodPressureSketch");
blePeripheral.setAdvertisedServiceUuid(bloodPressureService.uuid()); // add the service UUID
blePeripheral.addAttribute(bloodPressureService); // Add the BLE Blood Pressure service
blePeripheral.addAttribute(bloodPressureChar); // add the blood pressure characteristic
将血压设备连接至 Arduino 101* 平台的模拟针 A0。 本例使用旋转角度传感器来模拟血压设备。
int pressure = analogRead(A0);
int bloodPressure = map(pressure, 0, 1023, 0, 100);
更新血压测量特征。 更新后的血压值将由中央设备发送。 例如,如果电话连接至外设血压设备,便可通过一款安卓应用来读取更新的血压值。
bloodPressureChar.setValue(bloodPressureCharArray, 2);
安卓设备与 Arduino 传感器通信
外设通过蓝牙* 广告与中央安卓设备通信。 在广告中,外设设备向它周围的每台设备发送数据包。 中央设备扫描并连接到外设设备,以便接收数据以及获得更多信息。 按照下面的步骤操作,确保安卓设备和 Arduino 传感器之间能够正常通信。
- 在安卓设备上启用蓝牙功能。
- Google Play 上有许多免费的 BLE 安卓应用。 在 Google Play 上搜索 BLE 并在安卓设备上安装 BLE 安卓应用。
- 启动 BLE 安卓应用。
- 扫描并连接到 BloodPressureSketch 外设设备。
- 读取或写入血压值。
图 7 展示了安卓设备扫描 BloodPressureSketch 外设的示例。
图 7:安卓设备扫描 BLE 服务。
打开旋转角度传感器,在安卓设备屏幕上查看血压值变化。
开发安卓应用
请访问 http://developer.android.com/guide/topics/connectivity/bluetooth-le.html,了解关于开发安卓应用的更多信息,以及如何通过 Arduino 101* 平台与外设设备通信。 如果您不了解安卓系统,请访问 https://developer.android.com/training/basics/firstapp/index.html,了解关于创建安卓项目以及首次构建安卓应用的信息。
示例 Arduino IDE Sketch
下面的代码示例 1 提供了血压测量示例代码。 打开串行控制台查看输出结果。
#include <CurieBLE.h> /* This sketch example partially implements the standard Bluetooth Low-Energy Battery service. For more information: https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx */ /* */ BLEPeripheral blePeripheral; // BLE Peripheral Device (the board you're programming) BLEService bloodPressureService("1810"); // Blood Pressure Service // BLE Blood Pressure Characteristic" //BLECharacteristic bloodPressureChar("2A49", // standard 16-bit characteristic UUID BLECharacteristic bloodPressureChar("2A35", // standard 16-bit characteristic UUID BLERead | BLENotify, 2); // remote clients will be able to // get notifications if this characteristic changes int oldBloodPressure = 0; // last blood pressure reading from analog input long previousMillis = 0; // last time the blood pressure was checked, in ms void setup() { Serial.begin(9600); // initialize serial communication pinMode(13, OUTPUT); // initialize the LED on pin 13 to indicate when a central is connected /* Set a local name for the BLE device This name will appear in advertising packets and can be used by remote devices to identify this BLE device The name can be changed but maybe be truncated based on space left in advertisement packet */ blePeripheral.setLocalName("BloodPressureSketch"); blePeripheral.setAdvertisedServiceUuid(bloodPressureService.uuid()); // add the service UUID blePeripheral.addAttribute(bloodPressureService); // Add the BLE Blood Pressure service blePeripheral.addAttribute(bloodPressureChar); // add the blood pressure characteristic const unsigned char charArray[2] = { 0, (unsigned char)0 }; bloodPressureChar.setValue(charArray, 2); // initial value for this characteristic /* Now activate the BLE device. It will start continuously transmitting BLE advertising packets and will be visible to remote BLE central devices until it receives a new connection */ blePeripheral.begin(); Serial.println("Bluetooth device active, waiting for connections..."); } void loop() { // listen for BLE peripherals to connect: BLECentral central = blePeripheral.central(); // if a central is connected to peripheral: if (central) { Serial.print("Connected to central: "); // print the central's MAC address: Serial.println(central.address()); // turn on the LED to indicate the connection: digitalWrite(13, HIGH); // check the blood pressure mesurement every 200ms // as long as the central is still connected: while (central.connected()) { long currentMillis = millis(); // if 200ms have passed, check the blood pressure mesurement: if (currentMillis - previousMillis >= 200) { previousMillis = currentMillis; updateBloodPressure(); } } // when the central disconnects, turn off the LED: digitalWrite(13, LOW); Serial.print("Disconnected from central: "); Serial.println(central.address()); } } void updateBloodPressure() { /* Read the current voltage mesurement on the A0 analog input pin. This is used here to simulate the blood pressure. */ int pressure = analogRead(A0); int bloodPressure = map(pressure, 0, 1023, 0, 100); // If the blood pressure has changed if (bloodPressure != oldBloodPressure) { Serial.print("The current blood pressure is: "); Serial.println(bloodPressure); const unsigned char bloodPressureCharArray[2] = { 0, (unsigned char)bloodPressure }; // Update the blood pressure measurement characteristic bloodPressureChar.setValue(bloodPressureCharArray, 2); // Save the measurement for next comparison oldBloodPressure = bloodPressure; } }
代码示例 1:面向 Arduino IDE 的血压示例代码。
总结
本文概述了 Arduino 101* 平台如何与安卓设备通信,并介绍了创建 BLE 服务的步骤。 请查看https://www.arduino.cc/en/Reference/CurieBLE,了解在 Arduino IDE 中使用 BLE 的更多示例。 如果您对 Arduino 101* 平台感兴趣,请访问 http://www.intel.com/buy/us/en/product/emergingtechnologies/intel-arduino-101-497161了解更多信息。
实用参考资料
- 英特尔® 开发人员专区:
https://software.intel.com/zh-cn/iot/home - 英特尔® Curie:
https://software.intel.com/zh-cn/iot/hardware/curie - Arduino 101* 硬件:
https://www.arduino.cc/en/Main/ArduinoBoard101
https://www.arduino.cc/en/Guide/Arduino101
https://software.intel.com/zh-cn/articles/fun-with-the-arduino-101-genuino-101 - Grove* - Starter Kit Plus:
https://software.intel.com/zh-cn/iot/hardware/devkit - 安卓蓝牙 LE:
http://developer.android.com/guide/topics/connectivity/bluetooth-le.html - 蓝牙*:
https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
https://www.bluetooth.com/what-is-bluetooth-technology - 蓝牙库:
https://www.arduino.cc/en/Reference/CurieBLE
关于作者
Nancy Le 是英特尔公司软件与服务事业部的一名软件工程师,主要负责英特尔® 凌动™ 处理器扩展支持项目。