首页 资讯 应用 高压 设计 行业 低压 电路图 关于

嵌入式

旗下栏目: PLC 嵌入式 单片机 DCS

BLE工程—电池电量服务

嵌入式 | 发布时间:2017-11-26 | 人气: | #评论# |本文关键字:BLE,电池
摘要:在理解ADC的基础上,就可以讲讲蓝牙低功耗设备如何添加电池服务(这里的电池指的是:纽扣电池CR2032,3V),让蓝牙主机可以知道蓝牙设备的电池电量。这个功能非常实用,可以设置一个电池低电

在理解ADC的基础上,就可以讲讲蓝牙低功耗设备如何添加电池服务(这里的电池指的是:纽扣电池CR2032, 3V),让蓝牙主机可以知道蓝牙设备的电池电量。这个功能非常实用,可以设置一个电池低电量的临界值,当电池的电量低于这个临界值时,就提醒用户更换电池。为了实现这个功能,需要用到HAL层的halAdc.c与halAdc.h两个文件来配置处理器的ADC模块,然后还需要在此基础上用到电池电量的配置文件:Battservice.c与Battservice.h。

通过CC2540/1的ADC模块来测量外接电池的电量:VADD5/3作为ADC的采样通道,参考电压选择芯片内部1.25V的参考电压,以10位精度采样,有效位为9位,最大的AD值为511,也就是说1.25V对应的AD值为511。对于纽扣电池3V来说,电池的电压在2V~3V之间可以正常给芯片供电,电池电压与电池电量之间的关系为:

2V <==> 0%

3V <==> 100%

因为选择AVDD5/3通道,正常使用的电池电压输入到ADC上实际上为2/3V~3/3V,即0.66V~1V,计算得到AD值为273~409(0.66/1.25*511 ~ 1/1.25*511)。最后可以得到采样到的AD值与电量的关系:

273 <==> 0%

409 <==> 100%

计算公式:Battery Level = (adc - 273) / (409 - 273) * 100

根据上面的公式,就可以计算得到蓝牙设备的电池电量。

检测到电池电量后,需要通过蓝牙上传。这时则需要向GATT增加电池服务,蓝牙设备会发送电池电量的通告给主机,这样的话蓝牙主机端(如手机等)看到蓝牙设备的电池电量。电池电量的通告只有在下面2种情况下才会发送:1、第一次连接时;2、电池电量较少时。可以设置一个电池电量的临界提醒值,当电池电量达到这个临界值时,就会给蓝牙主机发送通告,提醒用户更换蓝牙设备的电池。

下面就正式开始讲讲蓝牙的电池服务。

1、跟ADC相关的几个变量

(1)电池电压3V对应的AD值BATT_ADC_LEVEL_3V=409

#define BATT_ADC_LEVEL_3V           409

(2)电池电压2V对应的AD值BATT_ADC_LEVEL_2V=273

#define BATT_ADC_LEVEL_2V           273

(c)最低电量所对应的AD值battMinLevel=273

static uint16 battMinLevel = BATT_ADC_LEVEL_2V;

(d)最高电量所对应的AD值battMaxLevel=409

static uint16 battMaxLevel = BATT_ADC_LEVEL_3V;

(e)电池电量的临界值(提醒换电池的电量)battCriticalLevel

static uint8 battCriticalLevel;

(f)电池电压的AD值采样通道设置成VDD/3通道battServiceAdcCh

static uint8 battServiceAdcCh = HAL_ADC_CHANNEL_VDD;

2、跟ADC采样相关的几个回调函数

(1)AD测量设置回调函数battServiceSetupCB,在AD采样之前调用。

typedef void (*battServiceSetupCB_t)(void);

static battServiceSetupCB_t battServiceSetupCB = NULL;

(2)AD测量结束回调函数battServiceTeardownCB,在AD测量结束时调用。

typedef void (*battServiceTeardownCB_t)(void);

static battServiceTeardownCB_t battServiceTeardownCB = NULL;

(3)AD测量计算回调函数battServiceCalcCB,在AD测量后调用这个函数用来计算电池电量。

typedef uint8 (*battServiceCalcCB_t)(uint16 adcVal);

static battServiceCalcCB_t battServiceCalcCB = NULL;

3、用户自定义的电池服务应用回调函数battServiceCB,在操作电池服务写属性时调用这个函数。

typedef void (*battServiceCB_t)(uint8 event);

static battServiceCB_t battServiceCB;

4、电池服务的UUID定义

(1)电池服务的UUID

#define BATT_SERVICE_UUID               0x180F

CONST uint8 battServUUID[ATT_BT_UUID_SIZE] =

{

  LO_UINT16(BATT_SERVICE_UUID), HI_UINT16(BATT_SERVICE_UUID)

};

(2)电池电量的UUID

#define BATT_LEVEL_UUID                 0x2A19

CONST uint8 battLevelUUID[ATT_BT_UUID_SIZE] =

{

  LO_UINT16(BATT_LEVEL_UUID), HI_UINT16(BATT_LEVEL_UUID)

};

5、电池电量服务的配置文件(Profiles)相关的变量

(1)电池服务属性的GATT属性类型格式

static CONST gattAttrType_t battService = { ATT_BT_UUID_SIZE, battServUUID };

(2)电池电量特性权限battLevelProps 设置为可读、可通告

static uint8 battLevelProps = GATT_PROP_READ | GATT_PROP_NOTIFY;

(3)电池电量值默认设置成battLevel=100

static uint8 battLevel = 100;

(4)保存电池客户端连接的属性配置数组battLevelClientCharCfg[]

static gattCharCfg_t battLevelClientCharCfg[GATT_MAX_NUM_CONN];

(5)HID报告参考特性描述

static uint8 hidReportRefBattLevel[HID_REPORT_REF_LEN] ={HID_RPT_ID_BATT_LEVEL_IN, HID_REPORT_TYPE_INPUT };


6、电池服务中的几个变量

(1)电池电量值变量地址BATT_PARAM_LEVEL=0

#define BATT_PARAM_LEVEL                0

(2)电池电量临界值变量地址BATT_PARAM_CRITICAL_LEVEL=1

#define BATT_PARAM_CRITICAL_LEVEL       1

(3)电池服务句柄变量地址BATT_PARAM_SERVICE_HANDLE = 2

#define BATT_PARAM_SERVICE_HANDLE       2

(4)电池电量报告地址BATT_PARAM_BATT_LEVEL_IN_REPORT=3

#define BATT_PARAM_BATT_LEVEL_IN_REPORT 3

7、电池电量服务在GATT层上的属性配置数组battAttrTbl[]

static gattAttribute_t battAttrTbl[] ={};

这个属性配置数组共有5个元素。

(1)电池服务声明

{

  { ATT_BT_UUID_SIZE, primaryServiceUUID },/* type */

  GATT_PERMIT_READ,                    /* permissions */

  0,                                       /* handle */

  (uint8 *)&battService                      /* pValue */

},

(2)电池电量声明

{

  { ATT_BT_UUID_SIZE, characterUUID },

  GATT_PERMIT_READ,

  0,

  &battLevelProps

},

(3)电池电量值

{

  { ATT_BT_UUID_SIZE, battLevelUUID },

  GATT_PERMIT_READ,

  0,

  &battLevel

},

(4)电池电量客户端特征配置

{

  { ATT_BT_UUID_SIZE, clientCharCfgUUID },

  GATT_PERMIT_READ | GATT_PERMIT_WRITE,

  0,

  (uint8 *) &battLevelClientCharCfg

},

(5)HID报告参考特征描述

{

  ATT_BT_UUID_SIZE, reportRefUUID },

  GATT_PERMIT_READ,

  0,

  hidReportRefBattLevel

}

8、电池服务属性操作回调函数,有读、写、授权三个回调函数,这是只使用读、写属性两种。

CONST gattServiceCBs_t battCBs =

{

  battReadAttrCB,  // Read callback function pointer

  battWriteAttrCB,  // Write callback function pointer

  NULL           // Authorization callback function pointer

};

 

Batt_AddService() 向蓝牙协议添加电池服务

1、初始化客户端特征配置属性

GATTServApp_InitCharCfg( INVALID_CONNHANDLE, battLevelClientCharCfg );

2、向GATT注册电池服务的属性列表和属性操作回调函数

status = GATTServApp_RegisterService( battAttrTbl,GATT_NUM_ATTRS( battAttrTbl ),&battCBs );

 

Batt_SetParameter() 设置电池服务的变量

参数:

param-变量地址

len-数据的长度

*value-指向要设置的数据

在之前定义过4个变量地址BATT_PARAM_LEVEL、BATT_PARAM_CRITICAL_LEVEL、BATT_PARAM_SERVICE_HANDLE、BATT_PARAM_BATT_LEVEL_IN_REPORT,其中只有BATT_PARAM_CRITICAL_LEVEL这个变量的值是可以设置的。

1、设置电池电量临界值

case BATT_PARAM_CRITICAL_LEVEL:

  battCriticalLevel = *((uint8*)value);

  break;

2、如果当前电池的电量小于这个临界值,则发出一则通告

if ( battLevel < battCriticalLevel )

{

battNotifyLevel();

}

 

Batt_GetParameter() 获取电池服务的变量

参数:

param-参数的地址

*value-用于保存获取到变量的值

在之前定义过4个变量地址BATT_PARAM_LEVEL、BATT_PARAM_CRITICAL_LEVEL、BATT_PARAM_SERVICE_HANDLE、BATT_PARAM_BATT_LEVEL_IN_REPORT。这4个变量都可以获取其值。

1、获取当前电量变量

case BATT_PARAM_LEVEL:

  *((uint8*)value) = battLevel;

  break;

2、获取电池电量临界值变量

case BATT_PARAM_CRITICAL_LEVEL:

  *((uint8*)value) = battCriticalLevel;

  break;

3、获取电池服务句柄变量

case BATT_PARAM_SERVICE_HANDLE:

  *((uint16*)value) = GATT_SERVICE_HANDLE( battAttrTbl );

  break;

4、获取电池电量服务报告

case BATT_PARAM_BATT_LEVEL_IN_REPORT:

  {

    hidRptMap_t *pRpt = (hidRptMap_t *)value;

    pRpt->id = hidReportRefBattLevel[0];

    pRpt->type = hidReportRefBattLevel[1];

pRpt->handle = battAttrTbl[BATT_LEVEL_VALUE_IDX].handle;

    pRpt->cccdHandle=battAttrTbl[BATT_LEVEL_VALUE_CCCD_IDX].handle;

    pRpt->mode = HID_PROTOCOL_MODE_REPORT;

  }

  break;

5、其他非法参数

default:

  ret = INVALIDPARAMETER;

  break;

 

battReadAttrCB() 电池服务读属性操作的回调函数

参数:

connHandle-客户端连接的句柄

*pAttr-要操作的属性

*pValue-保存属性值元素的值

pLen-属性的值元素长度

offset-偏移

maxLen-读取数据值的最大长度

电池服务属性数组battAttrTbl[]共有5种属性,其中电池电量属性和HID报告特征参考属性可以读操作,他们对应的UUID分别为BATT_LEVEL_UUID、GATT_REPORT_REF_UUID。

1、获取属性对应的UUID

uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1] );

2、如果读取电池电量值

(1)读取电量的值

level = battMeasure();

(2)如果电量减少了,则更新当前的电量

battLevel = level;

(3)保存读出的数据与长度

*pLen = 1;

pValue[0] = battLevel;

3、如果读取HID报告特征参考属性

*pLen = HID_REPORT_REF_LEN;

osal_memcpy( pValue, pAttr->pValue, HID_REPORT_REF_LEN );

 

battWriteAttrCB() 电池服务写属性回调函数

参数:

connHandle-客户端连接的句柄

*pAttr-要操作的属性

*pValue-要写入的属性值元素的值

pLen-属性的值元素长度

offset-偏移

电池服务属性数组battAttrTbl[]共有5种属性,其中只有电池电量客户端特征配置属性可以写操作,对应的UUID为GATT_CLIENT_CHAR_CFG_UUID。

1、获取GATT属性对应的UUID

uuid = BUILD_UINT16( pAttr->type.uuid[0], pAttr->type.uuid[1]);

2、如归哦是电池电量客户端特征配置属性所对应的UUID。则处理这个写请求

status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len,offset, GATT_CLIENT_CFG_NOTIFY );

3、如果定义了电池服务的应用回调函数battServiceCB,则执行这个回调函数

if ( battServiceCB )

{

  (*battServiceCB)( (charCfg == GATT_CFG_NO_OPERATION) ?

                   BATT_LEVEL_NOTI_DISABLED :

                   BATT_LEVEL_NOTI_ENABLED);

}

 

Batt_HandleConnStatusCB() 电池服务连接状态改变处理函数

参数:

connHandle-连接的句柄

changeType-改变的状态

当连接断开时,则复位客户端特征配置。

if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED )      ||

 ( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) &&

  ( !linkDB_Up( connHandle ) ) ) )

{

  GATTServApp_InitCharCfg( connHandle, battLevelClientCharCfg );

}


Batt_Register() 注册电池服务的应用回调函数

参数:

pfnServiceCB-注册的函数指针

battServiceCB = pfnServiceCB;

 

Batt_Setup() 设置ADC模块

参数:

adc_ch-AD的采样通道

minVal-电池的最低电量AD值

maxVal-电池最高电量的AD值

sCB-ADC采样前的配置回调函数

tCB-ADC采样结束时的回调函数

cCB-ADC采样结束后的电量值计算的回调函数

1、设置ADC的配置

battServiceAdcCh = adc_ch;

battMinLevel = minVal;

battMaxLevel = maxVal;

2、注册ADC采样前后的需要的回调函数

battServiceSetupCB = sCB;/* 测量设置回调函数 */

battServiceTeardownCB = tCB;/* 测量结束回调函数 */

battServiceCalcCB = cCB;/* 测量后的计算回调函数 */

 

battMeasure() 测量电池电量

1、如果注册了测量设置回调函数,则在AD采样前执行该函数

if (battServiceSetupCB != NULL)

{

  battServiceSetupCB();

}

2、设置ADC的参考电压,并以10位分辨率读取VDD/3通道的AD值

HalAdcSetReference( HAL_ADC_REF_125V );

adc = HalAdcRead( battServiceAdcCh, HAL_ADC_RESOLUTION_10 );

3、AD值读取完后,如果注册了测量结束回电函数,则执行该函数。

if (battServiceTeardownCB != NULL)

{

  battServiceTeardownCB();

}

4、检测读取到的AD值是否有效,无效则设置上下限值

if (adc >= battMaxLevel)

{

  percent = 100;

}

else if (adc <= battMinLevel)

{

  percent = 0;

}

5、开始计算电池电量

(1)如果注册了计算回调函数,则执行这个回调函数来计算电池电量

if (battServiceCalcCB != NULL)

{

  percent = battServiceCalcCB(adc);

}

(2)如果没有注册计算回调函数,则使用默认公式极端电池电量

{

  uint16 range =  battMaxLevel - battMinLevel + 1;

  range >>= 2; 

  percent = (uint8) ((((adc - battMinLevel) * 25) + (range - 1)) / range);

}

这里计算公式跟文章最开始将的公式(adc - 273) / (409 - 273) * 100有一点出入。但实际上差别不大。代码中只不过把计算好的电量值取顶操作,例如电量计算得为21.1%,则取顶为22%。

 

Batt_MeasLevel() 测量电池电量

1、测量电池电量

level = battMeasure();

2、如果电量下降了,则更新电量值,并发送一个通告。

if (level < battLevel)

{

  battLevel = level;

  battNotifyLevel();

}

 

battNotifyLevel() 注册通告发送回调函数

linkDB_PerformFunc( battNotifyCB );

battNotifyCB() 发送通告

参数:

pLinkItem-条目

1、如果连接状态为连接着,则读取客户端的特征属性

value = GATTServApp_ReadCharCfg( pLinkItem->connectionHandle, battLevelClientCharCfg );

2、如果读取到的值为客户端的属性配置为通告,则发送通告

if ( value & GATT_CLIENT_CFG_NOTIFY )

{

  attHandleValueNoti_t noti;

 

  noti.handle = battAttrTbl[BATT_LEVEL_VALUE_IDX].handle;

  noti.len = 1;

  noti.value[0] = battLevel;

  GATT_Notification( pLinkItem->connectionHandle, ¬i, FALSE );

}

 

这里涉及到很多回调函数的,下面讲讲它们的关系如下所示:

BLE工程—电池电量服务


责任编辑:BLE工程
首页 | 资讯 | 应用 | 高压 | 设计 | 行业 | 低压 | 电路图 | 关于

Copyright 2017-2018 电气自动化网 版权所有 辽ICP备17010593号-1

电脑版 | 移动版

Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。