御坂10032号 发表于 2024-6-10 01:44

SparkFun Pro nRF52840 Mini 蓝牙广播 + 软件收发数据

<div class='showpostmsg'> 本帖最后由 御坂10032号 于 2024-6-10 01:38 编辑

<p>在这篇帖子中,我将详细讲解一个基于nRF52芯片的蓝牙低功耗(BLE)UART示例程序。该程序使用Adafruit的Bluefruit库来实现BLE功能,并包括了几个关键的BLE服务。我们将逐步解析代码,了解其每个部分的功能。此外,我们还将简要介绍蓝牙协议的基本概念。</p>

<h3>蓝牙概述</h3>

<p>蓝牙是一种短距离无线通信技术,广泛应用于各种设备之间的数据传输。蓝牙标准由蓝牙技术联盟(Bluetooth Special Interest Group,SIG)制定和维护。蓝牙技术主要有两种模式:</p>

<ol>
        <li><strong>经典蓝牙(BR/EDR)</strong>:适用于高数据传输速率和音频传输的应用,如无线耳机和音箱。</li>
        <li><strong>蓝牙低功耗(BLE)</strong>:针对低功耗和间歇性数据传输的应用,如智能手表、健康监测设备和IoT设备。</li>
</ol>

<h3>蓝牙低功耗(BLE)</h3>

<p>BLE是蓝牙4.0引入的技术,专门设计用于低功耗应用。其特点包括:</p>

<ul>
        <li><strong>低功耗</strong>:适用于电池供电设备。</li>
        <li><strong>快速连接</strong>:可以快速建立和断开连接,节省能量。</li>
        <li><strong>灵活的数据传输</strong>:支持小数据包的高效传输。</li>
</ul>

<p>BLE设备主要分为两类:</p>

<ul>
        <li><strong>外围设备(Peripheral)</strong>:广播其存在,并等待中心设备连接。</li>
        <li><strong>中心设备(Central)</strong>:扫描外围设备并发起连接。</li>
</ul>

<p>&nbsp;</p>

<p>蓝牙协议稍微复杂,不过好在Sparkfun 提供的Arduino支持中包括了对蓝牙的支持。同时还有大量的蓝牙demo供我们学习。这些Arduino蓝牙的适配大大的降低了使用这一块MCU开发项目时的困难程度。</p>

<p>&nbsp;</p>

<p>我们可以在下述位置找到示例代码</p>

<p>&nbsp;</p>

<p> &nbsp;</p>

<pre>
<code class="language-cpp">#include &lt;bluefruit.h&gt;</code></pre>

<p>我们首先引入了Bluefruit库,它提供了对蓝牙功能的支持,使我们能够轻松地构建BLE应用。</p>

<p>&nbsp;</p>

<pre>
<code class="language-cpp">// BLE Service
BLEDfubledfu;// OTA DFU service
BLEDisbledis;// device information
BLEUart bleuart; // uart over ble
BLEBasblebas;// battery
</code></pre>

<p>&nbsp;</p>

<p>之后,我们初始化了几个BLE服务对象,包括(OTA的服务暂时还没发现怎么用):</p>

<ul>
        <li><strong>BLEDfu</strong>:支持空中下载(OTA)的DFU服务。</li>
        <li><strong>BLEDis</strong>:设备信息服务。</li>
        <li><strong>BLEUart</strong>:通过BLE实现的UART服务。</li>
        <li><strong>BLEBas</strong>:电池服务,用于监控电池状态。</li>
</ul>

<p>&nbsp;</p>

<pre>
<code class="language-cpp">void startAdv(void)
{
// 设置广播数据包
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();

// Include bleuart 128-bit uuid 设置蓝牙广播的唯一标识
Bluefruit.Advertising.addService(bleuart);

// Secondary Scan Response packet (optional)
Bluefruit.ScanResponse.addName();

/* Start Advertising 开始广播
   * - Enable auto advertising if disconnected
   * - Interval:fast mode = 20 ms, slow mode = 152.5 ms
   * - Timeout for fast mode is 30 seconds
   * - Start(timeout) with timeout = 0 will advertise forever (until connected)
   */
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244);    // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30);      // number of seconds in fast mode
Bluefruit.Advertising.start(0);                // 0 = Don't stop advertising after n seconds
}
</code></pre>

<p>&nbsp;</p>

<p>startAdv函数负责设置并启动蓝牙广播:</p>

<ol>
        <li>
        <p><strong>设置广告包</strong>:</p>

        <ul>
                <li>添加标志信息,指示设备为普通可连接模式。</li>
                <li>添加发射功率信息。</li>
                <li>添加BLE UART服务的UUID。</li>
        </ul>
        </li>
        <li>
        <p><strong>设置扫描响应包</strong>:</p>

        <ul>
                <li>添加设备名称,这样在扫描响应时可以显示设备名称。</li>
        </ul>
        </li>
        <li>
        <p><strong>启动广告</strong>:</p>

        <ul>
                <li>配置在断开连接时自动重新开始广播。</li>
                <li>设置广播间隔和超时时间。</li>
                <li>开始广播,参数为0表示广播将持续进行直到设备连接 (如果持续没有设备连接的话,开发板上的LED灯将持续闪烁)。</li>
        </ul>
        </li>
</ol>

<p>&nbsp;</p>

<pre>
<code class="language-cpp">void connect_callback(uint16_t conn_handle)
{
// 获取当前连接的引用
BLEConnection* connection = Bluefruit.Connection(conn_handle);

char central_name = { 0 };
connection-&gt;getPeerName(central_name, sizeof(central_name));

Serial.print("Connected to ");
Serial.println(central_name);
}

/**
* 连接断开时调用的回调函数
* @param conn_handle 连接句柄
* @param reason 断开原因
*/
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
(void) conn_handle;
(void) reason;

Serial.println();
Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX);
}
</code></pre>

<p>&nbsp;</p>

<p>这些回调函数在设备连接和断开连接时被调用:</p>

<ol>
        <li>
        <p><strong>连接回调函数</strong>:</p>

        <ul>
                <li>当设备连接时,获取并打印中央设备的名称。</li>
        </ul>
        </li>
        <li>
        <p><strong>断开连接回调函数</strong>:</p>

        <ul>
                <li>当设备断开连接时,打印断开原因。</li>
        </ul>
        </li>
</ol>

<p>&nbsp;</p>

<p>&nbsp;</p>

<pre>
<code class="language-cpp">void loop()
{
// Forward data from HW Serial to BLEUART
while (Serial.available())
{
    // 延迟以等待足够的输入,因为我们有一个有限的传输缓冲区
    delay(2);

    uint8_t buf;
    int count = Serial.readBytes(buf, sizeof(buf));
    bleuart.write(buf, count);
}

// 从BLEUART转发到HW Serial
while (bleuart.available())
{
    uint8_t ch;
    ch = (uint8_t) bleuart.read();
    Serial.write(ch);
}
}
</code></pre>

<p>&nbsp;</p>

<p>loop函数实现了串口和BLE UART之间的数据转发:</p>

<ol>
        <li>
        <p><strong>从硬件串口转发数据到BLE UART</strong>:</p>

        <ul>
                <li>如果串口有数据可读,读取数据到缓冲区,并通过BLE UART发送出去。</li>
        </ul>
        </li>
        <li>
        <p><strong>从BLE UART转发数据到硬件串口</strong>:</p>

        <ul>
                <li>如果BLE UART有数据可读,读取一个字节并通过串口发送出去。</li>
        </ul>
        </li>
</ol>

<p>&nbsp;</p>

<p>上述程序实现的基本功能是初始化串口,和蓝牙。并且开启蓝牙的广播功能。 当用户连接或者断开于当前蓝牙的连接的时候会触发上述的回调函数。当用户使用APP发送消息给Sparkfun开发板的时候。开发板将会以串口的方式发送给上位机。同时上位机也可以通过串口的方式通过蓝牙发送消息给APP(用户)&nbsp;</p>

<p>&nbsp;</p>

<p>此时我们我们将代码编译并且下载到开发板中</p>

<p>&nbsp;</p>

<p>设备未连接蓝牙的时候</p>

<p>8c25bc0a3a2a7b2f78bd5e647db24d5e<br />
&nbsp;</p>

<p>完整使用手机APP 发送和接收数据演示</p>

<p>&nbsp;</p>

<p>1de70756feebef247002130218b007f5<br />
&nbsp;</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>

御坂10032号 发表于 2024-6-10 21:12

苹果用户我建议大家使用BleTools 我视频上的那个广告太多了。 BleTools 没有广告

haoayou 发表于 2024-6-11 10:47

<p>这个写的真好,使我对蓝牙有了更好的认识,感谢博主,博主一切顺利</p>
页: [1]
查看完整版本: SparkFun Pro nRF52840 Mini 蓝牙广播 + 软件收发数据