BLE 蓝牙低能耗(Bluetooth Low Energy)
BLE发送简单信息
#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
BLECharacteristic *pCharacteristic; //创建一个BLE特性pCharacteristic
bool deviceConnected = false; //连接否标志位
uint8_t txValue = 0; //TX的值
long lastMsg = 0; //存放时间的变量
String rxload = "BlackWalnutLabs"; //RX的预置值
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
//服务器回调
class MyServerCallbacks : public BLEServerCallbacks
{
void onConnect(BLEServer *pServer)
{
deviceConnected = true;
};
void onDisconnect(BLEServer *pServer)
{
deviceConnected = false;
}
};
//特性回调
class MyCallbacks : public BLECharacteristicCallbacks
{
void onWrite(BLECharacteristic *pCharacteristic)
{
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0)
{
rxload = "";
for (int i = 0; i < rxValue.length(); i++)
{
rxload += (char)rxValue[i];
Serial.print(rxValue[i]);
}
Serial.println("");
}
}
};
void setupBLE(String BLEName)
{
const char *ble_name = BLEName.c_str(); //将传入的BLE的名字转换为指针
BLEDevice::init(ble_name); //初始化一个蓝牙设备
BLEServer *pServer = BLEDevice::createServer(); // 创建一个蓝牙服务器
pServer->setCallbacks(new MyServerCallbacks()); //服务器回调函数设置为MyServerCallbacks
BLEService *pService = pServer->createService(SERVICE_UUID); //创建一个BLE服务
pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY);
//创建一个(读)特征值 类型是通知
pCharacteristic->addDescriptor(new BLE2902());
//为特征添加一个描述
BLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE);
//创建一个(写)特征 类型是写入
pCharacteristic->setCallbacks(new MyCallbacks());
//为特征添加一个回调
pService->start(); //开启服务
pServer->getAdvertising()->start(); //服务器开始广播
Serial.println("Waiting a client connection to notify...");
}
void setup()
{
Serial.begin(115200);
setupBLE("ESP32BLE"); //设置蓝牙名称
}
void loop()
{
long now = millis(); //记录当前时间
if (now - lastMsg > 1000)
{ //每隔1秒发一次信号
if (deviceConnected && rxload.length() > 0)
{
String str = rxload;
Serial.println("send");
if (str=="10086")
{
Serial.println("get");
const char *newValue = "OK"; //str.c_str();
pCharacteristic->setValue(newValue);
pCharacteristic->notify();
}
}
lastMsg = now; //刷新上一次发送数据的时间
}
}
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
// 访问下述网站生成自己的UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "b3f48ce7-6322-49e4-ab01-e672744db6fb"
#define CHARACTERISTIC_UUID "ef6a6b6a-5a46-474c-8b2a-93f05a2179f3"
void setup() {
Serial.begin(115200);
Serial.println("BLE开启!");
BLEDevice::init("ESP32-Test"); //初始化
BLEServer *pServer = BLEDevice::createServer(); //创建server
BLEService *pService = pServer->createService(SERVICE_UUID); //创建Service
BLECharacteristic *pCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID,BLECharacteristic::PROPERTY_READ |BLECharacteristic::PROPERTY_WRITE);
pCharacteristic->setValue("Hello World From ESP32");
pService->start(); //服务开启
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
// BLEAdvertising *pAdvertising = pServer->getAdvertising(); //兼容写法 this still is working for backward compatibility
pAdvertising->addServiceUUID(SERVICE_UUID); //设置服务UUID
pAdvertising->setScanResponse(true); //开启扫描响应(?)
pAdvertising->setMinPreferred(0x06); // 解决ipone手机连接问题,functions that help with iPhone connections issue
pAdvertising->setMinPreferred(0x12);
BLEDevice::startAdvertising(); //开始广播
Serial.println("Characteristic(特征)已定义,你可以在手机上查看");
}
void loop() {
delay(2000);
}
不断的扫描蓝牙设备
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
int scanTime = 5; //In seconds
BLEScan* pBLEScan;
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
}
};
void setup() {
Serial.begin(115200);
Serial.println("Scanning...");
BLEDevice::init("");
pBLEScan = BLEDevice::getScan(); //create new scan
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
pBLEScan->setInterval(100);
pBLEScan->setWindow(99); // less or equal setInterval value
}
void loop() {
// put your main code here, to run repeatedly:
BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
Serial.print("Devices found: ");
Serial.println(foundDevices.getCount());
Serial.println("Scan done!");
pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
delay(2000);
}
iBeacon 是苹果公司2013年9月发布的移动设备用OS(iOS7)上配备的新功能。其工作方式是,配备有 低功耗蓝牙(BLE)通信功能的设备使用BLE技术向周围发送自己特有的ID,接收到该ID的应用软件会根据该ID采取一些行动。比如,在店铺里设置iBeacon通信模块的话,便可让iPhone和iPad上运行一资讯告知服务器,或者由服务器向顾客发送折扣券及进店积分。此外,还可以在家电发生故障或停止工作时使用iBeacon向应用软件发送资讯。
其实iBeacon就是一个BLE(低功耗蓝牙)设备,不断的发出BLE广播。 iBeacon规定了广播里的数据格式,iBeacon理论上应该不能被连接,假如被连上了,别的手机就搜不到了,这样就失去了iBeacon广播数据的功能。
另:iBeacon 是苹果公司推出的一项室内定位技术,通过软件和硬件的结合,从而大大提高室内精度。
通过iBeacon软件,可以显示与信标的距离(感觉是通过Rssi信号强弱来估算的)。有机会可以试试通过笔记本的蓝牙来获取这些信标的信号。
#include "sys/time.h"
#include "BLEDevice.h"
#include "BLEUtils.h"
#include "BLEBeacon.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
#ifdef __cplusplus
extern "C" {
#endif
uint8_t temprature_sens_read();
//uint8_t g_phyFuns;
#ifdef __cplusplus
}
#endif
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
BLEAdvertising *pAdvertising;
struct timeval now;
#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 setBeacon() {
BLEBeacon oBeacon = BLEBeacon();
oBeacon.setManufacturerId(0x4C00); // fake 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; // Type
strServiceData += oBeacon.getData();
oAdvertisementData.addData(strServiceData);
pAdvertising->setAdvertisementData(oAdvertisementData);
pAdvertising->setScanResponseData(oScanResponseData);
pAdvertising->setAdvertisementType(ADV_TYPE_NONCONN_IND);
}
void setup() {
Serial.begin(115200);
gettimeofday(&now, NULL);
Serial.printf("start ESP32 %d\n",bootcount++);
Serial.printf("deep sleep (%lds since last reset, %lds since last boot)\n",now.tv_sec,now.tv_sec-last);
last = now.tv_sec;
// Create the BLE Device
BLEDevice::init(""); // 这里可以添加一个名称
// Create the BLE Server
// BLEServer *pServer = BLEDevice::createServer(); // <-- no longer required to instantiate BLEServer, less flash and ram usage
pAdvertising = BLEDevice::getAdvertising();
setBeacon();
// Start advertising
pAdvertising->start();
Serial.println("Advertizing started...");
delay(5000);
pAdvertising->stop();
Serial.printf("enter deep sleep\n");
esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
Serial.printf("in deep sleep\n");
}
void loop() {
}
esp32如果使同时使用了蓝牙模块、wifi模块和ota的话很有可能会导致程序过大(超过1M),系统无法启动的情况。这里提供一种通过修改分区表扩大程序储存空间的方法来避免这一问题。这一解决方法同样只用于因为其他问题导致的程序过大的情况。
esp32 同时打开蓝牙,wifi和ota后程序过大导致无法启动
然而,Arduino中需要如何呢?除了配置中的no OTA。有OTA还是方便许多。我选择了大程序3MB后,OTA功能是没有的。