Arduino UNO R4 WiFiでBLE ⑤ BME280のBLEペリフェラル

 前回、気圧センサBME280で、気圧と温度、湿度を測定し、グラフィック・ディスプレイに表示しました。

 ここでは、測定した二つのデータをBLE(Bluetooth Low Energy)で送信するBLEペリフェラル(peripheral を作成します。受信するほうはBLEセントラル(central )と呼ばれます。

 ArduinoBLEライブラリを利用してスケッチを作成します。執筆時点では、1.3.6が最新です。

 前の気圧センサLPS22では、データは、測定した実数をそのまま送信しました。キャラクタリスティックはBLEFloatCharacteristicでした。ここでは、実数を10倍もしくは100倍し、整数で送ることにします。使うのは、BLEIntCharacteristicです。

 このほかに、下記のキャラクタリスティックが利用できます。

ArduinoBLE - BLECharacteristic()

BLEBoolCharacteristic(uuid, properties)
BLEBooleanCharacteristic(uuid, properties)
BLECharCharacteristic(uuid, properties)
BLEUnsignedCharCharacteristic(uuid, properties)
BLEByteCharacteristic(uuid, properties)
BLEShortCharacteristic(uuid, properties)
BLEUnsignedShortCharacteristic(uuid, properties)
BLEWordCharacteristic(uuid, properties)
BLEIntCharacteristic(uuid, properties)
BLEUnsignedIntCharacteristic(uuid, properties)
BLELongCharacteristic(uuid, properties)
BLEUnsignedLongCharacteristic(uuid, properties)
BLEFloatCharacteristic(uuid, properties)
BLEDoubleCharacteristic(uuid, properties)

使用環境

  • Arduino UNO R4 WiFi
  • Arduino IDE 2.2.1
  • Windows10 22H2

BLEの各種定義

 ペリフェラルとセントラル間でBLEが接続されたとき、GATT通信が行われます。GATTはGeneric attribute profileの略です。

 GATT通信の中には複数のService(サービス)が入っています。ここでは、BME280という名称の一つのサービスだけが存在します。

 サービスの中には、複数のCharacteristic(キャラクタリスティック)が含まれています。ここでは、温度気圧湿度の三つです。

 キャラクタリスティックには、説明;Descriptorディスクリプタ)をつけられます。ない場合もあります。

 いろいろな機器の間でそれらのサービスやキャラクタリスティックとかが重ならないようにユニークなUUIDで識別します。

 BLEReadはセントラル側でCharacteristicの値を読み出し、BLENotifyはペリフェラル側でCharacteristicの値を通知する処理内容です。セントラルは、読み出しを実行したときに新しいデータを受信します。Notifyは、その機能をオンしておけば、常に新しいデータを受信できます。

 Descriptorの2901は、ユーザが可読できるCharacteristicの説明文字列(UTF-8)の指定です。

#define BME280_SERVICE_UUID   "F000AA30-0452-4000-B000-000000000000"  // BLE Service
BLEService Sensor_BME280_Service(BME280_SERVICE_UUID);

#define BME280_Temp_Characteristic_UUID    "F000AA31-0452-4000-B000-000000000000"  // BLE  Characteristic
#define BME280_Press_Characteristic_UUID   "F000AA32-0452-4000-B000-000000000000"
#define BME280_Humidity_Characteristic_UUID   "F000AA33-0452-4000-B000-000000000000"
BLEIntCharacteristic  BME280_Temp(BME280_Temp_Characteristic_UUID, BLERead | BLENotify);
BLEIntCharacteristic  BME280_Press(BME280_Press_Characteristic_UUID, BLERead | BLENotify);
BLEIntCharacteristic  BME280_Humidity(BME280_Humidity_Characteristic_UUID, BLERead | BLENotify);

#define BME280_Temp_Descriptor_UUID    "2901"  // BLE  Descriptor
#define BME280_Press_Descriptor_UUID   "2901"
#define BME280_Humidity_Descriptor_UUID   "2901"
BLEDescriptor   BME280_Temp_Descriptor(BME280_Temp_Descriptor_UUID, "Temperature: `C int format");
BLEDescriptor   BME280_Press_Descriptor(BME280_Press_Descriptor_UUID, "Pressure: hPa");
BLEDescriptor   BME280_Humidity_Descriptor(BME280_Humidity_Descriptor_UUID, "Humidity: %");

●setupーBLE

 最初に初期化します。

BLE.begin();


 localnameを指定します。

#define localNAME  "BME280_int"

 BLE.setLocalName(localNAME);


 service、characteristic、descriptorをBLEに追加します。

  BLE.setAdvertisedService(Sensor_BME280_Service);  // add the service UUID
  Sensor_BME280_Service.addCharacteristic(BME280_Temp);  // add characteristic
  Sensor_BME280_Service.addCharacteristic(BME280_Press);
  Sensor_BME280_Service.addCharacteristic(BME280_Humidity);
  BME280_Temp.addDescriptor(BME280_Temp_Descriptor);  // add descriptor
  BME280_Press.addDescriptor(BME280_Press_Descriptor);
  BME280_Humidity.addDescriptor(BME280_Humidity_Descriptor);
  BLE.addService(Sensor_BME280_Service);  // Add service


 Characteristicに初期値を入れます。

  BME280_Temp.writeValue(oldValue);  // set initial value for this characteristic
  BME280_Press.writeValue(oldValue);
  BME280_Humidity.writeValue(oldValue);


 準備が整ったので、セントラルからの接続待ち=アドバタイズを起動します。

  BLE.advertise();  // start advertising
  Serial.println("Bluetooth device active, waiting for connections...");

loopーBLE

 セントラルとの接続を待ちます。

  // wait for a BLE central
  BLEDevice central = BLE.central();


 つながったら、メッセージを出します。

  // if a central is connected to the peripheral:
  if (central) {
    delay(100);
    Serial.print("Connected to central: ");
    // print the central's BT address:
    Serial.println(central.address());
 
 つながっている間、updateValue();でデータを送信します。
 

    while (central.connected()) {
      updateValue();
      delay(1000);
    }

 接続が切れると、メッセージを出します。
 
 
    // when the central disconnects
    Serial.print("Disconnected from central: ");
    Serial.println(central.address());
 
 
  updateValue() {}関数内で、温度を100倍、気圧を10倍、湿度を10倍して、いずれも整数に変換したのち送ります。受信するセントラル側では、それぞれ、100や10で割ると、実数の測定値が得られます。
 

    BME280_Temp.writeValue((int)(tempC*100.0));
    BME280_Press.writeValue((int)(pressure*10.0));
    BME280_Humidity.writeValue((int)(humidity*10.0));
 
全体のスケッチ
 

// This is a library for the BME280 humidity, temperature & pressure sensor
//  Designed specifically to work with the Adafruit BME280 Breakout
//  ----> http://www.adafruit.com/products/2650
//  Written by Limor Fried & Kevin Townsend for Adafruit Industries.

#include <ArduinoBLE.h>

#define BME280_SERVICE_UUID   "F000AA30-0452-4000-B000-000000000000"  // BLE Service
BLEService Sensor_BME280_Service(BME280_SERVICE_UUID);

#define BME280_Temp_Characteristic_UUID    "F000AA31-0452-4000-B000-000000000000"  // BLE  Characteristic
#define BME280_Press_Characteristic_UUID   "F000AA32-0452-4000-B000-000000000000"
#define BME280_Humidity_Characteristic_UUID   "F000AA33-0452-4000-B000-000000000000"
BLEIntCharacteristic  BME280_Temp(BME280_Temp_Characteristic_UUID, BLERead | BLENotify);
BLEIntCharacteristic  BME280_Press(BME280_Press_Characteristic_UUID, BLERead | BLENotify);
BLEIntCharacteristic  BME280_Humidity(BME280_Humidity_Characteristic_UUID, BLERead | BLENotify);

#define BME280_Temp_Descriptor_UUID    "2901"  // BLE  Descriptor
#define BME280_Press_Descriptor_UUID   "2901"
#define BME280_Humidity_Descriptor_UUID   "2901"
BLEDescriptor   BME280_Temp_Descriptor(BME280_Temp_Descriptor_UUID, "Temperature: `C int format");
BLEDescriptor   BME280_Press_Descriptor(BME280_Press_Descriptor_UUID, "Pressure: hPa");
BLEDescriptor   BME280_Humidity_Descriptor(BME280_Humidity_Descriptor_UUID, "Humidity: %");

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_SSD1306.h> float tempC; float pressure; float humidity; Adafruit_BME280 bme; // I2C Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire); #define localNAME "BME280_int" int oldValue = 0; // last value void setup() { Serial.begin(115200); while (!Serial) delay(10); Serial.println(F("BME280 + ssd1306 + BLE")); // begin initialization if (!BLE.begin()) { Serial.println("starting BLE failed!"); while (1); } unsigned status; // default settings status = bme.begin(); // You can also pass in a Wire library object like &Wire2 // status = bme.begin(0x76, &Wire2) if (!status) { Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!"); Serial.print("SensorID was: 0x"); Serial.println(bme.sensorID(),16); Serial.print(" ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n"); Serial.print(" ID of 0x56-0x58 represents a BMP 280,\n"); Serial.print(" ID of 0x60 represents a BME 280.\n"); Serial.print(" ID of 0x61 represents a BME 680.\n"); while (1) delay(10); } Serial.println(); // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) { // Address 0x3C for 128x32 Serial.println(F("SSD1306 allocation failed")); for (;;) ; // Don't proceed, loop forever } display.display(); delay(500); // Pause for 2 seconds display.setTextSize(1); display.setTextColor(WHITE); display.setRotation(0); display.clearDisplay(); BLE.setLocalName(localNAME); BLE.setAdvertisedService(Sensor_BME280_Service); // add the service UUID Sensor_BME280_Service.addCharacteristic(BME280_Temp); // add characteristic Sensor_BME280_Service.addCharacteristic(BME280_Press); Sensor_BME280_Service.addCharacteristic(BME280_Humidity); BME280_Temp.addDescriptor(BME280_Temp_Descriptor); // add descriptor BME280_Press.addDescriptor(BME280_Press_Descriptor); BME280_Humidity.addDescriptor(BME280_Humidity_Descriptor); BLE.addService(Sensor_BME280_Service); // Add service BME280_Temp.writeValue(oldValue); // set initial value for this characteristic BME280_Press.writeValue(oldValue); BME280_Humidity.writeValue(oldValue); BLE.advertise(); // start advertising Serial.println("Bluetooth device active, waiting for connections..."); } void loop() { // wait for a BLE central BLEDevice central = BLE.central(); // if a central is connected to the peripheral: if (central) { delay(100); Serial.print("Connected to central: "); // print the central's BT address: Serial.println(central.address()); while (central.connected()) { updateValue(); delay(1000); } // when the central disconnects Serial.print("Disconnected from central: "); Serial.println(central.address()); } } void updateValue() { display.clearDisplay(); display.setCursor(0, 0); tempC = bme.readTemperature(); pressure = bme.readPressure() / 100.0; humidity = bme.readHumidity(); Serial.print("Temperature = "); Serial.print(tempC); Serial.println(" °C"); Serial.print("Pressure = "); Serial.print( pressure); Serial.println(" hPa"); Serial.print("Humidity = "); Serial.print(humidity); Serial.println(" %"); Serial.println(); display.println("Temperature: - `C"); display.print(tempC, 2); display.println(""); display.println(""); display.println("Pressure: - hPa"); display.print(pressure, 1); display.println(""); display.println(""); display.println("Humidity: - %"); display.print(humidity, 1); display.display(); // if value has changed if (tempC != oldValue) { // update characteristic BME280_Temp.writeValue((int)(tempC*100.0)); BME280_Press.writeValue((int)(pressure*10.0)); BME280_Humidity.writeValue((int)(humidity*10.0)); oldValue = tempC; // save the level for next comparison } }

動作の確認
 オン・セミコンダクターのBLEであるRSL10 Bluetooth Low Enaergy Exploerのセントラルの機能を使って、PCで情報を見ます。
 localnameをスキャンします。BME280_intを見つけたので、Connectします。Discover Servicesをクリックして、Servicesの内容を表示した画面です。
 Notificationをチェックすると、つねに最新データが送られてきます。
 

 送られてきたデータは、リトル・エンディアンの16ビット整数で読み取り、温度は100で割り、気圧と湿度は10で割ります。 

 16ビット整数は、-32768~32767 を表現できるので、測定値を十分に表現できます。

前へ

Arduino UNO R4 WiFiでBLE ④ 気圧センサBME280をつなぐ

次へ

Arduino UNO R4 WiFiでBLE ⑥ BME280のBLEペリフェラルと接続するセントラル