Adafruit Feather nRF52840 setWriteCallback丢失回调问题如何解决
问题根因
- BLE事件队列默认深度不足:Adafruit Bluefruit BLE栈默认的事件队列深度通常为2,同时到达的写事件超过队列容量时,新事件会被直接丢弃。
- 回调函数执行效率过低:回调中使用的
Serial打印属于阻塞IO操作,若第一个回调的打印逻辑未执行完成,第二个写事件到达时会因栈无法及时响应而丢失。 - 传输模式配置问题:如果特征值配置的是无应答写(Write Without Response),链路层本身不保证传输可靠性,两个数据包同时发送时可能出现空中碰撞,数据未到达开发板就已丢失。
解决方案
- 调大BLE事件队列深度:找到项目中的
Bluefruit_config.h配置文件,将CFG_BLE_EVENT_HANDLER_QUEUE_SIZE参数修改为4或更高,预留足够的事件缓存空间。 - 优化回调函数逻辑,移除阻塞操作:回调中仅做数据存储,将耗时的打印等逻辑移到主循环执行,参考实现如下:
// 定义环形缓冲区缓存触摸事件,可根据需求调整容量 typedef struct { uint8_t hand_type; // 0=左手,1=右手 } touch_event_t; #define EVENT_BUF_SIZE 8 touch_event_t event_buf[EVENT_BUF_SIZE]; volatile uint8_t buf_write_pos = 0, buf_read_pos = 0; void charact_write_callback(uint16_t conn_hdl, BLECharacteristic* chr, uint8_t *data, uint16_t len) { if(len >= 2 && data[0] == 2){ // 回调仅存储数据,不执行耗时操作 event_buf[buf_write_pos].hand_type = data[1]; buf_write_pos = (buf_write_pos + 1) % EVENT_BUF_SIZE; } } void loop() { // 主循环统一处理事件 while(buf_read_pos != buf_write_pos) { Serial.print(event_buf[buf_read_pos].hand_type == 0 ? "Left" : "Right"); Serial.println(" Hand Touch occured"); buf_read_pos = (buf_read_pos + 1) % EVENT_BUF_SIZE; } // 原有其他业务逻辑 }
- 修改传输模式为带应答写:配置特征值时添加
BLECharacteristic::PROPERTY_WRITE属性,不要仅使用PROPERTY_WRITE_NO_RESPONSE,同时要求发送端使用带应答的写操作,避免传输层丢包。 - 调整发送端发包间隔:若两个数据包从同一设备发出,设置至少10ms的发包间隔,避免BLE链路层缓存不足导致丢包。
内容的提问来源于stack exchange,提问作者Acimaz
相关产品推荐
相关产品推荐

