nRF52实践:BLE下获取内部温度

427 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情

本文介绍在 BLE 协议栈下如何获取芯片内部温度。

方法一

SDK有相关例程,在文件examples\peripheral\temperature\main.c。函数如下:

int main(void)
{
    // This function contains workaround for PAN_028 rev2.0A anomalies 28, 29,30 and 31.
    int32_t volatile temp;
​
    nrf_temp_init();
​
    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_DEFAULT_BACKENDS_INIT();
    NRF_LOG_INFO("Temperature example started.");
​
    while (true)
    {
        NRF_TEMP->TASKS_START = 1; /** Start the temperature measurement. */
​
        /* Busy wait while temperature measurement is not finished, you can skip waiting if you enable interrupt for DATARDY event and read the result in the interrupt. */
        /*lint -e{845} // A zero has been given as right argument to operator '|'" */
        while (NRF_TEMP->EVENTS_DATARDY == 0)
        {
            // Do nothing.
        }
        NRF_TEMP->EVENTS_DATARDY = 0;
​
        /**@note Workaround for PAN_028 rev2.0A anomaly 29 - TEMP: Stop task clears the TEMP register. */
        temp = (nrf_temp_read() / 4);
​
        /**@note Workaround for PAN_028 rev2.0A anomaly 30 - TEMP: Temp module analog front end does not power down when DATARDY event occurs. */
        NRF_TEMP->TASKS_STOP = 1; /** Stop the temperature measurement. */
​
        NRF_LOG_INFO("Actual temperature: %d", (int)temp);
        nrf_delay_ms(500);
​
        NRF_LOG_FLUSH();
    }
}

将示例代码稍作整理,编译并烧录到板子后,提示:

app: SOFTDEVICE: INVALID MEMORY ACCESS

后发现这是普通外设示例,无法在BLE协议栈中使用,故舍弃。

方法二

由前面涉及的函数nrf_temp_read搜索SDK,得到相关文件modules\nrfx\drivers\src\nrfx_temp.cmodules\nrfx\drivers\include\nrfx_temp.h

根据头文件函数声明实现如下:

初始化:

    ret_code_t err_code;
    nrfx_temp_config_t config;
    config.interrupt_priority = NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY;
    err_code = nrfx_temp_init(&config, NULL); // 第二参数为数据处理函数指针,如无则为阻塞方式
    MY_APP_ERROR_CHECK(err_code);

读取内部温度:

int app_temp_read(void)
{
    int32_t temp = 0;
    int32_t raw_temperature = 0;
    ret_code_t err_code = 0;
    err_code = nrfx_temp_measure(); // 开始读,阻塞方式需再调用nrfx_temp_result_get
    MY_APP_ERROR_CHECK(err_code);
    raw_temperature = nrfx_temp_result_get();
    temp = nrfx_temp_calculate(raw_temperature); // 转换为实际温度
    NRF_LOG_INFO("Actual temperature: %d %d", temp, raw_temperature);
​
    return (int)temp;
}

烧录到板子后,提示:

app: SOFTDEVICE: INVALID MEMORY ACCESS

搜索网络资料,查SDK在线文档,问题在于 SoftDevice 无法访问一些寄存器。SoftDevice 的接口以sd_开头。于是有了方法三。

方法三

在SDK搜索sd_temp打头字符,发现有函数声明。

相关文件components\softdevice\s132\headers\nrf_soc.h。声明如下:

SVCALL(SD_TEMP_GET, uint32_t, sd_temp_get(int32_t * p_temp));

该函数将阻塞直到读取温度值,耗时约50 us。

新的方法非常简单,无须初始化,读取温度函数如下:

int app_temp_read(void)
{
    int32_t temp = 0;
    int32_t raw_temperature = 0;
    sd_temp_get(&raw_temperature);
    temp = nrfx_temp_calculate(raw_temperature);
    NRF_LOG_INFO("Actual temperature: %d %d", temp, raw_temperature);
    return (int)temp;
}

测试结果:

00> <info> app_timer: RTC: initialized.
00> <info> app: BLE slave example started.
00> <info> app: Fast advertising.
00> <info> app: Actual temperature: 2650 106
00> <info> app: Actual temperature: 2625 105
00> <info> app: Actual temperature: 2625 105

sd_temp_get获取的值需经过转换,转换函数为nrfx_temp_calculate ,其内部实现为(raw_measurement * 100) / 4,精度为 0.25 摄氏度。测试结果的2650表示 26.50 摄氏度。

小结

网上没有现成的例程,本文首先找到SDK温度的示例,再从源码搜索得到相关接口并做实验达到目的。从中也学会了 nRF52 SDK的一些规范,对于获取温度功能,不同的场景使用不同的方法,按需确定适合的即可。如开发BLE程序,涉及外设的接口,最好用sd_xx函数,但不是所有的外设都不能在BLE协议下使用,具体有哪些,需看文档和例程。