如何使用ESP32构建一个BLE iBeacon

RF/无线

1773人已加入

描述

  ESP32 确实是一款功能强大的物联网设备,内置了对蓝牙和 WiFi 的支持。ESP32 是其前身 ESP8266 的高级版本,具有 RAM、ROM、GPIO 引脚等额外功能。ESP32 模块支持经典蓝牙和低功耗蓝牙 (BLE),经典蓝牙可用于传输歌曲或文件,BLE该选项可用于电池优化应用,如蓝牙信标、健身手环、接近度广告等。也可以将ESP32 用作串行蓝牙,如用于简单微控制器项目的 HC-05 或 HC-06 模块。

  在本教程中,我们将使用 ESP32 构建一个 BLE iBeacon,其中 ESP32 将充当服务器,智能手机将充当客户端。

  所需组件

  硬件:

  ESP32 开发板

  微型 USB 数据线

  软件:

  Arduino IDE

  Android 应用程序:nRF Connect for Mobile(由 Nordic Semiconductor 提供)

  有许多 BLE 扫描仪应用程序,其中一个我们在之前的项目“如何将 HM-10 BLE 模块与 Arduino 一起使用”中使用过。这个 BLE 扫描仪应用程序提供了良好的图形界面 (GUI),但缺乏额外的信息,所以在这个项目中,我们使用NRF Connect for Mobile 应用程序。

  使用适用于 ESP32 iBeacon 的 nRF Connect Android 应用程序

  1. 从 Google Play 商店下载 nRF Connect 应用程序并打开它。

iBeacon

  2. 画面如下。当找到设备时,此项目的有用选项将是“扫描”、“扫描仪”和“信息”。

  “扫描”选项将用于查看所有可用的 iBeacon。要开始搜索 iBeacon,请下拉屏幕或转到屏幕右上角的“扫描”选项。这将开始搜索可用的 iBeacons。

iBeacon

  3.搜索iBeacon后,可以看到iBeacon的RSSI、UUID、Major和Minor。如果您将移动设备或 iBeacon 彼此远离,RSSI 将发生变化。在此屏幕中,RSSI 为 (-37)。除此之外,还有一些详细信息,例如虚拟公司名称、设备类型、字节长度、ESP32 的本地名称。这里是“ ESP32 as iBeacon ”。您可以在草图中更改本地名称。

iBeacon

  4. 从iBeacon 拿走智能手机后,RSSI 值从-37 变为-58。如果您移动其中一台设备,这些值将不断变化。

iBeacon

  RSSI 信号可接受值如下:

iBeacon

将 ESP32 编程为 BLE iBeacon

当您在 Arduino IDE 中安装 ESP32 Board 时,可以使用 ESP32 BLE iBeacon 的示例程序。但是我们在本教程中稍微编辑了这个草图,示例程序的完整编辑版本在本教程的末尾给出。

要打开 ESP32 BLE_iBeacon的示例程序,请按照以下步骤操作。

打开 Arduino IDE 并选择“ESP32 Dev Module”。(如果您没有找到此板,请检查您是否安装了 ESP32 板包)

转到文件>示例> ESP32 BLE Arduino > BLE_iBeacon

打开“BLE_iBeacon”草图。

现在对本教程中的代码进行了轻微修改。ESP32 名称也将在此草图中更新。因此,首先要包含必要的库,这些库将用于创建 BLE 服务器和 iBeacon。

 

#include "sys/time.h"

 

这是一个获取当前系统时间的时间库。这包含诸如tv_sec、gettimeofday() 等函数。有关更多信息,您可以访问' sys/time.h '的官方 UNIX 版本。

然后包含 ESP32 BLE 库,其中包含许多用于在不同配置中制作 ESP32 的函数,例如 BLE 客户端或 BLE 服务器。

 

#include "BLEDevice.h" 
#include "BLEUtils.h" 
#include "BLEServer.h"

 

包含 iBeacon 库,它将 ESP32 设置为 iBeacon。除此之外,ESP32还包含深度睡眠库。该库将用于在定义的时间段内以深度睡眠模式发送 ESP32。

 

#include "BLEBeacon.h" 
#include "esp_sleep.h"

 

定义 ESP32 的睡眠时间。在这里,ESP32 将进入深度睡眠 10 秒,它会做广告,然后再次进入深度睡眠 10 秒。

 

#define GPIO_DEEP_SLEEP_DURATION 10

 

这里定义了RTC_DATA_ATTR。请注意,如果您使用 RTC_DATA_ATTR 属性定义全局变量,该变量将被放入 RTC_SLOW_MEM 内存中。因此,声明为 RTC_DATA_ATTR 的结构并在深度睡眠之前将动态内存复制到此结构有助于在唤醒后将其恢复到动态内存中。简而言之,我们正在从动态内存中节省静态内存中的时间,以便在深度睡眠后再次恢复它。这里定义了两个变量。' last ' 用于获取 ESP32 进入深度睡眠的最后时间,并且bootcount用于计数重置次数。

 

RTC_DATA_ATTR 静态 time_t 最后;        
RTC_DATA_ATTR 静态 uint32_t 引导计数;

 

然后定义 BLE 广告类型。定义如下。

 

BLEAdvertising *pAdvertising;

 

timeval被定义为访问当前时间的结构。

 

现在构造timeval;

 

还定义了 UUID。可以从此链接生成 UUID 。

 

#define BEACON_UUID "87b99b2c-9XXd-11e9-bXX2-526XXXX64f64"

 

现在创建一个函数,该函数将包含 iBeacon 属性,例如 UUID、Major、Minor 等。在此函数中,为 BLE 创建一个实例作为 iBeacon,并将 ESP32 的假制造商 ID、UUID、主要和次要设置为 iBeacon。

 

无效 setBeacon() { 
BLEBeacon oBeacon = BLEBeacon(); 
oBeacon.setManufacturerId(0x4C00); 
oBeacon.setProximityUUID(BLEUUID(BEACON_UUID)); 
  oBeacon.setMajor((bootcount & 0xFFFF0000) >> 16); 
  oBeacon.setMinor(bootcount & 0xFFFF);

 

将该标志设置为 0x04,以便它将在扫描仪中输出BrEdrNotSupported。

 

  oAdvertisementData.setFlags(0x04);

 

设置发布的广告数据。

 

  std::string strServiceData = "";

 

一个接一个地添加字符串进行广告。

 

  strServiceData += (char)26; // Len 
  strServiceData += (char)0xFF; //
  输入 strServiceData += oBeacon.getData(); 
  oAdvertisementData.addData(strServiceData);

 

通过发布数据开始广告。

 

  pAdvertising->setAdvertisementData(oAdvertisementData); 
  pAdvertising->setScanResponseData(oScanResponseData);

 

以 115200 波特率启动串行监视器并获取时间。还要增加引导计数以存储重置次数。

 

  序列号.开始(115200);
  gettimeofday(&now, NULL); 
  Serial.printf("启动 ESP32 %d\n", bootcount++);

 

将当前时间存储在静态存储器中。

 

最后 = now.tv_sec;

 

创建一个 BLE 设备并根据需要命名。这里 ESP32 被命名为“ ESP2 as iBeacon ”。请注意,名称可以很长,但此版本的代码已开始支持长名称。

 

BLEDevice::init("ESP32 作为 iBeacon");

 

创建 BLE 服务器以进行广告并开始广告。

 

BLEServer *pServer = BLEDevice::createServer(); 
pAdvertising = BLEDevice::getAdvertising(); 
BLEDevice::startAdvertising();

 

然后将 ESP32 设置为 iBeacon 模式。

 

设置信标();

 

开始广告然后停止广告并进入深度睡眠 10 秒。

 

p广告->开始();
pAdvertising->stop(); 
esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);

 

  最后,使用 Micro USB 电缆将 ESP32 开发板与您的笔记本电脑连接,并使用 Arduino IDE 将代码上传到 ESP32。然后在您的智能手机中打开nRF Connect Android 应用程序并开始扫描。您会发现ESP32 作为 iBeacon广播,如下图所示:

iBeacon

  #include “sys/time.h”

  #include “BLEDevice.h”

  #include “BLEUtils.h”

  #include “BLEServer.h”

  #include “BLEBeacon.h”

  #include “esp_sleep.h”

  #define GPIO_DEEP_SLEEP_DURATION 10 // 休眠 x 秒,然后唤醒

  RTC_DATA_ATTR static time_t last;// 记住 RTC 内存中的上次启动

  RTC_DATA_ATTR static uint32_t bootcount; // 记住 RTC 内存中的启动次数

  // 有关生成 UUID,请参见以下内容:

  // https://www.uuidgenerator.net/

  BLEAdvertising *pAdvertising; // BLE 广告类型

  struct timeval now;

  #define BEACON_UUID “87b99b2c-90fd-11e9-bc42-526af7764f64” // UUID 1 128 位(可以使用 linux 工具 uuidgen 或通过https://www.uuidgenerator.net/随机数)

  无效 setBeacon() {

  BLEBeacon oBeacon = BLEBeacon();

  oBeacon.setManufacturerId(0x4C00); // 假 Apple 0x004C LSB (ENDIAN_CHANGE_U16!)

  oBeacon.setProximityUUID(BLEUUID(BEACON_UUID));

  oBeacon.setMajor((bootcount & 0xFFFF0000) 》》 16);

  oBeacon.setMinor(bootcount & 0xFFFF);

  BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();

  BLEAdvertisementData oScanResponseData = BLEAdvertisementData();

  oAdvertisementData.setFlags(0x04); // BR_EDR_NOT_SUPPORTED 0x04

  std::string strServiceData = “”;

  strServiceData += (char)26; // Len

  strServiceData += (char)0xFF; //

  输入 strServiceData += oBeacon.getData();

  oAdvertisementData.addData(strServiceData);

  pAdvertising-》setAdvertisementData(oAdvertisementData);

  pAdvertising-》setScanResponseData(oScanResponseData);

  }

  无效设置(){

  序列号。开始(115200);

  gettimeofday(&now, NULL);

  Serial.printf(“启动 ESP32 %d\n”, bootcount++);

  Serial.printf(“深度睡眠(自上次重置以来的 %lds,自上次启动以来的 %lds)\n”, now.tv_sec, now.tv_sec - last);

  最后 = now.tv_sec;

  // 创建 BLE 设备

  BLEDevice::init(“ESP32 as iBeacon”);

  // 创建 BLE 服务器

  BLEServer *pServer = BLEDevice::createServer(); // 《-- 不再需要实例化 BLEServer,更少的闪存和内存使用

  pAdvertising = BLEDevice::getAdvertising();

  BLEDevice::startAdvertising();

  设置信标();

  // 开始广告

  pAdvertising-》start();

  Serial.println(“广告开始。..”);

  延迟(100);

  pAdvertising-》stop();

  Serial.printf(“进入深度睡眠\n”);

  esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);

  Serial.printf(“处于深度睡眠中\n”);

  }

  无效循环(){

  }

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分