Nordic nRF5 SDK 学习笔记之七, 功耗评估及电源优化

NORDIC 官方评估功耗在线测试

NORDIC Online Power Profiler,https://devzone.nordicsemi.com/power/


NORDIC 关于低功耗的官方博客

https://devzone.nordicsemi.com/tutorials/b/hardware-and-layout/posts/nrf51-current-consumption-guide


功耗优化技巧

1. 使能电源 DC/DC 转换, 可大幅降低功耗; 于 sdk_config.h 中设置;

 

于main.c 中,初始化 softDeivce 协议栈前, 执行 NRF_POWER->DCDCEN = 1;

或者,在 softDeivce 协议栈初始化后, 执行 sd_power_dcdc_mode_set(1);


2. 使用外部 32KHz 晶振; 于 sdk_config.h 中设置;

于  nrf_sdh.c 文件中,修改 nrf_clock_lf_cfg_t 设置; 如下所示:

nrf_clock_lf_cfg_t const clock_lf_cfg =
{
    .source       = NRF_CLOCK_LF_SRC_XTAL,           //脉冲时钟源为外部晶振 32.768KHz
    .rc_ctiv      = NRF_SDH_CLOCK_LF_RC_CTIV,        //校准时间间隔:使用外部晶振源设置为0
    .rc_temp_ctiv = NRF_SDH_CLOCK_LF_RC_TEMP_CTIV,   //振荡器校准频率,使用外部晶振源设置为0
    .accuracy     = NRF_SDH_CLOCK_LF_ACCURACY        
                                            //外部时钟精度设置为 RF_CLOCK_LF_ACCURACY_20_PPM
    };

3. 去除 log 功能; 于 sdk_config.h 中, log 配置均不启用,其值均为 0; 主函数中 log_init() 同样去除;

4. SPI,TWI,UART 外设有较高的功耗,并它们不用时,最好注销复位以降低功耗;

5. 使用定时器而不是软件延迟, 因软件延迟循环将保持CPU的运行能力而消耗额外的能量;

6. 仅对需要保留的内存使用 RAM_RETENTION,以尽可能节省功耗;


7. 蓝牙 BLE 广播对功耗影响;

    7.1 广播间隔越大, 功耗越低;

          (广播间隔改大之后,相应地会影响BLE设备的连接速度) (init.config.ble_adv_fast_interval =APP_ADV_INTERVAL;)

    7.2 广播持续时间越长,功耗越大; (init.config.ble_adv_fast_timeout = APP_ADV_DURATION;)

    7.3 蓝牙发射功率越高,功耗越大;  (init.advdata.p_tx_power_level  = &bt_tx_power_level;)

void advertising_init(void)
{
    uint32_t               		err_code;
    ble_advertising_init_t 		init;
    ble_advdata_manuf_data_t 	adv_manuf_data;
    uint8_array_t            	adv_manuf_data_array;
    uint8_t                  	adv_manuf_data_data[1];
    adv_manuf_data_data[0] 		= 0x33;
    int8_t	bt_tx_power_level	= 8;					
	
    memset(&init, 0, sizeof(init));

    init.advdata.name_type          	=	BLE_ADVDATA_FULL_NAME;
    init.advdata.include_appearance 	= false;
    init.advdata.flags             		= BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;
	init.advdata.p_tx_power_level		= &bt_tx_power_level;
	
    init.srdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
    init.srdata.uuids_complete.p_uuids  = m_adv_uuids;
		
	
    adv_manuf_data_array.p_data 		= adv_manuf_data_data;
    adv_manuf_data_array.size 			= sizeof(adv_manuf_data_data);
    adv_manuf_data.company_identifier 	= 0x9876;
    adv_manuf_data.data 				= adv_manuf_data_array;
    init.advdata.p_manuf_specific_data	= &adv_manuf_data;	
	
    init.config.ble_adv_whitelist_enabled      			= false;
    init.config.ble_adv_directed_high_duty_enabled 	    = false;
    init.config.ble_adv_directed_enabled       			= false;	
    init.config.ble_adv_fast_enabled  					= true;
    init.config.ble_adv_fast_interval 					= APP_ADV_INTERVAL;
    init.config.ble_adv_fast_timeout  					= APP_ADV_DURATION;
    init.evt_handler = on_adv_evt;

    err_code = ble_advertising_init(&m_advertising, &init);
    APP_ERROR_CHECK(err_code);

    ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
}

8. 蓝牙 BLE 联结对功耗影响;

    8.1 联结间隔

蓝牙BLE设备联结后,蓝牙主机会向BLE设备发送连接事件(Connection Events),BLE设备接收到连接事件后,会进行回复,以通知蓝牙主机连接通路正常。而这是BLE设备连接后最耗电的工况,所以增加连接间隔时间会降低BLE设备的功耗,但是需要注意的是,改变连接间隔时间就相应地会改变蓝牙的通讯速度

    8.2 从机延时次数

从机延时(Slave Latency)次数,就是在连接时忽略连接事件的次数。

在每一个连接事件(Connection Event)中,蓝牙主机须先发包,然后蓝牙设备必须回复,一直这样重复下去,不然蓝牙主机会认为蓝牙设备那边不正常。而通过设置从机延时的次数,允许蓝牙设备一定次数内不对蓝牙主机数据进行回复,蓝牙主机即使没有收到蓝牙设备的回复也不会认为蓝牙设备不正常,这样的话,蓝牙设备也就降低了功耗。

void gap_params_init(void)
{
    uint32_t                err_code;
    ble_gap_conn_params_t   gap_conn_params;
    ble_gap_conn_sec_mode_t sec_mode;

    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);

    err_code = sd_ble_gap_device_name_set(&sec_mode,
                                          (const uint8_t *) DEVICE_NAME,
                                          strlen(DEVICE_NAME));
    APP_ERROR_CHECK(err_code);

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

    gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;    // 最小蓝牙联结间隔
    gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;    // 最大蓝牙联结间隔
    gap_conn_params.slave_latency     = SLAVE_LATENCY;        // 从机延时(Slave Latency)次数
    gap_conn_params.conn_sup_timeout  = CONN_SUP_TIMEOUT;

    err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
    APP_ERROR_CHECK(err_code);																																									
}

9. 系统电源有 SYSTEM_ON和SYSTEM_OFF 两种模式;

     SYSTEM_OFF 模式时钟停止,相当于关机,为最低功耗模式,工作电流为300nA (nRF52832)或400nA (nRF52840);

     SYSTEM_ON 为默认的低功耗模式,通常最低功耗为1.9uA (nRF52832)或1.5uA(nRF52840);

10. 设备在 3VDC 而不是 5VDC 运行; 

11. 程序下载器联结到设备上测试功耗,也要导致测量功耗上升;


申明:

本文部分参考大牛文章 ---- ”nRF52 Power优化降低70%以上耗电量“,感谢!

其原文链接为: https://blog.csdn.net/Uda_CADN/article/details/81230370

 

 

  • 6
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,下面是使用Nordic nRF5 SDK创建新的BLE服务的详细示例: 1. 首先,在nRF5 SDK中打开“examples\ble_peripheral\ble_app_template”示例。 2. 在“ble_app”文件夹中,打开“ble_srv_common.h”文件。此文件包含了一些常用的BLE服务定义,你可以通过阅读该文件来了解BLE服务的实现方式。 3. 在“ble_app”文件夹中,打开“ble_srv_common.c”文件。此文件包含了一些常用的BLE服务实现代码,你可以通过阅读该文件来了解BLE服务的实现方式。 4. 在“ble_app”文件夹中,创建一个新的文件夹,命名为“my_service”。 5. 在“my_service”文件夹中,创建一个新的文件,命名为“my_service.h”。在该文件中,你需要定义你的自定义BLE服务的UUID,以及相关的特性和属性等信息。例如: ``` #ifndef MY_SERVICE_H #define MY_SERVICE_H #include "ble.h" #include "ble_srv_common.h" #define BLE_UUID_MY_SERVICE 0x1234 // 自定义服务的UUID // 自定义服务的特性UUID #define BLE_UUID_MY_SERVICE_CHARACTERISTIC 0x5678 // 自定义服务的特性值结构体 typedef struct { uint8_t value; } ble_my_service_characteristic_t; // 自定义服务的事件结构体 typedef struct { ble_my_service_characteristic_t char_value; } ble_my_service_evt_t; // 自定义服务的事件句柄类型 typedef void (*ble_my_service_evt_handler_t) (ble_my_service_evt_t * p_evt); // 自定义服务的初始化函数 uint32_t ble_my_service_init(void); // 自定义服务的事件注册函数 void ble_my_service_evt_handler_register(ble_my_service_evt_handler_t evt_handler); #endif // MY_SERVICE_H ``` 6. 在“my_service”文件夹中,创建一个新的文件,命名为“my_service.c”。在该文件中,你需要实现你的自定义BLE服务的初始化、事件处理等功能。例如: ``` #include "my_service.h" static uint16_t m_service_handle; // 自定义服务的句柄 static ble_gatts_char_handles_t m_char_handles; // 自定义服务的特性句柄 static ble_my_service_evt_handler_t m_evt_handler; // 自定义服务的事件处理函数 // 自定义服务的事件回调函数 static void my_service_evt_handler(ble_evt_t const * p_ble_evt) { switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_CONNECTED: break; case BLE_GAP_EVT_DISCONNECTED: break; case BLE_GATTS_EVT_WRITE: if (p_ble_evt->evt.gatts_evt.params.write.handle == m_char_handles.value_handle) { ble_my_service_evt_t evt; evt.char_value.value = p_ble_evt->evt.gatts_evt.params.write.data[0]; m_evt_handler(&evt); } break; default: break; } } // 自定义服务的事件注册函数 void ble_my_service_evt_handler_register(ble_my_service_evt_handler_t evt_handler) { m_evt_handler = evt_handler; } // 自定义服务的初始化函数 uint32_t ble_my_service_init(void) { uint32_t err_code; ble_uuid_t ble_uuid; ble_uuid128_t base_uuid = {BLE_UUID_MY_SERVICE_BASE}; // 生成自定义服务的UUID err_code = sd_ble_uuid_vs_add(&base_uuid, &ble_uuid.type); VERIFY_SUCCESS(err_code); ble_uuid.uuid = BLE_UUID_MY_SERVICE; // 添加自定义服务 err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &m_service_handle); VERIFY_SUCCESS(err_code); // 添加自定义服务的特性 ble_gatts_char_md_t char_md; memset(&char_md, 0, sizeof(char_md)); char_md.char_props.read = 1; char_md.char_props.write = 1; ble_gatts_attr_md_t attr_md; memset(&attr_md, 0, sizeof(attr_md)); attr_md.read_perm = BLE_GAP_CONN_SEC_MODE_OPEN; attr_md.write_perm = BLE_GAP_CONN_SEC_MODE_OPEN; attr_md.vloc = BLE_GATTS_VLOC_STACK; ble_uuid_t char_uuid; char_uuid.uuid = BLE_UUID_MY_SERVICE_CHARACTERISTIC; char_uuid.type = ble_uuid.type; ble_gatts_attr_t attr; memset(&attr, 0, sizeof(attr)); attr.p_uuid = &char_uuid; attr.p_attr_md = &attr_md; attr.init_len = sizeof(ble_my_service_characteristic_t); attr.max_len = sizeof(ble_my_service_characteristic_t); attr.p_value = NULL; err_code = sd_ble_gatts_characteristic_add(m_service_handle, &char_md, &attr, &m_char_handles); VERIFY_SUCCESS(err_code); // 注册事件回调函数 err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_GENERIC_TAG); VERIFY_SUCCESS(err_code); err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *) DEVICE_NAME, strlen(DEVICE_NAME)); VERIFY_SUCCESS(err_code); err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, m_adv_handle, TX_POWER); VERIFY_SUCCESS(err_code); err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_SCAN_INIT, 0, TX_POWER); VERIFY_SUCCESS(err_code); err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_CONN, 0, TX_POWER); VERIFY_SUCCESS(err_code); err_code = sd_ble_gap_ppcp_set(&ppcp); VERIFY_SUCCESS(err_code); return NRF_SUCCESS; } ``` 7. 在“main.c”文件中,包含“my_service.h”头文件,并在初始化函数中调用“ble_my_service_init()”函数来初始化你的自定义BLE服务。例如: ``` #include "my_service.h" int main(void) { uint32_t err_code; // 初始化BLE协议栈 ble_stack_init(); // 初始化GAP参数 gap_params_init(); // 初始化GATT参数 gatt_init(); // 初始化自定义服务 err_code = ble_my_service_init(); APP_ERROR_CHECK(err_code); // 启动广播 advertising_start(); // 进入主循环 for (;;) { idle_state_handle(); } } ``` 到此为止,我们已经完成了一个简单的自定义BLE服务的创建实例。你可以根据自己的需要修改“my_service.h”和“my_service.c”文件,来实现更加复杂的自定义BLE服务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值