1. 概述
在藍牙4.0發布以前,給大家的直觀印象就是藍牙耳機,它就是用來滿足短距離內中等帶寬的音頻通信需求。然而藍牙4.0發布之后,用途就大不一樣了,特別是現在物聯網和可穿戴之風盛行的年代,很多小玩意都使用了它,如心率計、手環、鑰匙扣等等物件,最終它能夠和用戶的手機、Pad以及PC等設備連接,實現五花八門的功能。為什么藍牙4.0的用途廣泛了呢?首先歸功於低功耗,運行Bluetooth Low Energy的設備,一節紐扣電池可以支持其半年的時間;其次是低成本,如TI公司的CC2540藍牙SoC售價是1美元。自iOS和Android支持藍牙4.0 BLE以后,在今年4月份微軟的BUILD 2014大會上,終於官方宣布在Windows 8.1和Windows Phone 8.1中支持藍牙4.0 BLE,值得注意的是,目前為止,Windows 8.1 只支持GATT Client模式,而不支持GATT Server模式。下面我們就一起來了解一下如何在Windows 8.1平台上開發藍牙 4.0 BLE的應用。
2. 設備
首先是配有藍牙4.0的Windows 8.1系統的PC或者平板,以Surface Pro 2為例,可以打開“設備管理器”->藍牙,查看下面的列表,如果里面有“Microsoft Bluetooth LE 枚舉器”的話,如下圖1所示,就說明是支持藍牙4.0 LE的,如果沒有的話,是無法搜索到藍牙4.0 LE設備的,這時候就需要去更新系統和藍牙驅動了。
圖1
注意,在進行這一步以前,最好先去“設置”->“更改電腦設置”->“電腦和設備”->“藍牙”中,把藍牙打開。因為在我測試的時候發現,Surface Pro 2在藍牙關閉的時候,不會出現“Microsoft Bluetooth LE 枚舉器”這一項,如下圖2所示,只有在藍牙打開的情況下才會出現。
圖2
其次,就是藍牙4.0 BLE設備了,目前最流行的應該就是TI的CC2541 Sensor Tag,淘寶上都有賣,價格在200以內。Sensor Tag內部包含了6種傳感器:IR temperature Sensor, Humidity Sensor, Pressure Sensor, Accelerometer, Gyroscope, Magnetometer。
3. 准備
如果在Windows設備上第一次使用Sensor Tag,我們還需要手動進行配對工作,這也是在Windows平台上使用藍牙一貫以來的風格,包括以前的Windows Mobile,Windows CE,也包括現在的Windows Phone。當然,第一次使用配對成功以后,后面就不需要再配對了。首先,需要打開藍牙開關,等待TI BLE Sensor Tag的出現,然后點擊它,首次配對的PIN碼為0000。如下圖3所示。
圖3
之后,系統會自動配置GATT服務,配置完成以后,可以去“設備管理器”->藍牙那一項看看,你會發現里面多了很多GATT Services。如下圖4所示。
圖4
有關Sensor Tag提供的服務和對應的UUID,可以參考TI官方的文檔:TI Development KIT。
其中用的典型的UUID包括:
Thermometer "f000aa00-0451-4000-b000-000000000000"
Accelerometer "f000aa10-0451-4000-b000-000000000000"
Humidity "f000aa20-0451-4000-b000-000000000000"
Magnetometer "f000aa30-0451-4000-b000-000000000000"
Barometer "f000aa40-0451-4000-b000-000000000000"
Gyroscope "f000aa50-0451-4000-b000-000000000000"
Key Service "0000ffe0-0000-1000-8000-00805f9b34fb"
Generic Access: 00001800-0000-1000-8000-00805f9b34fb
Generic Attribute: 00001801-0000-1000-8000-00805f9b34fb
Device Information: 0000180A-0000-1000-8000-00805f9b34fb
4. 創建應用
創建一個Windows Store應用,然后使用記事本或者在View Code下編輯Package.appxmanifest文件,加入以下Capabilities:
<Capabilities>
<Capability Name="internetClient" />
<m2:DeviceCapability Name="bluetooth.genericAttributeProfile">
<m2:Device Id="any">
<m2:Function Type="serviceId:f000aa00-0451-4000-b000-000000000000"/>
<m2:Function Type="serviceId:F000AA10-0451-4000-B000-000000000000"/>
<m2:Function Type="serviceId:F000AA20-0451-4000-B000-000000000000"/>
<m2:Function Type="serviceId:F000AA30-0451-4000-B000-000000000000"/>
<m2:Function Type="serviceId:F000AA40-0451-4000-B000-000000000000"/>
<m2:Function Type="serviceId:F000AA50-0451-4000-B000-000000000000"/>
<m2:Function Type="serviceId:0000ffe0-0000-1000-8000-00805f9b34fb"/>
<m2:Function Type="serviceId:00001800-0000-1000-8000-00805f9b34fb"/>
<m2:Function Type="serviceId:00001801-0000-1000-8000-00805f9b34fb"/>
<m2:Function Type="serviceId:0000180A-0000-1000-8000-00805f9b34fb"/>
</m2:Device>
</m2:DeviceCapability>
</Capabilities>
然后,使用Generic Access Service來讀取Sensor Tag的Device Name,代碼如下:
//Find the devices that expose the service
var devices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(GattDeviceService.GetDeviceSelectorFromUuid(GattServiceUuids.GenericAccess));
if (devices.Count==0)
return;
//Connect to the service
var service = await GattDeviceService.FromIdAsync(devices[0].Id);
if (service == null)
return;
//Obtain the characteristic we want to interact with
var characteristic = service.GetCharacteristics(GattCharacteristic.ConvertShortIdToUuid(0x2A00))[0];
//Read the value
var deviceNameBytes=(await characteristic.ReadValueAsync()).Value.ToArray();
//Convert to string
var deviceName=Encoding.UTF8.GetString(deviceNameBytes,0,deviceNameBytes.Length);
接着,我們來看看如何讀取加速度傳感器等數據:
//Find the devices that expose the service
var devices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(GattDeviceService.GetDeviceSelectorFromUuid(new Guid("F000AA10-0451-4000-B000-000000000000")));
if (devices.Count==0)
return;
//Connect to the service
var accService = await GattDeviceService.FromIdAsync(devices[0].Id);
if (accService == null)
return;
//Get the accelerometer data characteristic
var accData = accService.GetCharacteristics(new Guid("F000AA11-0451-4000-B000-000000000000"))[0];
//Subcribe value changed
accData.ValueChanged += accData_ValueChanged;
//Set configuration to notify
await accData.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
//Get the accelerometer configuration characteristic
var accConfig = accService.GetCharacteristics(new Guid("F000AA12-0451-4000-B000-000000000000"))[0];
//Write 1 to start accelerometer sensor
await accConfig.WriteValueAsync((new byte[]{1}).AsBuffer());
訂閱數據變更的notifications,加速度傳感器默認的數據更新頻率是1秒,這個值我們也可以進行修改。
async void accData_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
var values = (await sender.ReadValueAsync()).Value.ToArray();
var x = values[0];
var y = values[1];
var z = values[2];
}
5. 使用第三方庫
大家知道,按照上面的步驟來做,自己需要寫很多數據交互的代碼。如果你想偷懶,可以參考一下第三方庫,SebastianL在codeplex上給出了TI Sensor Tag的開源庫,鏈接地址為:Link。目前的版本是1.2,支持Windows 8.1,據作者說支持Windows Phone 8.1的版本會很快到來。使用這個庫很簡單:
第一步,在新建Store應用中加入應用的Capabilities,步驟與上面第4節中的一樣。
第二步,下載X2CodingLab.SensorTag庫,並在項目中添加對X2CodingLab.SensorTag的引用,如下圖5所示。
圖5
第三步,在需要使用Sensor Tag的頁面后台文件中,實例化相應的傳感器,以加速度傳感器為例:
Accelerometer accelerometer = new Accelerometer();
第四步,初始化傳感器,調用封裝好的Initialize()方法:
await accelerometer.Initialize();
如果沒有配對的Sensor Tag,這里會拋出異常DeviceNotFoundException。
第五步,獲取傳感器數據,使用EnableSensor和DisableSensor方法來打開獲取數據的開關,另外,如果獲取數據結束了,最好調用DisableSensor來節省Sensor Tag的功耗。
await accelerometer.EnableSensor();
await accelerometer.DisableSensor();
使用EnableNotifications() 和 DisableNotification()來允許或者禁止數據通知:
private async void Notify()
{
await accelerometer.DisableNotifications();
await accelerometer.EnableNotifications();
accelerometer.SensorValueChanged += accelerometer_SensorValueChanged;
}
void accelerometer_SensorValueChanged(object sender, X2CodingLab.SensorTag.SensorValueChangedEventArgs e)
{
byte[] sensorData = e.RawData;
}
下面是應用運行界面圖。
圖6
再給出實物的圖片吧,紅色的是Sensor Tag。
最后,還是給出源代碼工程的下載鏈接:Link。最近OneDrive不能用,用微盤代替一下。