Arduino ESP32 蓝牙(BLE)发送beacon帧

news2024/12/26 0:01:07

简介

蓝牙(BLE)发送beacon帧 就是说在没有配对连接的情况下进行广播数据帧,不是蓝牙数据传输。因为蓝牙数据传输需要配对连接蓝牙才可以,且配对连接设备数量有限。但需要大量设备都能收到数据帧时,就只能是通过发送广播包,使其不需要配对连接,就能收到数据帧,一般用作广播报文,日志等。

广播包起始是长度,AD_type,一帧数据。

注意广播包长度这个字节是不算在总长度之内的。

比如广播{0x02,0x01,0x06} - 长度为2 ,AD_type 为0x01,0x06为数据。2长度就是0x01和0x06,而不包括0x02。
AD_Type 类型包括以下几种
在这里插入图片描述

目前试了两种方法都可行,代码如下:

第一种方法
/*
   EddystoneTLM beacon by BeeGee based on https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_Eddystone_TLM_deepsleep/ESP32_Eddystone_TLM_deepsleep.ino
   EddystoneTLM frame specification https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md
*/

/*
   Create a BLE server that will send periodic Eddystone URL frames.
   The design of creating the BLE server is:
   1. Create a BLE Server
   2. Create advertising data
   3. Start advertising.
   4. wait
   5. Stop advertising.
   6. deep sleep
   
*/
#include "sys/time.h"

#include <Arduino.h>

#include "BLEDevice.h"
#include "BLEUtils.h"
#include "BLEBeacon.h"
#include "BLEAdvertising.h"
#include "BLEEddystoneURL.h"

#include "esp_sleep.h"

#define GPIO_DEEP_SLEEP_DURATION 10     // sleep x seconds and then wake up
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

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
BLEAdvertising *pAdvertising;
struct timeval nowTimeStruct;

time_t lastTenth;

//#define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/)

void setBeacon1()  //第一帧数据包
{
  static uint8_t Count1;
  uint8_t i = 0;
  char beacon_data1[40];
  uint16_t beconUUID = 0xFFFA;
  char Test_Buff1[27] = {0x00,0x00,0x01,0x12,0x31,0x39,0x35,0x32,0x46,0x30,0x39,0x30,0x43,0x4e,0x32,0x33,0x31,0x32,0x30,0x36,0x30,0x31,0x33,0x34,0x00,0x00,0x00};
  
  BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();//创建广告数据对象
  BLEAdvertisementData oScanResponseData = BLEAdvertisementData(); //创建扫描数据对象
  
 oScanResponseData.setFlags(0x06); // GENERAL_DISC_MODE 0x02 | BR_EDR_NOT_SUPPORTED 0x04   //广播{0x02,0x01,0x06} 设置蓝牙为显性
  oScanResponseData.setCompleteServices(BLEUUID(beconUUID));//广播//beconUUID
  beacon_data1[0] = 0x0D;
  beacon_data1[1] = Count1;
  Count1++;
  if(Count1>252)
  Count1 = 0;
  for(i=2;i<27;i++)
  {
    beacon_data1[i] = Test_Buff1[i];
  }
 

  oScanResponseData.setServiceData(BLEUUID(beconUUID), std::string(beacon_data1, 27));//把第一帧扫描数据加入扫描数据
  oAdvertisementData.setName("TLMBeacon");//把蓝牙名字加入广告数据
  pAdvertising->setAdvertisementData(oAdvertisementData);//把广告数据放入广告帧
  pAdvertising->setScanResponseData(oScanResponseData);//把扫描数据放入扫描帧
}

void setBeacon2() //第二帧数据同上
{
  static uint8_t Count2;
  uint8_t i = 0;
  char beacon_data2[40];
  uint16_t beconUUID = 0xFFFA;
  char Test_Buff2[27] = {0x00,0x00,0x41,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x08,0x00,0x31,0x00,0x03,0x00,0x00,0x28,0x00,0x00,0x01,0x00,0x00};
  BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
  BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
  
  //oScanResponseData.setFlags(0x06); // GENERAL_DISC_MODE 0x02 | BR_EDR_NOT_SUPPORTED 0x04
  //oScanResponseData.setCompleteServices(BLEUUID(beconUUID));
  beacon_data2[0] = 0x0D;
  beacon_data2[1] = Count2;
  beacon_data2[2] = 0x41;
  beacon_data2[3] = 0x68;
  Count2++;
  if(Count2>252)
  Count2 = 0;
  for(i=4;i<27;i++)
  {
    beacon_data2[i] = Test_Buff2[i];
  }
 

  oScanResponseData.setServiceData(BLEUUID(beconUUID), std::string(beacon_data2, 27));
  oAdvertisementData.setName("TLMBeacon");
  pAdvertising->setAdvertisementData(oAdvertisementData);
  pAdvertising->setScanResponseData(oScanResponseData);
}

void setBeacon3()第三帧数据同上
{
  static uint8_t Count3;
  uint8_t i = 0;
  char beacon_data3[40];
  uint16_t beconUUID = 0xFFFA;
  char Test_Buff3[27] = {0x00,0x00,0x11,0x00,0x06,0x03,0x08,0x00,0x01,0x01,0x00,0x00,0x01,0x01,0x00,0x00,0x22,0x00,0x21,0xD0,0x07,0x6C,0x64,0x00,0x00,0x00,0x00};
  BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
  BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
  
  //oScanResponseData.setFlags(0x06); // GENERAL_DISC_MODE 0x02 | BR_EDR_NOT_SUPPORTED 0x04
  //oScanResponseData.setCompleteServices(BLEUUID(beconUUID));
  beacon_data3[0] = 0x0D;
  beacon_data3[1] = Count3;
  Count3++;
  if(Count3>252)
  Count3 = 0;
  for(i=2;i<27;i++)
  {
    beacon_data3[i] = Test_Buff3[i];
  }
 

  oScanResponseData.setServiceData(BLEUUID(beconUUID), std::string(beacon_data3, 27));
  oAdvertisementData.setName("TLMBeacon");
  pAdvertising->setAdvertisementData(oAdvertisementData);
  pAdvertising->setScanResponseData(oScanResponseData);
}


void setup()
{

  Serial.begin(115200);
  //gettimeofday(&nowTimeStruct, NULL);

  //Serial.printf("start ESP32 %d\n", bootcount++);

  //Serial.printf("deep sleep (%lds since last reset, %lds since last boot)\n", nowTimeStruct.tv_sec, 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(ESP_PWR_LVL_N12); //设置蓝牙功率

  pAdvertising = BLEDevice::getAdvertising(); //创建BLEAdvertising 对象,可以用于设置和配置蓝牙广播数据。

  setBeacon1();
  // Start advertising
  pAdvertising->start(); //开始广播
  Serial.println("Advertizing started for 10s ...");
  delay(1000);
  setBeacon2();
  // Start advertising
  pAdvertising->start();//开始广播
  Serial.println("Advertizing started for 10s ...");
  delay(1000);
  setBeacon3();
  // Start advertising
  pAdvertising->start();//开始广播
  Serial.println("Advertizing started for 10s ...");
  delay(1000);
  pAdvertising->stop();//停止广播
  Serial.printf("enter deep sleep for 10s\n");
  //esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
  Serial.printf("in deep sleep\n");
}

void loop()
{
  setBeacon1();//第一帧数据
  // Start advertising
  pAdvertising->start();//开始广播
  Serial.println("Advertizing started for 10s ...");
  delay(1000); //留时间给设备收数据
  setBeacon2();//第二帧数据
  // Start advertising
  pAdvertising->start();//开始广播
  Serial.println("Advertizing started for 10s ...");
  delay(1000);//留时间给设备收数据
  setBeacon3();//第三帧数据
  // Start advertising
  pAdvertising->start();//开始广播
  delay(1000);//留时间给设备收数据
}

第二种方法
#include <ArduinoBLE.h>


BLEService myService("fff0"); //创建了一个 UUID 为 "fff0" 的 BLEService 对象
BLEIntCharacteristic myCharacteristic("fff1", BLERead | BLEBroadcast); //创建了一个 UUID 为 "fff1" 的 BLEIntCharacteristic 对象,该特征具有 BLERead 和 BLEBroadcast 权限。

// Advertising parameters should have a global scope. Do NOT define them in 'setup' or in 'loop'
const uint8_t completeRawAdvertisingData1[31] = {0x1E,0x16,0xfa,0xff,0x0D,0x01,0x01,0x12,0x31,0x39,0x35,0x32,0x46,0x30,0x39,0x30,0x43,0x4e,0x32,0x33,0x31,0x32,0x30,0x36,0x30,0x31,0x33,0x34,0x00,0x00,0x00}; 
const uint8_t completeRawAdvertisingData2[31] = {0x1E,0x16,0xfa,0xff,0x0D,0x01,0x41,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x08,0x00,0x31,0x00,0x03,0x00,0x00,0x28,0x00,0x00,0x01,0x00,0x00};
const uint8_t completeRawAdvertisingData3[31] = {0x1E,0x16,0xfa,0xff,0x0D,0x01,0x11,0x00,0x06,0x03,0x08,0x00,0x01,0x01,0x00,0x00,0x01,0x01,0x00,0x00,0x22,0x00,0x21,0xD0,0x07,0x6C,0x64,0x00,0x00,0x00,0x00};  

BLEAdvertisingData advData; //创建了一个 BLEAdvertisingData 对象,用于设置蓝牙广播数据。

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

  if (!BLE.begin()) {
    Serial.println("failed to initialize BLE!");
    while (1);
  }

  //myService.addCharacteristic(myCharacteristic);将特征 myCharacteristic 添加到服务 myService 中
  //BLE.addService(myService);将服务添加到 BLE 对象中,以便在蓝牙设备上广播该服务和特征
  //关闭了可以不广播
  // Build advertising data packet
  
  // If a packet has a raw data parameter, then all the other parameters of the packet will be ignored
  advData.setRawData(completeRawAdvertisingData1,    sizeof(completeRawAdvertisingData1));  //设置完整的原始广播数据到 advData 对象中
  // Copy set parameters in the actual advertising packet
  BLE.setAdvertisingData(advData);//将该数据设置到蓝牙广播中

  // Build scan response data packet
  BLEAdvertisingData scanData;//创建一个新的 BLEAdvertisingData 对象 scanData,用于构建扫描响应数据包。
  scanData.setLocalName("Test advertising raw data");
  // Copy set parameters in the actual scan response packet
  BLE.setScanResponseData(scanData);//将 scanData 设置为蓝牙设备的扫描响应数据,也就是看到的蓝牙名字为Test advertising raw data
  
  BLE.advertise(); //通过 advertise() 方法开始广播这些设置的数据

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

void loop() 
{
  static uint16_t count,Ble_Count;
  volatile static uint16_t i,j,k;
  //检测服务器端是否有活动的客户端连接
  Ble_Count++;
  if(Ble_Count == 100)  //不用死延时广播多包数据,这样不会影响添加的其他功能
  {
     advData.setRawData(completeRawAdvertisingData1, sizeof(completeRawAdvertisingData1));  //实时更新数据包
  // Copy set parameters in the actual advertising packet
    BLE.setAdvertisingData(advData);
    BLE.advertise(); //实时广播更新的数据包
  }
  else if(Ble_Count == 200)
  {
    advData.setRawData(completeRawAdvertisingData2, sizeof(completeRawAdvertisingData2));  
  // Copy set parameters in the actual advertising packet
    BLE.setAdvertisingData(advData);
    BLE.advertise();

  }
  else if(Ble_Count == 300)
  {
    Ble_Count = 0;
    advData.setRawData(completeRawAdvertisingData3, sizeof(completeRawAdvertisingData3));  
  // Copy set parameters in the actual advertising packet
    BLE.setAdvertisingData(advData);
    BLE.advertise();
  }

 // BLE.poll();//用于轮询 BLE 设备以查看是否有新的事件发生
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1692691.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++ RBTree封装mapset

目录 RBTreeNode的声明 RBTree结构 map结构 set结构 改造红黑树 迭代器类 迭代器成员函数 默认成员函数 Insert set map RBTreeNode的声明 template<class T> struct RBTreeNode {RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>*…

Seurat Dimplot函数学习总结

今天为了画这个cluster中怎么显示标签的图&#xff0c;研究了一个Seurat中怎么画这个图的&#xff0c;下面是学习过程中做的总结 运行例子 rm(listls()) library(Seurat) library(SeuratData) library(ggplot2) library(patchwork) pbmc3k.final <- LoadData("pbmc3k…

链路初始化和训练

一、总览 链路初始化和训练&#xff0c;由物理层进行控制&#xff0c;是一个基于硬件的过程。初始化设备的链路和端口&#xff0c;使得设备能够收发报文&#xff0c;在链路上正常通信。 在reset后由硬件自动启动完整的训练过程&#xff0c;并由LTSSM管理。 1 位锁定 训练开始…

禅道密码正确但是登录异常处理

禅道密码正确&#xff0c;但是登录提示密码错误的异常处理 排查内容 # 1、服务器异常&#xff0c;存储空间、数据库异常 # 2、服务异常&#xff0c;文件丢失等异常问题定位 # 1、df -h 排查服务器存储空间 # 2、根据my.php排查数据库连接是否正常 # 3、修改my.pho,debugtrue…

【百度云千帆AppBuilder】诗词达人:AI引领的诗词文化之旅

文章目录 写在前面&#xff1a;百度云千帆AppBuilder诗词达人&#xff1a;AI引领的诗词文化之旅功能介绍&#xff1a;诗词达人智能体的深度体验1. 诗词接龙学习2. 诗词深度解析3. 互动式问答4. 诗词创作辅助 技术特点详解&#xff1a;"诗词达人"智能体的创新技术零代…

牛客小白月赛94 解题报告 | 珂学家 | 茴字有36种写法

前言 很久没写题解了&#xff0c;有幸参加了94小白月赛内测&#xff0c;反馈是很nice&#xff0c;AK场。 争议的焦点在于哪题最难 D题E题(没有F题)F题(没有E题) 你选哪题呢&#xff1f; 题解 欢迎关注 珂朵莉 牛客周赛专栏 珂朵莉 牛客小白月赛专栏 A. 小苯的九宫格 思路…

驱动与系统学习网址

DRM&#xff08;Direct Rendering Manager&#xff09;学习简介-CSDN博客 Android Qcom Display学习(零)-CSDN博客 https://blog.csdn.net/hexiaolong2009/category_9705063.htmlhttps://blog.csdn.net/hexiaolong2009/category_9705063.htmlRender Hell —— 史上最通俗易懂…

OA界面这么香吗?总有老铁私信,让我多发点,他好参考。

OA的确是B端系统应用最为广泛的一种&#xff0c;这次再给大家分享十来个页面&#xff0c;希望对他们的界面提升有所帮助。 举报 评论 3

2024 一键批量下载微博内容/图片/视频/评论/转发数据,导出excel和pdf

以李健的微博为例&#xff0c;抓取2010-2024年所有的微博数据excel&#xff0c;包含微博链接&#xff0c;微博内容&#xff0c;发布时间&#xff0c;点赞数&#xff0c;转发数&#xff0c;评论数&#xff0c;话题等。 每个月的微博转评赞总数曲线&#xff0c;2015年是高峰。 微…

[OpenGL] opengl切线空间

目录 一 引入 二 TBN矩阵 三 代码实现 3.1手工计算切线和副切线 3.2 像素着色器 3.3 切线空间的两种使用方法 3.4 渲染效果 四 复杂的物体 本章节源码点击此处 继上篇法线贴图 来熟悉切线空间是再好不过的。对于法线贴图来说,我们知道它就是一个2D的颜色纹理,根据rgb…

Go语言的命名规范是怎样的?

文章目录 Go语言的命名规范详解一、标识符命名规范示例代码 二、包名命名规范示例代码 三、变量命名规范示例代码 四、常量命名规范示例代码 五、函数命名规范示例代码 总结 Go语言的命名规范详解 在Go语言中&#xff0c;代码的命名规范对于项目的可读性、可维护性和可扩展性至…

智能体之斯坦福AI小镇(Generative Agents: Interactive Simulacra of Human Behavior)

相关代码地址见文末 论文地址&#xff1a;Generative Agents: Interactive Simulacra of Human Behavior | Proceedings of the 36th Annual ACM Symposium on User Interface Software and Technology 1.概述 论文提出了一种多个智能体进行协同&#xff0c;进而模拟可信的人…

Java中String类型的大小

java对象在HotSpot虚拟机中的结构 Java对象由三部分组成&#xff0c;对象头、实例数据、填充数据。 对象头 markwork 存储对象运行时数据&#xff0c;HashCode、GC分代年龄、锁状态标志、线程持有的锁、偏向锁ID、偏向时间戳等。在64位虚拟机中&#xff0c;如果没有开启压缩指…

数据库系统基础知识

一、基本概念 二、数据库三级模式两级映像 三、数据库的分析与设计过程 四、数据模型 五、关系代数 六、数据库完整性约束 七、关系型数据库SQL简介 八、关系数据库的规范化 九、数据库的控制功能 十、数据仓库与数据挖掘基础 十一、大数据基本概念 数据库基本概念 1、数据库…

论文笔记:GPT4Rec: Graph Prompt Tuning for Streaming Recommendation

SIGIR 2024 1 intro 1.1 背景 传统推荐系统方法在实际应用中往往未能兑现基准数据集所做的承诺 这种差异主要源于传统的离线训练和测试方法在这些场景中&#xff0c;模型在大型静态数据集上训练&#xff0c;然后在有限的测试集上评估&#xff0c;这一过程没有考虑到现实世界…

第二十届文博会沙井艺立方分会场启幕!大咖齐打卡!

2024年5月24日-27日&#xff0c;第二十届中国&#xff08;深圳&#xff09;国际文化产业博览交易会沙井艺立方分会场活动将在艺立方非遗&#xff08;文旅&#xff09;产业园盛大举办。 本届文博会艺立方分会场活动办展特色鲜明&#xff0c;亮彩纷呈&#xff0c;将以“种下梧桐树…

留学培训行业PaaS应用系统架构的设计与实践

随着留学需求的增长和教育培训市场的不断扩大&#xff0c;留学培训行业正面临着越来越多的挑战和机遇。在这个背景下&#xff0c;利用PaaS&#xff08;Platform as a Service&#xff09;平台来构建留学培训行业的应用系统架构&#xff0c;将成为提升服务质量和效率的重要手段。…

工厂生产管理系统

为应对一些国内验厂&#xff0c;如大疆等&#xff0c;他们需要客户有自己的生产管理系统的&#xff0c;但实际很多公司是没有引入ERP这类的系统的&#xff0c;从而想开发一套简单的生产管理系统。 参考了网上一个比较古老的StorageMange项目&#xff0c;此项目用到DevExpress的…

「探讨」:什么是网络审计?好用的网络审计系统推荐【图文详解】

网络是企业运营、政府管理、个人生活不可或缺的基础设施。 然而网络安全问题却日益凸显&#xff0c;数据泄露、网络攻击、欺诈行为等风险日益严重。 一、网络审计的定义 网络审计&#xff0c;又称信息技术审计或电子审计&#xff0c;是指审计人员运用专业技能和工具&#xff…

亚马逊测评技术自己掌控:打造爆款产品,快速突破销量瓶颈

不管新老店铺来说&#xff0c;出单都是至关重要的&#xff0c;在我们的理解当中测评应该是一种成长剂&#xff0c;是一个加快店铺成长的工具&#xff0c;因为它在店铺的破0、突破瓶颈期、引爆爆款以及在后期店铺的一个补量上都会有一个明显的作用 测评有什么意义&#xff1f; …