蓝牙BLE句柄指示\确认(Handle Value Indication\Confirmation)(CH582)

本文详细介绍了蓝牙BLE中的Handle Value Indication及Confirmation,重点解析了CH58x芯片如何实现Indication功能。从修改特征值属性、配置文件、发送与确认流程,到手机连接验证和Central接收Indication的步骤,展示了Indication相对于Notification的特性和应用场景。通过示例代码,帮助开发者理解和应用Indication功能。

原文链接:

蓝牙BLE句柄指示\确认(Handle Value Indication\Confirmation)(CH582) - SweetTea_lllpc - 博客园 (cnblogs.com)

前言:

CH583 是集成 BLE 无线通讯的 RISC-V MCU 微控制器。一般在使用BLE协议进行数据传输,会优先考虑Peripheral(外设从机角色例程)。在CH582的SDK中,自定义包含五种不同属性的服务,包含可读、可写、通知、可读可写、安全可读,唯独没有indication属性的特征值。本篇博客针对Indication使用进行讲解。

一、indication属性原理

当Server想要Client发送快速的属性状态更新时,它可以发送一条句柄值通知(Notification)。这是Server能够发给Client的两种消息中的一种,并且是不要求响应的。Server可以在任何时刻发送该Notification,同时该Notification也是不可靠的。

句柄值指示(Indication)类似于Notification,它有着相同的属性句柄字段和数值,不同的是Client收到Indication以后需要回复。Server一次只能发送一条Indication,并且只有在收到确认响应(Confirmation)后才能发起下一条Indication。这些行为都是在GATT层完成。由于有自动确认机制,Indication在很多应用层级的协议制定中有比较广泛应用。

二、CH58x芯片Indication的实现

由于Peripheral例程中已包含了Notification的功能,通道4进行Noti数据传输。本篇博客基于该功能进行修改,对以前只接触过Notification的小白来说更加通俗易懂。

1、特征值4属性修改,给Characteristic 的属性添加indication 属性

static uint8_t simpleProfileChar4Props = GATT_PROP_INDICATE;

按照如上修改配置文件属性后,对应的属性表也配置成功了,不需要再进行修改,默认的Noti已经配置好属性表

// Characteristic Value 4
{
    {ATT_BT_UUID_SIZE, simpleProfilechar4UUID},
    0,
    0,
    simpleProfileChar4},

2、配置文件修改,在peripheral.c文件夹中基于Notification进行修改

static void peripheralChar4Notify(uint8_t *pValue, uint16_t len)
{
#if 0                                  //原始程序是Noti
    attHandleValueNoti_t noti;
    if(len > (peripheralMTU - 3))
    {
        PRINT("Too large noti\n");
        return;
    }
    noti.len = len;
    noti.pValue = GATT_bm_alloc(peripheral
<think>我们基于CH582的Peripheral例程来实现BLE控制LED亮灭。CH582是沁恒微电子推出的支持BLE4.2的MCU。我们将通过添加一个自定义服务(包含一个可写特征)来控制LED。###步骤概览:1.**环境准备**:确保有CH582开发板、MounRiverStudio开发环境。2.**例程选择**:使用官方提供的`Peripheral`例程(在EVT包中)。3.**修改代码**:-定义LED引脚并初始化。-添加自定义服务(UUID:FFE0)和特征(UUID:FFE1,可写)。-在GATT写回调中解析特征值,控制LED。4.**编译烧录**:使用MounRiverStudio编译,用WCHISPTool烧录。5.**测试**:使用BLE调试APP(如nRFConnect)连接设备并发送控制指令。###详细步骤:####1.定义LED引脚在`peripheral.h`中添加:```c#defineLED_PINGPIO_Pin_4//假设LED接在PB4#defineLED_PORTGPIOB#defineLED_ON()GPIOB_ResetBits(LED_PIN)//低电平点亮#defineLED_OFF()GPIOB_SetBits(LED_PIN)//高电平熄灭```####2.初始化LED在`Peripheral_Init()`函数中(位于`peripheral_main.c`)添加GPIO初始化:```cvoidPeripheral_Init(void){//...其他初始化代码//初始化LEDGPIOB_ModeCfg(LED_PIN,GPIO_ModeOut_PP_5mA);LED_OFF();//初始熄灭}```####3.添加自定义LED控制服务在`peripheral.c`中添加以下代码:#####定义服务UUID在文件顶部添加:```c//自定义LED服务UUID#defineLED_SERVICE_UUID0xFFE0#defineLED_CHARACTERISTIC_UUID0xFFE1//全局变量staticuint8_tledState=0;//用于存储特征值staticgattAttribute_tledService[4];//服务声明+特征声明+特征值+特征描述符```#####创建服务添加函数`LEDService_AddService()`:```cvoidLEDService_AddService(void){uint8_tcharProps=GATT_PROP_WRITE;//可写特征//1.服务声明ledService[0].type=ATT_BT_UUID_SIZE;ledService[0].permissions=GATT_PERMIT_READ;ledService[0].pValue=(uint8_t*)&LED_SERVICE_UUID;//2.特征声明ledService[1].type=ATT_BT_UUID_SIZE;ledService[1].permissions=GATT_PERMIT_READ;ledService[1].pValue=(uint8_t*)&LED_CHARACTERISTIC_UUID;//3.特征值ledService[2].type=ATT_BT_UUID_SIZE;ledService[2].permissions=GATT_PERMIT_WRITE;ledService[2].pValue=&ledState;//绑定到变量//4.特征描述符(客户端特征配置,可选,这里为了简单可以不处理)ledService[3].type=ATT_BT_UUID_SIZE;ledService[3].permissions=(GATT_PERMIT_READ|GATT_PERMIT_WRITE);ledService[3].pValue=NULL;//注册服务GATT_AddService(ledService,4);}```#####在初始化调用在`Peripheral_Init()`中调用上述函数(在`peripheral_main.c`):```cvoidPeripheral_Init(void){//...其他初始化LEDService_AddService();//添加LED服务}```####4.处理写操作在`Peripheral_ProcessGATTMsg()`函数(位于`peripheral.c`)中处理对LED特征的写请求:```cstaticuint8_tPeripheral_ProcessGATTMsg(gattMsgEvent_t*pMsg){switch(pMsg->method){caseATT_WRITE_REQ:caseATT_WRITE_CMD://检查是否写入LED特征(特征值句柄)if(pMsg->msg.handle==ledService[2].handle){//写入的值在pMsg->msg.pValue中,长度为lenuint8_t*pValue=pMsg->msg.pValue;if(pValue[0]==0x01){//开灯LED_ON();}elseif(pValue[0]==0x00){//关灯LED_OFF();}returnSUCCESS;}break;//...其他事件处理}return0;//其他消息返回0(非SUCCESS状态)}```####5.修改广播名称(可选)在`Peripheral_Init()`中修改广播名称:```cgapRoles_Init(ROLE_PERIPHERAL,"LED_Controller",DEFAULT_ADVERTISING_INTERVAL);```###编译烧录1.在MounRiverStudio中编译工程。2.使用WCHISPTool烧录生成的HEX文件。###测试1.使用手机APP(如nRFConnect)扫描并连接设备"LED_Controller"。2.找到UUID为FFE0的服务,其中的FFE1特征。3.向FFE1特征写入:-01:点亮LED-00:熄灭LED###注意事项-如果LED引脚与你的硬件不符,请修改`LED_PIN`和`LED_PORT`定义。-特征值句柄(`ledService[2].handle`)在服务注册后由系统分配,所以我们在回调中直接使用该变量是安全的。-广播间隔、连接参数等可根据需要调整。###相关问题1.**如何修改CH582BLE设备名称?**在`Peripheral_Init()`函数中,修改`gapRoles_Init()`函数的第二个参数,例如:`"MyDevice"`。2.**CH582BLE广播数据格式如何自定义?**通过修改`gap_SetAdvData()`函数中的广播数据数组。广播数据格式遵循BLE规范,包括标志、设备名称、服务UUID等。3.**如何实现CH582BLE连接密码配对?**在`Peripheral_Init()`中设置配对参数,例如:`gapBondMgr_SetParameter(GAPBOND_DEFAULT_PASSCODE,sizeof(uint32_t),&passcode);`,并在回调中处理配对事件。4.**CH582BLE服务最多能添加多少个?**受限于芯片的RAM和GATT表大小,具体可参考手册。通常可以添加多个服务,但总属性数量不能超过GATT表最大条目数(CH582约20个左右)。[^1]:CH579CH573CH582CH592蓝牙主机(Central)实例应用讲解()[^2]:基于CH579实现蓝牙ble4.2)串口透传[^3]:沁恒CH32V208蓝牙串口透传例程§§相关问题§§1.如何修改CH582的广播间隔以降低功耗?2.CH582BLE连接参数如何优化以实现更低功耗?3.如何在CH582上实现多个自定义BLE服务?4.CH582BLE从机模式下最大连接数是多少?</think>基于 CH582 Peripheral 例程实现 BLE 4.2 控制 LED 亮灭功能的详细步骤如下: ### 一、开发环境准备 1. **硬件连接** - 将 LED 连接到 PB4 引脚(默认配置,可根据实际修改) - 开发板:CH582 开发板 2. **软件资源** - MounRiver Studio 开发环境 - CH582 EVT 包(包含 Peripheral 例程) - BLE 调试工具:nRF Connect 或 BLE Scanner ### 二、代码修改步骤(基于 Peripheral 例程) #### 1. 添加 LED 控制宏(在 `peripheral.h`) ```c // 添加LED引脚定义 #define LED_PIN GPIO_Pin_4 #define LED_PORT GPIOB #define LED_ON() GPIOB_ResetBits(LED_PIN) // 低电平点亮 #define LED_OFF() GPIOB_SetBits(LED_PIN) // 高电平熄灭 ``` #### 2. 初始化 LED GPIO(修改 `peripheral_main.c`) ```c void Peripheral_Init(void) { // ...其他初始化代码... // 添加LED初始化 GPIOB_ModeCfg(LED_PIN, GPIO_ModeOut_PP_5mA); LED_OFF(); // 初始状态熄灭 } ``` #### 3. 添加自定义 LED 控制服务(在 `peripheral.c`) ```c // 定义LED控制服务的UUID #define LED_SERVICE_UUID 0xFFE0 #define LED_CHARACTERISTIC_UUID 0xFFE1 static gattAttribute_t ledService[4]; // 服务声明+特征声明+特征值+特征描述 void LEDService_AddService(void) { // 1. 服务声明 ledService[0].type = ATT_BT_UUID_SIZE; ledService[0].permissions = GATT_PERMIT_READ; ledService[0].pValue = (uint8_t *)&LED_SERVICE_UUID; // 2. 特征声明 ledService[1].type = ATT_BT_UUID_SIZE; ledService[1].permissions = GATT_PERMIT_READ; ledService[1].pValue = (uint8_t *)&LED_CHARACTERISTIC_UUID; // 3. 特征值 ledService[2].type = ATT_BT_UUID_SIZE; ledService[2].permissions = GATT_PERMIT_WRITE; ledService[2].pValue = NULL; // 实际值通过回调处理 // 4. 特征描述符 ledService[3].type = ATT_BT_UUID_SIZE; ledService[3].permissions = (GATT_PERMIT_READ | GATT_PERMIT_WRITE); ledService[3].pValue = NULL; // 注册服务 GATT_AddService(ledService, 4); } ``` #### 4. 在初始化函数中调用服务(修改 `peripheral_main.c`) ```c void Peripheral_Init(void) { // ...原有初始化... LEDService_AddService(); // 添加自定义LED服务 } ``` #### 5. 处理 BLE 写操作(修改 `peripheral.c`) ```c static uint8_t Peripheral_ProcessGATTMsg(gattMsgEvent_t *pMsg) { switch(pMsg->method) { case ATT_WRITE_REQ: case ATT_WRITE_CMD: // 检查是否写入LED特征 if(pMsg->msg.handle == ledService[2].handle) { uint8_t cmd = pMsg->msg.pValue[0]; // 获取写入值 if(cmd == 0x01) { LED_ON(); PRINT("LED ON\n"); } else if(cmd == 0x00) { LED_OFF(); PRINT("LED OFF\n"); } return SUCCESS; } break; // ...其他GATT消息处理... } return 0; } ``` #### 6. 优化连接状态指示(可选) ```c static void Peripheral_ProcessGAPMsg(gapEventHdr_t *pMsg) { switch(pMsg->opcode) { case GAP_EVENT_SIGN: // BLE状态事件 if(pMsg->status == SUCCESS) { gapEventSign_t *pSign = (gapEventSign_t*)pMsg; switch(pSign->evenCode) { case GAP_ESTABLISH_LINK: // 连接建立 LED_ON(); // 连接后亮灯指示 break; case GAP_TERMINATE_LINK: // 连接断开 LED_OFF(); // 断开后灭灯 break; } } break; } } ``` ### 三、关键配置说明 1. **BLE 参数配置** - 修改设备名称:在 `Peripheral_Init()` 中修改 `gapRoles_Init()` 参数 ```c gapRoles_Init(ROLE_PERIPHERAL, "LED_Controller", DEFAULT_ADVERTISING_INTERVAL); ``` 2. **广播数据配置** - 在 `Peripheral_Init()` 中添加自定义广播数据: ```c uint8_t advData[] = {0x02, 0x01, 0x06, 0x03, 0x03, 0xFF, 0xE0}; gap_SetAdvData(sizeof(advData), advData); ``` ### 四、编译与测试 1. **编译步骤** - 在 MounRiver Studio 中打开 Peripheral 例程 - 添加上述代码修改 - 编译生成 HEX 文件 2. **烧录步骤** - 使用 WCHISPTool 烧录程序到 CH582 开发板 3. **手机 APP 测试** - 扫描设备 "LED_Controller" - 查找 UUID 为 FFE0 的服务 - 向特征 FFE1 写入: - 十六进制 `01`:点亮 LED - 十六进制 `00`:熄灭 LED ### 五、功耗优化建议 1. 调整广播间隔(单位 0.625ms): ```c #define SLOW_ADVERTISING_INTERVAL 1600 // 1秒 gapRoles_Init(ROLE_PERIPHERAL, "LED_Controller", SLOW_ADVERTISING_INTERVAL); ``` 2. 连接后降低功耗: ```c gap_SetParamValue(TGAP_CONN_PAUSE_PERIPHERAL, 6); // 降低连接间隔 ``` ### 六、常见问题解决 1. **无法发现服务**: - 检查 UUID 是否匹配 - 确认服务注册成功(`GATT_AddService` 返回值) 2. **写入无响应**: - 检查特征权限是否为 `GATT_PERMIT_WRITE` - 验证回调函数是否正确处理写请求 > 完整实现参考 CH582EVT 包的 `BLE/Peripheral` 例程[^1][^2]
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值