Try   HackMD

如何使用iOS設備控制藍牙開發板

本文章使用esp32作為範例
#iPhone #esp32 #藍牙 #iPhone控制esp32

方法

  1. 我的GitHub將blueToastDemo資料夾下載並開啟(不熟悉GitHub操作的話可以至文章底部複製)
  2. 到例如 https://www.uuidgenerator.net/ 之類的UUID生成網站產生一份UUID,並將此行UUID替換掉
#define myUuid "aaaaaaae-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
  1. 測試腳位為15,可自行更改
#define testPin 15 // 測試腳位
  1. 於Ios設備顯示之名稱,預設為"espDevice",可自行更改
BLEDevice::init("espDevice");
  1. 撰寫自己所需功能程式,範例為開關燈範例程式,stringValue為藍牙接收到之指令(可在後續於App自定義)
// ----------------- ↓ 自定義功能區↓ ----------------- // 以下為開燈範例,請自己撰寫所需功能 if (stringValue == "lightOn") { digitalWrite(testPin, 1); } else if (stringValue == "lightOff") { digitalWrite(testPin, 0); } // ----------------- ↑ 自定義功能區↑ -----------------
  1. 將程式燒入進開發板內

  2. 至App Store下載 不如吐司App

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
  3. 授權藍牙權限

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
  4. 如果順利的話應該開啟後就會找到你取的裝置名稱

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
  5. 連接裝置後可以點擊右上角加號新增自訂按鈕,編輯頁面最下方輸入指令區為設定藍牙傳送之字串,按下按鈕後即發送此串字串,而同時開發板程式中的stringValue變數會變為接收到之字串。

    圖標庫是使用蘋果系統內建的SF Symbols所以搜尋時需使用英文名稱搜尋,此圖標庫有5000多個圖標,若找不到理想icon時可以多換關鍵字搜尋,例如燈相關可以搜尋"light"之類的單字。

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
  6. 想要刪除或編輯按鈕的話長按按鈕即可叫出選單選擇

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

完整範例程式

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

BLEServer *pServer = NULL;
BLECharacteristic * pTxCharacteristic;
String stringValue = "";
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint8_t value[2];
#define testPin 15 // 測試腳位
// ↓ 請至 https://www.uuidgenerator.net/ 自行產生一組 UUID
#define myUuid "aaaaaaae-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
// 	↑請將上方字串更換為自己的 UUID
#define service_uuid myUuid
#define rx_uuid myUuid
#define tx_uuid myUuid

class MyServerCallbacks: public BLEServerCallbacks{
  void onConnect(BLEServer* pServer){
    deviceConnected = true;
  };
  void onDisconnect(BLEServer* pServer){
    deviceConnected = false;
    }
};
String values(uint8_t value) {
  char hex[2];
  sprintf(hex, "%02X", value);
  return hex;
};

class MyCallbacks: public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *pCharacteristic) {
    std::string rxValue = pCharacteristic->getValue();
    if (rxValue.length() >0) {
      String allValues = "";
      String stringValues = "";
      for(int i=0; i<rxValue.length(); i++) allValues += values(rxValue[i]);
      for(int i=0; i<rxValue.length(); i++) stringValues += rxValue[i];
      Serial.println(allValues);
      Serial.println(stringValues);
      value[0] = rxValue[0];
      value[1] = rxValue[1];
    }
  }
};


void setup() {
  pinMode(testPin, OUTPUT);
  Serial.begin(115200);
  // 裝置名稱↓ 
  BLEDevice::init("espDevice");
  // 裝置名稱↑
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());
  BLEService *pService = pServer->createService(service_uuid);
  pTxCharacteristic = pService->createCharacteristic(tx_uuid, BLECharacteristic::PROPERTY_NOTIFY);
  pTxCharacteristic->addDescriptor(new BLE2902());
  BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(rx_uuid, BLECharacteristic::PROPERTY_WRITE);
  pRxCharacteristic->setCallbacks(new MyCallbacks());
  pService->start();
  pServer->getAdvertising()->start();
  Serial.println("waiting a client connection to notify...");
}

void loop(){
  if(deviceConnected) {
    pTxCharacteristic->setValue((uint8_t*)&value, sizeof(value));
    pTxCharacteristic->notify();
		delay(10);
	}
  // ----------------- ↓ 自定義功能區↓  -----------------
  // 以下為開燈範例,請自己撰寫所需功能
	if (stringValue == "lightOn") {
	  digitalWrite(testPin, 1);
  } else if (stringValue == "lightOff") {
	  digitalWrite(testPin, 0);
	}
  // ----------------- ↑ 自定義功能區↑  -----------------
 
	if (!deviceConnected && oldDeviceConnected) {
	  delay(500);
	  pServer->startAdvertising();
	  Serial.println("start advertising");
	  oldDeviceConnected = deviceConnected;
	}
	if (deviceConnected && !oldDeviceConnected) {
	  oldDeviceConnected = deviceConnected;
	}
}