联系我们CONTACT US

深圳市卓联微科技有限公司
电话:400-8515398
传真:0755-83047615
深圳市宝安区宝源路互联网产业基地A区五栋四楼3B02/3B06
长沙市高新区岳麓西大道588号芯城科技园2栋1105室
杭州市上城区新风路288号红街天城4幢1107#
Nordic下高精度RTC的设计 此文来源网络 如有侵权请联系删除
Nordic下高精度RTC的设计
nordic芯片内置有RTC定时器功能,但这并不是全部的实时时钟功能,充其量是一个超低功耗的定时器(时钟一般为32768HZ)。但是nordic做的产品往往是和时间相关的(如手环、手表等等),如果不额外增加RTC芯片的情况下,实现实时时钟的功能,nordic芯片能否做到?答案是:能!
我们来假定一些实现的思路:
1. 利用普通定时器设计成1秒定时器,设计高优先级中断,在中断中维护Unix时间戳。
2. 利用Apptimer,创建一个1秒定时器,在回调中维护Unix时间戳。
3. 利用RTC设计成1秒定时器,设计高优先级中断,在中断函数中维护Unix时间戳。
认真从时序上分析,
方案1,不符合低功耗的要求,舍弃。
方案2,受Apptimer定时器任务队列调度的影响,延时因素并不明确,将会导致定时不准。
方案3,看似符合要求,低功耗也符合。但我们再仔细核对一下时序,该定时器将会产生一个中断并且在中断里维护Unix时间戳,假定中断没有收到任何协议栈中断的打断,我们可以通过时差补偿将中断函数里维护时间戳的耗费的时间补偿回来,基本满足比较准确的定时。但如果考虑BLE高速通信下,RTC中断很可能被打断导致精准性引入一些不确定因素。
该如何解决这个问题?
RTC实现高精度的方法核心应该是绕开中断,如果硬件上没法实现,应该通过软件实现,说简单点就是通过查询的方法避开中断对精度的干扰。本文就是通过查询法设计一个高精度的RTC时钟。
rtc_app.c
static uint32_t rtc_unix_value = 0;
//设置UNIX时间戳
void RTC_Set_Unix(uint32_t Unix_value)
{
rtc_unix_value = Unix_value;
}
//获取UNIX时间戳
uint32_t RTC_Get_Unix(uint32_t RTC_count)
{
static uint32_t last_rtc_value = 0xffffffff;
uint32_t curr_timestamp;
uint32_t time_interval;
//关键1
curr_timestamp = RTC_count >> 15;
if(last_rtc_value == 0xffffffff)
{
last_rtc_value = curr_timestamp;
}
//关键2
if(curr_timestamp >= last_rtc_value)
{
time_interval = curr_timestamp - last_rtc_value;
}
//关键3
else
{
time_interval = (0x200-last_rtc_value) + curr_timestamp;
}
last_rtc_value = curr_timestamp;
rtc_unix_value += time_interval;
return rtc_unix_value;
}
下面,我们利用Noinit RAM设计一个实用的RTC系统,好处是系统将不受复位的影响持续计时。
书生:MDK平台下Nordic系列芯片Noinit RAM的设置和应用探讨
该设计通过查询RTC0的计数器,可以在Apptimer里每隔0.5-1秒查询一次Unix时间,由于没有被任何中断打断,理论上,这个RTC的秒偏差只取决于32768HZ低频晶振的精度。并且能省去多余的一个RTC的硬件开销和功耗。
//NoInit RAM
typedef struct
{
uint32_t power_flag;
uint32_t unix_timemap;
} noinit_data_t;
#define __noinit__ __attribute__((at(0x2000FFF0)))
__noinit__ noinit_data_t noinit_data;
int main()
{
uint32_t last_timemap;
//恢复RTC,信息丢失,则从flash恢复 2018年8月-2038年8月,如果没有flash记忆,可以默认一个出厂时间
if((noinit_data.unix_timemap < 1533052800)||(noinit_data.unix_timemap > 2164204800))
{
RTC_Set_Unix(flash_storage_data.unix_timemap);
}
//从Noinit RAM里初始化Unix时间戳
else
{
RTC_Set_Unix(noinit_data.unix_timemap);
}
while(1)
{
//RTC处理
noinit_data.unix_timemap = RTC_Get_Unix((NRF_RTC0->COUNTER)&0x00ffffff);
if(noinit_data.unix_timemap != last_timemap)
{
LOG("unix_timemap=%d
",noinit_data.unix_timemap);
/*
将Unix时间戳转化为当地时间
*/
last_timemap = noinit_data.unix_timemap;
}
nrf_delay_ms(500);
}
}
该方法在几款量产的产品上经过验证,非常稳定实用。该方法同理也兼容任何有RTC定时器的MCU。
- 电容式触摸芯片的应用2023-01-31
- MAX电机驱控门驱芯片2023-08-01
- 展会回顾 | 卓联微在北京国际电机展览的风采2023-07-08
- 展会回顾 | 卓联微在CACLP的风采2023-05-31
- 展会回顾 | 卓联微在2023年深圳国际工业自动化及机器人展的精彩瞬间2023-05-19