汇承HC-08蓝牙C#通讯 目录
问题背景
因最近新项目需要与蓝牙仪器通讯,起初以为很简单,搜索一下C#蓝牙都是调用InTheHand.Net这个第三方库,但是采购的时HC-08模块,低功耗模块。发现无法使用这个库,网上资料也很少,客服给了安卓手机调试软件,但对Windows桌面也不是很懂,但是给了个win10应用商店,(最后我发现这个应用里管这叫BLE模块,汗…也是涨姿势了)。本着既然手机和安卓都能通讯的原则,我想肯定笔记本能与蓝牙模块通讯上,就开始头秃般的研究了…
感谢
我喜欢把感谢放在前面,互联网就是应该互相学习帮助!感谢这几位大师和微软的库,基本解决了当前的问题,附出来供大家参考少走弯路。
BLE介绍
具体不介绍了,总结下就是对安卓等手机便携端很友好,电脑端可能没人去弄,有兴趣看看
感谢SamSamCai
BLE入门https://blog.csdn.net/ccslff/article/details/51599148
参考代码
Jerrt-J C# BLE蓝牙开发之使用Windows.Devices.Bluetooth获取小米体重秤的体重(特别感谢)
【https://blog.csdn.net/flj135792468/article/details/115480703】
code_long C# ble 4.0 低能耗 蓝牙交互 (特别特别感谢)
【https://blog.csdn.net/code_long/article/details/105636398】
美渊科技 Win10 平台C#与低功耗蓝牙BLE设备通信案例(特别感谢)
【https://blog.csdn.net/shengfakun1234/article/details/110928783】
鞪林 windows BLE编程 net winform 连接蓝牙4.0
【https://www.cnblogs.com/webtojs/p/9675956.html】
A_DUO C#控制台使用低功耗蓝牙BLE进行多设备通信小结(解决了一些细节问题)
【https://blog.csdn.net/A_DUO/article/details/92841314】
参考业务逻辑
艾希红红 C# ble 低功耗蓝牙读写 C#蓝牙(桌面应用)
【https://www.jianshu.com/p/0151c2bacb66】
肖邦kaka 蓝牙BLE(BlueTooth BLE)入门及爬坑指南
【https://www.jianshu.com/p/d991f0fdec63】
WCH_SoftGroup Windows端用于开发低功耗蓝牙项目的DLL
【https://blog.csdn.net/WCH_TechGroup/article/details/103778978】(一)
【https://blog.csdn.net/WCH_TechGroup/article/details/103892909】(二)
丶麦芽 低功耗蓝牙Ble的详细使用流程
【https://www.jianshu.com/p/3d4bfdc72384】
参考库和例程
感谢微软相关库
【https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth?view=winrt-19041】WIN10蓝牙库
【https://docs.microsoft.com/zh-cn/windows/uwp/devices-sensors/gatt-client】蓝牙业务逻辑
【https://docs.microsoft.com/en-us/windows/win32/api/bluetoothleapis/nf-bluetoothleapis-bluetoothgattgetcharacteristics】C++头
【https://github.com/microsoft/Windows-universal-samples/tree/b1cb20f191d3fd99ce89df50c5b7d1a6e2382c01/Samples/BluetoothLE】官方例程
【https://github.com/kaka10xiaobang/BlueToothBLE】kaka10xiaobang的例子
程序思路
参考了以上的这些资料,低功耗蓝牙大致连接思路就有了。我们就按照我的调试程序倒推。
- 搜索蓝牙,我们选中我要通讯的蓝牙
- 匹配低功耗蓝牙(具体机制我也没研究 抱歉)
- 获取服务,选择需要使用的服务(比如HC-08模块ffe0那个就是读写用的)
- 获取特征,选择需要使用的特征(比如HC-08模块ffe1那个就是读写用的这两个估计都差不多应该是遵循协议走的)
- 获取操作,具体下面会细讲,获取之后你就可以知道你这个模块能读还是能写,可以进行操作了
- 最后才是发送和接收数据
大体就是这么个流程
难点介绍
借鉴别人的代码总是不会一帆风顺。
问题1平台和windows sdk 的组件
软件开发环境是WIN10+vs2019+Framework 4.7.2
因为使用到了windows sdk ,必须是win10下才能正常运行,根据之前大伙的方法,部分出现如下图问题
我重新虚拟机安装的win10+vs2017没有出现此问题,但我的笔记本WIN10教育+VS2019出现了此问题,我直接把C盘的.winmd拷贝出来直接浏览,就能添加
这里也要修改下别忘了
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<TargetPlatformVersion>10.0</TargetPlatformVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
问题2优化速度和更改同步
感谢 美渊科技,基本就是按照他的《Win10 平台C#与低功耗蓝牙BLE设备通信案例》来的
修改发现设备慢
public void StartBleDeviceWatcher()
{
watcher = new BluetoothLEAdvertisementWatcher();
watcher.ScanningMode = BluetoothLEScanningMode.Active;
// only activate the watcher when we're recieving values >= -80
watcher.SignalStrengthFilter.InRangeThresholdInDBm = -80;
// stop watching if the value drops below -90 (user walked away)
watcher.SignalStrengthFilter.OutOfRangeThresholdInDBm = -90;
// register callback for when we see an advertisements
watcher.Received += OnAdvertisementReceived;
// wait 5 seconds to make sure the device is really out of range
watcher.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(5000);
watcher.SignalStrengthFilter.SamplingInterval = TimeSpan.FromMilliseconds(2000);
// starting watching for advertisements
watcher.Start();
string msg = "自动发现设备中..";
this.MessAgeChanged(MsgType.NotifyTxt, msg);
}
private void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
BluetoothLEDevice.FromBluetoothAddressAsync(eventArgs.BluetoothAddress).Completed = async (asyncInfo, asyncStatus) =>
{
if (asyncStatus == AsyncStatus.Completed)
{
if (asyncInfo.GetResults() == null)
{
//this.MessAgeChanged(MsgType.NotifyTxt, "没有得到结果集");
}
else
{
BluetoothLEDevice currentDevice = asyncInfo.GetResults();
Boolean contain = false;
foreach (BluetoothLEDevice device in DeviceList)//过滤重复的设备
{
if (device.DeviceId == currentDevice.DeviceId)
{
contain = true;
}
}
if (!contain)
{
byte[] _Bytes1 = BitConverter.GetBytes(currentDevice.BluetoothAddress);
Array.Reverse(_Bytes1);
this.DeviceList.Add(currentDevice);
this.MessAgeChanged(MsgType.NotifyTxt, "发现设备:" + currentDevice.Name + " address:" + BitConverter.ToString(_Bytes1, 2, 6).Replace('-', ':').ToLower());
this.DeviceWatcherChanged(MsgType.BleDevice, currentDevice);
}
}
}
};
}
修改获取服务码和特征码同步,另外为了方便加了筛选HC-08的码,如果要更换模块需要对应修改
/// <summary>
/// 获取蓝牙服务
/// </summary>
public async void FindService()
{
this.CurrentDevice.GetGattServicesAsync().Completed = async (asyncInfo, asyncStatus) =>
{
if (asyncStatus == AsyncStatus.Completed)
{
var services = asyncInfo.GetResults().Services;
this.MessAgeChanged(MsgType.NotifyTxt, "GattServices size=" + services.Count);
foreach (GattDeviceService ser in services)
{
this.GattDeviceServiceAdded(ser);
}
}
};
}
/// <summary>
/// 获取特性
/// </summary>
// [Obsolete]
public async void FindCharacteristic(GattDeviceService gattDeviceService)
{
gattDeviceService.GetCharacteristicsAsync().Completed = async (asyncInfo, asyncStatus) =>
{
// gattDeviceService.GetCharacteristicsAsync();
if (asyncStatus == AsyncStatus.Completed)
{
var character = asyncInfo.GetResults().Characteristics;
this.MessAgeChanged(MsgType.NotifyTxt, "GattCharacteristics size=" + character.Count);
foreach (GattCharacteristic c in character)
{
this.CharacteristicAdded(c);
}
this.MessAgeChanged(MsgType.NotifyTxt, "获取特征码收集完毕");
}
};
}
对应窗体事件修改
/// <summary>
/// 获取蓝牙服务列表
/// </summary>
private void BleCore_GattDeviceServiceAdded(Windows.Devices.Bluetooth.GenericAttributeProfile.GattDeviceService gattDeviceService)
{
RunAsync(() =>
{
try
{
this.cmbServer.Items.Add(gattDeviceService.Uuid.ToString());
//提高效率 匹配到HC08服务码
if (cmbServer.SelectedIndex == -1)
{
if (gattDeviceService.Uuid.ToString().Substring(4, 4) == "ffe0")
{
cmbServer.SelectedIndex = cmbServer.Items.IndexOf(gattDeviceService.Uuid.ToString());
}
}
this.GattDeviceServices.Add(gattDeviceService);
this.btnFeatures.Enabled = true;
}
catch
{ }
});
}
/// <summary>
/// 获取特征列表
/// </summary>
private void BleCore_CharacteristicAdded(Windows.Devices.Bluetooth.GenericAttributeProfile.GattCharacteristic gattCharacteristic)
{
RunAsync(() =>
{
try
{
this.cmbFeatures.Items.Add(gattCharacteristic.Uuid);
//同理提高效率 匹配到HC08特征码
if (cmbFeatures.SelectedIndex == -1)
{
if (gattCharacteristic.Uuid.ToString().Substring(4, 4) == "ffe1")
{
cmbFeatures.SelectedIndex = cmbFeatures.Items.IndexOf(gattCharacteristic.Uuid);
}
}
this.GattCharacteristics.Add(gattCharacteristic);
this.btnOpteron.Enabled = true;
}
catch
{ }
});
}
问题3蓝牙模块获取操作
这一步自己研究了许多资料,发现不同的模块获取的内容不同,之前几位博主没有很详细的介绍操作获取,其实这反映了这个蓝牙模块的功能(用户能对它进行什么样的操作),期初只能粗暴加断点调试出来。
/// <summary>
/// 获取操作
/// </summary>
/// <returns></returns>
public async Task SetOpteron(GattCharacteristic gattCharacteristic)
{
byte[] _Bytes1 = BitConverter.GetBytes(this.CurrentDevice.BluetoothAddress);
Array.Reverse(_Bytes1);
this.CurrentDeviceMAC = BitConverter.ToString(_Bytes1, 2, 6).Replace('-', ':').ToLower();
string msg = "正在连接设备<" + this.CurrentDeviceMAC + ">..";
this.MessAgeChanged(MsgType.NotifyTxt, msg);
if (gattCharacteristic.CharacteristicProperties == GattCharacteristicProperties.Write)
{
this.CurrentWriteCharacteristic = gattCharacteristic;
}
if (gattCharacteristic.CharacteristicProperties == GattCharacteristicProperties.Notify)
{
this.CurrentNotifyCharacteristic = gattCharacteristic;
}
if ((uint)gattCharacteristic.CharacteristicProperties == 26)
{
}
//这里是难点 返回一个enum枚举
if (gattCharacteristic.CharacteristicProperties == (GattCharacteristicProperties.Write | GattCharacteristicProperties.Notify))
{
this.CurrentWriteCharacteristic = gattCharacteristic;
this.CurrentNotifyCharacteristic = gattCharacteristic;
this.CurrentNotifyCharacteristic.ProtectionLevel = GattProtectionLevel.Plain;
this.CurrentNotifyCharacteristic.ValueChanged += Characteristic_ValueChanged;
this.CurrentDevice.ConnectionStatusChanged += this.CurrentDevice_ConnectionStatusChanged;
await this .EnableNotifications(CurrentNotifyCharacteristic);
}
if (gattCharacteristic.CharacteristicProperties == (GattCharacteristicProperties.Notify | GattCharacteristicProperties.Read | GattCharacteristicProperties.WriteWithoutResponse))
{
this.CurrentWriteCharacteristic = gattCharacteristic;
this.CurrentNotifyCharacteristic = gattCharacteristic;
this.CurrentNotifyCharacteristic.ProtectionLevel = GattProtectionLevel.Plain;
this.CurrentNotifyCharacteristic.ValueChanged += Characteristic_ValueChanged;
await this.EnableNotifications(CurrentNotifyCharacteristic);
}
}
加断点我们看到,汇承-08模块获取到的操作是Read |Notify |WriteWithoutResponse,并不是单单的Write
所以实际应用要在这里进行修改。
问题4
剩下因为时间原因,没有解决一部分的警告和数据richTextBox上显示,所以你点击数据收发,功能没有做。
分享测试程序
开发不易,程序给大家参考 源代码就斗胆支持下博主。
调试程序
https://download.csdn.net/download/Vishera/18593913
欢迎指导
源代码
https://download.csdn.net/download/Vishera/18595325