NRF51822蓝牙服务(3)——电池电量采集

 

前言

由于蓝牙BLE就是为低功耗手持设备存在的,那电池电量的监测服务就不可或缺了。由于电量服务是蓝牙兴趣小组指定的服务,不需要用户去创建私有服务,所以这个实验我们直接使用官方提供的驱动文件即可。

实验分析

由于我的开发板没有提供AD口检测电量,所以实验直接使用一个全局变量代表电量值,每隔一秒更新一次。

首先,我们需要把官方驱动例程添加到我们的工程目录里面:

路径是:工程目录\components\ble\ble_services\ble_bas

接着,我们去看看官方提供给我们的电量更新接口函数:

ble_bas.c:

uint32_t ble_bas_battery_level_update(ble_bas_t * p_bas, uint8_t battery_level)
{
    if (p_bas == NULL)
    {
        return NRF_ERROR_NULL;
    }
    
    uint32_t err_code = NRF_SUCCESS;
    ble_gatts_value_t gatts_value;

    if (battery_level != p_bas->battery_level_last)
    {
        // Initialize value struct.
        memset(&gatts_value, 0, sizeof(gatts_value));

        gatts_value.len     = sizeof(uint8_t);
        gatts_value.offset  = 0;
        gatts_value.p_value = &battery_level;

        // Update database.
        err_code = sd_ble_gatts_value_set(p_bas->conn_handle,
                                          p_bas->battery_level_handles.value_handle,
                                          &gatts_value);
        if (err_code == NRF_SUCCESS)
        {
            // Save new battery value.
            p_bas->battery_level_last = battery_level;
        }
        else
        {
            return err_code;
        }

        // Send value if connected and notifying.
        if ((p_bas->conn_handle != BLE_CONN_HANDLE_INVALID) && p_bas->is_notification_supported)
        {
            ble_gatts_hvx_params_t hvx_params;

            memset(&hvx_params, 0, sizeof(hvx_params));

            hvx_params.handle = p_bas->battery_level_handles.value_handle;
            hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
            hvx_params.offset = gatts_value.offset;
            hvx_params.p_len  = &gatts_value.len;
            hvx_params.p_data = gatts_value.p_value;

            err_code = sd_ble_gatts_hvx(p_bas->conn_handle, &hvx_params);
        }
        else
        {
            err_code = NRF_ERROR_INVALID_STATE;
        }
    }

    return err_code;
}

分析这个函数可以知道,执行更新数据之后,会调用sd_ble_gatts_hvx函数通知手机;

接下来,我们直接开始应用层的设计。既然我们要做到定时更新,那么定时器就首先要创建:

//定时器初始化
APP_TIMER_DEF(m_battery_timer_id);//宏定义一个电量测量定时器id
static void timers_init(void)
{
	uint32_t err_code;
	
	APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false);
	err_code = app_timer_create(&m_battery_timer_id, APP_TIMER_MODE_REPEATED, battery_level_meas_timeout_handler);
	APP_ERROR_CHECK(err_code);
}
	err_code = app_timer_start(m_battery_timer_id, APP_TIMER_TICKS(1000,APP_TIMER_PRESCALER), NULL);
    APP_ERROR_CHECK(err_code);

在main函数启动定时器。

然后,我们需要创建一个定时器超时的回调函数:

uint8_t adc = 0;
static void battery_level_update(void)
{
	uint32_t err_code;
	uint8_t battery_level;
	
	battery_level = adc;
	adc++;
	if(adc >= 100)	adc = 0;
	err_code = ble_bas_battery_level_update(&m_bas, battery_level);
	if((err_code != NRF_SUCCESS) && 
		(err_code != NRF_ERROR_INVALID_STATE) && 
		(err_code != BLE_ERROR_NO_TX_BUFFERS) &&
		(err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING))
	{
		APP_ERROR_HANDLER(err_code);
	}
}
static void battery_level_meas_timeout_handler(void *p_context)
{
	UNUSED_PARAMETER(p_context);
	//数据处理
	battery_level_update();
}

接着,我们要把电池服务注册到服务初始化里面:

/**@brief Function for initializing services that will be used by the application.
 */
static void services_init(void)
{
    uint32_t       err_code;
	ble_bas_init_t bas_init;

	//电池服务
	memset(&bas_init, 0, sizeof(bas_init));
	BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.cccd_write_perm);
	BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.read_perm);
	BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&bas_init.battery_level_char_attr_md.write_perm);
	BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_report_read_perm);
	bas_init.evt_handler		  = NULL;
	bas_init.support_notification = 1;
	bas_init.p_report_ref         = NULL;
	bas_init.initial_batt_level = 100;
	m_bas.is_notification_supported = 1;
	err_code = ble_bas_init(&m_bas, &bas_init);
	APP_ERROR_CHECK(err_code);
}

需要注意的是,一定要把上面的几个安全模式设置打开,因为官方驱动代码里面没有添加,所以需要我们自行添加。

最后,再把电池服务的事件派发函数添加到BLE事件派发函数里即可:

static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
{
    ble_conn_params_on_ble_evt(p_ble_evt);
    on_ble_evt(p_ble_evt);
    ble_advertising_on_ble_evt(p_ble_evt);

    ble_bas_on_ble_evt(&m_bas, p_ble_evt);
}

结果验证

  • 手机连接蓝牙,我们可以看到一个Battery Service的服务
  • 这个服务包含read和notify特性
  • 打开调试app的监听功能后,发现电池电量1秒更新一次

总结

通过这个实验,我们学会如何开发一个电池电量的监听服务。

猜你喜欢

转载自blog.csdn.net/SammySum/article/details/103383954