基于C#使用WPF开发的低功耗蓝牙调试助手,使用C#调用win10SDK操作笔记本,台式电脑上的蓝牙发送接收数据
上截图先看一下,有一个换肤的功能
左边显示的是当前连接中的蓝牙,蓝牙的服务与特征会全部显示,中间是运行日志,右边是一个配置文件窗口,可以存一些常用的指令。
暗色
亮色
需要基于WIN10SDK,需要在NuGet里面搜索下图红框的东西,网上说只有win10才支持低功耗蓝牙。
讲一下蓝牙的大概把,每一个蓝牙设备里面会有服务,服务里面会有一些叫特征的东西,一个蓝牙设备会有多个服务,然后每一个服务里面呢,又会有多个特征。
每一个特征会又一些属性,当然这些属性都是定义在了蓝牙设备的蓝牙芯片里面,不知道我说得对不对。每一个服务跟特征都有一个叫UUID的东西,这个UUID都是看自定义的,当然我们肯定不能改他。它反映到c#里面就是一个GUID。具体的可以参考这个连接
网上其他大神发的关于c#操作蓝牙实例都是很多的代码 看着头大。我就尽量通俗易懂的话来简单的带领大家入门。不懂可以加我+q 11656012,
首先想要控制蓝牙发送接收数据肯定得要一个蓝牙对象把,就跟我们使用串口收发数据得用到SerialPort类,这个蓝牙对象叫BluetoothLEDevice,如下图
怎么获取这个蓝牙对象呢。我目前了解到有两种方式,我就说一种在微软官方文档里面推荐的一种。它需要用另外一个类,叫做DeviceWatcher,如下图
这个类怎么使用的呢,肯定不能通过new来得到,所以这个时候又会用到另外一个类叫做DeviceInformation,如下图
使用方法如下
private DeviceWatcher DeviceWatcher; public WatcherViewModel() { string[] requestedProperties = { "System.Devices.Aep.IsConnected", "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.Bluetooth.Le.IsConnectable", "System.Devices.Aep.SignalStrength", "System.Devices.Aep.IsPresent" }; DeviceWatcher = DeviceInformation.CreateWatcher( BluetoothLEDevice.GetDeviceSelectorFromPairingState(false), requestedProperties, DeviceInformationKind.AssociationEndpoint); DeviceWatcher.Added += DeviceWatcher_Added; DeviceWatcher.Updated += DeviceWatcher_Updated; DeviceWatcher.Removed += DeviceWatcher_RemoStoppedved; DeviceWatcher.Stopped += DeviceWatcher_Stopped; }
调用DeviceInformation.CreateWatcher()方法会返回一个DeviceWatcher 对象,需要给这个CreateWatcher()方法传入三个参数,这三个参数目前可以不用管什么意思。因为我也不太清楚,照抄就行,这些参数可以理解为电脑对搜索到蓝牙设备的时候对它的过滤规则。我目前还没搞懂这个规则是怎么样子的,以至于现在的调试助手不能像电脑系统设置里添加蓝牙页面里面搜到的设备一样,目前只能搜到正在广播的设备。有时候还能搜到一些莫名奇妙的蓝牙。什么摩拜单车,没有名字的蓝牙啥的。主要我们就拿到一个用于获取蓝牙设备的对象了。
介绍完怎么获取DeviceWatcher对象之后,我们我们看到上面的代码的下面还订阅了DeviceWatcher对象的四个事件,分别的是Added,Updated,Removed,Stopped,稍后就解释一下这四个事件什么意思。
我们在拿到DeviceWatcher对象之后,就需要调用它的Start方法,才能开始搜索(官方话就做枚举)。当然它也有一个Stop方法。在调用Start方法之后,就会开始搜索了,我们必须在调用Start方法之前订阅这些事件。
下面我着重介绍这个Added事件(因为主要靠他),我们可以理解为每搜索到一个设备就会触发一次Added事件,然后这个事件它有一个事件参数,类型是DeviceInformation类型的,没错这个类型也是用来创建DeviceWatcher对象的那个类。
这个类可以理解为就是代表搜到的设备的基本参数,如下图为DeviceInformation类的全貌,重点在红框内的东西,我们主要用到的是它的 Id 这个属性。你看上面它还有一些方法,看名字都是用来获取一些DeviceInformation集合的。
在真实情况中是很多设备的,所以这个时候Added事件会触发很多次,但是可能会出现相同的mac地址的设备会触发这个事件(这是我这边遇到的),所以需要自己维护一个设备列表。出现了重复的设备就直接return,靠这个Id属性来辨识。
然后就是Updated事件,这个事件触发之后会带着一个DeviceInformationUpdate对象,我们看名字就知道它是一个更新的信息,比如信号的强弱。
Removed事件,就是在设备消失的时候,这个事件会触发,事件参数里面回携带是哪个设备,都是靠里面的id属性。
回到前面,怎么获取一个蓝牙对象。一句话:就是通过这个Added事件的事件参数传过来的DeviceInformation对象里面的Id属性。
用法如下:
先向上看图,就是通过BluetoothLEDevice的静态方法FromIdAsync,这是个异步方法,返回一个异步操作,在异步的结果里面就是我们要的BluetoothLEDevice对象。通过传入DeviceInformation对象里面的Id属性来获得,你看它里面还有两中方法可以用。可以自己试一试。
现在拿到了BluetoothLEDevice对象就好办了,一般在拿到蓝牙设备对象之后第一个就是先 获取服务,调用BluetoothLEDevice.GetGattServicesAsync()方法。这是一个异步方法,也是返回一个异步操作,在异步的结果里面是一个GattDeviceServicesResult对象,如下图
着重看那个Services属性。它是一个GattDeviceService类型的一个集合对象。蓝牙里面的每一个服务都是一个GattDeviceService对象。来看一下GattDeviceService里面有哪些成员
你看底下的几个属性,有代表这个服务的UUID,属于哪个蓝牙设备的Device,还有几个其他的,自己研究把,对于目前来说,其他的不重要。
当我们获取到了某一个服务之后,我们需要再调用这个服务的GetCharacteristicsAsync()方法来获取服务里面的特征,这也是一个异步的,也是返回一个异步操作,异步的结果是一个GattCharacteristicsResult类型,下面是GattCharacteristicsResult类型的成员,
着重看里面的第一个属性Characteristics,它是一个GattCharacteristic类型的一个集合,服务里面的每一个特征都是一个GattCharacteristic对象,
我们来看看GattCharacteristic对象里面的成员
你看它里面有一些ReadValueAsync(); WriteValueAsync(IBuffer value); 这样的一些方法。我们通过调用这写方法,就可以跟蓝牙设备通讯啦。
具体怎么写,怎么读,直接看代码吧。
github: shijianoo/BluetoothLEAssistant (github.com)
如果是在net framework项目上安装了win10sdk包之后还是无法引用的话,需要在你的项目上右键然后点击 (从 packages.config 迁移到 PackageReference)
这个低功耗蓝牙通讯不同于常见的socket或者串口通讯他们都有输入输出缓冲区,都提供对应的read跟write方法。在低功耗蓝牙通讯里面都是对 Characteristics 进行操作,一般写入就是调用对应的WriteValue方法,它有几个重载,可以自己用合适的。发送数据用WriteValue,那接收数据呢?大部分情况(我所遇见的)就是订阅 Characteristics 里面的 ValueChanged 这个事件。这个事件什么时候触发?那就是当硬件那边收到我们写过去的数据之后,他如果想给我们返回数据,他们那边可能也会调用一些api,传入数据。这个时候我们这边的这个事件就会触发,这样我们就接收到返回的数据了。