通过蓝牙和esp32通信

[复制链接]
 楼主| keer_zu 发表于 2025-5-25 03:53 | 显示全部楼层 |阅读模式
可以连接和写入:

PC端python:

  1. import asyncio
  2. import json
  3. from bleak import BleakClient, discover

  4. class BluetoothInterface:
  5.     def __init__(self, device_name="ESP32-led", tx_uuid=None, rx_uuid=None):
  6.         """
  7.         初始化蓝牙接口
  8.         
  9.         :param device_name: 目标设备名称,默认"ESP32-led"
  10.         :param tx_uuid: 发送数据的Characteristic UUID
  11.         :param rx_uuid: 接收数据的Characteristic UUID
  12.         """
  13.         self.device_name = device_name
  14.         self.tx_uuid = tx_uuid or "00001101-0000-1000-8000-00805F9B34FB"
  15.         self.rx_uuid = rx_uuid or "00001101-0000-1000-8000-00805F9B34FB"
  16.         self.client = None
  17.         self.connected = False
  18.         self.receive_callback = None

  19.     async def connect(self):
  20.         """连接到蓝牙设备"""
  21.         devices = await discover()
  22.         for d in devices:
  23.             if d.name == self.device_name:
  24.                 self.device_address = d.address
  25.                 break
  26.         else:
  27.             raise Exception(f"未找到设备: {self.device_name}")

  28.         self.client = BleakClient(self.device_address)
  29.         try:
  30.             await self.client.connect()
  31.             self.connected = True
  32.             print("蓝牙连接成功")
  33.         except Exception as e:
  34.             print(f"连接失败: {str(e)}")
  35.             self.connected = False

  36.     async def disconnect(self):
  37.         """断开蓝牙连接"""
  38.         if self.connected:
  39.             await self.client.disconnect()
  40.             self.connected = False
  41.             print("蓝牙已断开")

  42.     async def send_data(self, data):
  43.         """发送JSON数据"""
  44.         if not self.connected:
  45.             raise Exception("未连接设备")
  46.         
  47.         try:
  48.             json_str = json.dumps(data) + "\r\n"  # 添加帧结束符
  49.             await self.client.write_gatt_char(self.tx_uuid, json_str.encode('utf-8'))
  50.             print(f"发送数据: {json_str.strip()}")
  51.         except Exception as e:
  52.             print(f"发送失败: {str(e)}")

  53.     def register_receive_callback(self, callback):
  54.         """注册数据接收回调函数"""
  55.         self.receive_callback = callback

  56.     async def _receive_loop(self):
  57.         """内部接收循环"""
  58.         while self.connected:
  59.             try:
  60.                 data = await self.client.read_gatt_char(self.rx_uuid)
  61.                 cleaned_data = data.decode('utf-8').strip('\x0d\x0a')
  62.                 if cleaned_data:
  63.                     json_data = json.loads(cleaned_data)
  64.                     if self.receive_callback:
  65.                         self.receive_callback(json_data)
  66.             except Exception as e:
  67.                 print(f"接收错误: {str(e)}")
  68.                 await asyncio.sleep(1)

  69.     async def start_receive(self):
  70.         """启动数据接收"""
  71.         if self.connected:
  72.             asyncio.create_task(self._receive_loop())

  73. async def main():
  74.     # 配置UUID(根据实际设备修改)
  75.     DEVICE_NAME = "ESP32-led"
  76.     TX_UUID = "0000ffe1-0000-1000-8000-00805f9b34fb"  # 替换为实际发送UUID
  77.     RX_UUID = "0000ffe1-0000-1000-8000-00805f9b34fb"  # 替换为实际接收UUID

  78.     interface = BluetoothInterface(
  79.         device_name=DEVICE_NAME,
  80.         tx_uuid=TX_UUID,
  81.         rx_uuid=RX_UUID
  82.     )

  83.     await interface.connect()
  84.     interface.register_receive_callback(print)  # 打印接收数据

  85.     try:
  86.         await interface.start_receive()
  87.         
  88.         while True:
  89.             status = input("请输入状态(start/listening/thinking/speaking/stop): ").strip()
  90.             score = input("请输入评分(0-10): ").strip()
  91.             
  92.             # 构造数据包
  93.             data_packet = {
  94.                 "status": status,
  95.                 "score": score
  96.             }
  97.             
  98.             # 发送数据
  99.             await interface.send_data(data_packet)
  100.             await asyncio.sleep(0.5)  # 防止快速发送导致丢包
  101.             
  102.     except KeyboardInterrupt:
  103.         print("\n程序终止")
  104.     finally:
  105.         await interface.disconnect()

  106. if __name__ == "__main__":
  107.     # 运行主程序
  108.     asyncio.run(main())


esp32:
  1. #include <ArduinoJson.h>
  2. #include <BLEDevice.h>
  3. #include <BLEServer.h>
  4. #include <BLEUtils.h>
  5. #include <BLE2902.h>

  6. // 根据实际硬件定义LED引脚
  7. #ifndef LED_BUILTIN
  8. #define LED_BUILTIN 2  // ESP32默认LED引脚
  9. #endif

  10. // 配置与Python端一致的UUID
  11. #define SERVICE_UUID        "00001101-0000-1000-8000-00805F9B34FB"  // 服务UUID
  12. #define CHARACTERISTIC_UUID_RX "0000ffe1-0000-1000-8000-00805F9B34FB"  // 接收特征UUID

  13. BLEServer* pServer = NULL;
  14. BLECharacteristic* pRxCharacteristic;

  15. // 接收数据缓冲区
  16. String receivedData = "";

  17. class MyServerCallbacks : public BLEServerCallbacks {
  18.   void onConnect(BLEServer* pServer) {
  19.     Serial.println("设备已连接");
  20.   };
  21.   
  22.   void onDisconnect(BLEServer* pServer) {
  23.     Serial.println("设备已断开");
  24.   }
  25. };

  26. void blue_setup() {
  27.   Serial.begin(115200);
  28.   
  29.   // 创建BLE设备
  30.   BLEDevice::init("ESP32-led");
  31.   
  32.   // 创建服务器
  33.   pServer = BLEDevice::createServer();
  34.   pServer->setCallbacks(new MyServerCallbacks());
  35.   
  36.   // 创建服务
  37.   BLEService* pService = pServer->createService(SERVICE_UUID);
  38.   
  39.   // 创建接收特征(修改此处UUID)
  40.   pRxCharacteristic = pService->createCharacteristic(
  41.     CHARACTERISTIC_UUID_RX,
  42.     BLECharacteristic::PROPERTY_WRITE_NR   // 支持无响应写入
  43.   );
  44.   
  45.   // 启动服务
  46.   pService->start();
  47.   
  48.   // 开始广播
  49.   pServer->getAdvertising()->start();
  50.   Serial.println("等待Python设备连接...");
  51. }



  52. void processReceivedData(String data) {
  53.   // 去除可能的多余字符
  54.   data.trim();
  55.   
  56.   // 解析JSON
  57.   DynamicJsonDocument doc(2048);  // 使用DynamicJsonDocument替代(更灵活)
  58.   DeserializationError error = deserializeJson(doc, data);
  59.   
  60.   if (error) {
  61.     Serial.println("JSON解析错误: " + String(error.c_str()));
  62.     return;
  63.   }
  64.   
  65.   // 提取字段
  66.   String status = doc["status"].as<String>();
  67.   int score = doc["score"].as<int>();
  68.   
  69.   // 验证数据有效性
  70.   if (status.isEmpty() || score < 0 || score > 10) {
  71.     Serial.println("数据验证失败");
  72.     return;
  73.   }
  74.   
  75.   // 处理有效数据
  76.   Serial.print("收到指令: ");
  77.   Serial.print("Status=");
  78.   Serial.print(status);
  79.   Serial.print(", Score=");
  80.   Serial.println(score);
  81.   
  82.   // 根据状态执行操作示例
  83.   if (status == "start") {
  84.     digitalWrite(LED_BUILTIN, HIGH);
  85.     Serial.println("疗愈开始");
  86.   } else if (status == "stop") {
  87.     digitalWrite(LED_BUILTIN, LOW);
  88.     Serial.println("疗愈停止");
  89.   }
  90.   
  91.   // 其他状态处理...
  92. }

  93. // BLE写入回调
  94. class RxCharacteristicCallbacks : public BLECharacteristicCallbacks {
  95.   void onWrite(BLECharacteristic *pCharacteristic) {
  96.     String rxValue = pCharacteristic->getValue().c_str();  // 直接转换为String
  97.    
  98.     if (rxValue.length() > 0) {
  99.       receivedData += rxValue;
  100.       Serial.println(rxValue);
  101.     }
  102.   }
  103. };

  104. void initCallbacks() {
  105.   pRxCharacteristic->setCallbacks(new RxCharacteristicCallbacks());
  106. }

  107. void data_process() {
  108.   // 处理接收数据
  109.   if (receivedData.length() > 0) {
  110.     Serial.println("on data recv\n");
  111.     // 检查帧结束符
  112.     if (receivedData.endsWith("\r\n")) {
  113.       processReceivedData(receivedData);
  114.       receivedData = "";
  115.     }
  116.   }
  117.   delay(10);  // 避免空循环占用过高CPU
  118. }



您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

1478

主题

12912

帖子

55

粉丝
快速回复 在线客服 返回列表 返回顶部