MCU上的RTC的相关问题探究---多篇合辑

第一篇

低温下部分产品RTC不工作的问题探析

前言

客户反馈在批量生产阶段,发现部分产品的MCU的RTC在低温(0℃)下工作不正常,但是在常温下又是正常的,且其他正常的MCU的RTC在常温与低温下都是正常的。

问题跟进

通过与客户邮件沟通,了解到客户使用的MCU型号是STM32F030C6T6TR。在产品的主从结构中主要用作电源管理和时钟管理。通过客户的描述,似乎相同型号不同片子都存在较大的差异。

由于时间紧急,在了解到初步信息后拜访客户,针对客户认为有问题的MCU芯片做针对性试验。通过STM32CubMx生成测试工程,分别使用LSI(40K),LSE(32.768K),RTC工作时每秒通过LED1(PB5)取反一次(通过LED1灯是否闪烁来指示RTC是否工作正常),然后分别测量OSC管脚与PA8脚(输出LSI或LSE),并对比ST官方的NUCLEO-F030板,最终测试结果如下:

1、当使用LSI时,无论常温还是低温下都能正常工作。

2、当使用LSE时,常温下能正常工作,但在低温(0度)时,RTC不再工作(LED1停止闪烁),且PA8管脚无输出,但保持为高电平,且此时OSC管脚此时是存在32.768K的波形的。

3、通过修改负载电容C1&C2的电容值从5.1pF修改到6.8pF时,原本低温下不工作的RTC又能恢复正常工作。

4、对比ST官方的NUCLEO-F030板子,在常温与低温下均能正常工作。

从测试结果来看,通过修改负载电容的方式能让原本不能正常工作的RTC恢复正常工作,这个似乎为客户的负载电容不能精准的匹配系统的原因所致。

但客户对于这个做法不接受的,理由是现在设计的负载电容5.1pF是通过测试后的值,精度可以达到6.5ppm,但如果改为6.8pF,那么精度将会变到大约30ppm,这个会影响到MCU的RTC的时间精准度,系统在长时间运行后,时间必然会偏差很大,超出设计合理范围,这个是不允许的。

问题分析

既然客户不接受修改负载电容,那么首先我们重新梳理下客户的晶振设计各种参数是否准确,客户的LSE电路设计如下所示:

 

如上图,图中的MR10 10Mohm这个反馈电阻在实际电路中是没有加的,晶振使用的是TXC的,从晶振厂商提供的数据手册中得到相关参数如下:

 

再者,由于客户代码中使用的LSE drive配置的是最高等级,从下图芯片对应的数据手册中可以找到对应的gm值为25uA/V,此时的驱动电流为1.6uA:

 

前面提到过AN2867这个文档,我们打开这个文档,在3.4节,发现有这个要求:

 

也就是要求gain margin的值要求大于5,这样晶振才能正常起振,那么gain margin又是如何计算的呢?接下来找到gainmargin 的计算公式,如下:

 

其中gm就是图4中从数据手册中提到的跨导值,STM32F030 LSE的不同驱动等级对应着不同的gm值,由于我们的测试代码使用的是CubeMx自动生成的代码,其默认使用的是最高等级,且客户使用的也是最高等级,因此,这个得出的gm值为25 uA/V, gm有了,那么上面公式中的gmcrit又该如何计算,我们接下来找到它的计算公式,如:

 

通过晶振对应参数,我们可以得出:

ESR =70KΩ,C0 =1.0pF, CL =7.0pF, 而F就是LSE的频率,为32.768KHz.

于是:

g_mcrit =4 * 7E4 *POWER(2*PI()*32768,2) * POWER ((1.0E-12 + 7.0E-12),2) =7.6E-07

最终得到:

gain_magin =gm/g_mcrit=2.5E-05/7.6E-07 =32.89

这个值是远大于5,因此,理论上不会存在晶振不起振是的问题,实际上当在低温下,之前在测试中也有发现晶振也是有起振,有波形输出的,只不过PA8脚没有波形输出,那个又是什么问题呢?

最终定位到LSE的驱动等级过高,在AN2867这个文档中,有这样的描述:

 

也就是说,在STM32F0和STM32F3中,当使用最高驱动模式(gm_crit_max=5uA/V, 见Figure9gm_crit_max)时,对应地应该只使用在CL=12.5pF的晶振上,以此避免振荡回路饱和,从而导致启动失败。若此时使用了一个较小的CL(如CL=6pF),那么会导致振荡频率不稳定和工作周期可能被扭曲。

AN2867随后给出了一张表,列出了驱动等级与gm_min、gm_crit_max的关系,如下:

 

如上图,对于STM32F0,当使用最高驱动模式High时,此时的gm_min=25 uA/V,这个与数据手册中是一致的,另外gm_crit_max=5uA/V,正是上面所描述的。

也就是说,在使用最高驱动模式下,此时与之对应的CL应该使用12.5pF,而客户所使用的CL是7pF,这个与手册AN2867的建议内容是不相符的。从图4可以看出,在最高驱动等级模式下,此时驱动电流最大(1.6uA),但这里使用了一个比较小的负载电容(CL=7pF),按AN2867所述,此时有可能导致振荡回路饱和,振荡不稳定,工作周期扭曲。

此时,应该对应地下调这个LSE驱动等级,减小驱动电流,这里有4档(见Figure9):Low,Medium Low,Medium High,High. 目前使用的是High,正是它出了问题,为保守起见,使用Medium High相对合适。

 

如上图,将LSEDRV[1:0]这两个为修改为10即可,将原先低温下RTC有问题的MCU芯片修改后再次放到低温下进行验证,测试结果为正常。由于此问题是部分芯片有可能会出现的问题,客户需要对修改后的芯片进行持续跟踪,至今没有再反馈出现过此问题,由此,此问题基本解决。

总结

AN2867这个文档总结了关于STM32晶振匹配方面的信息。里边有提到,负载电容CL值越大,所需的驱动电流也就越大,但牵引度越小。这也就解释了表1中通过增大C1&C2的电容值,原本出现问题的RTC能恢复正常的现象,这是由于C1&C2的电容值变大将导致负载电容CL变大,进而对应所需的驱动电流也就跟着增加,这反而减少了在高驱动模式情况下振荡回路出现饱和的机会。

出处:https://mcu.eetrend.com/content/2017/100007912.html


 

第二篇

RTC时钟偶发性延时或超时该怎么办?

在非常温的工作环境下,RTC时钟出现偶发性的延时或者超时现象。成熟的RTC电路设计看似简单,但如何保证RTC时钟的精确度?在出现偶发性异常现象时,如何快速定位和解决问题?本文将分享一个案例。

案例情况

工控板使用了NXP的PCF8563 RTC 芯片方案,在研发做环境温度摸底测试的时候, RTC时钟出现偶发性延时或者超前现象,于是研发展开一系列的问题定位。

排查分析

1、工控板使用了NXP的PCF8563 RTC 芯片方案,该方案是外置32.768kHz的石英晶体和电容,该RTC芯片的输出精度取决于其外接的石英晶体输出的时钟频率是否精准。

石英晶体本身输出频率带有一定的误差,常温25℃下,频率的误差为±20ppm,平均误差可达5分钟/年。且随着时间的增加,晶体电路元件的缓慢变化会造成长期性的频率漂移。同时,在外部温度较为极端的时候,时钟震荡回路可能出现异常,影响到RTC的正常计时。

2、工控板RTC芯片供电电池选用了型号为CR2032的锂二氧化锰电池,该电池理论工作温度范围是-30℃~60℃。

和其他锂电池类似,若外部温度较为极端的时候,会改变其内部的化学反应,导致电池寿命的降低或者电压异常的风险,从而影响RTC电路的正常工作。

 

1 PCF8563参考电路图

解决方案

极限温度下长时间的高精度保证,有以下的解决方案:

1、选择带有温度补偿的RTC芯片如EPSON的RX-8025T。这款芯片是内置32.768kHz的晶体,具有高精度的温度补偿功能,输出的波形都是经过温度补偿校准过的,这样可以提高RTC的稳定性和精度。因为内嵌的晶体已经经过高温老化处理,比独立的晶体有更好的稳定性,精度误差在-40°~85°范围内小于±5ppm。

2、选择工业级电池(例如:FANSO ER14505)。理论上在工作温度-40~85°范围内能正常工作。参考电路图如图2所示:

 

2 RX-8025T参考电路图

由图2可知,RTC芯片工作电源由系统VCC_3.3电源和电池电源两部分组成。此电源电路的设计目的是当有外部电源供电时,RTC时钟工作时使用由外部电源经LDO转化而来的VCC_3.3电源,当外部电源停止供电时就自动切换到电池电源供电。这样可以保证RTC芯片一直能够正常地工作,同时可以延长电池的使用时间。

此电路的设计如以下所述:

1、电源切换电路设计

由RX-8025T芯片的数据手册上可知:

    •   其工作电压范围是1.7V到5.5V;

    •   系统电源为3.3V、工业级电池ER14505电压为3.6V;

    •   可以通过二极管的正向导通特性来自动切换系统电源和电池电源的供电状态,使得RTC芯片能够保持正常工作状态。

由于系统电源电压为3.3V,电池电压为3.6V;如果要做到优先使用系统电源,那么就需要系统电源经过二极管后的电压比电池经过二极管后的电压要高,这样才能保证由系统电源优先工作。

可以通过选择两只不同管压降的二极管来实现,二极管SS14的正向导通电压为0.2V左右,1N4148的正向导通电压为0.7V左右。那么可以在系统电源线路上串接一只SS14二极管,而在电池供电线路上串接一只1N4148二极管;这样当外部供电时,系统电源经过SS14后得到的电压值大于电池经过1N4148后的电压值,此时由主电源供电;当外部电源停止供电后,电路自动切换成电池供电状态。

 图3 电源切换电路

2、电压滞后处理

ER14505电池是一种供电电压为3.6V ,容量为2700mAh的锂亚硫酰氯电池;它的自身容量损耗极小,可以忽略不计。以待机电流为20uA计算,电池的供电可以达15年左右。

但是在实际应用中,发现在系统电源长期供电后,突然切换到电池供电时发生电压不足,导致RTC时钟出现异常,其根本原因是电池发生了钝化现象。

当RTC芯片由系统电源供电时,锂电池相当于闲置开路,如果电池闲置的时间过长,那么电池的内部会产生钝化膜,而切换到锂电池供电时,如果滞后的电压低于时钟芯片的工作电压,那么时钟芯片就会完全“失压”,系统时钟就会恢复到初始时间,导致时钟工作异常。为了消除这种现象的影响,我们可以通过在时钟芯片的电源上增加储能电容,以消除这种影响。

 

4 电压滞后处理电路图

3、控制钝化膜生成

电池的钝化膜是由于电池长时间处于闲置开路状态而形成的,那么我们可以使电池一直维持在一个较小的电流放电工作状态,这样可以减缓电池的钝化膜生成的速度。通过选择合适的电阻值,使电池处于放电状态,比如放电电流控制在待机电流20uA左右,这样电池容量足够支撑15年左右,同时不会使钝化膜过厚而出现电压滞后导致RX-8025T完全掉电现象,从而影响RTC时钟的正常工作。

  •   当系统电源供电时,Q1导通,由电池BT1、R1、Q1形成回路,实现电池的放电状态;

  •   当系统电源停止供电时,Q1截至,电池经过D2给RTC芯片U1供电。

经实测时钟芯片及电池内阻自放电的电流为8uA左右,那么我们需要控制的电阻R1的阻值为3.6V/(20-8)uA=300k。

 

5 控制钝化膜电路图

4、PCB设计

在PCB layout的时候需要注意RX-8052T与MCU的I2C走线应该越短越好,并且远离高频、高电流的信号线。同时旁路电容也应该靠近RX-8025T的电源端,并增加地线敷铜的面积,以防止干扰的产生。

来源: ZLG致远电子

 

 


 

第三篇

MCU微课堂 | CKS32F107xx RTC

RTC实时时钟简介

RTC外设(Real Time Clock)实质是一个掉电后还继续运行的定时器。从定时器的角度,相对于通用定时器Timer外设,它十分简单,只有很纯粹的计时和触发中断的功能,但具备掉电还能继续运行的特殊功能,可以应用在特定场景。这里所说的掉电是指主电源VDD断开的情况,因此为了RTC外设掉电继续运行,必须接上锂电池通过VBAT引脚供电。当主电源VDD有效时,由VDD给RTC外设供电;而当VDD掉电后,由VBAT给RTC外设供电。但无论由什么电源供电,RTC中的数据都保存在属于RTC的备份域中,若主电源VDD和VBAT都掉电,那么备份域中保存的所有数据将丢失。

从RTC的定时器特性来说,它是一个32位的计数器,只能向上计数。在相应软件配置下,可提供时钟日历的功能,修改计数器的值可以重新设置系统当前的时间和日期。它使用的时钟源有三种,分别为高速外部时钟的128分频(HSE/128)、低速内部时钟LSI以及低速外部时钟LSE。在主电源VDD掉电的情况下,HSE和LSI这两个时钟来源都会受到影响,没法保证RTC正常工作,因此RTC一般使用低速外部时钟LSE供电。在主电源VDD有效的情况下(待机),RTC还可以配置闹钟事件使CKS32退出待机模式。

RTC框图结果分析

RTC由两个主要部分组成,参见下图。第一部分(背景灰色区域)用来和APB1总线相连,属于备份域,在VDD掉电时可在VBAT的驱动下继续运行。这部分仅包括RTC的分频器,计数器和闹钟控制器。若VDD电源有效,RTC可以触发RTC_Second(秒中断)、RTC_Overflow(溢出事件)和RTC_Alarm(闹钟中断)。此单元还包含一组16位寄存器,可通过APB1总线对其进行读写操作。APB1接口由APB1总线时钟驱动,用来与APB1总线连接。

另一部分(RTC核心)由一组可编程计数器组成,分成两个主要模块。第一个模块是RTC的预分频模块,它可编程产生最长为1秒的RTC时间基准TR_CLK。RTC的预分频模块包含了一个20位的可编程分频器(RTC 预分频器)。如果在RTC_CR寄存器中设置了相应的允许位,则在每个TR_CLK周期中RTC产生一个中断(秒中断)。第二个模块是一个32位的可编程计数器,可被初始化为当前的系统时间,按秒钟计算,可以记录4294967296秒,约合136年左右,作为一般应用已经足够。RTC还有一个闹钟寄存器RTC_ALR,用于产生闹钟。系统时间按TR_CLK周期累加并与存储在RTC_ALR寄存器中的可编程时间相比较,如果RTC_CR控制寄存器中设置了相应允许位,比较匹配时将产生一个闹钟中断。

 

 

图1 简化的RTC框图

由于备份域的存在,使得RTC内核具有了完全独立于APB1接口的特性,也因此对RTC寄存器的访问要遵守一定的规则。系统复位后,默认禁止访问后备寄存器和RTC,防止对后备区域BKP的意外写操作。需要执行以下操作使能才可以对后备寄存器和RTC的访问:(1)设置RCC_APB1ENR寄存器的PWREN和BKPEN位来使能电源和后备接口时钟。(2)设置PWR_CR寄存器的DBP位使能对后备寄存器和RTC的访问。设置后备寄存器为可访问后,在第一次通过APB1接口访问RTC时,因为时钟频率的差异,所以必须等待APB1与RTC外设同步,确保被读取出来的RTC寄存器值是正确的。如果内核要对RTC寄存器进行任何的写操作,在内核发出写指令后,RTC模块在3个RTCCLK时钟之后才开始正式的写RTC寄存器操作。由于RTCCLK的频率比内核主频低得多,所以每次操作后必须要检查RTC关闭操作标志位RTOFF,当这个标志被置1时,写操作才正式完成。当然,以上的操作都具有库函数来快速实现。

RTC控制相关库函数

标准库对RTC控制提供了完善的函数,使用它们可以方便地进行控制,本小节对这些内容进行讲解。RTC相关的库函数在文件cks32f10x_rtc.c和cks32f10x_rtc.h文件中。

1、等待时钟同步和操作完成

RTC区域的时钟比APB时钟慢,访问前需要进行时钟同步,只要调用库函数 RTC_WaitForSynchro即可,而如果修改了RTC的寄存器,又需要调用RTC_WaitForLastTask函数确保数据已写入。这两个库函数主要通过while循环检测RTC控制寄存器的RSF和RTOFF位实现等待功能。

 

/**

* @brief  等待RTC寄存器与APB时钟同步 (RTC_CNT, RTC_ALR and RTC_PRL)

* @note   在APB时钟复位或停止后,在对RTC寄存器的任何操作前,必须调用本函数

* @param  None

* @retval None

*/

 

void RTC_WaitForSynchro(void)

{    

    RTC->CRL &= (uint16_t)~RTC_FLAG_RSF;    // 清除RSF寄存器位     

    while ((RTC->CRL & RTC_FLAG_RSF) == (uint16_t)RESET); //等待RSF寄存器位为SET

}

/**

* @brief  等待上一次对RTC寄存器的操作完成

* @note   修改RTC寄存器后,必须调用本函数

* @param  None

* @retval None

*/

 

void RTC_WaitForLastTask(void)

{    

    while ((RTC->CRL & RTC_FLAG_RTOFF) == (uint16_t)RESET) ; //等待至 RTOFF 寄存器位为SET

}

 

2、使能备份域及RTC访问

默认情况下RTC 所属的备份域禁止访问,可用库函数PWR_BackupAccessCmd使能访问。

/**

* @brief  使能对RTC和Backup寄存器的访问

* @param  ENABLE 或 DISABLE

* @retval None

*/

void PWR_BackupAccessCmd(FunctionalState NewState)

{

  *(__IO uint32_t *) CR_DBP_BB = (uint32_t)NewState;

}

该函数通过PWR_CR寄存器的DBP位使能访问,使能后才可以访问RTC相关的寄存器,然而若希望修改RTC的寄存器,还需要进一步调用RTC_EnterConfigMode使能RTC控制寄存器的CNF位使能寄存器配置。

/**
* @brief  进入RTC配置模式
* @param  None
* @retval None
*/
 
void RTC_EnterConfigMode(void)
{     
    RTC->CRL |= RTC_CRL_CNF; //设置CNF位进入配置模式
}

3、设置RTC时钟分频

选择RTC使用的时钟后,可以使用库函数RTC_SetPrescaler进行分频,把函数参数PrescalerValue写入到RTC的PRLH和PRLL寄存器,一般会把RTC时钟分频得到1Hz时钟。

/**
* @brief  设置RTC分频配置
* @param  PrescalerValue:RTC分频值
* @retval None
*/
void RTC_SetPrescaler(uint32_t PrescalerValue)
{   
    RTC_EnterConfigMode();   
    RTC->PRLH = (PrescalerValue & PRLH_MSB_MASK) >> 16;  //设置RTC分频值的高八位   
    RTC->PRLL = (PrescalerValue & RTC_LSB_MASK);         //设置RTC分频值的低八位   
    RTC_ExitConfigMode();
}

4、设置RTC计数器

RTC外设中最重要的就是计数器以及闹钟寄存器了,它们可以使用RTC_SetCounter、RTC_GetCounter以及RTC_SetAlarm库函数操作。利用RTC_SetCounter可以向RTC的计数器写入新数值,通常这些数值被设置为时间戳以更新时间。RTC_GetCounter函数则用于在RTC正常运行时获取当前计数器的值以获取当前时间。RTC_SetAlarm函数用于配置闹钟时间,当计数器的值与闹钟寄存器的值相等时,可产生闹钟事件或中断,该事件可以把睡眠、停止和待机模式的芯片唤醒。

/**
* @brief  设置RTC计数器的值
* @param  CounterValue:要设置的RTC计数值
* @retval None
*/
void RTC_SetCounter(uint32_t CounterValue)
{    
    RTC_EnterConfigMode();    
    RTC->CNTH = CounterValue >> 16;       //设置RTC计数值的高八位    
    RTC->CNTL = (CounterValue & RTC_LSB_MASK); //设置RTC计数值的低八位    
    RTC_ExitConfigMode();
}
 
/**
* @brief  获取RTC计数器的值
* @param  None
* @retval 返回RTC计数器的值
*/
 
uint32_t RTC_GetCounter(void)
{    
    uint16_t tmp = 0;    
    tmp = RTC->CNTL;    
    return (((uint32_t)RTC->CNTH << 16 ) | tmp) ;
}
/**
* @brief  设置RTC闹钟的值
* @param  AlarmValue:要设置的RTC闹钟值
* @retval None
*/
 
void RTC_SetAlarm(uint32_t AlarmValue)
{      
    RTC_EnterConfigMode();
    RTC->ALRH = AlarmValue >> 16;        //设置RTC闹钟的高八位
    RTC->ALRL = (AlarmValue & RTC_LSB_MASK); //设置RTC闹钟的低八位    
    RTC_ExitConfigMode();
}

UNIX时间戳

在使用RTC外设前,还需要引入UNIX时间戳的概念。如果从现在起,把计数器RTC_CNT的计数值置0,然后每秒加1,RTC_CNT什么时候会溢出呢?由于RTC_CNT是32位寄存器,可存储的最大值为(232-1),这样计时的话,在232秒后溢出,N=232/365/24/60/60≈136年,即它将在今后136年时溢出。

假如某个时刻读取到计数器的数值为X=60*60*24*2,即两天时间的秒数,而假设又知道计数器是在2011年1月1日的0时0分0秒置0的,那么就可以根据计数器的这个相对时间数值,计算得这个X时刻是2011年1月3日的0时0分0秒了。而计数器则会在(2011+136)年左右溢出,也就是说到了(2011+136)年时,如果我们还在使用这个计数器提供时间的话就会出现问题。在这个例子中,定时器被置0的这个时间被称为计时元年,相对计时元年经过的秒数称为时间戳,也就是计数器中的值。 

大多数操作系统都是利用时间戳和计时元年来计算当前时间的,而这个时间戳和计时元年大家都取了同一个标准——UNIX时间戳和UNIX计时元年。UNIX计时元年被设置为格林威治时间1970年1月1日0时0分0秒,大概是为了纪念UNIX的诞生的时代吧,而UNIX时间戳即为当前时间相对于UNIX计时元年经过的秒数。因为UNIX时间戳主要用来表示当前时间或者和电脑有关的日志时间(如文件创立时间,log发生时间等),考虑到所有电脑文件不可能在1970年前创立,所以用UNIX时间戳很少用来表示1970前的时间。

在这个计时系统中,使用的是有符号的32位整型变量来保存UNIX时间戳的,即实际可用计数位数比我们上面例子中的少了一位,少了这一位,UNIX 计时元年也相对提前了一半,这个计时方法在2038年1月19日03时14分07秒将会发生溢出,这个时间离我们并不远,在设计预期寿命较长的设备需要注意。

小结

本章内容介绍了CKS32F107系列RTC实时时钟外设的硬件结构和工作原理,并结合相关寄存器讲解了与RTC控制相关的外设库函数使用方法,最后介绍了UNIX时间戳的概念。从上述内容可知,RTC外设是个连续计数的计数器,利用它提供的时间戳,可通过程序转换输出实时时钟和日历的功能,修改计数器的值则可以重新设置系统当前的时间和日期。由于它的时钟配置系统(RCC_BDCR寄存器)是在备份域,在系统复位或从待机模式唤醒后RTC的设置维持不变,而且使用备份域电源可以让RTC计时器在主电源关掉的情况下仍然运行,保证时间的正确。有了这些基础,下一节将详细介绍如何利用RTC的计时功能实现一个简单的万年历效果。

来源:中科芯MCU

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

 


 

第四篇

干货:如何解决RTC精度、功耗问题?

RTC为整个电子系统提供时间基准,主控设计均离不开RTC电路设计,在应用RTC时,会出现精度或功耗大的现象,如何解决RTC精度及功耗问题?本文将为您介绍时钟芯片应用问题及解决方法。

一、什么是RTC

实时时钟(Real_Time Clock)简称为RTC,主要为各种电子系统提供时间基准。通常把集成于芯片内部的RTC称为片内RTC,在芯片外扩展的RTC称为外部RTC,PCF8563是一款低功耗的CMOS实时时钟/日历外部芯片,支持可编程时钟输出、中断输出、低压检测等,与处理器通过I2C串行总线进行通信,最大总线速率可达400kHz。

二、RTC精度设计

RTC的主要职责就是提供准确的时间基准,计时不准的RTC毫无价值可言。目前部分MCU在片内已集成RTC,实际测试中在电池供电6小时环境下片内RTC的偏差在1-2分钟。因此,若对实时时钟有较高的要求则需优先考虑外扩RTC,同时要求时钟精度更高的RTC,比如PCF8563,表1所示是不同RTC的时钟精度对比。

1 常见RTC时钟精度对比

 

1、电路设计

RTC设计电路简约而不简单,时钟芯片的选择、晶振的选择、电路设计、器件放置、阻抗控制、PCB走线规范均会影响RTC的时间基准的稳定性,图1为RTC芯片PCF8563电路设计。

 

1 PCF8563参考电路图

2、晶体对地电容容值选择

负载电容:

Cload= [ (Ca*Cb)/(Ca+Cb) ]+Cstray

其中Ca、Cb为接在晶体两引脚到地的电容,Cstray为晶体引脚至处理器晶体管脚的走线电容(即杂散电容总和),一般Cstray的典型值取4~6pF之间;

如要满足晶体12.5pF负载电容的要求:

Cload= [ (15*15)/(15+15) ]+5=12.5pF

 

3、PCB布线

由于RTC的晶振输入电路具有很高的输入阻抗,因此它与晶振的连线犹如一个天线,很容易耦合系统其余电路的高频干扰。而干扰信号被耦合到晶振引脚导致时钟数的增加或者减少,考虑到线路板上大多数信号的频率高于32.768kHz,所以通常会发生额外的时钟脉冲计数,因此晶振应尽可能靠近OSC1和OSC2引脚放置,同时晶振、OSC1和OSC2的引脚最好布成地平面,具体PCB布线如图3所示。

 

3 PCB布线

 

 

4、电路相关说明

如图1所示,R56、R57为I2C总线上拉电阻,PCF8563中断输出及时钟输出均为开漏输出,所以也需要外接上拉电阻,如图1中的的R58、R59,若不使用这两个信号,对应的上拉电阻可以不用。

对于PCF8563芯片,需外接时钟晶振32.768kHz(如图1的X1),推荐使用±20ppm或更稳定的晶振。PCF8563典型应用电路推荐使用15pF的晶振匹配电容,实际应用时可以作相应的调整,以使RTC获得更高精度的时钟源。一般晶振匹配电容在15pF~21pF之间调整(相对于±20ppm精度的32.768kHz晶振),15pF电容时时钟频率略偏高,21pF电容时时钟频率略偏低。

5、精度调整方法

  • 设置PCF8563时钟输出有效(CLKOUT),输出频率为32.768kHz;
  • 使用高精度频率计测量CLKOUT输出的频率;
  • 根据测出的频率,对CB1、CB2、CB3作短接或断开调整,频率比32.768kHz偏高时,加大电容值,频率比32.768kHz偏低时,减小电容值。

说明:图1中的C41、C42、C43的值在1pF~3pF之间,根据实际情况确定组合方式,以便于快速调整,推荐使用(3pF、3pF、3pF)、(1pF、2pF、3pF)、(2pF、3pF、4pF)。

三、RTC低功耗设计

很多RTC设计成可以只依靠一块电池供电就能工作,如果主电源关闭,仅依靠一小块锂电池就能够驱动振荡器和整个时钟电路,如何降低RTC电路工作时功率消耗?

通过应用几种不同的方法可以降低RTC功耗:

  • 选择低功耗的RTC,比如PCF8563,表2所示是不同RTC的功率消耗对比:

2 常见RTC功率消耗对比

 

 

  • RTC电源切换电路中,选择漏电流小的二极管比如BAV74,当系统电源电压3.3V断开时,BT1锂电池CR2032(3V/225mAh)通过二极管向RTC供电;

 

4 RTC电源切换电路

  • 尽量少而且合理地访问RTC,减少I2C总线的动态电流;
  • 将I2C总线的上拉电阻设计得尽量大些,比如10k;
  • 在应用时,通过设置寄存器关闭RTC的时钟CLKOUT输出。

本文转自: ZLG立功科技,转载此文目的在于传递更多信息,版权归原作者所有。

 


 

第五篇

RTC起振电容的容值计算

问腾讯元宝:

请问在MCU单片机的RTC电路中,如何计算晶振的起振电容容值应为多少,这里假设电路板的杂散电容为5pf。使用无源晶振,其数据手册中告知,频率32.768KHz,常温频差±20ppm,负载电容12.5pF,等效串联电阻(ESR)70kΩ,工作温度-40℃~+85℃。

 

答:

在MCU单片机的RTC电路中,计算晶振起振电容容值的关键在于确保晶振的总负载电容等于其数据手册中指定的负载电容(C_L)。以下是详细的计算步骤:

1. 明确参数​​

  • 晶振频率 f = 32.768 kHz(低频音叉型晶体)。
  • 晶振负载电容 CL = 12.5 pF(数据手册指定)。
  • 电路板杂散电容Cstray = 5 pF(需并联计入总负载)。
  • 外部电容对称设计(C1 = C2 = Cext,常见工程实践)。

2. 总负载电容的组成​​

晶振的总负载电容 CL 由外部电容和杂散电容共同决定。由于外部电容Cext 分别接在晶振的两个引脚(OSC_IN和OSC_OUT)到地,且杂散电容 Cstray 等效并联在晶振两端,因此总负载电容的计算公式为:

CL  ​= Cext /2 +Cstray​

其中,Cext /2是两个相同外部电容Cext 的串联等效电容(因两个电容分别接在晶振两引脚到地,形成串联关系),Cstray为杂散电容的并联贡献。

3. 计算外部电容 Cext

 

 

4. 实际应用注意事项​

  • 电容选型​:选择标准电容值(如15pF),若杂散电容存在误差(如4~6pF),可微调 Cext(如12~18pF)以确保频率精度。
  • ESR验证​:晶振的等效串联电阻(ESR=70kΩ)需小于MCU的起振允许电阻(通常由MCU数据手册规定),否则可能无法正常起振。
  • 温度补偿​:若系统需宽温工作(-40℃~+85℃),需选择温度稳定性好的晶振(如±20ppm已满足常规RTC需求)。

结论:

在给定条件下,晶振的起振电容(两个对称外部电容)容值应约为 ​15pF​(每个电容)。

答案:起振电容的容值应为15pF(每个电容,两个对称电容并联计算)。

 


 

第六篇

以1945年1月1日为计时元年的实现

在STM32的RTC中实现自定义计时元年(1945年1月1日代替UNIX标准的1970年),需要​计算时间偏移量并封装时间转换函数​。以下是具体步骤和代码实现:


1. ​计算时间偏移量

首先计算1945年1月1日到1970年1月1日的秒数差:

// 宏定义偏移量(单位:秒)
#define EPOCH_OFFSET 788918400ULL  // 1945-01-01 00:00:00 → 1970-01-01 00:00:00的秒数

计算逻辑​:

  • 1945 → 1970 共25年
  • 包含6个闰年(1948、1952、1956、1960、1964、1968)
  • 总天数​ = 25 * 365 + 6 = 9131
  • 总秒数​ = 9131 * 86400 = 788,918,400

2. ​时间转换函数封装

封装自定义的时间转换函数,实现以下操作:

a. ​设置RTC时间(以1945为起点)

void Set_1945Epoch_Time(uint32_t sec_since_1945) {
    // 转换为UNIX时间戳(1970起点)
    uint32_t unix_timestamp = sec_since_1945 + EPOCH_OFFSET;
 
    // 写入STM32 RTC计数器
    HAL_RTCEx_SetTime(&hrtc, &(RTC_TimeTypeDef){0}, RTC_FORMAT_BIN);
    HAL_RTCEx_SetSecond(&hrtc, unix_timestamp, RTC_FORMAT_BIN);
}

b. ​读取RTC时间(转回1945起点)

uint32_t Get_1945Epoch_Time(void) {
    RTC_TimeTypeDef sTime;
    HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
 
    // 读取UNIX时间戳并减去偏移量
    return (uint32_t)(sTime.Seconds - EPOCH_OFFSET);
}

c. ​日期结构体转换(可选)

typedef struct {
    uint8_t year;   // 从1945开始的年数
    uint8_t month;  // 1-12
    uint8_t day;    // 1-31
    uint8_t hour;
    uint8_t min;
    uint8_t sec;
} CustomTime_1945;
 
CustomTime_1945 SecondsTo_1945Date(uint32_t sec_since_1945) {
    // 在此实现秒数→日期结构体的转换算法
    // (需自行编写闰年判断和日历时序计算)
}

3. ​应用层调用示例

// 设置RTC起始时间:1945年1月1日 00:00:00
Set_1945Epoch_Time(0);
 
// 设置特定时间:1949年10月1日 10:00:00
uint32_t sec_1949 = (4 * 365 + 1) * 86400  // 1945~1949(含1948闰年)
                 + (273 * 86400)           // 1月1日→10月1日的天数
                 + 10 * 3600;              // 10小时
Set_1945Epoch_Time(sec_1949);
 
// 读取当前时间(基于1945)
uint32_t now = Get_1945Epoch_Time();

关键注意事项

  1. 32位计数限制​:
  2. 时区处理​:
  3. 如需要时区支持,在偏移量上追加:
  4. 闰年算法​:
  5. SecondsTo_1945Date()中需实现精确的闰年计算:
    • STM32 RTC计数器是32位(最大计数 ≈ ​136​)
    • 时间范围​:1945年 → 1945+136=2081年
      (若需超过2081年,需扩展64位软件计时)
4.  #define TIMEZONE_OFFSET (8 * 3600)  // 东八区示例
uint32_t unix_timestamp = sec_since_1945 + EPOCH_OFFSET - TIMEZONE_OFFSET;
7.  int is_leap_year(int year) {
8.      int y = year + 1945;
9.      return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0);
}

10.​RTC配置步骤​:

    • 在CubeMX中启用RTC时钟源(LSE/LSI)
    • 开启RTC日历功能(即使内部使用UNIX时间戳)
    • 调用封装函数而非直接使用HAL_RTC_GetTime()

✅ 此方案无需修改RTC硬件层,仅通过软件偏移量实现纪元切换,兼容所有STM32系列。

 

posted @ 2025-06-24 18:33  xyzjacky  阅读(235)  评论(0)    收藏  举报