본문 바로가기

아두이노우노 R4

UNO R4 WiFi BLE ⑤ BME280의 BLE peripheral

반응형

 

Arduino UNO R4 WiFi로 BLE ⑤ BME280의 BLE peripheral 

 

지난번에는 기압센서 BME280으로 기압과 온도, 습도를 측정하여 그래픽 디스플레이에 표시하였다.여기서는 측정한 두 데이터를 BLE(Bluetooth Low Energy)로 전송하는 BLE 페리페럴(peripheral)을 만든다.수신하는 쪽을 BLE 센트럴(central)이라고 합니다.

 

 

본 문서의 전체 리스트를 링크로 연결하였습니다. 참고하세요.

UNO R4 WiFi BLE ⑥ BME280의 BLE 주변기기와 연결되는 센트럴

UNO R4 WiFi BLE ⑤ BME280의 BLE peripheral

UNO R4 WiFi BLE ④ 기압 센서 BME280을 연결

UNO R4 WiFi BLE ③ LPS22의 BLE 주변기기와 연결되는 센트럴

UNO R4 WiFi BLE ② LPS22의 BLE 주변기기

UNO R4 WiFi BLE ① 기압 센서 LPS22 연결 

 

 

ArduinoBLE 라이브러리를 이용하여 스케치를 작성합니다.작성 시점에는 1.3.6이 최신 버전입니다.

 

이전 기압센서 LPS22에서는 데이터는 측정한 실수를 그대로 전송했다.Characteristic은 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) 

 

● 환경 사용

아두이노 UNO R4 WiFi

아두이노 IDE 2.2.1

Windows10 22H2 

 

● BLE의 각종 정의

 

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 Energy Explorer의 중앙 기능을 사용하여 PC에서 정보를 확인합니다.

 

localname을 검색하여 BME280_int를 찾았으니 Connect를 클릭하고, Discover Services를 클릭하여 Services의 내용을 표시한 화면이다.

 

Notification을 체크하면 항상 최신 데이터가 전송됩니다. 

 

 

 

전송된 데이터는 리틀엔디안의 16비트 정수로 읽고, 온도는 100으로 나누고 기압과 습도는 10으로 나눈다.

 

16비트 정수는 -32768~32767까지 표현할 수 있어 측정값을 충분히 표현할 수 있다. 

 

본 문서의 원문 자료는 이곳을 따라가면 만나실 수 습니다.

 

 

반응형

더욱 좋은 정보를 제공하겠습니다.~ ^^