ESP32 確實(shí)是一款功能強(qiáng)大的物聯(lián)網(wǎng)設(shè)備,內(nèi)置了對(duì)藍(lán)牙和 WiFi 的支持。ESP32 是其前身 ESP8266 的高級(jí)版本,具有 RAM、ROM、GPIO 引腳等額外功能。ESP32 模塊支持經(jīng)典藍(lán)牙和低功耗藍(lán)牙 (BLE),經(jīng)典藍(lán)牙可用于傳輸歌曲或文件,BLE該選項(xiàng)可用于電池優(yōu)化應(yīng)用,如藍(lán)牙信標(biāo)、健身手環(huán)、接近度廣告等。也可以將ESP32 用作串行藍(lán)牙,如用于簡單微控制器項(xiàng)目的 HC-05 或 HC-06 模塊。
在本教程中,我們將使用 ESP32 構(gòu)建一個(gè) BLE iBeacon,其中 ESP32 將充當(dāng)服務(wù)器,智能手機(jī)將充當(dāng)客戶端。
所需組件
硬件:
ESP32 開發(fā)板
微型 USB 數(shù)據(jù)線
軟件:
Arduino IDE
Android 應(yīng)用程序:nRF Connect for Mobile(由 Nordic Semiconductor 提供)
有許多 BLE 掃描儀應(yīng)用程序,其中一個(gè)我們?cè)谥暗捻?xiàng)目“如何將 HM-10 BLE 模塊與 Arduino 一起使用”中使用過。這個(gè) BLE 掃描儀應(yīng)用程序提供了良好的圖形界面 (GUI),但缺乏額外的信息,所以在這個(gè)項(xiàng)目中,我們使用NRF Connect for Mobile 應(yīng)用程序。
使用適用于 ESP32 iBeacon 的 nRF Connect Android 應(yīng)用程序
1. 從 Google Play 商店下載 nRF Connect 應(yīng)用程序并打開它。
2. 畫面如下。當(dāng)找到設(shè)備時(shí),此項(xiàng)目的有用選項(xiàng)將是“掃描”、“掃描儀”和“信息”。
“掃描”選項(xiàng)將用于查看所有可用的 iBeacon。要開始搜索 iBeacon,請(qǐng)下拉屏幕或轉(zhuǎn)到屏幕右上角的“掃描”選項(xiàng)。這將開始搜索可用的 iBeacons。
3.搜索iBeacon后,可以看到iBeacon的RSSI、UUID、Major和Minor。如果您將移動(dòng)設(shè)備或 iBeacon 彼此遠(yuǎn)離,RSSI 將發(fā)生變化。在此屏幕中,RSSI 為 (-37)。除此之外,還有一些詳細(xì)信息,例如虛擬公司名稱、設(shè)備類型、字節(jié)長度、ESP32 的本地名稱。這里是“ ESP32 as iBeacon ”。您可以在草圖中更改本地名稱。
4. 從iBeacon 拿走智能手機(jī)后,RSSI 值從-37 變?yōu)?58。如果您移動(dòng)其中一臺(tái)設(shè)備,這些值將不斷變化。
RSSI 信號(hào)可接受值如下:
將 ESP32 編程為 BLE iBeacon
當(dāng)您在 Arduino IDE 中安裝 ESP32 Board 時(shí),可以使用 ESP32 BLE iBeacon 的示例程序。但是我們?cè)诒窘坛讨猩晕⒕庉嬃诉@個(gè)草圖,示例程序的完整編輯版本在本教程的末尾給出。
要打開 ESP32?BLE_iBeacon的示例程序,請(qǐng)按照以下步驟操作。
打開 Arduino IDE 并選擇“ESP32 Dev Module”。(如果您沒有找到此板,請(qǐng)檢查您是否安裝了 ESP32 板包)
轉(zhuǎn)到文件>示例>?ESP32 BLE Arduino?>?BLE_iBeacon
打開“BLE_iBeacon”草圖。
現(xiàn)在對(duì)本教程中的代碼進(jìn)行了輕微修改。ESP32 名稱也將在此草圖中更新。因此,首先要包含必要的庫,這些庫將用于創(chuàng)建 BLE 服務(wù)器和 iBeacon。
?
#include "sys/time.h"
?
這是一個(gè)獲取當(dāng)前系統(tǒng)時(shí)間的時(shí)間庫。這包含諸如tv_sec、gettimeofday() 等函數(shù)。有關(guān)更多信息,您可以訪問'?sys/time.h?'的官方 UNIX 版本。
然后包含 ESP32 BLE 庫,其中包含許多用于在不同配置中制作 ESP32 的函數(shù),例如 BLE 客戶端或 BLE 服務(wù)器。
?
#include "BLEDevice.h" #include "BLEUtils.h" #include "BLEServer.h"
?
包含 iBeacon 庫,它將 ESP32 設(shè)置為 iBeacon。除此之外,ESP32還包含深度睡眠庫。該庫將用于在定義的時(shí)間段內(nèi)以深度睡眠模式發(fā)送 ESP32。
?
#include "BLEBeacon.h" #include "esp_sleep.h"
?
定義 ESP32 的睡眠時(shí)間。在這里,ESP32 將進(jìn)入深度睡眠 10 秒,它會(huì)做廣告,然后再次進(jìn)入深度睡眠 10 秒。
?
#define GPIO_DEEP_SLEEP_DURATION 10
?
這里定義了RTC_DATA_ATTR。請(qǐng)注意,如果您使用 RTC_DATA_ATTR 屬性定義全局變量,該變量將被放入 RTC_SLOW_MEM 內(nèi)存中。因此,聲明為 RTC_DATA_ATTR 的結(jié)構(gòu)并在深度睡眠之前將動(dòng)態(tài)內(nèi)存復(fù)制到此結(jié)構(gòu)有助于在喚醒后將其恢復(fù)到動(dòng)態(tài)內(nèi)存中。簡而言之,我們正在從動(dòng)態(tài)內(nèi)存中節(jié)省靜態(tài)內(nèi)存中的時(shí)間,以便在深度睡眠后再次恢復(fù)它。這里定義了兩個(gè)變量。'?last?' 用于獲取 ESP32 進(jìn)入深度睡眠的最后時(shí)間,并且bootcount用于計(jì)數(shù)重置次數(shù)。
?
RTC_DATA_ATTR 靜態(tài) time_t 最后; RTC_DATA_ATTR 靜態(tài) uint32_t 引導(dǎo)計(jì)數(shù);
?
然后定義 BLE 廣告類型。定義如下。
?
BLEAdvertising *pAdvertising;
?
timeval被定義為訪問當(dāng)前時(shí)間的結(jié)構(gòu)。
?
現(xiàn)在構(gòu)造timeval;
?
還定義了 UUID??梢詮拇随溄由?UUID 。
?
#define BEACON_UUID "87b99b2c-9XXd-11e9-bXX2-526XXXX64f64"
?
現(xiàn)在創(chuàng)建一個(gè)函數(shù),該函數(shù)將包含 iBeacon 屬性,例如 UUID、Major、Minor 等。在此函數(shù)中,為 BLE 創(chuàng)建一個(gè)實(shí)例作為 iBeacon,并將 ESP32 的假制造商 ID、UUID、主要和次要設(shè)置為 iBeacon。
?
無效 setBeacon() { BLEBeacon oBeacon = BLEBeacon(); oBeacon.setManufacturerId(0x4C00); oBeacon.setProximityUUID(BLEUUID(BEACON_UUID)); oBeacon.setMajor((bootcount & 0xFFFF0000) >> 16); oBeacon.setMinor(bootcount & 0xFFFF);
?
將該標(biāo)志設(shè)置為 0x04,以便它將在掃描儀中輸出BrEdrNotSupported。
?
oAdvertisementData.setFlags(0x04);
?
設(shè)置發(fā)布的廣告數(shù)據(jù)。
?
std::string strServiceData = "";
?
一個(gè)接一個(gè)地添加字符串進(jìn)行廣告。
?
strServiceData += (char)26; // Len strServiceData += (char)0xFF; // 輸入 strServiceData += oBeacon.getData(); oAdvertisementData.addData(strServiceData);
?
通過發(fā)布數(shù)據(jù)開始廣告。
?
pAdvertising->setAdvertisementData(oAdvertisementData); pAdvertising->setScanResponseData(oScanResponseData);
?
以 115200 波特率啟動(dòng)串行監(jiān)視器并獲取時(shí)間。還要增加引導(dǎo)計(jì)數(shù)以存儲(chǔ)重置次數(shù)。
?
序列號(hào).開始(115200); gettimeofday(&now, NULL); Serial.printf("啟動(dòng) ESP32 %d\n", bootcount++);
?
將當(dāng)前時(shí)間存儲(chǔ)在靜態(tài)存儲(chǔ)器中。
?
最后 = now.tv_sec;
?
創(chuàng)建一個(gè) BLE 設(shè)備并根據(jù)需要命名。這里 ESP32 被命名為“?ESP2 as iBeacon?”。請(qǐng)注意,名稱可以很長,但此版本的代碼已開始支持長名稱。
?
BLEDevice::init("ESP32 作為 iBeacon");
?
創(chuàng)建 BLE 服務(wù)器以進(jìn)行廣告并開始廣告。
?
BLEServer *pServer = BLEDevice::createServer(); pAdvertising = BLEDevice::getAdvertising(); BLEDevice::startAdvertising();
?
然后將 ESP32 設(shè)置為 iBeacon 模式。
?
設(shè)置信標(biāo)();
?
開始廣告然后停止廣告并進(jìn)入深度睡眠 10 秒。
?
p廣告->開始(); pAdvertising->stop(); esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
?
最后,使用 Micro USB 電纜將 ESP32 開發(fā)板與您的筆記本電腦連接,并使用 Arduino IDE 將代碼上傳到 ESP32。然后在您的智能手機(jī)中打開nRF Connect Android 應(yīng)用程序并開始掃描。您會(huì)發(fā)現(xiàn)ESP32 作為 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 內(nèi)存中的上次啟動(dòng)
RTC_DATA_ATTR static uint32_t bootcount; // 記住 RTC 內(nèi)存中的啟動(dòng)次數(shù)
// 有關(guān)生成 UUID,請(qǐng)參見以下內(nèi)容:
// 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/隨機(jī)數(shù))
無效 setBeacon() {
BLEBeacon oBeacon = BLEBeacon();
oBeacon.setManufacturerId(0x4C00); // 假 Apple 0x004C LSB (ENDIAN_CHANGE_U16?。?/p>
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);
}
無效設(shè)置(){
序列號(hào)。開始(115200);
gettimeofday(&now, NULL);
Serial.printf(“啟動(dòng) ESP32 %d\n”, bootcount++);
Serial.printf(“深度睡眠(自上次重置以來的 %lds,自上次啟動(dòng)以來的 %lds)\n”, now.tv_sec, now.tv_sec - last);
最后 = now.tv_sec;
// 創(chuàng)建 BLE 設(shè)備
BLEDevice::init(“ESP32 as iBeacon”);
// 創(chuàng)建 BLE 服務(wù)器
BLEServer *pServer = BLEDevice::createServer(); // 《-- 不再需要實(shí)例化 BLEServer,更少的閃存和內(nèi)存使用
pAdvertising = BLEDevice::getAdvertising();
BLEDevice::startAdvertising();
設(shè)置信標(biāo)();
// 開始廣告
pAdvertising-》start();
Serial.println(“廣告開始。..”);
延遲(100);
pAdvertising-》stop();
Serial.printf(“進(jìn)入深度睡眠\(yùn)n”);
esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
Serial.printf(“處于深度睡眠中\(zhòng)n”);
}
無效循環(huán)(){
}
評(píng)論
查看更多