通过观察nRF52服务的回调,解释两种回调函数的区别,以及为什么看不到他们回调函数的调用
一、nRF52的两种回调
我们在服务初始化的时候,会有回调函数的传入
这个回调到底是干什么的?
简单来说: 它是你告诉服务:“当这个服务发生重要事情时,请通知我(调用我的这个函数)”。
具体作用:
- 对于 led_write_handler(LBS 服务):
- 当手机写入LED Characteristic 时,服务会调用 led_write_handler,并把写入的值(开/关)传给你。
- 你可以在里面控制实际的 LED 灯。
- 对于 on_bas_evt(Battery Service):
- 当手机启用或禁用电池电量通知(Notification)时,服务会调用 on_bas_evt,并告诉你事件类型(BLE_BAS_EVT_NOTIFICATION_ENABLED 或 DISABLED)。
- 你可以在里面启动/停止电池测量定时器。
两种回调最根本的区别就是“事件产生的方式”不同
二、通过bsp_event_handler和on_bas_evt分析
蓝牙按键自动使能通知下的 bsp_event_handler 回调
函数调用:
蓝牙电池公共服务下的 on_bas_evt 回调
函数调用:
为什么搜索不到回调函数的调用?
1. on_bas_evt 和 led_write_handler为什么搜不到?因为在事件观察者中,中断回调函数是被函数指针(evt_handler)被调用的
它的实际调用路径是这样的(多层间接):
你在 services_init() 中注册回调:
当 BLE 事件发生时(例如手机写 Characteristic 或启用通知):
SoftDevice 产生具体 BLE 事件(如 BLE_GATTS_EVT_WRITE)
nrf_sdh_ble 把事件分发给所有注册的Observer(包括服务注册的 Observer)
服务内部的处理函数被调用:
- BAS 服务 → ble_bas_on_ble_evt()(位于 ble_bas.c)
- LBS 服务 → ble_lbs_on_ble_evt()(位于 ble_lbs.c)
服务内部函数解析事件后,通过函数指针间接调用你的回调:
关键点: on_bas_evt 和 led_write_handler 是通过函数指针(evt_handler 或 led_write_handler)被调用的,而不是在代码中直接出现 on_bas_evt(...) 或 led_write_handler(...) 的形式。
因此,你在整个工程中全局搜索 on_bas_evt( (带括号的调用)是搜不到的,这属于正常现象。
二、重要总结
只要是 BLE 服务相关的回调:
led_write_handler、on_bas_evt、ble_evt_handler全部 ← 主循环上下文全部 ←SoftDevice产生事件,事件(在事件观察者中)触发回调
只有外设驱动(ADC、定时器、UART、GPIO)
才 ←硬件产生中断,中断产生事件,事件(在事件观察者中)触发回调
SoftDevice 会产生很多具体可见的事件,你在代码里完全能看到,不是“看不到的”。常见例子(你在代码中已经处理过的):BLE_GAP_EVT_CONNECTED → 设备连接成功
BLE_GAP_EVT_DISCONNECTED → 设备断开连接
BLE_GATTS_EVT_WRITE → 手机写了某个 Characteristic(比如写 LED、写 CCCD 使能通知)
BLE_GATTS_EVT_TIMEOUT、BLE_GATTC_EVT_TIMEOUT → GATT 超时
