打印

ESP32通过蓝牙(BLE或经典蓝牙)接收JSON数据的完整协议设计方案

[复制链接]
544|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
keer_zu|  楼主 | 2025-5-20 13:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

以下是针对ESP32通过蓝牙(BLE或经典蓝牙)接收JSON数据的完整协议设计方案和代码实现,重点解决数据分包、粘包处理JSON解析问题。


协议设计方案

1. 数据帧格式

为可靠接收不定长的JSON数据,设计基于长度前缀 + 数据内容的协议:

[起始标志][数据长度][JSON数据][结束标志]
  • 起始标志(1字节):固定为 0xAA,标识数据帧开始。
  • 数据长度(2字节):JSON数据的实际长度(大端序)。
  • JSON数据(N字节):UTF-8编码的JSON字符串。
  • 结束标志(1字节):固定为 0x55,标识数据帧结束。

2. 数据传输流程

发送端:
  1. 计算JSON数据长度(N)。
  2. 构造帧:[0xAA][高8位长度][低8位长度][JSON数据][0x55]
  3. 通过蓝牙发送完整帧。

接收端:
  1. 检测起始标志0xAA。
  2. 读取长度字段,计算需接收的JSON数据长度。
  3. 读取指定长度的JSON数据和结束标志0x55。
  4. 校验结束标志,若正确则解析JSON。

3. 优点

  • 明确标识数据边界,解决粘包问题。
  • 长度校验避免缓冲区溢出。
  • 支持动态长度JSON数据。

代码实现

1. 依赖库

  • ArduinoJson:处理JSON解析。
  • BluetoothSerial:ESP32经典蓝牙库。

2. 完整代码

#include <BluetoothSerial.h>
#include <ArduinoJson.h>

BluetoothSerial SerialBT;
#define BUFFER_SIZE 512  // 根据实际JSON长度调整

// 协议常量
#define START_MARKER 0xAA
#define END_MARKER   0x55

// 接收状态机
enum RecvState {
  WAIT_START,
  READ_LENGTH_HIGH,
  READ_LENGTH_LOW,
  READ_DATA,
  CHECK_END
};

// 全局变量
uint8_t buffer[BUFFER_SIZE];
uint16_t data_length = 0;
uint16_t data_index = 0;
RecvState state = WAIT_START;

void setup() {
  Serial.begin(115200);
  SerialBT.begin("ESP32_JSON"); // 蓝牙设备名称
  Serial.println("Bluetooth Started!");
}

void loop() {
  while (SerialBT.available() > 0) {
    uint8_t byte = SerialBT.read();

    switch (state) {
      case WAIT_START:
        if (byte == START_MARKER) {
          state = READ_LENGTH_HIGH;
        }
        break;

      case READ_LENGTH_HIGH:
        data_length = byte << 8;
        state = READ_LENGTH_LOW;
        break;

      case READ_LENGTH_LOW:
        data_length |= byte;
        if (data_length > BUFFER_SIZE) {
          // 数据过长,重置状态
          resetState();
          Serial.println("Error: Data too long!");
        } else {
          data_index = 0;
          state = READ_DATA;
        }
        break;

      case READ_DATA:
        buffer[data_index++] = byte;
        if (data_index >= data_length) {
          state = CHECK_END;
        }
        break;

      case CHECK_END:
        if (byte == END_MARKER) {
          // 完整帧接收完成,解析JSON
          processJSON(buffer, data_length);
        } else {
          Serial.println("Error: End marker mismatch!");
        }
        resetState();
        break;
    }
  }
}

// 解析JSON数据
void processJSON(uint8_t* data, uint16_t len) {
  // 转换为字符串并添加终止符
  char json_str[len + 1];
  memcpy(json_str, data, len);
  json_str[len] = '\0';

  // 解析JSON
  DynamicJsonDocument doc(1024);
  DeserializationError error = deserializeJson(doc, json_str);

  if (error) {
    Serial.print("JSON解析失败: ");
    Serial.println(error.c_str());
    return;
  }

  // 提取数据示例
  if (doc.containsKey("sensor")) {
    const char* sensor = doc["sensor"];
    float value = doc["value"];
    Serial.printf("传感器: %s, 值: %.2f\n", sensor, value);
  }
}

// 重置接收状态
void resetState() {
  state = WAIT_START;
  data_length = 0;
  data_index = 0;
}

关键点说明

1. 状态机设计

  • 使用状态机(WAIT_STARTREAD_LENGTHREAD_DATACHECK_END)确保按协议顺序处理数据。
  • 解决蓝牙数据分包和粘包问题。

2. 缓冲区安全

  • 检查 data_length 是否超过 BUFFER_SIZE,防止溢出。
  • 动态分配缓冲区(可根据项目需求改用静态分配)。

3. 错误处理

  • 结束标志校验:检测帧是否完整。
  • JSON解析失败时输出错误信息。

发送端示例(Python模拟)

# 安装依赖: pip install pybluez
import bluetooth
import struct

def send_json_over_bt(address, json_str):
    sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
    sock.connect((address, 1))

    # 构造协议帧
    start_marker = b'\xAA'
    end_marker = b'\x55'
    data = json_str.encode('utf-8')
    length = struct.pack('>H', len(data))  # 大端序2字节

    frame = start_marker + length + data + end_marker
    sock.send(frame)
    sock.close()

# 使用示例
send_json_over_bt("ESP32_JSON_MAC", '{"sensor":"temperature","value":25.5}')

优化建议

  1. 增加CRC校验:在帧尾添加2字节CRC16校验,提高数据可靠性。

  2. 超时机制:若长时间未收到结束标志,自动重置接收状态。

  3. PSRAM支持:如果JSON数据较大,启用ESP32的PSRAM:

    // 替换DynamicJsonDocument为PSRAM版本
    DynamicJsonDocument doc(8192); // 8KB PSRAM

通过以上方案,可稳定实现ESP32通过蓝牙接收并解析JSON数据。实际项目中需根据数据量调整缓冲区大小和JSON文档容量。

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:qq群:49734243 Email:zukeqiang@gmail.com

1445

主题

12781

帖子

53

粉丝