蓝牙的发送和接收以及蓝牙的室内定位和蓝牙的基础知识

在嵌入式环境中,低功耗蓝牙(Bluetooth Low Energy, BLE)可以实现多种功能,主要包括:

  1. 数据传输:BLE可以用于传输小数据包,适合传感器数据、状态信息等。
  2. 设备控制:通过BLE可以远程控制设备,如开关、调节参数等。
  3. 位置服务:利用BLE信标,可以实现室内定位和导航。
  4. 健康监测:BLE常用于可穿戴设备,监测健康数据如心率、步数等。
  5. 智能家居:BLE可以连接智能家居设备,实现自动化控制。

BLE 接收和发送的实现

在嵌入式系统中,BLE的接收和发送通常通过特定的BLE模块或芯片来实现。以下是一个简单的示例,使用Python和pybluez库来实现BLE的接收和发送功能。请注意,实际的嵌入式开发可能需要使用C/C++和特定的SDK。

发送数据
import bluetooth

def send_data(address, port, data):
    # 创建蓝牙套接字
    sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
    try:
        # 连接到目标设备
        sock.connect((address, port))
        # 发送数据
        sock.send(data)
        print("数据发送成功")
    except Exception as e:
        print(f"发送失败: {
      
      e}")
    finally:
        # 关闭套接字
        sock.close()

# 示例用法
target_address = "00:11:22:33:44:55"  # 目标设备的MAC地址
target_port = 1  # 目标设备的端口
data_to_send = "Hello, BLE!"
send_data(target_address, target_port, data_to_send)
接收数据
import bluetooth

def receive_data(port):
    # 创建蓝牙套接字
    server_sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
    try:
        # 绑定到本地端口
        server_sock.bind(("", port))
        # 开始监听
        server_sock.listen(1)
        print("等待连接...")
        # 接受连接
        client_sock, address = server_sock.accept()
        print(f"已连接到 {
      
      address}")
        # 接收数据
        data = client_sock.recv(1024)
        print(f"接收到的数据: {
      
      data}")
    except Exception as e:
        print(f"接收失败: {
      
      e}")
    finally:
        # 关闭套接字
        client_sock.close()
        server_sock.close()

# 示例用法
receive_port = 1  # 本地监听的端口
receive_data(receive_port)

注意事项

  • 硬件支持:确保你的嵌入式设备支持BLE,并且正确配置了BLE模块。
  • 库和驱动:在嵌入式系统中,可能需要使用特定的库或驱动来与BLE模块通信。
  • 安全性:在实现BLE通信时,注意数据的加密和认证,以确保安全性。

以上代码是一个简单的示例,实际的嵌入式开发可能需要根据具体的硬件和平台进行调整。

蓝牙定位

在嵌入式环境中,低功耗蓝牙(Bluetooth Low Energy,简称BLE)是一种广泛应用的无线通信技术。它因其低功耗、低成本和易于部署的特点,适用于各种物联网(IoT)设备和应用。以下将详细介绍在嵌入式环境中使用BLE所需的基础知识、设备端口配置、连接管理、BLE信标功能以及其他相关内容,并提供相应的代码示例。

一、基础知识

1. BLE的工作原理

BLE是一种短距离无线通信技术,主要用于传输小量数据。它基于GATT(Generic Attribute Profile,通用属性配置文件)架构,分为两种核心角色:

  • 中央设备(Central):通常是智能手机、平板电脑等设备,负责扫描并连接外围设备。
  • 外围设备(Peripheral):如传感器、可穿戴设备等,负责广播其存在并接受中央设备的连接。

2. GATT架构

GATT架构包括:

  • 服务(Service):一组相关的特性(Characteristics)的集合,用于定义外围设备的功能。
  • 特性(Characteristic):包含特定的数据和相关的描述,以便中央设备读取、写入或订阅。

3. BLE协议栈

BLE协议栈主要分为以下几层:

  • 物理层(PHY Layer):负责无线信号的传输和接收。
  • 链路层(Link Layer):负责建立和维护物理连接。
  • L2CAP层(Logical Link Control and Adaptation Protocol):负责数据分段和重组。
  • ATT层(Attribute Protocol):用于定义设备上的属性(服务和特性)。
  • GATT层(Generic Attribute Profile):构建在ATT之上,定义设备的服务和特性。

二、硬件要求与设备端口配置

1. 硬件选择

常见的BLE模块和芯片包括:

  • Nordic Semiconductor nRF52系列:功能强大,支持多种协议,适合复杂应用。
  • Espressif ESP32:集成了Wi-Fi和BLE,性价比高,适用于多功能设备。
  • Dialog Semiconductor DA14580/14581:低功耗,适合小型设备。

2. 接口与端口配置

通常,BLE模块通过以下接口与主控微控制器(如MCU、单片机)连接:

  • UART(串口):用于AT命令通信,配置模块参数。
  • SPI/I2C:用于更高速的数据传输和控制。
  • GPIO:用于控制模块的复位、进入固件升级模式等。

示例:ESP32与外部BLE模块连接

ESP32          BLE模块
-------------------------
GPIO 17  <--> TXD
GPIO 16  <--> RXD
GND      <--> GND
3.3V     <--> VCC

3. 电源管理

由于BLE强调低功耗,设备端应合理管理电源:

  • 睡眠模式:在不需要通信时,进入低功耗睡眠模式。
  • 动态频率调节:根据需要调整通信频率,降低功耗。

三、BLE的连接管理

1. 广播与扫描

  • 广播(Advertising):外围设备周期性发送广播包,包含设备信息和可用服务。
  • 扫描(Scanning):中央设备监听广播包,发现可连接的外围设备。

2. 建立连接

一旦中央设备扫描到外围设备并决定连接,通信过程如下:

  1. 中央设备发送连接请求
  2. 外围设备接受连接,建立物理链路。
  3. 双方交换配对信息,完成安全认证(可选)。

3. 数据传输

建立连接后,中央设备可以读取、写入外围设备的特性,或订阅特性以接收通知。

4. 断开连接

通信完成或设备不再需要通信时,中央或外围设备均可主动断开连接。

四、BLE信标功能

1. 信标简介

BLE信标是一种特定的BLE外围设备,主要用于广播固定的信息,用于定位、广告和交互。常见的信标协议包括iBeacon和Eddystone。

2. iBeacon

由苹果公司推出,包含以下主要信息:

  • UUID:唯一标识符,区分不同的信标。
  • MajorMinor:进一步标识具体的信标或位置。
  • Tx Power:信标的发射功率,用于估算距离。

3. Eddystone

由Google推出,支持多种数据格式:

  • UID:唯一标识符。
  • URL:支持广播URL,便于网页互动。
  • TLM:传输信标状态信息,如电池电量、温度等。
  • EID:加密的临时标识符,增强安全性。

4. 实现信标功能

以下以ESP32为例,使用Arduino框架实现iBeacon信标功能。

4.1 硬件连接

ESP32自带BLE功能,无需外部BLE模块。

4.2 代码示例
// 文件路径: src/ble_beacon.ino
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEBeacon.h>
#include <esp_sleep.h>

void setup() {
    
    
  Serial.begin(115200);
  Serial.println("Starting BLE work!");

  // 初始化BLE设备
  BLEDevice::init("");

  // 设置iBeacon参数
  BLEBeacon beacon = BLEBeacon();
  beacon.setManufacturerId(0x4C00); // Apple的制造商ID
  beacon.setProximityUUID("12345678-1234-1234-1234-123456789ABC");
  beacon.setMajor(1);
  beacon.setMinor(1);
  beacon.setSignalPower(-59); // Tx Power

  // 创建Advertising数据
  BLEAdvertisementData advertisementData = BLEAdvertisementData();
  advertisementData.setFlags(0x04); // BR_EDR_NOT_SUPPORTED 0x04
  std::string beaconData = beacon.getAdvertisementData();
  advertisementData.addData(beaconData);

  // 开始广播
  BLEAdvertising *advertising = BLEDevice::getAdvertising();
  advertising->setAdvertisementData(advertisementData);
  advertising->setScanResponse(false);
  advertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
  advertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();
  Serial.println("Beacon started...");
}

void loop() {
    
    
  // 信标只需广播,无需在loop中执行任何操作
  delay(2000);
}

说明

  • BLEBeacon 类用于设置iBeacon的各项参数。
  • setProximityUUIDsetMajorsetMinor用于唯一标识信标。
  • setSignalPower设置信标的发射功率,用于距离估算。
  • 信标一旦启动,将持续广播其信息,中央设备可通过扫描接收。

五、BLE通信的接收与发送实现

在嵌入式系统中,实现BLE通信通常需要以下步骤:

  1. 初始化BLE模块
  2. 配置设备角色(中央或外围)。
  3. 定义GATT服务和特性
  4. 处理连接和数据传输

以下以ESP32为例,使用Arduino框架,实现BLE外围设备发送和接收数据。

1. 发送数据(作为外围设备)

// 文件路径: src/ble_peripheral_send.ino
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

// 定义服务和特性的UUID
#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

BLECharacteristic *pCharacteristic;
bool deviceConnected = false;

// 连接回调
class MyServerCallbacks: public BLEServerCallbacks {
    
    
    void onConnect(BLEServer* pServer) {
    
    
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {
    
    
      deviceConnected = false;
    }
};

void setup() {
    
    
  Serial.begin(115200);
  
  // 初始化BLE设备
  BLEDevice::init("ESP32_Peripheral");
  
  // 创建BLE服务器
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());
  
  // 创建BLE服务
  BLEService *pService = pServer->createService(SERVICE_UUID);
  
  // 创建BLE特性
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID,
                      BLECharacteristic::PROPERTY_NOTIFY
                    );
  
  pCharacteristic->addDescriptor(new BLE2902());
  
  // 启动服务
  pService->start();
  
  // 开始广告
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06); // for iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();
  Serial.println("Waiting for a client connection...");
}

void loop() {
    
    
  if (deviceConnected) {
    
    
      String dataToSend = "Hello from ESP32!";
      pCharacteristic->setValue(dataToSend.c_str());
      pCharacteristic->notify(); // 发送通知
      Serial.println("Sent data: " + dataToSend);
      delay(1000); // 每秒发送一次
  }
}

2. 接收数据(作为中央设备)

// 文件路径: src/ble_central_receive.ino
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>

// 定义扫描参数
int scanTime = 5; // 扫描时间(秒)
BLEScan* pBLEScan;

// 扫描到的设备处理
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
    
    
    void onResult(BLEAdvertisedDevice advertisedDevice) {
    
    
      Serial.print("发现设备: ");
      Serial.println(advertisedDevice.toString().c_str());
      
      // 判断是否为目标设备
      if (advertisedDevice.haveName() && advertisedDevice.getName() == "ESP32_Peripheral") {
    
    
        Serial.println("目标设备已发现,停止扫描...");
        pBLEScan->stop();
      }
    }
};

void setup() {
    
    
  Serial.begin(115200);
  Serial.println("初始化BLE扫描...");
  
  BLEDevice::init("");
  pBLEScan = BLEDevice::getScan(); // 创建扫描对象
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true); // 主动扫描
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(99);
}

void loop() {
    
    
  BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
  Serial.print("扫描完成,发现设备数量: ");
  Serial.println(foundDevices.getCount());
  Serial.println("扫描结束");
  pBLEScan->clearResults();   // 清除结果以释放内存
  delay(2000); // 等待2秒后重新扫描
}

3. 发送与接收数据的注意事项

  • 角色配置:确保设备角色正确,外围设备负责广播和通知,中央设备负责扫描和连接。
  • UUID管理:服务和特性的UUID需要保持唯一,避免冲突。
  • 连接管理:处理好设备连接和断开后的状态,确保资源释放。
  • 数据格式:定义统一的数据格式,便于解析和处理。

六、BLE的安全性

BLE通信中,安全性尤为重要,尤其是在传输敏感数据时。以下是一些常见的安全措施:

  • 配对与绑定:通过加密的配对过程,确保通信双方的身份。
  • 加密传输:使用AES-128加密算法,保护数据不被窃取或篡改。
  • 认证与授权:限制只有授权设备才能连接和通信。

示例:启用BLE的加密通信

// 文件路径: src/ble_secure.ino
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>

BLEServer* pServer = NULL;

class MySecurityCallbacks : public BLESecurityCallbacks {
    
    
    bool onConfirmPIN(uint32_t pin) {
    
    
      Serial.println("确认PIN代码");
      return true; // 自动确认PIN
    }

    uint32_t onPassKeyRequest() {
    
    
      Serial.println("请求PIN代码");
      return 123456; // 设置PIN代码
    }

    void onPassKeyNotify(uint32_t pass_key) {
    
    
      Serial.print("PIN代码通知: ");
      Serial.println(pass_key);
    }

    bool onSecurityRequest() {
    
    
      Serial.println("安全请求");
      return true;
    }

    void onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl) {
    
    
      if (cmpl.success) {
    
    
        Serial.println("BLE认证成功");
      } else {
    
    
        Serial.println("BLE认证失败");
      }
    }
};

void setup() {
    
    
  Serial.begin(115200);
  BLEDevice::init("ESP32_Secure");
  pServer = BLEDevice::createServer();
  
  // 设置安全回调
  BLESecurity* pSecurity = new BLESecurity();
  pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_MITM_BOND);
  pSecurity->setCapability(ESP_IO_CAP_NONE);
  pSecurity->setInitPairing(true);
  pSecurity->setRespPairing(true);
  pSecurity->setSecurityCallbacks(new MySecurityCallbacks());
  
  // 其余BLE配置...
}

void loop() {
    
    
  // 实现BLE服务和特性
}

七、其他重要考虑因素

1. 能源管理

在低功耗要求的应用中,合理的能源管理至关重要:

  • 动态调节广播间隔:根据需要调整广播频率,降低功耗。
  • 睡眠模式:在不需要通信时,进入睡眠模式,节省能源。
  • 功耗优化:选择低功耗的硬件组件,优化代码以减少CPU使用率。

2. 调试与测试

  • BLE调试工具:使用如nRF Connect、LightBlue等移动应用进行BLE设备的扫描、连接和数据交互测试。
  • 逻辑分析仪:监控BLE通信过程中的数据包,进行故障排查。
  • 测试框架:编写自动化测试脚本,验证BLE功能的正确性和稳定性。

3. 多设备管理

在复杂应用中,可能需要管理多个BLE设备:

  • 地址管理:跟踪各个BLE设备的MAC地址和连接状态。
  • 资源管理:合理分配BLE模块的资源,避免同时连接过多设备导致资源耗尽。
  • 优先级处理:根据应用需求,设置设备连接的优先级,确保重要数据的传输优先。

4. 数据同步与存储

确保BLE传输的数据能够正确同步和持久化:

  • 缓存机制:在连接不稳定时,缓存待发送的数据,待连接恢复后再发送。
  • 数据完整性:通过校验和或其他机制,确保传输数据的完整性。
  • 存储策略:根据数据的重要性,选择合适的数据存储策略,防止数据丢失。

八、总结

在嵌入式环境中使用低功耗蓝牙(BLE)涉及多方面的知识和技能,包括理解BLE的基本原理、选择合适的硬件、配置设备端口、实现连接管理、利用信标功能以及确保通信的安全性等。通过合理的设计和实施,BLE可以为各种物联网应用提供高效、可靠的无线通信解决方案。

以下是一个综合示例,展示如何在ESP32上实现BLE外围设备的发送和中央设备的接收,并包含信标功能。

综合示例代码

1. BLE外围设备发送数据并作为iBeacon信标
// 文件路径: src/ble_combined.ino
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLEBeacon.h>
#include <BLEAdvertising.h>

// 定义服务和特性的UUID
#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

BLECharacteristic *pCharacteristic;
bool deviceConnected = false;

// 连接回调
class MyServerCallbacks: public BLEServerCallbacks {
    
    
    void onConnect(BLEServer* pServer) {
    
    
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {
    
    
      deviceConnected = false;
    }
};

void setup() {
    
    
  Serial.begin(115200);
  Serial.println("Initializing BLE...");

  // 初始化BLE设备
  BLEDevice::init("ESP32_Combined");

  // 创建BLE服务器
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // 创建BLE服务
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // 创建BLE特性
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID,
                      BLECharacteristic::PROPERTY_NOTIFY
                    );

  pCharacteristic->addDescriptor(new BLE2902());

  // 启动服务
  pService->start();

  // 设置iBeacon参数
  BLEBeacon beacon = BLEBeacon();
  beacon.setManufacturerId(0x4C00); // Apple的制造商ID
  beacon.setProximityUUID("12345678-1234-1234-1234-123456789ABC");
  beacon.setMajor(1);
  beacon.setMinor(1);
  beacon.setSignalPower(-59);

  // 创建Advertising数据
  BLEAdvertisementData advertisementData = BLEAdvertisementData();
  advertisementData.setFlags(0x04); // BR_EDR_NOT_SUPPORTED
  std::string beaconData = beacon.getAdvertisementData();
  advertisementData.addData(beaconData);

  // 开始广告
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->setAdvertisementData(advertisementData);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06); // for iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();
  Serial.println("BLE Combined Peripheral Started as iBeacon.");
}

void loop() {
    
    
  if (deviceConnected) {
    
    
      String dataToSend = "Sensor Data: 25.3°C";
      pCharacteristic->setValue(dataToSend.c_str());
      pCharacteristic->notify(); // 发送通知
      Serial.println("Sent data: " + dataToSend);
      delay(1000); // 每秒发送一次
  }
}
2. BLE中央设备扫描、连接并接收数据
// 文件路径: src/ble_central_receive.ino
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>

// 定义扫描参数
int scanTime = 5; // 扫描时间(秒)
BLEScan* pBLEScan;

// 目标服务UUID
#define TARGET_SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"

// 连接回调
class MyClientCallbacks : public BLEClientCallbacks {
    
    
    void onConnect(BLEClient* pClient) {
    
    
    }

    void onDisconnect(BLEClient* pClient) {
    
    
      Serial.println("Disconnected from server");
    }
};

// 全局变量
BLEClient*  pClient;
BLERemoteCharacteristic* pRemoteCharacteristic;
bool connected = false;

// 查找目标服务和特性
bool connectToServer(BLEAdvertisedDevice advertisedDevice) {
    
    
  Serial.println("创建客户端...");
  pClient = BLEDevice::createClient();
  pClient->setClientCallbacks(new MyClientCallbacks());

  Serial.println("连接到服务器...");
  pClient->connect(&advertisedDevice); // 连接到外围设备

  // 获取服务
  BLERemoteService* pRemoteService = pClient->getService(TARGET_SERVICE_UUID);
  if (pRemoteService == nullptr) {
    
    
    Serial.println("无法找到目标服务");
    return false;
  }

  // 获取特性
  pRemoteCharacteristic = pRemoteService->getCharacteristic("beb5483e-36e1-4688-b7f5-ea07361b26a8");
  if (pRemoteCharacteristic == nullptr) {
    
    
    Serial.println("无法找到目标特性");
    return false;
  }

  // 订阅通知
  if(pRemoteCharacteristic->canNotify()) {
    
    
    pRemoteCharacteristic->registerForNotify([](BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {
    
    
      Serial.print("接收到通知: ");
      Serial.println((char*)pData);
    });
  }

  Serial.println("连接成功并订阅通知");
  return true;
}

// 扫描回调
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
    
    
    void onResult(BLEAdvertisedDevice advertisedDevice) {
    
    
      Serial.println(advertisedDevice.toString().c_str());
      
      // 判断是否为目标设备
      if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(BLEUUID(TARGET_SERVICE_UUID))) {
    
    
        Serial.println("目标设备已发现,尝试连接...");
        if (connectToServer(advertisedDevice)) {
    
    
          Serial.println("连接并订阅成功");
          connected = true;
          pBLEScan->stop();
        }
      }
    }
};

void setup() {
    
    
  Serial.begin(115200);
  Serial.println("初始化BLE中央设备...");

  BLEDevice::init("");
  pBLEScan = BLEDevice::getScan(); // 创建扫描对象
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true); // 主动扫描
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(99);
}

void loop() {
    
    
  if (!connected) {
    
    
    Serial.println("开始扫描...");
    pBLEScan->start(scanTime, false);
    Serial.println("扫描结束");
    delay(2000); // 等待2秒后重新扫描
  }
}

说明

  • BLE外围设备代码负责广播iBeacon信标信息,并在有中央设备连接时,通过通知方式发送传感器数据。
  • BLE中央设备代码扫描目标服务UUID,连接到外围设备后,订阅特性通知,并接收数据。

九、结论

在嵌入式环境中实现低功耗蓝牙(BLE)功能需要综合考虑硬件选择、通信协议、能源管理、安全性等多个方面。通过理解BLE的基础知识、合理配置设备端口、有效管理连接、利用信标功能以及确保数据传输的安全性,可以创建高效、可靠的BLE应用。以上提供的示例代码和详细说明,旨在帮助开发者更好地掌握在嵌入式系统中使用BLE的技巧和方法。

猜你喜欢

转载自blog.csdn.net/u011027104/article/details/143406875