初めてのBLE (15) ESP32でペリフェラル③浮動小数点形式
連載の第13回では、CPUの温度を1バイトで一度だけ送るペリフェラルを作成しました。ここでは、連続してCPUの温度を浮動小数点形式で送るように改造します。また、浮動小数点形式のデータを受け取るセントラルのスケッチも作ります。
●ESP32のペリフェラル
第13回のスケッチを手直しします。
BLECharacteristic *pCharacteristic;
キャラをインスタンス化する部分をsetup()の外に持ってきました。これで、loop()内でもキャラが使えます。
setup()では、byte変数で温度データを1byte送りました。
| int temp = temperatureRead(); Serial.println(temp); pCharacteristic->setValue((uint8_t*)&temp,1); |
それを、loop()内で、
| float temp = temperatureRead(); Serial.println(temp); pCharacteristic->setValue(temp); |
float型で送るようにします。IEEE754のunsign32ビット・データになります。
/*
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp
Ported to Arduino ESP32 by Evandro Copercini
updates by chegewara
*/
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
BLECharacteristic *pCharacteristic;
void setup() {
Serial.begin(115200);
Serial.println("Starting BLE work!");
BLEDevice::init("ESP32 peripheral");
BLEServer *pServer = BLEDevice::createServer();
BLEService *pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE
);
int temp = temperatureRead();
Serial.println(temp);
pCharacteristic->setValue((uint8_t*)&temp,1);
pService->start();
// BLEAdvertising *pAdvertising = pServer->getAdvertising(); // this still is working for backward compatibility
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
pAdvertising->setMinPreferred(0x12);
BLEDevice::startAdvertising();
// Serial.println("Characteristic defined! Now you can read it in your phone!");
}
void loop() {
// put your main code here, to run repeatedly:
float temp = temperatureRead();
Serial.println(temp);
pCharacteristic->setValue(temp);
pCharacteristic->notify();
delay(2000);
}
●NANO 33 BLE senseのセントラル
サンプル・スケッチPeripheralExploreを改造しています。
float型IEEE754のunsign32ビット・データは、次のような形式ですが、uint8_t四個に分割され、逆順(リトル・エンディアン)で送られてきます。
85行では、最後の桁 (uint8_t)*(ledCharacteristic.value()+3) から読み出し、四個を合成します。
87~89行では、その32ビットのデータの先頭1ビットを符号(f)で取り出し、次の8ビットを指数(s)、残りの22ビットの先頭に1を加えて仮数(k)とします。三つの結果をかけると浮動小数点の値に戻ります。
#include <ArduinoBLE.h>
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define localNAME "ESP32 peripheral"
void setup() {
Serial.begin(9600);
while (!Serial);
BLE.begin();
Serial.println("\nstart BLE Central - CPU temp");
// start scanning for peripherals
BLE.scanForName(localNAME);
}
void loop() {
// check if a peripheral has been discovered
BLEDevice peripheral = BLE.available();
if (peripheral) {
// discovered a peripheral, print out address, local name, and advertised service
Serial.print("Found ");
Serial.print(peripheral.address());
Serial.print(" '");
Serial.print(peripheral.localName());
Serial.print("' ");
Serial.print(peripheral.advertisedServiceUuid());
Serial.println();
if (peripheral.localName() != localNAME) {
return;
}
// stop scanning
BLE.stopScan();
controlLed(peripheral);
// peripheral disconnected, start scanning again
BLE.scanForName(localNAME);
}
}
void controlLed(BLEDevice peripheral) {
// connect to the peripheral
Serial.print("Connecting ...");
if (peripheral.connect()) {
Serial.println("Connected");
} else {
Serial.println("Failed to connect!");
return;
}
// discover peripheral attributes
Serial.print("Discovering attributes ...");
if (peripheral.discoverAttributes()) {
Serial.println("Attributes discovered\n");
} else {
Serial.println("Attribute discovery failed!");
peripheral.disconnect();
return;
}
// retrieve the LED characteristic
BLECharacteristic ledCharacteristic = peripheral.characteristic(CHARACTERISTIC_UUID);
if (!ledCharacteristic) {
Serial.println("Peripheral does not have LED characteristic!");
peripheral.disconnect();
return;
} else if (!ledCharacteristic.canWrite()) {
Serial.println("Peripheral does not have a writable LED characteristic!");
peripheral.disconnect();
return;
}
Serial.println("---Found CHARACTERISTIC_UUID");
while (peripheral.connected()) {
if (ledCharacteristic.canRead()) {
// read the characteristic value
ledCharacteristic.read();
if (ledCharacteristic.valueLength() > 0) {
uint32_t data = ((uint8_t)*(ledCharacteristic.value()+3) << 24) + ((uint8_t)*(ledCharacteristic.value()+2) << 16) + ((uint8_t)*(ledCharacteristic.value()+1) << 8) + ((uint8_t)*ledCharacteristic.value());
// Serial.println();Serial.println(data,HEX);
int32_t f = pow(-1, int(bitRead(data,31)));
double k =1 + ((((data<<1)<<8)>>9))/pow(2,23);
int32_t s = pow(2,((((data<<1)>>24))-127));
Serial.println();
Serial.println(f*k*s);
// print out the value of the characteristic
Serial.print("\nvalue 0x");
printData(ledCharacteristic.value(), ledCharacteristic.valueLength());
delay(5000);
}
}
}
Serial.println("Peripheral disconnected");
}
void printData(const unsigned char data[], int length) {
for (int i = 0; i < length; i++) {
unsigned char b = data[i];
if (b < 16) {
Serial.print("0");
}
Serial.print(b, HEX);Serial.print("(");Serial.print(b);Serial.print(")");
}
}
実行中の様子です。
(役立つサイト)Floating Point to Hex Converter
(2021/12/19 追加 文字列で送信) 本文中では、pCharacteristic->setValue(temp);とfloartのデータを送信しています。このCharacteristicはいろいろな型に対応していて、Arduino IDE-BLEライブラリのように文字型とか整数型の指定は不要です。
文字型にした事例です。電圧を読み取ってきます。
float Volts = read_Voltsdata(); String s = String(Volts,6); char sVolts[16]; s.toCharArray(sVolts,s.length()); Serial.println(&sVolts[0]); pCharacteristic->setValue(&sVolts[0]); pCharacteristic->notify();