#include <SPI.h>
#include <BLEDevice.h>
#include <BLE2902.h>
#include <Arduino.h>
// ==================== 引脚定义 ====================
#define SCK_PIN 13
#define MISO_PIN 11
#define MOSI_PIN 14
#define CS_PIN 12
// =============== 每块从板烧录前修改此 ID ==================
#define SLAVE_ID 7 // 可设为 0~7
// ==================== 启用调试模式 ====================
//#define DEBUG_GMD1032
// ==================== GMD1032 命令列表 ====================
const uint16_t CMD_START_MEASUREMENT = 0x2A16;
const uint16_t CMD_CLEAR_ADC_RESULTS = 0x243C;
const uint16_t CMD_READ_CFG0 = 0xC08E;
const uint16_t CMD_READ_STS0 = 0xC9B1;
// CELL 分组命令
const uint16_t CMD_READ_CELL_1_3 = 0xD0FE;
const uint16_t CMD_READ_CELL_4_6 = 0xD1F9;
const uint16_t CMD_READ_CELL_7_9 = 0xD2F0;
const uint16_t CMD_READ_CELL_10_12 = 0xD3F7;
const uint16_t CMD_READ_CELL_13_15 = 0xD4E2;
const uint16_t CMD_READ_CELL_16_18 = 0xD5E5;
const uint16_t CMD_READ_VREF2_V3 = 0xDFD3;
const uint16_t CMD_READ_V5_DIETEMP_VSTK = 0xE06E;
SPISettings spiSettings(1000000, MSBFIRST, SPI_MODE3);
SPIClass spi;
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
BLECharacteristic* pCharacteristic = nullptr;
bool deviceConnected = false;
uint16_t sharedCellRaw[16] = {0};
uint16_t sharedDieTempRaw = 0;
portMUX_TYPE sensorMutex = portMUX_INITIALIZER_UNLOCKED;
class MyServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer* pServer) override {
deviceConnected = true;
#ifdef DEBUG_GMD1032
Serial.println("设备已连接");
#endif
}
void onDisconnect(BLEServer* pServer) override {
deviceConnected = false;
pServer->startAdvertising();
#ifdef DEBUG_GMD1032
Serial.println("设备断开,重启广播");
#endif
}
};
class MyCharacteristicCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic* pCharacteristic) override {
std::string value = pCharacteristic->getValue();
if (!value.empty()) {
// 可选:处理写入命令
}
}
};
void wakeUpGMD1032() {
SPI.beginTransaction(spiSettings);
digitalWrite(CS_PIN, LOW);
delayMicroseconds(10);
SPI.transfer(0x00);
digitalWrite(CS_PIN, HIGH);
SPI.endTransaction();
delay(5);
}
bool sendCommand(uint16_t command) {
SPI.beginTransaction(spiSettings);
digitalWrite(CS_PIN, LOW);
SPI.transfer16(command);
digitalWrite(CS_PIN, HIGH);
SPI.endTransaction();
return true;
}
void parseReverseFields(uint8_t* buffer, uint16_t* results, int count) {
for (int i = 0; i < count; i++) {
int bufIdx = i * 2;
results[count - 1 - i] = (buffer[bufIdx] << 8) | buffer[bufIdx + 1];
}
}
bool readAllCellRawValues(uint16_t* cellRaw) {
const uint16_t cmds[] = {
CMD_READ_CELL_1_3, CMD_READ_CELL_4_6, CMD_READ_CELL_7_9,
CMD_READ_CELL_10_12, CMD_READ_CELL_13_15, CMD_READ_CELL_16_18
};
const int groupCount = 6;
const int perGroup[] = {3, 3, 3, 3, 3, 3};
SPI.beginTransaction(spiSettings);
for (int g = 0; g < groupCount; g++) {
digitalWrite(CS_PIN, LOW);
SPI.transfer16(cmds[g]);
uint8_t buffer[8];
for (int i = 0; i < 8; i++) {
buffer[i] = SPI.transfer(0x00);
}
digitalWrite(CS_PIN, HIGH);
uint16_t raw[3];
parseReverseFields(buffer, raw, perGroup[g]);
for (int i = 0; i < perGroup[g]; i++) {
int idx = g * 3 + i;
if (idx >= 16) continue;
cellRaw[idx] = raw[i];
}
}
SPI.endTransaction();
return true;
}
bool readDieTempRaw(uint16_t* raw_dieTemp) {
uint8_t buffer[8];
SPI.beginTransaction(spiSettings);
digitalWrite(CS_PIN, LOW);
SPI.transfer16(CMD_READ_V5_DIETEMP_VSTK);
for (int i = 0; i < 8; i++) {
buffer[i] = SPI.transfer(0x00);
}
digitalWrite(CS_PIN, HIGH);
SPI.endTransaction();
*raw_dieTemp = (buffer[2] << 8) | buffer[3];
return true;
}
void updateBLECharacteristic() {
uint8_t binBuffer[35]; // 34 data + 1 id
portENTER_CRITICAL(&sensorMutex);
for (int i = 0; i < 16; i++) {
binBuffer[i * 2] = (sharedCellRaw[i] >> 8) & 0xFF;
binBuffer[i * 2 + 1] = sharedCellRaw[i] & 0xFF;
}
binBuffer[32] = (sharedDieTempRaw >> 8) & 0xFF;
binBuffer[33] = sharedDieTempRaw & 0xFF;
binBuffer[34] = SLAVE_ID; // 添加 Slave ID
portEXIT_CRITICAL(&sensorMutex);
if (pCharacteristic && deviceConnected) {
pCharacteristic->setValue(binBuffer, 35);
pCharacteristic->notify();
}
#ifdef DEBUG_GMD1032
Serial.printf("Sent to BLE: ID=%d\n", SLAVE_ID);
#endif
}
void sensorTask(void *parameter) {
// 允许蓝牙睡眠
esp_bt_sleep_enable();
// 可选:降频省电
setCpuFrequencyMhz(80);
for (;;) {
yield();
wakeUpGMD1032();
delay(2);
sendCommand(CMD_START_MEASUREMENT);
delay(10);
uint16_t cellRaw[16] = {0};
uint16_t dieTempRaw = 0;
readAllCellRawValues(cellRaw);
readDieTempRaw(&dieTempRaw);
portENTER_CRITICAL(&sensorMutex);
memcpy(sharedCellRaw, cellRaw, sizeof(cellRaw));
sharedDieTempRaw = dieTempRaw;
portEXIT_CRITICAL(&sensorMutex);
#ifdef DEBUG_GMD1032
Serial.printf("Slave %d: CELL1=%d, DieTemp=%d\n", SLAVE_ID, cellRaw[0], dieTempRaw);
#endif
// 使用 vTaskDelay 替代 delay 让系统可休眠
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void bleTask(void *parameter) {
char deviceName[20];
sprintf(deviceName, "GMD1032-Slave-%d", SLAVE_ID);
BLEDevice::init(deviceName);
BLEDevice::setMTU(256);
BLEServer* 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
);
pCharacteristic->addDescriptor(new BLE2902());
pCharacteristic->setCallbacks(new MyCharacteristicCallbacks());
pCharacteristic->setValue("Ready");
pService->start();
BLEAdvertising* pAdvertising = pServer->getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->start();
#ifdef DEBUG_GMD1032
Serial.println("BLE 广播已启动,开始10秒连接倒计时...");
#endif
// 记录启动时间
unsigned long startTime = millis();
bool connectedOnce = false;
for (;;) {
// 检查是否曾经连接过
if (deviceConnected) {
connectedOnce = true;
}
// 如果在10秒内曾经连接过,取消重启
if (connectedOnce) {
#ifdef DEBUG_GMD1032
Serial.println("已建立连接,取消重启计划。");
#endif
// 可选:清除标志避免重复打印
connectedOnce = true; // 保持即可
}
// 超时判断:10秒未连接则重启
else if (millis() - startTime > 10000) {
#ifdef DEBUG_GMD1032
Serial.println("10秒内未连接,即将重启...");
#endif
delay(100);
ESP.restart(); // 重启ESP32
}
// 正常更新数据(仅当连接后)
if (deviceConnected) {
updateBLECharacteristic();
}
vTaskDelay(pdMS_TO_TICKS(500)); // 每500ms检查一次
}
}
void setup() {
Serial.begin(115200);
while (!Serial && millis() < 3000);
#ifdef DEBUG_GMD1032
Serial.printf("[DEBUG] GMD1032 调试模式启用 - Slave ID: %d\n", SLAVE_ID);
#endif
pinMode(CS_PIN, OUTPUT);
digitalWrite(CS_PIN, HIGH);
SPI.begin(SCK_PIN, MISO_PIN, MOSI_PIN, CS_PIN);
// 创建任务并绑定到不同核心
xTaskCreatePinnedToCore(sensorTask, "SensorTask", 4096, NULL, 1, NULL, 0);
xTaskCreatePinnedToCore(bleTask, "BleTask", 4096, NULL, 2, NULL, 1);
}
void loop() {
// 所有逻辑在任务中完成,主 loop 空闲
}
将上述代码中的1032部分暂时注释掉,只保留蓝牙通信部分,将完整代码发出
最新发布