HonestQiao 发表于 2024-5-18 23:33

【Beetle ESP32 C6迷你开发板】低功耗蓝牙(BLE)功能初步使用

<div class='showpostmsg'> 本帖最后由 HonestQiao 于 2024-5-21 18:50 编辑

<p><strong>一、BLE功能了解</strong></p>

<p>ESP32-C6搭载160MHz的高性能RISC-V 32位处理器,支持Wi-Fi 6、Bluetooth 5、Zigbee 3.0、Thread 1.3通讯协议,可接入多种通讯协议的物联网网络。</p>

<p>其中的Bluetooth 5,是蓝牙标准第5代,和Bluetooth 4对比如下:</p>

<p>&nbsp; 从上面的对比可以看到,Bluetooth 5比Bluetooth 4提升了一大截。</p>

<p>&nbsp;</p>

<p>乐鑫的esp-idf,也为ESP32-C6提供了完善的低功耗蓝牙(BLE)支持能力。</p>

<p>&nbsp;</p>

<p><strong>二、BLE扫描功能使用</strong></p>

<p>为了方便分享,本篇分享的实例,使用了友好的Arduino开发平台。</p>

<p>在Arduino的ESP32支持库Arduino-ESP32中,有BLE能力的支持库:<a href="https://github.com/espressif/arduino-esp32/tree/master/libraries/BLE" target="_blank">https://github.com/espressif/arduino-esp32/tree/master/libraries/BLE</a></p>

<p>BLE的扫描功能,主要用于设备发现,通过周边BLE设备的广播信息,获取BLE设备的基础信息。</p>

<p>&nbsp;</p>

<p>要使用设备发现功能,首先需要调用几个关键的库文件:</p>

<pre>
<code class="language-cpp">#include &lt;BLEDevice.h&gt;
#include &lt;BLEUtils.h&gt;
#include &lt;BLEScan.h&gt;
#include &lt;BLEAdvertisedDevice.h&gt;</code></pre>

<p>上面的库文件,提供了BLE基本功能支持,扫描功能支持,和设备广播信息支持。</p>

<p>&nbsp;</p>

<p>然后实例化一个BLE设备对象:</p>

<pre>
<code class="language-cpp">BLEScan *pBLEScan;</code></pre>

<p>在开启扫描功能:</p>

<pre>
<code class="language-cpp">pBLEScan = BLEDevice::getScan();//create new scan
pBLEScan-&gt;setActiveScan(true);//active scan uses more power, but get results faster
pBLEScan-&gt;setInterval(100);
pBLEScan-&gt;setWindow(99);// less or equal setInterval value</code></pre>

<p>同时,还要设置一个广播信息获取后的回调,以便把扫描到的BLE谁被信息输出,具体如下:</p>

<pre>
<code>class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
    Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
}
};


pBLEScan-&gt;setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());</code></pre>

<p>上面代码中,定一个基类BLEAdvertisedDeviceCallbacks的类MyAdvertisedDeviceCallbacks,其中的onResult用于接收扫描到的设备信息。</p>

<p>&nbsp;</p>

<p>然后,启动扫描功能即可进行扫描和输出信息:</p>

<pre>
<code class="language-cpp">BLEScanResults *foundDevices = pBLEScan-&gt;start(5, false);
Serial.println(foundDevices-&gt;getCount()); // 获取扫描到的BLE设备数量
pBLEScan-&gt;clearResults();// 清理扫描结果</code></pre>

<p>&nbsp;</p>

<p>完整的代码如下:</p>

<pre>
<code class="language-cpp">/*
   Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
   Ported to Arduino ESP32 by Evandro Copercini
*/

#include &lt;BLEDevice.h&gt;
#include &lt;BLEUtils.h&gt;
#include &lt;BLEScan.h&gt;
#include &lt;BLEAdvertisedDevice.h&gt;

int scanTime = 5;//In seconds
BLEScan *pBLEScan;

class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
    Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
}
};

void setup() {
Serial.begin(115200);
Serial.println("Scanning...");

BLEDevice::init("");
pBLEScan = BLEDevice::getScan();//create new scan
pBLEScan-&gt;setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan-&gt;setActiveScan(true);//active scan uses more power, but get results faster
pBLEScan-&gt;setInterval(100);
pBLEScan-&gt;setWindow(99);// less or equal setInterval value
}

void loop() {
// put your main code here, to run repeatedly:
BLEScanResults *foundDevices = pBLEScan-&gt;start(scanTime, false);
Serial.print("Devices found: ");
Serial.println(foundDevices-&gt;getCount());
Serial.println("Scan done!");
pBLEScan-&gt;clearResults();// delete results fromBLEScan buffer to release memory
delay(2000);
}</code></pre>

<p>&nbsp;</p>

<p>在Arduino中,按照下面的设置,进行编译烧录:</p>

<p> &nbsp;</p>

<p>烧录后,打开串口监控,可以看到扫描输出信息:</p>

<p>&nbsp; 上面输出中的L4260,就是我家打印机了。</p>

<p>&nbsp;</p>

<p><strong>三、BLE UART功能使用</strong></p>

<p>BLE设备可以通过GATT的GAP定义自身的角色,例如:外围设备(Peripheral)和中心设备(Central)。</p>

<p>GATT 是一个在蓝牙连接之上的发送和接收很短的数据段的通用规范。</p>

<p>GAP定义了设备如何彼此发现、建立连接以及如何实现绑定,同时描述了设备如何成为广播者和观察者,并且实现无需连接的传输。GAP 使你的设备被其他设备可见,并决定了你的设备是否可以或者怎样与合同设备进行交互。</p>

<p>当做为外围设备(Peripheral),可以对外发布自身能够提供的服务。其中,最常见的一项服务是UART服务,可以通过低功耗蓝牙,实现乐思串口通讯的能力。UART服务最早是Nordic Semiconductor 的&nbsp;BLE 模组提供的自定义服务Nordic UART Service,现在只要遵循其标准定义,那么都可以提供该服务。</p>

<p>&nbsp;</p>

<p>通过BLE对外提供服务,主要需要定义服务(Service) 和 标签(Characteristic),以便告知其他设备,自己能够提供的服务和具体的功能:</p>

<p> &nbsp;</p>

<p>&nbsp;</p>

<p>而在UART服务中,Service包含两个Characteristic,一个被配置只读的通道(RX),另一个配置为只写的通道(TX)。</p>

<p>通常情况下,Service和Characteristic都是一个UUID,UART对应的如下:</p>

<ul>
        <li>UART Service:6E400001-B5A3-F393-E0A9-E50E24DCCA9E</li>
        <li>RX标签:6E400002-B5A3-F393-E0A9-E50E24DCCA9E,表示可以从该标签接收到信息</li>
        <li>TX标签:6E400003-B5A3-F393-E0A9-E50E24DCCA9E ,表示可以向改标签写入信息</li>
</ul>

<p>&nbsp;</p>

<p>要在ESP32-C6上提供UART 服务,需要按照以下的步骤进行:</p>

<ol>
        <li>&nbsp; &nbsp;创建BLE服务端</li>
        <li>&nbsp; &nbsp;创建BLE服务</li>
        <li>&nbsp; &nbsp;创建BLE服务对应的标签</li>
        <li>&nbsp; &nbsp;设置标签对应的描述信息</li>
        <li>&nbsp; &nbsp;启动服务</li>
        <li>&nbsp; &nbsp;启动广播</li>
</ol>

<p>参考官方的实例,测试代码如下:</p>

<pre>
<code class="language-cpp">#include &lt;BLEDevice.h&gt;
#include &lt;BLEServer.h&gt;
#include &lt;BLEUtils.h&gt;
#include &lt;BLE2902.h&gt;

BLEServer *pServer = NULL;
BLECharacteristic *pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint8_t txValue = 0;

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID         "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"// UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

class MyServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer *pServer) {
    deviceConnected = true;
};

void onDisconnect(BLEServer *pServer) {
    deviceConnected = false;
}
};

class MyCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
    String rxValue = pCharacteristic-&gt;getValue();

    if (rxValue.length() &gt; 0) {
      Serial.println("*********");
      Serial.print("Received Value: ");
      for (int i = 0; i &lt; rxValue.length(); i++) {
      Serial.print(rxValue);
      }

      Serial.println();
      Serial.println("*********");
    }
}
};

void setup() {
Serial.begin(115200);

// Create the BLE Device
BLEDevice::init("ESP32-C6 UART Service");

// Create the BLE Server
pServer = BLEDevice::createServer();
pServer-&gt;setCallbacks(new MyServerCallbacks());

// Create the BLE Service
BLEService *pService = pServer-&gt;createService(SERVICE_UUID);

// Create a BLE Characteristic
pTxCharacteristic = pService-&gt;createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY);

pTxCharacteristic-&gt;addDescriptor(new BLE2902());

BLECharacteristic *pRxCharacteristic = pService-&gt;createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE);

pRxCharacteristic-&gt;setCallbacks(new MyCallbacks());

// Start the service
pService-&gt;start();

// Start advertising
pServer-&gt;getAdvertising()-&gt;start();
Serial.println("Waiting a client connection to notify...");
}

void loop() {

if (deviceConnected) {
    pTxCharacteristic-&gt;setValue(&amp;txValue, 1);
    pTxCharacteristic-&gt;notify();
    txValue++;
    delay(1000);// bluetooth stack will go into congestion, if too many packets are sent

    pTxCharacteristic-&gt;setValue("\nESP32-C6\n");
    pTxCharacteristic-&gt;notify();
    delay(1000);// bluetooth stack will go into congestion, if too many packets are sent
}

// disconnecting
if (!deviceConnected &amp;&amp; oldDeviceConnected) {
    delay(500);                   // give the bluetooth stack the chance to get things ready
    pServer-&gt;startAdvertising();// restart advertising
    Serial.println("start advertising");
    oldDeviceConnected = deviceConnected;
}
// connecting
if (deviceConnected &amp;&amp; !oldDeviceConnected) {
    // do stuff here on connecting
    oldDeviceConnected = deviceConnected;
}
}</code></pre>

<p>&nbsp;</p>

<p>在上述代码中的setup()部分,按照以上步骤,进行了对应的服务的创建,标签的创建,以及服务和广播的启动。</p>

<p>另外,还定义了两个回调类,分别是MyServerCallbacks用于处理蓝牙连接状态,MyCallbacks用于处理收到信息时的处理。</p>

<p>&nbsp;</p>

<p>在loop()循环调用中,则进行了信息发送的处理,以及根据连接情况决定是否启动广播的处理。</p>

<p>&nbsp;</p>

<p>在Arduino中编译烧录后,串口监听输出如下:</p>

<p>&nbsp;表示ESP32-C6启动了广播,可以用手机或者电脑连接获取服务了。&nbsp;</p>

<p>&nbsp;</p>

<p>此时,用前面的扫描程序,可以扫描到:</p>

<p>&nbsp; 从上图中可以看到,找到了 ESP32-C6 UART Service 了。</p>

<p>&nbsp;</p>

<p>此时,用BLE工具,可以进行连接,就能够收到对应的信息了:</p>

<p> &nbsp;</p>

<p>在上面代码的loop()中,有两个设置发送信息的处理:</p>

<pre>
<code class="language-cpp">    pTxCharacteristic-&gt;setValue(&amp;txValue, 1);
    pTxCharacteristic-&gt;notify();

    pTxCharacteristic-&gt;setValue("\nESP32-C6\n");
    pTxCharacteristic-&gt;notify();</code></pre>

<p>第一个表示发送数值,大小为1字节;第二个表示发送一个字符串。</p>

<p>&nbsp;</p>

<p>把BLE工具的接收HEX打开,就可以看到发送的数值信息了:</p>

<p>&nbsp;</p>

<p> &nbsp;</p>

<p>&nbsp;</p>

<p>然后,在BLE工具中,给ESP32-C6发送信息:</p>

<p> &nbsp;</p>

<p>串口监控就会收到发送的信息了:</p>

<p> &nbsp;</p>

<p><strong>四、总结</strong></p>

<p>刚开始用BLE功能时,觉得基于GATT的处理过程很麻烦,但是一旦用上了后,会非常的好用,因为已经有很多标准化的处理了,符合标准定义的设备,可以轻松的进行互联和通信。</p>

<p>如果你的设备,按照标准定义来广播Service和通过Characteristic提供对应的实际功能,那么其他符合这个标准的设备,就能够快速连接获取数据或者发送数据。</p>

<p>现在有很多BLE低功耗设备,如心率传感器、手环、温度传感器、光纤传感器等采用,你不用了解它具体的工作细节,仅需要通过BLE扫描发现对应的BLE设备和服务,然后就可以通过标准定义的Characteristic来获取数据了,非常的方便。</p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

Jacktang 发表于 2024-5-21 07:29

<p>第三部分,BLE UART功能使用</p>

<p>有个图片不显示,</p>

<p> &nbsp;</p>

HonestQiao 发表于 2024-5-21 18:51

Jacktang 发表于 2024-5-21 07:29
第三部分,BLE UART功能使用

有个图片不显示,

&nbsp;

<p>多谢提醒,修改了,再看看</p>
页: [1]
查看完整版本: 【Beetle ESP32 C6迷你开发板】低功耗蓝牙(BLE)功能初步使用