一、基本概念
1. NOTIFY vs INDICATE
NOTIFY通知:服务器→客户端,单向通知,无需确认
INDICATE指示:服务器→客户端,需要客户端确认
两者都于GATT(通用属性协议)的Characteristic Value
2. 核心角色
服务器(Server/Peripheral):持有数据(如传感器)
客户端(Client/Central):接收数据(如手机)
特性(Characteristic):包含数据和描述符的数据结构
二、NOTIFY完整流程
阶段1:连接建立
阶段2:服务发现(连接后)
阶段3:启用NOTIFY
阶段4:数据通知流程
详细时序图:

为了便于理解,可以将BLE的NOTIFY与订阅杂志做对比:
杂志订阅  ↔  NOTIFY启用
杂志社     ↔  外设(服务器)
订阅者     ↔  手机/主机(客户端)
定期寄送 ↔  主动推送数据
取消订阅 ↔  禁用NOTIFY
 
完整的NOTIFY流程图:

三、NUCLEO-WBA65RI中实现NOTIFY
(一)STM32CuteMX配置
1、BLE选择

2、新增一个SERVER
name:SERVER1
UUID:FFE0
特征值:2个

3、其中一个特征值配置为NOTIFY
name:CHAR1
length:6   //陀螺仪数据至少需要6个字节
 

 
4、配置广播名:STM32-WBA65
 

 
(二)程序部分
App_ble.c文件
开启BLE广播:UTIL_TIMER_Start(&(bleAppContext.TimerAdvLowPower_Id));
复制

  
  1.   /* USER CODE BEGIN APP_BLE_Init_2 */
  2.         APP_BLE_Procedure_Gap_Peripheral(PROC_GAP_PERIPH_ADVERTISE_START_FAST);
  3.        
  4.         UTIL_TIMER_Create(&(bleAppContext.TimerAdvLowPower_Id),
  5.                       ADV_TIMEOUT_MS,
  6.                       UTIL_TIMER_ONESHOT,
  7.                       &APP_BLE_AdvLowPower_timCB, 0);
  8.   UTIL_TIMER_Start(&(bleAppContext.TimerAdvLowPower_Id));
  9.        
  10.   /* USER CODE END APP_BLE_Init_2 */

断开连接后再次开启BLE广播
复制

  
  1. case HCI_DISCONNECTION_COMPLETE_EVT_CODE:
  2.     {
  3.       hci_disconnection_complete_event_rp0 *p_disconnection_complete_event;
  4.       p_disconnection_complete_event = (hci_disconnection_complete_event_rp0 *) p_event_pckt->data;
  5.       if (p_disconnection_complete_event->Connection_Handle == bleAppContext.connectionHandle)
  6.       {
  7.         bleAppContext.connectionHandle = 0xFFFF;
  8.         bleAppContext.Device_Connection_Status = APP_BLE_IDLE;
  9.         LOG_INFO_APP(">>== HCI_DISCONNECTION_COMPLETE_EVT_CODE\n");
  10.         LOG_INFO_APP("     - Connection Handle:   0x%04X\n     - Reason:    0x%02X\n",
  11.                     p_disconnection_complete_event->Connection_Handle,
  12.                     p_disconnection_complete_event->Reason);
  13.         /* USER CODE BEGIN EVT_DISCONN_COMPLETE_2 */
  14.                                 APP_BLE_Procedure_Gap_Peripheral(PROC_GAP_PERIPH_ADVERTISE_START_FAST);
  15.         /* USER CODE END EVT_DISCONN_COMPLETE_2 */


获得陀螺仪数据、格式化数据、发送NOTIFY
关于陀螺仪这部分处理可以详见:https://bbs.21ic.com/forum.html?mod=viewthread&tid=3499881&highlight=NUCLEO-WBA65RI
复制

  
  1. /* USER CODE BEGIN FD_WRAP_FUNCTIONS */
  2. //定时执行函数
  3. //定时触发APP_PD_GYRO对应函数L3G4200D_Process
  4. static void APP_BLE_AdvLowPower_timCB(void *arg)
  5. {
  6.   /**
  7.    * The code shall be executed in the background as aci command may be sent
  8.    * The background is the only place where the application can make sure a new aci command
  9.    * is not sent if there is a pending one
  10.    */
  11.   UTIL_SEQ_SetTask(1<<APP_PD_GYRO, CFG_SEQ_PRIO_0);
  12.   return;
  13. }
  14. //格式化陀螺仪数据
  15. //格式:6字节
  16. //  |    1  |    2   |    3  |    4   |    5  |    6   |
  17. //  |X轴高位|X轴低位|Y轴高位|Y轴低位|Z轴高位|Z轴低位|
  18. //结果保存到a_SERVER1_UpdateCharData
  19. void formatSendData(int16_t x,int16_t y,int16_t z)  
  20. {  
  21.         a_SERVER1_UpdateCharData[0] = (x >> 8) & 0xFF;  
  22.         a_SERVER1_UpdateCharData[1] = x & 0xFF;  
  23.         a_SERVER1_UpdateCharData[2] = (y >> 8) & 0xFF;  
  24.         a_SERVER1_UpdateCharData[3] = y & 0xFF;         
  25.         a_SERVER1_UpdateCharData[4] = (z >> 8) & 0xFF;  
  26.         a_SERVER1_UpdateCharData[5] = z & 0xFF;      
  27. }
  28. //APP_PD_GYRO对应函数L3G4200D_Process
  29. //1、调用PrintGyroData,获得陀螺仪数值
  30. //2、调用formatSendData,格式化数据用于notify发送
  31. //3、调用update_Gyro_data_to_char,将数据通知出去
  32. static void L3G4200D_Process(void)
  33. {
  34.         int16_t x,y,z;
  35.         UTIL_TIMER_Stop(&(bleAppContext.TimerAdvLowPower_Id));
  36.        
  37.         PrintGyroData(&x,&y,&z);
  38.         formatSendData(x,y,z);
  39.         update_Gyro_data_to_char(a_SERVER1_UpdateCharData);
  40.         UTIL_TIMER_Start(&(bleAppContext.TimerAdvLowPower_Id));
  41. }
  42. /* USER CODE END FD_WRAP_FUNCTIONS */
 
//通过调用SERVER1_UpdateValue将陀螺仪数据发送出去
复制

  
  1. /* USER CODE BEGIN FD_LOCAL_FUNCTIONS */
  2. void update_Gyro_data_to_char(uint8_t *updateData)  
  3. {  
  4.         SERVER1_Data_t msg_conf;  
  5.         msg_conf.p_Payload=updateData;  
  6.         msg_conf.Length=6;//sizeof(updateData);  
  7.         SERVER1_UpdateValue(SERVER1_CHAR1, &msg_conf);  
  8. }  
  9. /* USER CODE END FD_LOCAL_FUNCTIONS */
 
四、运行验证
用手机蓝牙调试助手可以搜索到STM32-WBA65

连接后,可以看到SERVER和特征值

使能接收通知数据后,每1秒钟可以接收到1条陀螺仪数据(6个字节)


---------------------
作者:sujingliang
链接:https://bbs.21ic.com/icview-3500463-1-1.html?_dsign=a17ec1a7
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐