Nordic系列芯片讲解七 (Nordic 52832 RTC 实现万年历功能)

一、方案确定

今天要实现手表的万年历功能。实现万年历功能有三种方式

1.新建一个1秒定时的APP_TIMER。

  • 优点:创建方便。
  • 缺点:实时性太差。

APP_TIMER采用轮询执行而非抢占的方式,假如其它APP_TIMER耗时较长,例如有一个APP_TIMER在采集心率,万年历的APP_TIMER就必须等采集心率完成才能执行。

2.在APP_TIMER的中断中插入计算时间戳的代码

  • 优点:修改代码较少。
  • 缺点:代码耦合性高,易出现未知问题。

我们都知道APP_TIMER的实现就是使用了RTC1,那么我们就可以利用上RTC1的特点,适当修改代码来实现我们的需求,但这样容易造成代码耦合性高,不易维护和管理。

3.用一个新的RTC来实现。

  • 优点:不会影响原来APP_TIMER的功能,模块独立,方便管理。
  • 缺点:需要深入了解芯片的RTC,根据RTC特性来实现自己的功能。

二、实现功能
综上所述,我这里采用了第三种方案来实现。用RTC2来实现。
1.首先来看看RTC的框架图

这里写图片描述

2.时钟源 : LFCLK

这里写图片描述

3.频率计算方式:
这里写图片描述
如实现8HZ的频率,则PRESCALER 寄存器应该设为
32768/8-1 = 4095

4 . 采用RTC中断方式来计时,RTC中断方式有三种
A :TICK 滴答中断,那么在每个时钟滴答(即COUNTER计数一次)都会产生这个事件,COUNTER的技术值就会加1。
B :Overflow 溢出中断,在COUNTER溢出是产生。
C:COMPARE,比较中断,COUNTER计数值与cc[0-3]中的值相等时产生, COMPARE 的一些task, 如clear,stop,start 存在 us 级和 ns 级的延迟,使用 RTC
来计时应该考虑这些可能的延迟。

  1. 综合考虑,我这里用TICK中断来实现。
    TICK时序如下

这里写图片描述

由图可知当PRESCALER 设为1时,则TICK中断频率为f= (32768/(1+1))
我们要实现8Hz,则PRESCALER = 32768/8-1 = 4095; PRESCALER寄存器只有12bit,2^12-1 =4095,所以最大也只有8Hz了。

#include "nrf.h"
#include "nrf_gpio.h"
#include "nrf_drv_rtc.h"
#include "nrf_drv_clock.h"
#include "boards.h"
#include "app_error.h"
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include "nrf_log.h"
#include "app_utc.h"
#include "main.h"

#define  tm_t  struct tm

static struct tm  m_time;
static uint8_t m_time_count_1s =0;
volatile uint32_t m_timestamp=1530517467;

const nrf_drv_rtc_t rtc = NRF_DRV_RTC_INSTANCE(2); /**< Declaring an instance of nrf_drv_rtc for RTC0. */

static bool utc_to_calendar(uint32_t timestamp, tm_t* calendar);

/** @brief: Function for handling the RTC0 interrupts.
 * Triggered on TICK and COMPARE0 match.
 */
static void rtc_handler(nrf_drv_rtc_int_type_t int_type)
{
    if(int_type == NRF_DRV_RTC_INT_COMPARE0)
    {
    }
    else if (int_type == NRF_DRV_RTC_INT_TICK)
    {
        if(m_time_count_1s >=7 )//ÖжÏƵÂÊ125ms£¬ËùÒÔ125*8 =1000s
        {
            m_time_count_1s = 0;
            m_timestamp ++;
            
            utc_to_calendar(m_timestamp, &m_time);
            NRF_LOG_INFO(":%d/%d/%d,  weeday %d",m_time.tm_year, m_time.tm_mon,m_time.tm_mday,  m_time.tm_wday);
            NRF_LOG_INFO("%d-%d-%d", m_time.tm_hour, m_time.tm_min, m_time.tm_sec);
        }
        else
        {
            m_time_count_1s++;
        }
    }
}


/** @brief Function initialization and configuration of RTC driver instance.
 */
void bsp_rtc_config(void)
{
    uint32_t err_code;
        
    //Initialize RTC instance
    nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG;
    config.prescaler = 4095; 
    err_code = nrf_drv_rtc_init(&rtc, &config, rtc_handler);
    APP_ERROR_CHECK(err_code);

    //Enable tick event & interrupt
    nrf_drv_rtc_tick_enable(&rtc, true);
    
    //Power on RTC instance
    nrf_drv_rtc_enable(&rtc);
}


static void utc_to_calendar(uint32_t timestamp, tm_t* calendar)
{
   tm_t *tm_p;
   char *c;
    
   tm_p = localtime((time_t*)&timestamp); 
   memcpy(calendar,  tm_p, sizeof(tm_t));
}

sdk_config.h中要配置使能开关

#ifndef RTC2_ENABLED
#define RTC2_ENABLED 1
#endif

m_timestamp是一个32位的时间戳,最后需要手机发送当前时间戳给设备,然后设备一秒钟产生一个中断,用来计秒数,然后通过time.h标准库函数来转换成实际时间。最后在main函数中调用bsp_rtc_config就可以了。

另外,因为协议栈也是用到LFCLK时钟,所以在ble_stack_init函数中LFCLK已经被使能了。

欢迎关注个人公众号“低功耗蓝牙技术研究及推广”
在这里插入图片描述

  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值