Подключение двух Arduino через BLE 5.0
У меня возникла проблема при передаче данных датчика с платы Nano Sense Rev 2 (передатчик) на плату Nano 33 BLE Rev 2 (приёмник). Приёмник постоянно не может обнаружить передатчик и подключиться к нему, выдавая ошибку «Истек тайм-аут сканирования», из-за чего сканирование останавливается через несколько секунд. Обратите внимание, что мне удалось подключиться к своему передатчику с помощью приложения на телефоне. Это код моего передатчика:
#include <Arduino_LPS22HB.h>
#include <Arduino_HS300x.h>
#include <Arduino_APDS9960.h>
#include <ArduinoBLE.h>
// Пользовательские 128-битные UUID для сервиса и характеристик
BLEService sensorService("12345678-1234-5678-1234-56789abcdef0"); // Пользовательский UUID службы
BLECharacteristic pressureCharacteristic("12345678-1234-5678-1234-56789abcdef1", BLERead | BLENotify, sizeof(float)); // Пользовательский UUID характеристики давления
BLECharacteristic temperatureCharacteristic("12345678-1234-5678-1234-56789abcdef2", BLERead | BLENotify, sizeof(float)); // UUID пользовательской температурной характеристики
BLECharacteristic humidityCharacteristic("12345678-1234-5678-1234-56789abcdef3", BLERead | BLENotify, sizeof(float)); // Пользовательский UUID характеристики влажности
BLECharacteristic lightIntensityCharacteristic("12345678-1234-5678-1234-56789abcdef4", BLERead | BLENotify, sizeof(int)); // Пользовательский UUID характеристики интенсивности света
void setup() {
// Запустить последовательный монитор
Serial.begin(9600);
while (!Serial);
// Инициализация датчиков
if (!BARO.begin()) {
Serial.println("Failed to initialize pressure sensor!");
while (1);
}
if (!HS300x.begin()) {
Serial.println("Failed to initialize humidity temperature sensor!");
while (1);
}
if (!APDS.begin()) {
Serial.println("Error initializing APDS9960 sensor.");
}
// Инициализация BLE
if (!BLE.begin()) {
Serial.println("BLE initialization failed!");
while (1);
}
BLE.setLocalName("Nano33BLESense");
// Добавить характеристики в пользовательский сервис
sensorService.addCharacteristic(pressureCharacteristic);
sensorService.addCharacteristic(temperatureCharacteristic);
sensorService.addCharacteristic(humidityCharacteristic);
sensorService.addCharacteristic(lightIntensityCharacteristic);
// Добавить службу к периферийному устройству BLE
BLE.addService(sensorService);
// Начните рекламировать службу BLE (и повторяйте, чтобы она оставалась активной)
BLE.advertise();
Serial.println("BLE Peripheral started advertising.");
}
void loop() {
// Считать данные датчика
float pressure = BARO.readPressure();
float temperature = HS300x.readTemperature();
float humidity = HS300x.readHumidity();
int r, g, b;
while (!APDS.colorAvailable()) {
delay(5);
}
APDS.readColor(r, g, b);
int lightIntensity = r + g + b;
// Вывести значения датчика на последовательный монитор (для отладки)
Serial.print("Pressure: ");
Serial.println(pressure);
Serial.print("Temperature: ");
Serial.println(temperature);
Serial.print("Humidity: ");
Serial.println(humidity);
Serial.print("Light Intensity: ");
Serial.println(lightIntensity);
// Преобразовать значения с плавающей точкой в массивы байтов
byte pressureBytes[sizeof(float)];
memcpy(pressureBytes, &pressure, sizeof(float));
byte temperatureBytes[sizeof(float)];
memcpy(temperatureBytes, &temperature, sizeof(float));
byte humidityBytes[sizeof(float)];
memcpy(humidityBytes, &humidity, sizeof(float));
byte lightIntensityBytes[sizeof(int)];
memcpy(lightIntensityBytes, &lightIntensity, sizeof(int));
// Обновите характеристики BLE с использованием последних данных датчиков
pressureCharacteristic.setValue(pressureBytes, sizeof(pressureBytes));
temperatureCharacteristic.setValue(temperatureBytes, sizeof(temperatureBytes));
humidityCharacteristic.setValue(humidityBytes, sizeof(humidityBytes));
lightIntensityCharacteristic.setValue(lightIntensityBytes, sizeof(lightIntensityBytes));
// Библиотека BLE будет автоматически обрабатывать уведомления при вызове `setValue`
// поскольку BLENotify включен на характеристиках.
// Продолжайте рекламировать, чтобы убедиться, что сервис BLE остается видимым
BLE.advertise();
delay(1000); // Подождать 1 секунду перед отправкой следующих данных
}
а это код приемника:
#include <ArduinoBLE.h>
// Define the UUIDs for the custom service and characteristics
#define SENSOR_SERVICE_UUID "12345678-1234-5678-1234-56789abcdef0"
#define PRESSURE_CHAR_UUID "12345678-1234-5678-1234-56789abcdef1"
#define TEMPERATURE_CHAR_UUID "12345678-1234-5678-1234-56789abcdef2"
#define HUMIDITY_CHAR_UUID "12345678-1234-5678-1234-56789abcdef3"
#define LIGHT_INTENSITY_CHAR_UUID "12345678-1234-5678-1234-56789abcdef4"
// Declare BLE objects with proper UUIDs
BLEService sensorService(SENSOR_SERVICE_UUID);
BLECharacteristic pressureCharacteristic(PRESSURE_CHAR_UUID, BLERead | BLENotify, sizeof(float));
BLECharacteristic temperatureCharacteristic(TEMPERATURE_CHAR_UUID, BLERead | BLENotify, sizeof(float));
BLECharacteristic humidityCharacteristic(HUMIDITY_CHAR_UUID, BLERead | BLENotify, sizeof(float));
BLECharacteristic lightIntensityCharacteristic(LIGHT_INTENSITY_CHAR_UUID, BLERead | BLENotify, sizeof(int));
unsigned long scanStartTime;
bool scanInProgress = true;
int maxScanAttempts = 5; // Max number of scan attempts before stopping
int scanAttempts = 0; // Counter for scan attempts
void setup() {
// Start Serial Monitor
Serial.begin(9600);
while (!Serial);
// Initialize BLE
if (!BLE.begin()) {
Serial.println("BLE initialization failed!");
while (1);
}
BLE.setLocalName("BLEReceiver");
Serial.println("BLEReceiver started. Scanning for devices...");
// Start scanning for devices advertising the sensor service
BLE.scanForUuid(SENSOR_SERVICE_UUID); // Scan for the service
scanStartTime = millis(); // Start the scan timer
}
void loop() {
BLEDevice central = BLE.available();
if (central) {
// Device found, print address and attempt to connect
Serial.print("Found BLE Device: ");
Serial.println(central.address());
// Stop scanning and attempt to connect
BLE.stopScan();
delay(100); // Small delay before attempting to connect
if (central.connect()) {
Serial.println("Connected to device.");
BLEService sensorService = central.service(SENSOR_SERVICE_UUID);
if (sensorService) {
Serial.println("Sensor service found.");
// Discover characteristics
pressureCharacteristic = sensorService.characteristic(PRESSURE_CHAR_UUID);
temperatureCharacteristic = sensorService.characteristic(TEMPERATURE_CHAR_UUID);
humidityCharacteristic = sensorService.characteristic(HUMIDITY_CHAR_UUID);
lightIntensityCharacteristic = sensorService.characteristic(LIGHT_INTENSITY_CHAR_UUID);
if (pressureCharacteristic && temperatureCharacteristic && humidityCharacteristic && lightIntensityCharacteristic) {
Serial.println("Characteristics found. Reading values...");
while (central.connected()) {
if (pressureCharacteristic.canRead()) {
float pressure;
memcpy(&pressure, pressureCharacteristic.value(), sizeof(pressure));
Serial.print("Pressure: ");
Serial.println(pressure);
}
if (temperatureCharacteristic.canRead()) {
float temperature;
memcpy(&temperature, temperatureCharacteristic.value(), sizeof(temperature));
Serial.print("Temperature: ");
Serial.println(temperature);
}
if (humidityCharacteristic.canRead()) {
float humidity;
memcpy(&humidity, humidityCharacteristic.value(), sizeof(humidity));
Serial.print("Humidity: ");
Serial.println(humidity);
}
if (lightIntensityCharacteristic.canRead()) {
int lightIntensity;
memcpy(&lightIntensity, lightIntensityCharacteristic.value(), sizeof(lightIntensity));
Serial.print("Light Intensity: ");
Serial.println(lightIntensity);
}
delay(1000); // Wait for 1 second before reading again
}
} else {
Serial.println("Failed to find required characteristics.");
}
} else {
Serial.println("Sensor service not found.");
}
// Disconnect once done
central.disconnect();
Serial.println("Disconnected from device.");
scanAttempts = 0; // Reset scan attempts after successful connection
} else {
Serial.println("Failed to connect to device.");
}
}
// Check scan timeout and limit scan attempts
if (scanInProgress && millis() - scanStartTime > 10000) { // 10 seconds timeout
Serial.println("Scan timeout reached. Stopping scan.");
BLE.stopScan();
scanInProgress = false;
scanAttempts++;
// If max scan attempts reached, stop scanning and wait for user intervention
if (scanAttempts >= maxScanAttempts) {
Serial.println("Max scan attempts reached. Please reset the device.");
} else {
Serial.println("Resuming scan...");
BLE.scanForUuid(SENSOR_SERVICE_UUID); // Restart scanning after timeout
scanStartTime = millis(); // Reset the scan timer
scanInProgress = true; // Set scanInProgress back to true
}
}
// Continue scanning only if it is still ongoing and hasn't timed out
if (scanInProgress && !central) {
BLEDevice central = BLE.available();
}
}
Два устройства находятся на расстоянии 1 метра друг от друга. Это мой последовательный монитор (приемник).
14:52:23.321 -> Resuming scan...
14:52:33.314 -> Scan timeout reached. Stopping scan.
14:52:33.314 -> Resuming scan...
14:52:43.338 -> Scan timeout reached. Stopping scan.
14:52:43.387 -> Resuming scan...
14:52:53.379 -> Scan timeout reached. Stopping scan.
14:52:53.425 -> Max scan attempts reached. Please reset the device.
Почему я не могу подключиться?
@Anwar Elhadad, 👍0
Обсуждение1 ответ
Отсутствие BLE.setAdvertisedService(sensorService); бросается в глаза сразу. В ходе тестирования я разместил его, как в следующем фрагменте:
// Добавить службу к периферийному устройству BLE
BLE.addService(sensorService);
// Включить интересующую услугу в рекламные данные
// для другой стороны использовать с `BLE.scanForUuid(SENSOR_SERVICE_UUID);`
BLE.setAdvertisedService(sensorService);
Благодаря этому изменению принимающая сторона теперь сообщает:
BLEReceiver started. Scanning for devices...
Found BLE Device: xx:xx:xx:xx:xx:xx
Connected to device.
Sensor service not found.
Disconnected from device.
... где xx содержал OUI моего Nano BLE.
Короче говоря, когда вы вызываете BLE.advertise();, ваше устройство начинает сообщать о своём существовании. Оно может делать это с помощью небольшого объёма рекламных данных, которые могут включать некоторые (обычно не все) UUID своих сервисов. BLE.scanForUuid(SENSOR_SERVICE_UUID); ищет именно рекламируемую службу. Пока вы не взаимодействуете с устройством (кроме получения рекламы), вы не можете знать о каких-либо службах, не включённых в рекламные данные. Таким образом, без рекламируемого UUID сервиса вам пришлось бы дополнительно опрашивать каждое найденное устройство в рамках сеанса .scan() без использования UUID. Таким образом, эти рекламируемые UUID сервисов делают сканирование нужных вам устройств более эффективным.
В коде приемника у вас есть BLEDevice central = BLE.available();
.available() здесь возвращает периферийное устройство, найденное во время сканирования. На самом деле это должно быть BLEDevice periferial = . В любом случае, после вызова .connect() вы используете .service(). Здесь отсутствует один шаг, который вы можете увидеть в этой документации и этом примере. Пока вы не вызовете .discoverAttributes(), у вас не будет локальной копии всех служб, характеристик и т. д., которые есть у периферийного устройства. Вот почему .service() дает сбой.
Не сомневаюсь, что есть и другие проблемы. Похоже, это то, что мог бы выдать генератор кода на основе искусственного интеллекта. Если это так, остановитесь и прочтите документацию и примеры.
Хорошо, попробую завтра. Кстати, вы не реализовали никаких служб? Из-за этого пишет «Служба датчика не найдена» или это какая-то другая проблема?, @Anwar Elhadad
Я сейчас добавлю кое-что для решения этой проблемы. Но ответ, как есть, касается «того, с чем вы сталкиваетесь немедленно». Другими словами, первой из потенциально многих проблем, с которыми вы можете столкнуться. Это поиск устройства. Я не собираюсь исправлять весь ваш проект., @timemage
- Сломалась антенна Arduino nano IoT
- Raspberry Pi 3B+ BLE связь с Arduino Nano 33 IOT
- Bluetooth-модуль HC-05 — команда INQ не работает
- Самая низкая мощность, возможная в Arduino
- Аккумуляторное решение Nano 33 IoT
- MAX30100 не работает
- Arduino Nano BME280 странные значения
- Библиотека ардуино или код для ESP32 для сканирования устройств Bluetooth?
какой у вас вопрос?, @jsotola
Выполняли ли вы последовательное соединение с обоими устройствами одновременно во время своих тестов?, @timemage
@timemage Да, я подключил их к отдельному компьютеру одновременно и в разное время, чтобы убедиться, что я нацелился на рекламное окно., @Anwar Elhadad
По умолчанию библиотека ArduinoBLE использует случайные приватные адреса. Это может привести к тому, что устройства не будут обнаруживать друг друга стабильно., @liaifat85