C# 实现BLE Client 程序与ardunioESP32 通信

news2024/11/22 15:03:48

编写一个C# Windows 桌面应用程序,与ardunio ESP32 Client 通信。

预备工作 

  • 建立一个项目
  • Nuget安装 Microsoft.Windows.SDK.Contracts
  • 右击引用菜单中点击:从 packages.config 迁移到 PackageReference
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection.Emit;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Linq;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.Advertisement;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
namespace BluetoothCleint
{
    public partial class Form1 : Form
    {
        public static BluetoothLEAdvertisementWatcher watcher;
        public static byte[] RxData;
        public static GattCharacteristic CHARACTERISTIC_UUID_RX;
        public static GattCharacteristic CHARACTERISTIC_UUID_TX;
        public bool isBleWrite = false;
        public Form1()
        {
            InitializeComponent();
        }

        private void Btn_Connection_Click(object sender, EventArgs e)
        {

          
            watcher = new BluetoothLEAdvertisementWatcher();
            watcher.Received += Watcher_Received;
            watcher.ScanningMode = BluetoothLEScanningMode.Active;
            text_status.Text = "0";
            text_channel.Text = "0";
           watcher.Start();
        }
        public  async void Watcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
        {
          
            bool isBleFind = false;
            var bleServiceUUIDs = args.Advertisement.ServiceUuids;
            

            foreach (var uuidone in bleServiceUUIDs)
            {
                
                if (uuidone.ToString() == "4fafc201-1fb5-459e-8fcc-c5c9c331914b")    
                {
                   
                    isBleFind = true;
                }
                if (isBleFind == true)
                {
                    watcher.Stop();
                    
                    BluetoothLEDevice dev = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);
                    GattDeviceServicesResult services = await dev.GetGattServicesForUuidAsync(new Guid("4fafc201-1fb5-459e-8fcc-c5c9c331914b"));
                    var characteristicsRx = await services.Services[0].GetCharacteristicsForUuidAsync(new Guid("beb5483e-36e1-4688-b7f5-ea07361b26a8"));
                    Console.WriteLine(characteristicsRx.Status);
                    CHARACTERISTIC_UUID_RX = characteristicsRx.Characteristics[0];
                    if (CHARACTERISTIC_UUID_RX.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Notify))
                    {
                        CHARACTERISTIC_UUID_RX.ValueChanged += CharacteristicBleDevice;
                        await CHARACTERISTIC_UUID_RX.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
                     //   isBleNotify = true;
                    }
                     var characteristicsTx = await services.Services[0].GetCharacteristicsForUuidAsync(new Guid("cba1d466-344c-4be3-ab3f-189f80dd7518"));
                    CHARACTERISTIC_UUID_TX = characteristicsTx.Characteristics[0];
                    if (CHARACTERISTIC_UUID_TX.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Write))
                    {
                        isBleWrite = true;
                        Console.WriteLine("isBleWrite");
                    } 
                    break;
                }
            }
        }



        public  void CharacteristicBleDevice(GattCharacteristic sender, GattValueChangedEventArgs eventArgs)
        {
            byte[] data = new byte[eventArgs.CharacteristicValue.Length];
            Windows.Storage.Streams.DataReader.FromBuffer(eventArgs.CharacteristicValue).ReadBytes(data);
           
            int KnobValue = (data[3] << 24) | (data[2] << 16) | (data[1]) << 8 | (data[0]);
            int ButtonValue = (data[7] << 24) | (data[6] << 16) | (data[5]) << 8 | (data[4]);
            Invoke(new Action(() => {
                text_channel.Text = KnobValue.ToString();
                text_status.Text = ButtonValue.ToString();
            }));
            
                return;
        }

        private async void Btn_write_Click(object sender, EventArgs e)
        {
            String WriteMessage = text_write.Text; 
            Console.WriteLine(WriteMessage);
            byte[] TXdata = System.Text.Encoding.UTF8.GetBytes(WriteMessage);
            if (isBleWrite == true)
            {
              await CHARACTERISTIC_UUID_TX.WriteValueAsync(TXdata.AsBuffer());
                Console.WriteLine("Writed To Device");

            }
        }
    }
}

界面

 

附:ardunio 代码

/*
    Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp
    Ported to Arduino ESP32 by Evandro Copercini
    updates by chegewara
*/

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
// Define the pins used for the encoder
const int encoderPinA = 11;
const int encoderPinB = 10;
volatile int encoderPosCount = 0;
int lastEncoded = 0;
int MAX = 60;
int channel = -1;
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID_1 "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define CHARACTERISTIC_UUID_2 "cba1d466-344c-4be3-ab3f-189f80dd7518"
BLEServer* pServer = NULL;
bool deviceConnected = false;
bool oldDeviceConnected = false;
//创建一个旋钮属性
BLECharacteristic KnobCharacteristic(
  CHARACTERISTIC_UUID_1,
  BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_INDICATE);
BLEDescriptor KnobDescriptor(BLEUUID((uint16_t)0x2902));

BLECharacteristic TextCharacteristic(
  CHARACTERISTIC_UUID_2,
  BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_INDICATE);
BLEDescriptor TextDescriptor(BLEUUID((uint16_t)0x2903));
int KnobValue = 100;
int ButtonValue = 1;
class MyCharacteristicCallbacks: public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic* pCharacteristic) {

    std::string value = pCharacteristic->getValue();  //接收值
    if (value.length() > 0) {
      Serial.println(value.c_str());
    }
  }
};
class MyServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) {
    deviceConnected = true;  // 客户端连接到服务器,状态为true
  };
  void onDisconnect(BLEServer* pServer) {
    deviceConnected = false;
  }

};

void setup() {
  Serial.begin(115200);
  while(!Serial);
  Serial.println("Starting BLE work!");
  // Set encoder pins as input with pull-up resistors
  pinMode(encoderPinA, INPUT_PULLUP);
  pinMode(encoderPinB, INPUT_PULLUP);

  // Attach interrupts to the encoder pins
  attachInterrupt(digitalPinToInterrupt(encoderPinA), updateEncoder, CHANGE);
  attachInterrupt(digitalPinToInterrupt(encoderPinB), updateEncoder, CHANGE);
  BLEDevice::init("ESP32_KNOB");
  pServer = BLEDevice::createServer();
  // 将 BLE 设备设置为服务器并分配回调函数
  pServer->setCallbacks(new MyServerCallbacks());


  BLEService* pService = pServer->createService(SERVICE_UUID);
  //Knob
  pService->addCharacteristic(&KnobCharacteristic);
  KnobDescriptor.setValue("Knob");
  KnobCharacteristic.addDescriptor(&KnobDescriptor);
  //Text
  pService->addCharacteristic(&TextCharacteristic);
  TextDescriptor.setValue("Text");
  TextCharacteristic.addDescriptor(&TextDescriptor);
  TextCharacteristic.setCallbacks(new MyCharacteristicCallbacks());    
  pService->start();

  BLEAdvertising* pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  // BLEDevice::startAdvertising();
  pServer->getAdvertising()->start();
  //Serial.println("Characteristic defined! Now you can read it in your phone!");
}

void loop() {
  static int lastReportedPos = -1;  // Store the last reported position
  byte buffer[8];
  if (deviceConnected) {
    if (encoderPosCount != lastReportedPos) {

      if ((encoderPosCount / 2) > channel) {
        if (channel < MAX)
          channel++;
      }
      if ((encoderPosCount / 2) < channel) {
        if (channel > 0)
          channel--;
      }
      lastReportedPos = encoderPosCount;
      ButtonValue++;
      memcpy(&buffer[0], &channel, 4);
      memcpy(&buffer[4], &ButtonValue, 4);
      KnobCharacteristic.setValue((uint8_t*)&buffer, 8);
      KnobCharacteristic.notify();
    }
  }
  // disconnecting
  if (!deviceConnected && oldDeviceConnected) {
    Serial.println("Device disconnected.");
    delay(500);
    pServer->startAdvertising();  // restart advertising
    Serial.println("Start advertising");
    oldDeviceConnected = deviceConnected;
  }
  // connecting
  if (deviceConnected && !oldDeviceConnected) {
    // do stuff here on connecting
    oldDeviceConnected = deviceConnected;
    Serial.println("Device Connected");
  }
  delay(200);
}
void updateEncoder() {

  int MSB = digitalRead(encoderPinA);      // MSB = most significant bit
  int LSB = digitalRead(encoderPinB);      // LSB = least significant bit
  int encoded = (MSB << 1) | LSB;          // Converting the 2 pin value to single number
  int sum = (lastEncoded << 2) | encoded;  // Adding it to the previous encoded value

  if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) {

    if (encoderPosCount == MAX) encoderPosCount = 0;
    else
      encoderPosCount++;
  }
  if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) {
    if (encoderPosCount == 0) encoderPosCount = MAX;
    else
      encoderPosCount--;
  }

  lastEncoded = encoded;  // Store this value for next time
}

Serial Monitor

20:59:08.133 -> Starting BLE work!
20:59:22.573 -> Device Connected
21:03:42.862 -> Starting BLE work!
21:03:45.937 -> Device Connected
21:37:32.842 -> Starting BLE work!
21:37:38.471 -> Device Connected
21:37:51.608 -> On Write
21:37:51.608 -> Hello The World!

结论

程序都已经调通,放心参考。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2244483.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【c++丨STL】stack和queue的使用及模拟实现

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;C、STL 目录 前言 一、什么是容器适配器 二、stack的使用及模拟实现 1. stack的使用 empty size top push和pop swap 2. stack的模拟实现 三、queue的…

MyBatis-Plus分页插件IPage用法

首先就是service接口需要继承IService<entity> 然后就是业务类实现类中需要继承ServiceImpl<Mapper,entity> Mapper正常写法&#xff0c;继承baseMapepr<entity> IPage的使用方式 QueryWrapper<MdSaleDayPhone> queryWrappernew QueryWrapper<>…

基于阿里云服务器部署静态的website

目录 一&#xff1a;创建服务器实例并connect 二&#xff1a;本地文件和服务器share 三&#xff1a;关于IIS服务器的安装预配置 四&#xff1a;设置安全组 五&#xff1a;建站流程 六&#xff1a;关于备案 一&#xff1a;创建服务器实例并connect 创建好的服务器实例在云…

Android Studio 设置不显示 build-tool 无法下载

2024版本查看build-tool版本 File -> Settings -> Languages & Frameworks -> Android SDK 或者直接打开Settings后搜索“SDK” 解决方案 将 Android Studio 升级到2022.2.1以上的版本将 C:/Windows/System32/drivers/etc/hosts 文件用管理员身份打开&#xff0c…

【JavaSE】【网络编程】UDP数据报套接字编程

目录 一、网络编程简介二、Socket套接字三、TCP/UDP简介3.1 有连接 vs 无连接3.2 可靠传输 vs 不可靠传输3.3 面向字节流 vs 面向数据报3.4 双向工 vs 单行工 四、UDP数据报套接字编程4.1 API介绍4.1.1 DatagramSocket类4.1.1.1 构造方法4.1.1.2 主要方法 4.1.2 DatagramPocket…

MFC图形函数学习10——画颜色填充矩形函数

一、介绍绘制颜色填充矩形函数 前面介绍的几个绘图函数填充颜色都需要专门定义画刷&#xff0c;今天介绍的这个函数可以直接绘制出带有填充色的矩形。 原型1&#xff1a;void FillSolidRect(int x,int y,int cx,int cy,COLORREF color); 参数&#xff1a;&a…

macOS 无法安装第三方app,启用任何来源的方法

升级新版本 MacOS 后&#xff0c;安装下载的软件时&#xff0c;不能在 ”安全性与隐私” 中找不到 ”任何来源” 选项。 1. 允许展示任何来源 点击 启动器 (Launchpad) – 其他 (Other) – 终端 (Terminal)&#xff1a; 打开终端后&#xff0c;输入以下代码回车&#xff1a; …

基于“开源 2+1 链动模式 S2B2C 商城小程序”的社区团购运作主体特征分析

摘要&#xff1a;本文聚焦社区团购运作主体&#xff0c;深入探讨便利连锁店型与社会力量型运作主体在社区团购中的特点&#xff0c;并结合“开源 21 链动模式 S2B2C 商城小程序”&#xff0c;分析其对社区团购的影响与作用机制&#xff0c;旨在为社区团购的进一步发展与优化提供…

Properties文件:Properties属性文件键值对的获取方法、如何写入信息到Properties属性文件、Properties对象的用法

目录 1、什么是Properties文件&#xff1f;和普通txt文件有什么区别&#xff1f; 2、读写Properties文件 2.1 代码演示-读取属性文件 2.2、代码演示-把键值对的数据写入到属性文件中去 1、什么是Properties文件&#xff1f;和普通txt文件有什么区别&#xff1f; 我们都知道…

枫清科技亮相 2024 中国 5G+工业互联网大会,推动 AI 赋能新型工业化

11 月 19 日&#xff0c;2024 中国 5G工业互联网大会在武汉盛大开幕&#xff0c;吸引了来自国内外的行业专家与领先企业。本次大会以“实数融合 智造翘楚”为主题&#xff0c;重点围绕 5G 与工业互联网的深度融合应用、人工智能、智能网联汽车等领域展开讨论与成果展示。作为行…

Spring Boot 3.x + OAuth 2.0:构建认证授权服务与资源服务器

Spring Boot 3.x OAuth 2.0&#xff1a;构建认证授权服务与资源服务器 前言 随着Spring Boot 3的发布&#xff0c;我们迎来了许多新特性和改进&#xff0c;其中包括对Spring Security和OAuth 2.0的更好支持。本文将详细介绍如何在Spring Boot 3.x版本中集成OAuth 2.0&#xf…

使用Python编写脚本,为Excel表格添加水印

简介 这是本人实习中的一个小任务&#xff0c;经过无数努力&#xff0c;终于搞出来了。网上很多资料和博客都是lese&#xff0c;完全没有理清楚水印在excel中的定义是什么&#xff0c;插个图片就是水印吗&#xff1f;当然不是&#xff01;如果帮助到佬们请点个赞吧。 Ecxel中…

MacOS下的Opencv3.4.16的编译

前言 MacOS下编译opencv还是有点麻烦的。 1、Opencv3.4.16的下载 注意&#xff0c;我们使用的是Mac&#xff0c;所以ios pack并不能使用。 如何嫌官网上下载比较慢的话&#xff0c;可以考虑在csdn网站上下载&#xff0c;应该也是可以找到的。 2、cmake的下载 官网的链接&…

jspm东风锻造有限公司重大停管理系统

摘要 东风锻造有限公司重大停管理系统提供给员工和经理一个重大停信息管理的系统。本系统采用了B/S体系的结构&#xff0c;使用了java技术以及MYSQL作为后台数据库进行开发。系统主要分为系统管理员&#xff0c;员工和经理三个部分&#xff0c;系统管理员主要功能包括个人中心…

list =和addAll在List<实体类>数组的应用

实体类 A public class A {private String name;private Integer age;public String getName() {return name;}public void setName(String name) {this.name name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age age;} }用会报错 publi…

探索设计模式:原型模式

设计模式之原型模式 &#x1f9d0;1. 概念&#x1f3af;2. 原型模式的作用&#x1f4e6;3. 实现1. 定义原型接口2. 定义具体的原型类3. 定义客户端4. 结果 &#x1f4f0; 4. 应用场景&#x1f50d;5. 深拷贝和浅拷贝 在面向对象编程中&#xff0c;设计模式是一种通用的解决方案…

多目标优化算法:多目标极光优化算法(MOPLO)求解ZDT1、ZDT2、ZDT3、ZDT4、ZDT6,提供完整MATLAB代码

一、极光优化算法 极光优化算法&#xff08;Polar Lights Optimization, PLO&#xff09;是2024年提出的一种新型的元启发式优化算法&#xff0c;它从极光这一自然现象中汲取灵感。极光是由太阳风中的带电粒子在地球磁场的作用下&#xff0c;与地球大气层中的气体分子碰撞而产…

FPGA实现PCIE3.0视频采集转SFP光口千兆UDP网络输出,基于XDMA+GTH架构,提供2套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目我已有的PCIE方案1G/2.5G Ethernet Subsystem实现物理层方案1G/2.5G Ethernet PCS/PMA or SGMII Tri Mode Ethernet MAC实现物理层方案本博客方案的PCIE2.0版本 3、P…

40分钟学 Go 语言高并发:开发环境搭建与工程化实践

Day 01 - Go开发环境搭建与工程化实践 1. Go环境变量配置 1.1 重要的环境变量表格 环境变量说明示例值GOROOTGo语言安装根目录Windows: C:\goLinux/Mac: /usr/local/goGOPATH工作目录&#xff0c;包含src、pkg、binWindows: C:\Users\username\goLinux/Mac: ~/goGOBIN可执行…

【Mysql】函数-----窗口函数

1、介绍 Mysql 8.0 新增了窗口函数&#xff0c;窗口函数又被称为开窗函数&#xff0c;与orcale窗口函数相似&#xff0c;属于Mysql的一大特点。非聚合函数是相对于聚合函数来说的。聚合函数是一组数据计算后返回单个值&#xff08;即分组&#xff09;。非聚合函数一次只会处理…