#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
// ==================== 启用调试模式 ====================
#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;
// DIS 分组命令
const uint16_t CMD_READ_DIS_1_3 = 0xD6EC;
const uint16_t CMD_READ_DIS_4_6 = 0xD7EB;
const uint16_t CMD_READ_DIS_7_9 = 0xD8C6;
const uint16_t CMD_READ_DIS_10_12 = 0xD9C1;
const uint16_t CMD_READ_DIS_13_15 = 0xDAC8;
const uint16_t CMD_READ_DIS_16_18 = 0xDBCF;
// 其他测量命令
const uint16_t CMD_READ_VREF2_V3 = 0xDFD3;
const uint16_t CMD_READ_V5_DIETEMP_VSTK = 0xE06E;
// ==================== SPI 设置 ====================
SPISettings spiSettings(1000000, MSBFIRST, SPI_MODE3); // 1MHz, Mode3 (CPOL=1, CPHA=1)
// ==================== BLE 配置 ====================
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
BLECharacteristic* pCharacteristic = nullptr;
bool deviceConnected = false;
float sharedCellVoltages[16] = {0};
float sharedDisVoltages[16] = {0};
float sharedVref2 = 0.0f, sharedV3 = 0.0f, sharedV5 = 0.0f, sharedDieTemp = 0.0f, sharedVstk = 0.0f;
portMUX_TYPE sensorMutex = portMUX_INITIALIZER_UNLOCKED; // 保护共享数据
// 回调类声明
class MyServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer* pServer) override {
deviceConnected = true;
Serial.println("设备接入~");
}
void onDisconnect(BLEServer* pServer) override {
deviceConnected = false;
Serial.println("设备断开~");
pServer->startAdvertising(); // 重新开始广播
}
};
class MyCharacteristicCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic* pCharacteristic) override {
std::string value = pCharacteristic->getValue();
if (!value.empty()) {
Serial.print("特征值已更新,新值为: ");
Serial.println(value.c_str());
}
}
};
// ==================== 辅助函数:打印二进制 ====================
void printBinary(uint8_t b) {
for (int i = 7; i >= 0; i--) {
Serial.write((b & (1 << i)) ? '1' : '0');
}
}
// ==================== 唤醒芯片 ====================
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];
}
}
// ==================== 读取所有 CELL 电压 ====================
bool readAllCellVoltages(float* cellVoltages) {
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;
float voltage = (raw[i] - 10240) * 0.0001f;
cellVoltages[idx] = voltage;
}
}
SPI.endTransaction();
return true;
}
// ==================== 读取所有 DIS 电压 ====================
/*bool readAllDisVoltages(float* disVoltages) {
const uint16_t cmds[] = {
CMD_READ_DIS_1_3, CMD_READ_DIS_4_6, CMD_READ_DIS_7_9,
CMD_READ_DIS_10_12, CMD_READ_DIS_13_15, CMD_READ_DIS_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;
float voltage = (raw[i] - 10240) * 0.0001f;
disVoltages[idx] = voltage;
}
}
SPI.endTransaction();
return true;
}*/
// ==================== 读取 VREF2 和 V3 ====================
/*bool readVref2AndV3(float* vref2, float* v3) {
uint8_t buffer[8];
SPI.beginTransaction(spiSettings);
digitalWrite(CS_PIN, LOW);
SPI.transfer16(CMD_READ_VREF2_V3);
for (int i = 0; i < 8; i++) {
buffer[i] = SPI.transfer(0x00);
}
digitalWrite(CS_PIN, HIGH);
SPI.endTransaction();
uint16_t raw_v3 = (buffer[0] << 8) | buffer[1];
uint16_t raw_vref2 = (buffer[2] << 8) | buffer[3];
*v3 = (raw_v3 - 10240) * 0.0001f;
*vref2 = (raw_vref2 - 10240) * 0.0001f;
return true;
}*/
// ==================== 读取 V5 / DieTemp / VSTK ====================
bool readV5DieTempVStk(float* v5, float* dieTemp, float* vstk) {
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();
uint16_t raw_vstk = (buffer[0] << 8) | buffer[1];
uint16_t raw_dieTemp = (buffer[2] << 8) | buffer[3];
uint16_t raw_v5 = (buffer[4] << 8) | buffer[5];
*vstk = (raw_vstk - 10240) * 0.0016f;
*v5 = (raw_v5 - 10240) * 0.0001f;
if (raw_dieTemp >= 8000 && raw_dieTemp <= 30000) {
*dieTemp = raw_dieTemp * 0.27662 - 3105.59;
} else {
*dieTemp = NAN;
}
return true;
}
// ==================== 更新 BLE 特征值(从 Core 1 调用)====================
void updateBLECharacteristic() {
static char jsonBuffer[512]; // 300 足够容纳 cell[16] + temp
int offset = 0;
float cell[16];
float dieTemp;
// 安全拷贝共享数据
portENTER_CRITICAL(&sensorMutex);
memcpy(cell, sharedCellVoltages, sizeof(cell));
dieTemp = sharedDieTemp;
portEXIT_CRITICAL(&sensorMutex);
// 构造 JSON: {"cell":[...], "temp": ...}
offset += snprintf(jsonBuffer + offset, sizeof(jsonBuffer) - offset, "{\"cell\":[");
for (int i = 0; i < 16; i++) {
offset += snprintf(jsonBuffer + offset, sizeof(jsonBuffer) - offset,
"%.3f%s", cell[i], (i < 15) ? "," : "");
}
if (!isnan(dieTemp)) {
offset += snprintf(jsonBuffer + offset, sizeof(jsonBuffer) - offset,
"],\"temp\":%.2f}", dieTemp);
} else {
offset += snprintf(jsonBuffer + offset, sizeof(jsonBuffer) - offset,
"],\"temp\":null}");
}
// 防溢出兜底
if (offset >= sizeof(jsonBuffer)) {
strcpy(jsonBuffer, "{\"err\":\"long\"}");
}
// 发送到 BLE
if (pCharacteristic && deviceConnected) {
pCharacteristic->setValue(jsonBuffer);
pCharacteristic->notify(); // 触发通知
}
#ifdef DEBUG_GMD1032
Serial.printf("BLE Data: %s\n", jsonBuffer);
#endif
}
// ==================== 核心 0:传感器采集任务 ====================
void sensorTask(void *parameter) {
for (;;) {
yield(); // 让出时间片
wakeUpGMD1032();
delay(2);
sendCommand(CMD_START_MEASUREMENT);
delay(10);
float cellVoltages[16] = {0};
//float disVoltages[16] = {0};
float vref2 = 0.0f, v3 = 0.0f, v5 = 0.0f, dieTemp = 0.0f, vstk = 0.0f;
readAllCellVoltages(cellVoltages);
//readAllDisVoltages(disVoltages);
//readVref2AndV3(&vref2, &v3);
readV5DieTempVStk(&v5, &dieTemp, &vstk);
// 写入共享变量(加锁)
portENTER_CRITICAL(&sensorMutex);
memcpy(sharedCellVoltages, cellVoltages, sizeof(cellVoltages));
//memcpy(sharedDisVoltages, disVoltages, sizeof(disVoltages));
//sharedVref2 = vref2;
//sharedV3 = v3;
sharedV5 = v5;
sharedDieTemp = dieTemp;
sharedVstk = vstk;
portEXIT_CRITICAL(&sensorMutex);
#ifdef DEBUG_GMD1032
Serial.println("============== GMD1032 全通道数据 ==============");
for (int i = 0; i < 16; i++) {
if (i % 4 == 0) {
Serial.print(" ");
}
Serial.printf("CELL%2d:%5.3fV ", i + 1, cellVoltages[i]);
if ((i + 1) % 4 == 0 || i == 15) {
Serial.println();
}
}
if (!isnan(dieTemp)) {
Serial.printf("芯片温度: %.2f°C\n", dieTemp);
} else {
Serial.println("芯片温度: 无效数据");
}
Serial.println("---------------------------------------------");
#endif
delay(1000); // 每秒采集一次
}
}
// ==================== 核心 1:BLE 服务任务 ====================
void bleTask(void *parameter) {
BLEDevice::init("GMD1032-BLE-Slave");
bool mtuSet = BLEDevice::setMTU(256);
Serial.printf("MTU 设置 %s\n", mtuSet ? "成功" : "失败");
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("GMD1032 Ready");
pService->start();
BLEAdvertising* pAdvertising = pServer->getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->start();
Serial.println("BLE 广播已启动,等待连接... (运行于 Core 1)");
for (;;) {
if (deviceConnected) {
updateBLECharacteristic();
}
delay(5000); // 每 1000ms 尝试推送一次
}
}
// ==================== setup() ====================
void setup() {
Serial.begin(115200);
while (!Serial && millis() < 3000);
#ifdef DEBUG_GMD1032
Serial.println("[DEBUG] GMD1032 调试模式已启用");
#endif
// === 初始化 SPI ===
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); // Core 0
xTaskCreatePinnedToCore(bleTask, "BleTask", 4096, NULL, 2, NULL, 1); // Core 1
}
// ==================== loop() ====================
void loop() {
// 所有功能由 FreeRTOS 任务接管,loop 留空
}
这是ble蓝牙从机代码,现在要求取消使用加密,直接发送采集到的cell1-16与temp数据,不做计算