C#实现笔记本自带蓝牙与汇承HC-08(BLE)蓝牙模块通讯

问题背景

因最近新项目需要与蓝牙仪器通讯,起初以为很简单,搜索一下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的例子

程序思路

参考了以上的这些资料,低功耗蓝牙大致连接思路就有了。我们就按照我的调试程序倒推。
程序图

  1. 搜索蓝牙,我们选中我要通讯的蓝牙
  2. 匹配低功耗蓝牙(具体机制我也没研究 抱歉)
  3. 获取服务,选择需要使用的服务(比如HC-08模块ffe0那个就是读写用的)
  4. 获取特征,选择需要使用的特征(比如HC-08模块ffe1那个就是读写用的这两个估计都差不多应该是遵循协议走的)
  5. 获取操作,具体下面会细讲,获取之后你就可以知道你这个模块能读还是能写,可以进行操作了
  6. 最后才是发送和接收数据

大体就是这么个流程

难点介绍

借鉴别人的代码总是不会一帆风顺。

问题1平台和windows sdk 的组件

软件开发环境是WIN10+vs2019+Framework 4.7.2
因为使用到了windows sdk ,必须是win10下才能正常运行,根据之前大伙的方法,部分出现如下图问题缺SDK

我重新虚拟机安装的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

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vishera

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值