ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

arduino-esp32 实战:基于 BLEEddystoneTLM 库构建周期广播 + 深度睡眠的 Eddystone TLM 信标

arduino-esp32 实战:基于 BLEEddystoneTLM 库构建周期广播 + 深度睡眠的 Eddystone TLM 信标 arduino-esp32 实战基于 BLEEddystoneTLM 库构建周期广播 深度睡眠的 Eddystone TLM 信标【免费下载链接】arduino-esp32Arduino core for the ESP32 family of SoCs项目地址: https://gitcode.com/GitHub_Trending/ar/arduino-esp32本篇技术指南围绕 arduino-esp32 仓库中libraries/BLE/examples/EddystoneTLM_Beacon示例展开讲解如何基于 ESP32 BLE 库实现一个周期性广播 Eddystone TLM遥测帧的信标设备并通过深度睡眠deep sleep大幅降低功耗。读完本文你将掌握 Eddystone TLM 帧的 14 字节结构、BLEEddystoneTLM类的完整 API 用法、广播数据与扫描响应数据的组装方式以及如何用RTC_DATA_ATTR在深度睡眠间保留计数与时间信息。示例定位一个广播—等待—休眠的遥测信标EddystoneTLM_Beacon.md 明确指出该示例的目标是Create a BLE server that will send periodic Eddystone TLM frames创建一个周期性发送 Eddystone TLM 帧的 BLE 服务器其整体设计流程为Create a BLE Server创建 BLE 服务器Create advertising data创建广播数据Start advertising开始广播wait等待Stop advertising停止广播deep sleep深度睡眠核心思路并不复杂设备启动后短暂进入广播状态把遥测数据电池电压、温度、启动计数、开机时长通过 Eddystone TLM 帧广播出去随后立刻进入深度睡眠以节省电量间隔若干秒后由 RTC 定时器唤醒循环往复。这种广播 深睡模式非常契合依赖纽扣电池长期运行的资产追踪、环境监测类信标场景。对应源码为 EddystoneTLM_Beacon.ino示例作者为 BeeGee原始设计源自 pcbreflux 的 ESP32 Eddystone TLM deepsleep 方案。同目录下的 ci.yml 则记录了该示例在 CI 验证时的编译要求追加PartitionSchemehuge_app分区方案且仅在CONFIG_SOC_BLE_SUPPORTEDy或CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLEy的 SoC 上编译即硬件必须支持 BLE。理解 Eddystone TLM 帧结构源码级Eddystone TLM 帧的规范由 Google 的 Eddystone 项目定义本仓库在BLEEddystoneTLM类的实现中将其完整落地。从 BLEEddystoneTLM.h 可以看到帧数据的内存布局struct { uint8_t frameType; // 帧类型固定 0x20EDDYSTONE_TLM_FRAME_TYPE uint8_t version; // TLM 版本号当前为 0 uint16_t volt; // 电池电压单位 mV uint16_t temp; // 温度8.8 定点格式低 8 位为小数部分 uint32_t advCount; // 自上次上电以来的广播帧计数 uint32_t tmil; // 自上次上电以来的时间0.1 秒分辨率 } __attribute__((packed)) m_eddystoneData;整个 TLM 帧共 14 字节通过__attribute__((packed))确保结构体按 1 字节对齐、无填充字节从而与空中广播的字节流严格一致。构造函数BLEEddystoneTLM.cpp给出了各字段的默认值帧类型0x20、版本0、电压3300即 3.3 V、温度23.00、计数0、时间0。两个关键编码细节值得注意温度采用 8.8 定点数宏EDDYSTONE_TEMP_FLOAT_TO_U16(tempFloat)将浮点温度乘以 256 取整再经ENDIAN_CHANGE_U16交换字节序后存入帧中读取侧则通过EDDYSTONE_TEMP_U16_TO_FLOAT(tempU16)将 16 位值视为有符号数并除以 256.0 还原为浮点温度BLEEddystoneTLM.h。因此setTemp(23.5f)的实际含义是 23.5 °C而getRawTemp()返回的是帧内的原始 16 位编码值getTemp()返回的是换算后的浮点温度。字节序转换BLE 广播载荷使用小端序而 ESP32 内部处理这些字段时按大端习惯组织因此setVolt()与setTemp()写入时通过ENDIAN_CHANGE_U16交换高低字节读取时getVolt()、getTemp()、getCount()、getTime()再次交换还原BLEEddystoneTLM.cpp。getTime()的实现也印证了 0.1 秒分辨率约定tmil字段以 0.1 秒为单位递增读取时除以 10 得到秒数BLEEddystoneTLM.cpp。此外从BLEAdvertisedDevice构造的BLEEddystoneTLM重载会在广播载荷中扫描0x16Service Data AD Type、0xAA 0xFEEddystone Service UUID与0x20TLM 帧类型的序列来定位并解析收到的 TLM 帧BLEEddystoneTLM.cpp这正是接收端解析此类广播的基础。示例代码逐段拆解头文件与关键宏定义#include Arduino.h #include BLEDevice.h #include BLEUtils.h #include BLEBeacon.h #include BLEAdvertising.h #include BLEEddystoneTLM.h #include esp_sleep.h #define GPIO_DEEP_SLEEP_DURATION 10 // sleep x seconds and then wake up #define BEACON_POWER ESP_PWR_LVL_N12 #define BEACON_UUID 8ec76ea3-6668-48da-9866-75be8bc86f4d // UUID 1 128-BitGPIO_DEEP_SLEEP_DURATION每次深度睡眠的时长秒示例取 10 秒BEACON_POWER广播发射功率ESP_PWR_LVL_N12表示 -12 dBm在近距离信标场景中够用且省电BEACON_UUID示例中定义的 128 位 UUID可用于区分信标身份可借助uuidgen等工具生成。用 RTC_DATA_ATTR 跨睡眠保留状态RTC_DATA_ATTR static time_t last; // remember last boot in RTC Memory RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory这是 ESP32 低功耗编程的关键技巧普通静态变量在深度睡眠期间会被清空而RTC_DATA_ATTR修饰的变量存放在 RTC 慢速存储器中深度睡眠期间不掉电唤醒后值依然保留。示例借此累计开机次数bootcount并记录上次开机时刻last以计算两次开机间隔。setBeacon()组装 TLM 遥测数据void setBeacon() { BLEEddystoneTLM EddystoneTLM; EddystoneTLM.setVolt((uint16_t)random(2800, 3700)); // 3300mV 3.3V EddystoneTLM.setTemp(random(-3000, 3000) / 100.0f); // 3000 30.00 ˚C Serial.printf(Random Battery voltage is %u mV 0x%04X\n, EddystoneTLM.getVolt(), EddystoneTLM.getVolt()); Serial.printf(Random temperature is %.2f°C\n, EddystoneTLM.getTemp()); Serial.printf(Converted to 8.8 format: 0x%X\n, EddystoneTLM.getRawTemp()); BLEAdvertisementData oAdvertisementData BLEAdvertisementData(); BLEAdvertisementData oScanResponseData BLEAdvertisementData(); oScanResponseData.setServiceData(BLEUUID((uint16_t)0xFEAA), String(EddystoneTLM.getData().c_str(), EddystoneTLM.getData().length())); oAdvertisementData.setName(ESP32 TLM Beacon); pAdvertising-setAdvertisementData(oAdvertisementData); pAdvertising-setScanResponseData(oScanResponseData); }真实场景中电压应来自 ADC 或电源管理芯片温度应来自温度传感器示例为了便于演示使用random()生成随机遥测值setVolt(2800~3700)随机电池电压mV 单位3300 即 3.3 VsetTemp(-30.00~30.00)随机温度单位 °C代码注释专门提醒读者参照 TLM 帧规范了解 8.8 定点表示法广播数据与扫描响应数据分离广播包advertisement data只携带设备名ESP32 TLM Beacon扫描响应包scan response data承载 TLM 帧本体——通过setServiceData(BLEUUID((uint16_t)0xFEAA), data)将 14 字节 TLM 数据挂到 Eddystone 服务 UUID0xFEAA下。之所以这样拆分是因为单个广播包只有 31 字节上限而名称 14 字节 TLM 帧很可能放不下扫描响应通道可以显著扩充可用空间。BLEAdvertisementData::setServiceData的声明可参见 BLEAdvertising.h。setup()完整生命周期void setup() { Serial.begin(115200); gettimeofday(nowTimeStruct, NULL); Serial.printf(Starting ESP32. Bootcount % PRIu32 \n, bootcount); Serial.printf(Deep sleep (% PRIu32 s since last reset, % PRIu32 s since last boot)\n, (uint32_t)nowTimeStruct.tv_sec, (uint32_t)(nowTimeStruct.tv_sec - last)); last nowTimeStruct.tv_sec; lastTenth nowTimeStruct.tv_sec * 10; // Time since last reset as 0.1 second resolution counter // Create the BLE Device BLEDevice::init(TLMBeacon); BLEDevice::setPower(BEACON_POWER); pAdvertising BLEDevice::getAdvertising(); setBeacon(); // Start advertising pAdvertising-start(); Serial.println(Advertising started for 10s ...); delay(10000); pAdvertising-stop(); Serial.printf(Enter deep sleep for 10s\n); esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION); } void loop() {}启动流程与文档中 6 步设计一一对应创建 BLE 设备BLEDevice::init(TLMBeacon)初始化协议栈并设置设备名设置发射功率BLEDevice::setPower(ESP_PWR_LVL_N12)该 API 的签名setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType ESP_BLE_PWR_TYPE_DEFAULT)可参见 BLEDevice.h默认作用于通用功率类型获取广播句柄BLEDevice::getAdvertising()返回BLEAdvertising *组装广播数据调用setBeacon()见上文开始广播 → 等待 → 停止广播pAdvertising-start()后delay(10000)维持 10 秒广播再pAdvertising-stop()进入深度睡眠esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION)参数为微秒即睡眠 10 秒后由 RTC 定时器唤醒重新进入setup()。loop()保持为空——由于每次唤醒后都会立即睡眠主循环实际上不会被执行到。gettimeofday与last/bootcount的配合使用可以在串口日志中输出自上次复位以来的秒数以及自上次开机以来的秒数方便观察深睡-唤醒周期。串口输出与验证方法示例会在每次唤醒时通过 115200 波特率输出类似下面的日志Starting ESP32. Bootcount 3 Deep sleep (1234567s since last reset, 10s since last boot) Random Battery voltage is 3251 mV 0x0CB3 Random temperature is 12.34°C Converted to 8.8 format: 0xC31 Advertising started for 10s ... Enter deep sleep for 10sBootcount会随每次深睡唤醒单调递增依赖 RTC 内存持久化since last boot 约为 10 秒可直观验证深睡-唤醒循环正常工作。0x0CB3与0xC31分别是电压与温度在帧内的原始十六进制编码便于对照帧规范手工核验字节序与定点格式是否正确。示例代码注释中还提到要读取该信标广播的数据可使用另一块 ESP32 运行 BLE 信标扫描示例BLE_Beacon_Scanner。从实现上看接收端需要利用上文提到的BLEAdvertisedDevice构造函数或手动在广播载荷中定位0xFEAA服务 UUID 与0x20帧类型再通过BLEEddystoneTLM的getVolt()、getTemp()、getCount()、getTime()及toString()输出电压、温度、广播计数、开机秒数及可读的日.时:分:秒格式见 BLEEddystoneTLM.cpp还原遥测信息。构建与编译前提该示例在仓库 CI 中的编译约束记录在 ci.ymlfqbn_append: PartitionSchemehuge_app requires_any: - CONFIG_SOC_BLE_SUPPORTEDy - CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLEy两点含义必须选择 BLE 能力CONFIG_SOC_BLE_SUPPORTEDy表示芯片硬件支持 BLE或通过 hosted 方案启用 NimBLE 蓝牙协议栈ESP32 / ESP32-C3 / ESP32-S3 / ESP32-C6 等主流型号均满足推荐使用 huge_app 分区方案BLE 库尤其 Bluedroid 协议栈体积较大PartitionSchemehuge_app为应用程序预留了更大的分区空间避免默认分区方案下固件放不下的问题。在 Arduino IDE 的 Tools → Partition Scheme 中选择 Huge APP 即可对应此配置。该示例依赖BLEEddystoneTLM类其实现在 BLEEddystoneTLM.h 与 BLEEddystoneTLM.cpp 中并随 BLE 库一并提供编译时无需额外安装第三方库。关键 API 速查API作用说明BLEDevice::init(name)初始化 BLE 协议栈参数为广播设备名BLEDevice::setPower(powerLevel)设置发射功率如ESP_PWR_LVL_N12-12 dBmBLEDevice::getAdvertising()获取广播对象BLEAdvertising*用于后续启停广播BLEEddystoneTLM::setVolt(mV)设置电池电压单位 mV内部做字节序转换BLEEddystoneTLM::setTemp(°C)设置温度浮点摄氏度内部转 8.8 定点BLEEddystoneTLM::getData()取 14 字节 TLM 帧传给setServiceData广播BLEAdvertisementData::setServiceData(uuid, data)挂载服务数据Eddystone 服务 UUID 为0xFEAABLEAdvertising::start() / stop()启停广播广播窗口由delay控制esp_deep_sleep(us)进入深度睡眠参数为微秒唤醒后重跑setup()总结EddystoneTLM_Beacon示例展示了 arduino-esp32 BLE 生态中一个完整且实用的信标工作流用BLEEddystoneTLM封装 14 字节 TLM 帧帧类型、版本、电压、8.8 定点温度、广播计数、0.1 秒分辨率时间戳通过广播包携带设备名、扫描响应包携带遥测数据再配合esp_deep_sleep与RTC_DATA_ATTR实现短时广播 长时休眠的极低功耗循环。无论你是要做一个真正上报电池电压与温度的环境信标还是想理解 BLE 广播与扫描响应通道的配合方式这个示例都是绝佳的起点——只需把random()生成的占位数据替换为真实传感器读数与 ADC 采样值即可投入实际部署。【免费下载链接】arduino-esp32Arduino core for the ESP32 family of SoCs项目地址: https://gitcode.com/GitHub_Trending/ar/arduino-esp32创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表