и я действительно запутался и не знаю, как кодировать настоящий BLE 5.0, но это мое задание. Не могли бы вы мне с этим помочь?
Проблема:
Я хочу прочитать данные датчика моего ESP32C6, но код Android Studio не подключается. с моим устройством и поэтому не обмениваюсь нужными мне данными и не отображаю их в моем приложении. Не могли бы вы мне с этим помочь?
Код Arduino
Код: Выделить всё
#include
#include
#include
#include
#include
#include
#include "MAX30105.h" // Korrigierte Bibliothek
#include "heartRate.h" // Zusätzliche Bibliothek für Herzfrequenzberechnung
// BLE UUIDs
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
// Pin Definitions
#define OPA344_PIN A0
// Task handles for core management
TaskHandle_t Task1;
TaskHandle_t Task2;
// Mutex for protecting shared resources
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
SemaphoreHandle_t xMutex = NULL;
// Sensor objects
Adafruit_MPU6050 mpu;
MAX30105 particleSensor;
// Variables für Herzfrequenzberechnung
const byte RATE_SIZE = 4; // Größe des Arrays für die Mittelwertbildung
byte rates[RATE_SIZE]; // Array zur Speicherung der letzten Herzfrequenzen
byte rateSpot = 0;
long lastBeat = 0; // Zeit seit dem letzten Herzschlag
float beatsPerMinute;
int beatAvg;
// BLE objects
BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;
// Shared data structure
struct SensorData {
// MPU6050 data
float accX, accY, accZ;
float gyroX, gyroY, gyroZ;
// MAX30102 data
uint32_t red, ir;
float heartRate;
int avgHeartRate;
// OPA344 data
float soundLevel;
} sensorData;
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
Serial.println("Device connected!");
}
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
Serial.println("Device disconnected!");
}
};
// Core 0: Sensor data acquisition
void SensorTask(void * parameter) {
for(;;) {
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
// Read MPU6050
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
sensorData.accX = a.acceleration.x;
sensorData.accY = a.acceleration.y;
sensorData.accZ = a.acceleration.z;
sensorData.gyroX = g.gyro.x;
sensorData.gyroY = g.gyro.y;
sensorData.gyroZ = g.gyro.z;
// Read MAX30102 and calculate heart rate
sensorData.ir = particleSensor.getIR();
if (checkForBeat(sensorData.ir)) {
long delta = millis() - lastBeat;
lastBeat = millis();
beatsPerMinute = 60 / (delta / 1000.0);
if (beatsPerMinute < 255 && beatsPerMinute > 20) {
rates[rateSpot++] = (byte)beatsPerMinute;
rateSpot %= RATE_SIZE;
// Durchschnitt berechnen
beatAvg = 0;
for (byte x = 0; x < RATE_SIZE; x++)
beatAvg += rates[x];
beatAvg /= RATE_SIZE;
sensorData.heartRate = beatsPerMinute;
sensorData.avgHeartRate = beatAvg;
}
}
// Read OPA344
int rawValue = analogRead(OPA344_PIN);
sensorData.soundLevel = (rawValue * 3.3) / 4095.0;
xSemaphoreGive(xMutex);
}
vTaskDelay(pdMS_TO_TICKS(10)); // 100Hz sampling rate
}
}
// Core 1: BLE and data processing
void ProcessingTask(void * parameter) {
for(;;) {
if (deviceConnected && xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
// Format data for BLE transmission
String sensorDataStr =
"ACC:" + String(sensorData.accX) + "," +
String(sensorData.accY) + "," +
String(sensorData.accZ) +
";GYRO:" + String(sensorData.gyroX) + "," +
String(sensorData.gyroY) + "," +
String(sensorData.gyroZ) +
";HR:" + String(sensorData.heartRate) +
";AVG_HR:" + String(sensorData.avgHeartRate) +
";SND:" + String(sensorData.soundLevel);
// Send via BLE
pCharacteristic->setValue(sensorDataStr.c_str());
pCharacteristic->notify();
xSemaphoreGive(xMutex);
}
vTaskDelay(pdMS_TO_TICKS(100)); // 10Hz update rate for BLE
}
}
void setup() {
Serial.begin(115200);
Wire.begin();
// Create mutex
xMutex = xSemaphoreCreateMutex();
// Initialize MPU6050
if (!mpu.begin()) {
Serial.println("MPU6050 not found!");
while (1) delay(10);
}
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
// Initialize MAX30102
if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) {
Serial.println("MAX30102 not found!");
while (1) delay(10);
}
// Konfiguration für den MAX30102
particleSensor.setup();
particleSensor.setPulseAmplitudeRed(0x0A);
particleSensor.setPulseAmplitudeGreen(0);
particleSensor.setPulseAmplitudeIR(0x0A);
particleSensor.setSampleRate(200); // Setzt die Sample Rate auf 200Hz
particleSensor.setFIFOAverage(4); // Setzt den Durchschnitt auf 4 Samples
// Initialize BLE
BLEDevice::init("ESP32C6");
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY
);
pService->start();
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
pAdvertising->setMinPreferred(0x06);
pAdvertising->setMaxPreferred(0x12);
BLEDevice::startAdvertising();
// Create tasks for each core
xTaskCreatePinnedToCore(
SensorTask, // Task function
"SensorTask", // Name
10000, // Stack size
NULL, // Parameters
1, // Priority
&Task1, // Task handle
0 // Core ID (0)
);
xTaskCreatePinnedToCore(
ProcessingTask,
"ProcessingTask",
10000,
NULL,
1,
&Task2,
1 // Core ID (1)
);
Serial.println("Setup complete!");
}
void loop() {
// Empty loop as tasks handle all the work
vTaskDelay(pdMS_TO_TICKS(1000));
}
Код: Выделить всё
package com.example.project;
import android.Manifest;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.util.UUID;
public class MainActivity extends AppCompatActivity {
private static final int PERMISSION_REQUEST_CODE = 1;
private static final String DEVICE_NAME = "ESP32C6";
private static final UUID SERVICE_UUID = UUID.fromString("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
private static final UUID CHARACTERISTIC_UUID = UUID.fromString("beb5483e-36e1-4688-b7f5-ea07361b26a8");
private BluetoothManager bluetoothManager;
private BluetoothAdapter bluetoothAdapter;
private BluetoothLeScanner bluetoothLeScanner;
private BluetoothGatt bluetoothGatt;
private Button btnScan;
private TextView tvConnectionStatus, tvAccData, tvGyroData, tvHeartRate, tvSoundLevel;
private boolean scanning = false;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeViews();
setupBluetooth();
checkPermissions();
}
private void initializeViews() {
btnScan = findViewById(R.id.btnScan);
tvConnectionStatus = findViewById(R.id.tvConnectionStatus);
tvAccData = findViewById(R.id.tvAccData);
tvGyroData = findViewById(R.id.tvGyroData);
tvHeartRate = findViewById(R.id.tvHeartRate);
tvSoundLevel = findViewById(R.id.tvSoundLevel);
btnScan.setOnClickListener(v -> {
if (!scanning) {
startScan();
} else {
stopScan();
}
});
}
private void setupBluetooth() {
bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (bluetoothManager != null) {
bluetoothAdapter = bluetoothManager.getAdapter();
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
}
}
private void checkPermissions() {
String[] permissions = {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT
};
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE);
return;
}
}
}
@SuppressLint("MissingPermission")
private void startScan() {
if (bluetoothLeScanner != null) {
scanning = true;
btnScan.setText("Stop Scan");
bluetoothLeScanner.startScan(scanCallback);
handler.postDelayed(this::stopScan, 10000); // Stop scanning after 10 seconds
}
}
@SuppressLint("MissingPermission")
private void stopScan() {
if (bluetoothLeScanner != null) {
scanning = false;
btnScan.setText("Start Scan");
bluetoothLeScanner.stopScan(scanCallback);
}
}
private final ScanCallback scanCallback = new ScanCallback() {
@SuppressLint("MissingPermission")
@Override
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice device = result.getDevice();
if (DEVICE_NAME.equals(device.getName())) {
stopScan();
connectToDevice(device);
}
}
};
private void connectToDevice(BluetoothDevice device) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
bluetoothGatt = device.connectGatt(this, false, gattCallback);
}
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothGatt.STATE_CONNECTED) {
runOnUiThread(() -> tvConnectionStatus.setText("Status: Connected"));
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
bluetoothGatt.discoverServices();
} else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
runOnUiThread(() -> tvConnectionStatus.setText("Status: Disconnected"));
}
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
BluetoothGattService service = gatt.getService(SERVICE_UUID);
if (service != null) {
BluetoothGattCharacteristic characteristic = service.getCharacteristic(CHARACTERISTIC_UUID);
if (characteristic != null) {
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
gatt.setCharacteristicNotification(characteristic, true);
}
}
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
if (CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
final String data = new String(characteristic.getValue());
parseAndUpdateUI(data);
}
}
};
private void parseAndUpdateUI(final String data) {
runOnUiThread(() -> {
try {
String[] sections = data.split(";");
for (String section : sections) {
String[] parts = section.split(":");
if (parts.length == 2) {
String type = parts[0];
String values = parts[1];
switch (type) {
case "ACC":
String[] accValues = values.split(",");
String accText = String.format("X: %.2f\nY: %.2f\nZ: %.2f",
Float.parseFloat(accValues[0]),
Float.parseFloat(accValues[1]),
Float.parseFloat(accValues[2]));
tvAccData.setText(accText);
break;
case "GYRO":
String[] gyroValues = values.split(",");
String gyroText = String.format("X: %.2f\nY: %.2f\nZ: %.2f",
Float.parseFloat(gyroValues[0]),
Float.parseFloat(gyroValues[1]),
Float.parseFloat(gyroValues[2]));
tvGyroData.setText(gyroText);
break;
case "HR":
tvHeartRate.setText(values + " BPM");
break;
case "SND":
tvSoundLevel.setText(String.format("%.2f V", Float.parseFloat(values)));
break;
}
}
}
} catch (Exception e) {
Toast.makeText(MainActivity.this, "Error parsing data", Toast.LENGTH_SHORT).show();
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if (bluetoothGatt != null) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
bluetoothGatt.close();
}
}
}
Это также есть в моем манифесте:
Код: Выделить всё
Подробнее здесь: https://stackoverflow.com/questions/792 ... -android-s