Главная chevron_right Уроки chevron_right Связь chevron_right Bluetooth® Low Energy с Arduino

Bluetooth® Low Energy с Arduino

Узнайте, как работает Bluetooth® Low Energy, и научитесь создавать BLE-проекты на Arduino с помощью библиотеки ArduinoBLE.

Введение

Bluetooth® Low Energy (сокращённо Bluetooth® LE или BLE) — это беспроводная технология для обмена данными на коротких расстояниях между электронными устройствами. Она появилась как ответ на запрос рынка: нужна была связь, которая почти не расходует энергию, — особенно в устройствах, где каждый миллиампер на счету.

В отличие от классического Bluetooth®, рассчитанного на непрерывную передачу данных с относительно высокой скоростью, Bluetooth® LE жертвует скоростью ради экономии энергии. Именно поэтому его используют в фитнес-браслетах, медицинских датчиках, умных сенсорах и устройствах IoT.

Цель этой статьи — объяснить базовые концепции Bluetooth® Low Energy и показать, как применять библиотеку ArduinoBLE для создания BLE-проектов на совместимых платах Arduino.

Поддерживаемые платы

Bluetooth® LE работает на следующих платах Arduino:

Чтобы повторить примеры из этой статьи, вам понадобится совместимая плата и библиотека ArduinoBLE library

Немного истории: Харальд Синезубый

Название «Bluetooth®» восходит к датскому королю X века Харальду Синезубому (Harald Blåtand), правившему примерно с 958 по 986 год. Он прославился тем, что объединил разрозненные датские племена и принял христианство, что оказало огромное влияние на историю Дании. Прозвище «Blåtand» (буквально — «синий зуб») связывают с его потемневшим или мёртвым зубом.

Аналогия очевидна: как Харальд объединил племена, так и протокол Bluetooth® призван объединить разные устройства и стандарты связи.

Технические характеристики

Рассмотрим ключевые концепции и технические параметры Bluetooth® Low Energy.

Частотный диапазон

Bluetooth® LE работает в диапазоне 2,4 GHz ISM (промышленный, научный и медицинский диапазон), который также используется Wi-Fi, микроволновыми печами и другими беспроводными технологиями. Этот диапазон делится на несколько каналов, по которым устройства и обмениваются данными.

Дальность связи

В типичных условиях Bluetooth® LE обеспечивает связь на расстоянии до 50 метров (около 164 футов) при прямой видимости. На практике дальность зависит от нескольких факторов:

Препятствия. Стены, мебель и другие объекты заметно сокращают дальность. Особенно плохо сигнал проходит через толстые бетонные стены.

Помехи. Диапазон 2,4 GHz делят между собой множество устройств. Помехи от соседнего Wi-Fi или другого BLE-устройства могут снизить надёжность соединения.

Конструкция антенны. Качество и форм-фактор антенны напрямую влияют на зону покрытия. Хорошо спроектированная антенна — это заметно лучший сигнал.

Ориентация устройств. Прямая видимость между устройствами даёт максимальную дальность; любые препятствия на пути сигнала её уменьшают.

Центральное и периферийное устройство

В BLE каждое устройство выполняет одну из двух ролей.

Центральное устройство (Central). Как правило, это более мощное устройство — с быстрым процессором, достаточным объёмом памяти и ёмкой батареей. Именно центральное устройство инициирует подключение к периферийным. Например, ваш смартфон выступает центральным устройством, когда подключается к фитнес-браслету или плате Arduino.

Периферийное устройство (Peripheral). Периферийные устройства, как правило, ресурсно ограничены (например, плата Arduino по сравнению со смартфоном). Они периодически рассылают рекламные пакеты, оповещая о своём присутствии. В отличие от классического Bluetooth®, BLE-устройства не поддерживают постоянное соединение с центральным устройством — это экономит энергию.

Bluetooth® LE Roles Роли Bluetooth® LE: периферийные устройства подключаются к центральному устройству

Режимы рекламы и соединения

Режим рекламы (Advertising Mode). В этом режиме периферийное устройство периодически рассылает рекламные пакеты с информацией о себе: идентификатором, доступными сервисами и характеристиками. Центральные устройства сканируют эфир и обнаруживают такие пакеты. Пока соединение не установлено, периферия находится в энергосберегающем состоянии — она просто «ждёт» подключения.

Режим соединения (Connection Mode). Этот режим активируется после того, как центральное устройство успешно подключилось к периферийному. Теперь устройства могут обмениваться данными в обоих направлениях: центральное устройство читает данные с периферии и записывает данные на неё.

Bluetooth® LE Modes Режимы Bluetooth® LE: анимация показывает попытку подключения центрального устройства к недоступному периферийному

Сервисы и характеристики

Сервисы и характеристики — это основные строительные блоки BLE, определяющие, как организованы и передаются данные.

Сервисы (Services)

Сервис — это логическая группа связанных данных или функций, которые предоставляет периферийное устройство. Представьте метеосенсор: у него может быть сервис «Weather Data» с измерениями температуры, влажности и скорости ветра. Другой сервис — «Energy Information» — содержит данные об уровне заряда батареи и потреблении энергии.

Характеристики (Characteristics)

Внутри каждого сервиса находятся характеристики — отдельные точки данных. В сервисе «Weather Data» это могут быть «Temperature», «Humidity» и «Wind Speed». Характеристики непрерывно обновляются по мере поступления новых измерений.

Уникальные универсальные идентификаторы (UUIDs)

Чтобы различать сервисы и характеристики, BLE использует UUID — 128-битный идентификатор, уникальный для каждого сервиса или характеристики. Именно по UUID центральное устройство находит нужные данные на периферии.

UUIDs играют ключевую роль в BLE-коммуникации: они исключают путаницу и позволяют точно обращаться к нужным данным. UUIDs — это своего рода ключи, открывающие доступ к конкретным данным периферийного устройства.

Профили (Profiles)

Bluetooth® LE профили — это заранее определённые наборы сервисов и характеристик, стандартизирующие взаимодействие устройств. Каждый профиль ориентирован на конкретную задачу и гарантирует совместимость устройств разных производителей.

Наиболее распространённые стандартные профили:

  • Battery Service — информация об уровне заряда батареи. Центральное устройство читает характеристику Battery Level, чтобы знать, сколько заряда осталось у наушников или смарт-часов.
  • Heart Rate Service — данные о пульсе в реальном времени. Используется в фитнес-приложениях и медицинских мониторах.
  • Generic Access Profile (GAP) — определяет роли устройств и процедуры обнаружения и установки соединения. Это фундамент всей BLE-коммуникации.

Подробнее о профилях Bluetooth® можно прочитать here.

Помимо стандартных профилей, разработчики могут создавать собственные — с уникальными сервисами и характеристиками под конкретный проект. Это открывает широкие возможности: от мониторинга здоровья до умного дома.

Bluetooth® LE против Bluetooth® Classic

Bluetooth® LE и Bluetooth® Classic — это принципиально разные технологии. Классический Bluetooth® работает как последовательный порт (UART) и рассчитан на точечное соединение с непрерывной передачей данных.

Основные отличия:

Энергопотребление

  • Bluetooth® Classic: потребляет больше энергии из-за непрерывного соединения. Не подходит для устройств с маленькой батареей.
  • Bluetooth® LE: оптимизирован для минимального потребления. Устройства на BLE могут работать месяцами от небольшой батарейки или даже от энергосбора.

Скорость передачи данных

  • Bluetooth® Classic: высокая скорость — подходит для стриминга аудио и передачи файлов.
  • Bluetooth® LE: скорость ниже, зато потребление минимальное. Идеален для редкой отправки небольших порций данных: показаний сенсоров, команд управления.

Тип соединения

  • Bluetooth® Classic: постоянное соединение с относительно высоким потреблением.
  • Bluetooth® LE: два режима — реклама и соединение. В режиме рекламы периферия периодически сигнализирует о себе, не поддерживая постоянного соединения и экономя энергию. Соединение устанавливается только по запросу.

Библиотека ArduinoBLE

ArduinoBLE Library — главная библиотека для работы с Bluetooth® Low Energy на совместимых платах Arduino. Прежде всего установите библиотеку ArduinoBLE. Как это сделать, описано в руководстве instructions.

Ниже — обзор наиболее важных методов библиотеки.

  • BLE.begin() — инициализация библиотеки

Методы центрального устройства

  • BLE.scan() — начать сканирование периферийных устройств
  • BLE.available() — проверить наличие доступных периферийных устройств
  • BLE.scanForUuid("UUID") — сканировать периферийные устройства с конкретным UUID
  • bleDevice.address() — получить адрес периферийного устройства
  • bleDevice.localName() — получить имя периферийного устройства
  • bleDevice.advertisedServiceUuid() — получить рекламируемый сервис периферийного устройства
  • bleDevice.connect() — подключиться к BLE-устройству
  • BLE.connected() — проверить успешность подключения
  • bleDevice.discoverAttributes() — обнаружить атрибуты периферийного устройства
  • BLE.stopScan() — остановить сканирование
  • BLE.disconnect() — отключиться от периферийного устройства

Методы периферийного устройства

  • BLE.setLocalName(name) — задать имя устройства
  • BLEService newService(service) — создать объект сервиса

Подробнее о стандартных сервисах — в Assigned Numbers document.

  • BLEUnsignedCharCharacteristic customCharacteristic("UUID_here", Properties_here); — создать объект характеристики
  • BLE.setAdvertisedService(bleService) — задать рекламируемый сервис
  • bleService.addCharacteristic(bleCharacteristic) — добавить характеристику в сервис
  • bleCharacteristic.writeValue() — записать значение характеристики
  • BLE.advertise() — начать рекламу

Здесь перечислены только самые важные методы. Полный список с описанием каждого метода — в ArduinoBLE reference.

Примеры

Ниже приведены примеры: передача данных между двумя платами Arduino и управление платой со смартфона через приложение.

Дистанционное управление светодиодом

Для этого примера понадобятся две платы Arduino с поддержкой Bluetooth® LE. К одной подключается кнопка, другая управляет светодиодом. При нажатии кнопки первая плата рекламирует соответствующее значение (HIGH/LOW), которое принимает вторая плата и меняет состояние светодиода.

Центральное устройство

Этот скетч сканирует BLE-периферию с определённым UUID (в нашем случае — другую плату Arduino), подключается к ней и позволяет управлять встроенным светодиодом с помощью кнопки, подключённой к пину 4.

  • В схеме ниже используется [Arduino UNO R4 WiFi](). Вы можете взять любую совместимую плату из [этого списка]().

central Схема подключения: Arduino UNO R4 WiFi с кнопкой на макетной плате (центральное устройство)

Загрузите следующий скетч:

#include <ArduinoBLE.h>

// переменные для кнопки
const int buttonPin = 4;
int oldButtonState = LOW;

void setup() {
  Serial.begin(9600);
  while (!Serial);

  // настройка пина кнопки как входа
  pinMode(buttonPin, INPUT);

  // инициализация аппаратной части Bluetooth® Low Energy
  BLE.begin();

  Serial.println("Bluetooth® Low Energy Central - LED control");

  // начало сканирования периферийных устройств
  BLE.scanForUuid("19b10000-e8f2-537e-4f6c-d104768a1214");
}

void loop() {
  // проверка обнаружения периферийного устройства
  BLEDevice peripheral = BLE.available();

  if (peripheral) {
    // периферийное устройство обнаружено, вывод адреса, локального имени и рекламируемого сервиса
    Serial.print("Found ");
    Serial.print(peripheral.address());
    Serial.print(" '");
    Serial.print(peripheral.localName());
    Serial.print("' ");
    Serial.print(peripheral.advertisedServiceUuid());
    Serial.println();

    if (peripheral.localName() != "LED") {
      return;
    }

    // остановка сканирования
    BLE.stopScan();

    controlLed(peripheral);

    // периферийное устройство отключилось, возобновление сканирования
    BLE.scanForUuid("19b10000-e8f2-537e-4f6c-d104768a1214");
  }
}

void controlLed(BLEDevice peripheral) {
  // подключение к периферийному устройству
  Serial.println("Connecting ...");

  if (peripheral.connect()) {
    Serial.println("Connected");
  } else {
    Serial.println("Failed to connect!");
    return;
  }

  // обнаружение атрибутов периферийного устройства
  Serial.println("Discovering attributes ...");
  if (peripheral.discoverAttributes()) {
    Serial.println("Attributes discovered");
  } else {
    Serial.println("Attribute discovery failed!");
    peripheral.disconnect();
    return;
  }

  // получение характеристики LED
  BLECharacteristic ledCharacteristic = peripheral.characteristic("19b10001-e8f2-537e-4f6c-d104768a1214");

  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;
  }

  while (peripheral.connected()) {
    // пока периферийное устройство подключено

    // чтение пина кнопки
    int buttonState = digitalRead(buttonPin);

    if (oldButtonState != buttonState) {
      // состояние кнопки изменилось
      oldButtonState = buttonState;

      if (buttonState) {
        Serial.println("button pressed");

        // кнопка нажата, запись 0x01 для включения LED
        ledCharacteristic.writeValue((byte)0x01);
      } else {
        Serial.println("button released");

        // кнопка отпущена, запись 0x00 для выключения LED
        ledCharacteristic.writeValue((byte)0x00);
      }
    }
  }

  Serial.println("Peripheral disconnected");
}

Периферийное устройство

Этот скетч настраивает плату Arduino как периферийное устройство с нужным UUID и рекламирует характеристику встроенного светодиода. Дополнительных компонентов подключать не нужно — используется только LED_BUILTIN.

  • LED_BUILTIN работает на всех платах Arduino.
#include <ArduinoBLE.h>

BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // Bluetooth® Low Energy сервис LED

// Bluetooth® Low Energy характеристика переключения LED — пользовательский 128-битный UUID, доступен для чтения и записи центральным устройством
BLEByteCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);

const int ledPin = LED_BUILTIN; // пин для LED

void setup() {
  Serial.begin(9600);
  while (!Serial);

  // установка пина LED в режим выхода
  pinMode(ledPin, OUTPUT);

  // начало инициализации
  if (!BLE.begin()) {
    Serial.println("starting Bluetooth® Low Energy module failed!");

    while (1);
  }

  // установка рекламируемого локального имени и UUID сервиса:
  BLE.setLocalName("LED");
  BLE.setAdvertisedService(ledService);

  // добавление характеристики в сервис
  ledService.addCharacteristic(switchCharacteristic);

  // добавление сервиса
  BLE.addService(ledService);

  // установка начального значения характеристики:
  switchCharacteristic.writeValue(0);

  // начало рекламирования
  BLE.advertise();

  Serial.println("BLE LED Peripheral");
}

void loop() {
  // ожидание подключения Bluetooth® Low Energy периферийных устройств:
  BLEDevice central = BLE.central();

  // если центральное устройство подключено к периферийному:
  if (central) {
    Serial.print("Connected to central: ");
    // вывод MAC-адреса центрального устройства:
    Serial.println(central.address());

    // пока центральное устройство подключено к периферийному:
    while (central.connected()) {
      // если удалённое устройство записало значение в характеристику,
      // используем значение для управления LED:
      if (switchCharacteristic.written()) {
        if (switchCharacteristic.value()) {   // любое значение, кроме 0,
          Serial.println("LED on");
          digitalWrite(ledPin, HIGH);         // включит LED
        } else {                              // значение 0
          Serial.println(F("LED off"));
          digitalWrite(ledPin, LOW);          // выключит LED
        }
      }
    }

    // при отключении центрального устройства выводим сообщение:
    Serial.print(F("Disconnected from central: "));
    Serial.println(central.address());
  }
}

Практические замечания

  • Убедитесь, что UUID в скетчах центрального и периферийного устройства совпадают — иначе соединение не установится.
  • Если плата не обнаруживается при сканировании, проверьте, загружен ли скетч периферии и включена ли реклама (BLE.advertise()).
  • При отладке удобно использовать Serial Monitor: добавьте вывод адреса и имени найденного устройства через bleDevice.address() и bleDevice.localName().

Управление Arduino со смартфона

Этот пример позволяет управлять встроенным светодиодом платы Arduino прямо со смартфона. Рекомендуем использовать приложение LightBlue, доступное для Android и iOS . Загрузите скетч и следуйте шагам, показанным на изображении ниже.

Шаг 1 — Загрузите скетч

#include <ArduinoBLE.h>
BLEService newService("180A"); // создание сервиса

BLEUnsignedCharCharacteristic randomReading("2A58", BLERead | BLENotify); // создание характеристики аналогового значения
BLEByteCharacteristic switchChar("2A57", BLERead | BLEWrite); // создание характеристики LED

const int ledPin = 2;
long previousMillis = 0;


void setup() {
  Serial.begin(9600);    // инициализация последовательного соединения
  while (!Serial);       //программа запускается при открытии монитора порта

  pinMode(LED_BUILTIN, OUTPUT); // инициализация встроенного пина LED для индикации подключения центрального устройства
  pinMode(ledPin, OUTPUT); // инициализация встроенного пина LED для индикации подключения центрального устройства

  //инициализация библиотеки ArduinoBLE
  if (!BLE.begin()) {
    Serial.println("starting Bluetooth® Low Energy failed!");
    while (1);
  }

  BLE.setLocalName("<My Board Name>"); //установка имени, отображаемого при сканировании Bluetooth® устройств
  BLE.setAdvertisedService(newService);

  newService.addCharacteristic(switchChar); //добавление характеристик в сервис
  newService.addCharacteristic(randomReading);

  BLE.addService(newService);  // добавление сервиса

  switchChar.writeValue(0); //установка начальных значений характеристик
  randomReading.writeValue(0);

  BLE.advertise(); //начало рекламирования сервиса
  Serial.println(" Bluetooth® device active, waiting for connections...");
}

void loop() {

  BLEDevice central = BLE.central(); // ожидание центрального Bluetooth® Low Energy устройства

  if (central) {  // если центральное устройство подключено к периферийному
    Serial.print("Connected to central: ");

    Serial.println(central.address()); // вывод BT-адреса центрального устройства

    digitalWrite(LED_BUILTIN, HIGH); // включение LED для индикации подключения

    // проверка уровня заряда батареи каждые 200 мс
    // пока центральное устройство подключено:
    while (central.connected()) {
      long currentMillis = millis();

      if (currentMillis - previousMillis >= 200) { // если прошло 200 мс, проверяем уровень заряда батареи
        previousMillis = currentMillis;

        int randomValue = analogRead(A1);
        randomReading.writeValue(randomValue);

        if (switchChar.written()) {
          if (switchChar.value()) {   // любое значение, кроме 0,
            Serial.println("LED on");
            digitalWrite(ledPin, HIGH);         // включит LED
          } else {                              // значение 0
            Serial.println(F("LED off"));
            digitalWrite(ledPin, LOW);          // выключит LED
          }
        }

      }
    }

    digitalWrite(LED_BUILTIN, LOW); // при отключении центрального устройства выключаем LED
    Serial.print("Disconnected from central: ");
    Serial.println(central.address());
  }
}

Шаг 2 — Запустите приложение LightBlue Control your board using LightBlue Управление платой Arduino через приложение LightBlue®: выбор устройства (Select Device), чтение (Read Value) и запись значений (Write Value) цифровых и аналоговых характеристик

Типичные ошибки

  • Библиотека не установлена. Если при компиляции появляется ошибка ArduinoBLE.h: No such file or directory — откройте менеджер библиотек и установите ArduinoBLE.
  • Неверная плата. Убедитесь, что выбрана совместимая плата. На платах без BLE-модуля библиотека не работает.
  • UUID не совпадают. Центральное устройство ищет периферию по UUID сервиса. Если UUID в скетчах разные — устройства друг друга не найдут.
  • Устройство не появляется в приложении. Проверьте, вызван ли BLE.advertise() в скетче периферии. Попробуйте перезагрузить плату.
  • Соединение обрывается. Убедитесь, что расстояние между устройствами не превышает нескольких метров и нет сильных источников помех (роутер Wi-Fi рядом с платой).

Итоги

В этой статье мы разобрали основы Bluetooth® Low Energy: как работают роли центрального и периферийного устройства, что такое сервисы, характеристики и UUID, чем BLE отличается от классического Bluetooth®. На практике мы показали, как передавать данные между двумя платами Arduino и как управлять платой со смартфона с помощью библиотеки ArduinoBLE.