11. 蓝牙低功耗(BLE)串口透传

蓝牙低功耗(BLE, Bluetooth Low Energy)串口透传使用较为广泛。在苹果的iOS平台,经典蓝牙需要有MFi认证才可以和苹果的iOS设备进行连接。而蓝牙低功耗设备并没有这个限制。

蓝牙低功耗的协议栈和原理这里就不再赘述了,相关的文章和视频较多。简单的来说就是蓝牙服务以Profile的方式提供,每个服务的Profile下有N个具有独立ID(UUID)的character。每个character有不同的权限(read,write,notify,indicate)。用户定义character并且和权限组合后,就可以提供完整的服务了。

BLE透传的实际上是建立了一个BLE的Service,这个Profile下有2个character。

#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"

一个用于TX(发送数据),一个用于RX(接收数据)。为此他们有不同的权限。下面的代码是新建service和character的:

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);
  
  // Create a BLE Characteristic
  pTxCharacteristic = pService->createCharacteristic(
										CHARACTERISTIC_UUID_TX,
										BLECharacteristic::PROPERTY_NOTIFY
									);
                      
  pTxCharacteristic->addDescriptor(new BLE2902());

  BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
											 CHARACTERISTIC_UUID_RX,
											BLECharacteristic::PROPERTY_WRITE
										);

接下来是2个回调函数,分别在有连接时,以及有write RX character时进行的操作:

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) {
        Serial.println("*********");
        Serial.print("Received Value: ");
        for (int i = 0; i < rxValue.length(); i++)
          Serial.print(rxValue[i]);

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

最后主循环是连接的控制,判断是否又连接,是否断开连接。

    if (deviceConnected) {
        pTxCharacteristic->setValue(&txValue, 1);
        pTxCharacteristic->notify();
        txValue++;
		    delay(10); // bluetooth stack will go into congestion, if too many packets are sent
	  }
    
    // disconnecting
    if (!deviceConnected && oldDeviceConnected) {
        delay(500); // give the bluetooth stack the chance to get things ready
        pServer->startAdvertising(); // restart advertising
        Serial.println("start advertising");
        oldDeviceConnected = deviceConnected;
    }
    // connecting
    if (deviceConnected && !oldDeviceConnected) {
		// do stuff here on connecting
        oldDeviceConnected = deviceConnected;
    }

完整的代码见官方库的示例:ble_uart,调试工具可以使用LightBlue。

Last updated