[STM32WBA] 【NUCLEO-WBA65RI 测评】5、BLE发送通知(notify)
·
一、基本概念
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
name:CHAR1
length:6 //陀螺仪数据至少需要6个字节

4、配置广播名:STM32-WBA65

(二)程序部分
App_ble.c文件
开启BLE广播:UTIL_TIMER_Start(&(bleAppContext.TimerAdvLowPower_Id));
复制
/* USER CODE BEGIN APP_BLE_Init_2 */APP_BLE_Procedure_Gap_Peripheral(PROC_GAP_PERIPH_ADVERTISE_START_FAST);UTIL_TIMER_Create(&(bleAppContext.TimerAdvLowPower_Id),ADV_TIMEOUT_MS,UTIL_TIMER_ONESHOT,&APP_BLE_AdvLowPower_timCB, 0);UTIL_TIMER_Start(&(bleAppContext.TimerAdvLowPower_Id));/* USER CODE END APP_BLE_Init_2 */
断开连接后再次开启BLE广播
复制
case HCI_DISCONNECTION_COMPLETE_EVT_CODE:{hci_disconnection_complete_event_rp0 *p_disconnection_complete_event;p_disconnection_complete_event = (hci_disconnection_complete_event_rp0 *) p_event_pckt->data;if (p_disconnection_complete_event->Connection_Handle == bleAppContext.connectionHandle){bleAppContext.connectionHandle = 0xFFFF;bleAppContext.Device_Connection_Status = APP_BLE_IDLE;LOG_INFO_APP(">>== HCI_DISCONNECTION_COMPLETE_EVT_CODE\n");LOG_INFO_APP(" - Connection Handle: 0x%04X\n - Reason: 0x%02X\n",p_disconnection_complete_event->Connection_Handle,p_disconnection_complete_event->Reason);/* USER CODE BEGIN EVT_DISCONN_COMPLETE_2 */APP_BLE_Procedure_Gap_Peripheral(PROC_GAP_PERIPH_ADVERTISE_START_FAST);/* USER CODE END EVT_DISCONN_COMPLETE_2 */
获得陀螺仪数据、格式化数据、发送NOTIFY
关于陀螺仪这部分处理可以详见:https://bbs.21ic.com/forum.html?mod=viewthread&tid=3499881&highlight=NUCLEO-WBA65RI
复制
/* USER CODE BEGIN FD_WRAP_FUNCTIONS *///定时执行函数//定时触发APP_PD_GYRO对应函数L3G4200D_Processstatic void APP_BLE_AdvLowPower_timCB(void *arg){/*** The code shall be executed in the background as aci command may be sent* The background is the only place where the application can make sure a new aci command* is not sent if there is a pending one*/UTIL_SEQ_SetTask(1<<APP_PD_GYRO, CFG_SEQ_PRIO_0);return;}//格式化陀螺仪数据//格式:6字节// | 1 | 2 | 3 | 4 | 5 | 6 |// |X轴高位|X轴低位|Y轴高位|Y轴低位|Z轴高位|Z轴低位|//结果保存到a_SERVER1_UpdateCharDatavoid formatSendData(int16_t x,int16_t y,int16_t z){a_SERVER1_UpdateCharData[0] = (x >> 8) & 0xFF;a_SERVER1_UpdateCharData[1] = x & 0xFF;a_SERVER1_UpdateCharData[2] = (y >> 8) & 0xFF;a_SERVER1_UpdateCharData[3] = y & 0xFF;a_SERVER1_UpdateCharData[4] = (z >> 8) & 0xFF;a_SERVER1_UpdateCharData[5] = z & 0xFF;}//APP_PD_GYRO对应函数L3G4200D_Process//1、调用PrintGyroData,获得陀螺仪数值//2、调用formatSendData,格式化数据用于notify发送//3、调用update_Gyro_data_to_char,将数据通知出去static void L3G4200D_Process(void){int16_t x,y,z;UTIL_TIMER_Stop(&(bleAppContext.TimerAdvLowPower_Id));PrintGyroData(&x,&y,&z);formatSendData(x,y,z);update_Gyro_data_to_char(a_SERVER1_UpdateCharData);UTIL_TIMER_Start(&(bleAppContext.TimerAdvLowPower_Id));}/* USER CODE END FD_WRAP_FUNCTIONS */
//通过调用SERVER1_UpdateValue将陀螺仪数据发送出去
复制
/* USER CODE BEGIN FD_LOCAL_FUNCTIONS */void update_Gyro_data_to_char(uint8_t *updateData){SERVER1_Data_t msg_conf;msg_conf.p_Payload=updateData;msg_conf.Length=6;//sizeof(updateData);SERVER1_UpdateValue(SERVER1_CHAR1, &msg_conf);}/* 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所有,任何人未经允许禁止转载。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)