编写一个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!
结论
程序都已经调通,放心参考。