历史上的今天
返回首页

历史上的今天

今天是:2024年11月05日(星期二)

正在发生

2021年11月05日 | STM32F103ZET6 — RTC

2021-11-05 来源:eefocus

简介

"RTC"是Real Time Clock 的简称,意为实时时钟。即,提供类似于 PC 上的时间记录信息的功能。既然是实时时钟,则至少应该有秒、分、时等信息。也可以直观的把他理解成为一个计数器,一直累加。但又不同于 CPU 上电后的那些计数器,对于 RTC ,需要支持的是掉电后的继续计数(存在备用电源)。所谓掉电,是指电源Vpp断开的情况下,为了RTC外设掉电可以继续运行,必须给STM32芯片通过VBAT引脚街上锂电池.当主电源VDD有效时,由VDD给RTC外设供电.当VDD掉电后,由VBAT给RTC外设供电.无论由什么电源供电,RTC中的数据始终都保存在属于RTC的备份域中,如果主电源和VBA都掉电,那么备份域中保存的所有数据都将丢失.(备份域除了RTC模块的寄存器,还有42个16位的寄存器可以在VDD掉电的情况下保存用户程序的数序,系统复位或电源复位时,这些数据也不会被复位). 


STM32 的 RTC 操作,主要功能由三部分组成:


电源配置


后备(BKP配置)


RTC 配置


时钟

RTC 时钟可以选择三种时钟源的输入:


1. 高速外部时钟 HSE 的 128 分频


2. 低速外部时钟 LSE


3. 低速内部时钟 LSI

针对单板上,我们选择 LSE 32.768kHz 的 LSE 作为 RTC 的时钟输入。

当主电源掉电的时候,由Vbat进行供电:

工作原理

灰色部分为备用区域,系统掉电后,由后备电源持续供电,寄存器相关的值会持续存在并持续工作。同时,此部分的复位也单独存在 BKP 复位部分,即通过对 BKP 的复位来进行此部分的复位。


可以看到, RTC CLK 供给 RTC 模块时,首先通过一个分频器,进行分频,经过分频器后的时钟 TR_CLK 用于后续的计数器使用。RTC 支持闹钟功能,即,在 RTC_ALR 寄存器设置一个期望的值,RTC_CNT 在 TR_CLK 下进行计数,当计数器的值到达了 RTC_ALR ,则产生闹钟事件。


注:普通情况下,通过计算,使得 RTC 计数器能以 1s 一次的方式进行计数,这样能够满足基本使用。


除了RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器外,所有的系统寄存器都由系统复位或电源复位进行异步复位。

RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器仅能通过备份域复位信号复位。


中断

RTC 支持 3 个中断:


1. 秒中断:即经过分频器的时钟 TR_CLK 每次计数产生的中断


2. 溢出中断 : 计数器是 32bits 的,当计数器达到上限的时候产生的中断


3. 闹钟中断:当计数器的值达到配置的期望值 (RTC_ALR) 的时候产生闹钟


这三个中断均需要配置对应的中断使能位,进行使能后,方可使用。

访问限制

由于 RTC 处于 STM32 的备用区域(BKP),同时 RTC  的核心独立于 APB1,同时又是使用了 APB1 进行访问,此处,在访问 RTC 相关寄存器的时候,硬件有跨时钟域的同步操作,需要有几点注意的地方:


A. 访问 RTC 相关寄存器之前,首先需要开启 BKP 和 PWR 相关的时钟


B. 设置 PWR 的 DBP 位,使能对后备寄存器和RTC的访问


C. 若在读取 RTC 寄存器时,RTC 的 APB1 接口曾经处于禁止状态,则软件首先必须等待 RTC_CRL 寄存器中的 RSF 位(寄存器同步标志)被硬件置’1’。


D. 对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF状态位是’1’时,才可以写入RTC寄存器。


C. 使能 RTC 进入配置模式,在配置模式下进行寄存器更新,设置完后,退出配置模式


针对最后一项D,访问过程如下:


    D1. 查询RTOFF位,直到RTOFF的值变为’1’


    D2. 置 CNF 值为1,进入配置模式


    D3. 对一个或多个RTC寄存器进行写操作


    D4. 清除CNF标志位,退出配置模式


    D5. 查询RTOFF,直至RTOFF位变为’1’以确认写操作已经完成。


配置过程

1. 开启 PWR,BKP 区域的时钟


2. 写 PWR 的 DBP 位,使能后备区域的访问权限


3. Deinit RTC 模块


4. 配置 LSE 的时钟开启,并等待 LSE 稳定(32.768kHz)


5. 选择 RTC 的时钟为 LSE(注意,此部分不在 RTC 寄存器,故,无需满足”访问限制”章节的限制)


6. 使能 RTC


7. 由于是上电配置,故 APB1 之前出于禁止状态,故需要等待 RSF 置位


8. 等待 RTOFF 置位,即等待 RTC 出于 no busy


9. 设置分频系数为 32768 - 1,并等待 RTOFF 置位(等待写完成)


10. 配置使能秒中断,并等待 RTOFF 置位(等待写完成)


11. 初始化当前时间(这个可以随意设置)


12. 配置 NVIC


注意:为了使上电后,RTC 只被配置一次,这里使用了一个备用寄存器来作为 RTC 是否被配置过的标志(如果使用软件的一个变量,掉电后,变量的值会丢掉)。每次上电的时候进行 check, 如果配置过 RTC,则不再配置。


这里测试的时候,使用一个全局变量进行读数据,每次在秒中断中,将数据读出并解析。(因为寄存器中的计数器的单位是s秒)


当然,在中断处理程序 RTC_IRQHandler ,对 clear 中断 pending 的标志,也是需要等待写完成的 (RTOFF 置位)


代码如下:


#define LSE_CLK_32768KHZ     32768

#define RTC_CFG_DONE        0xAAAA

#define LEAP_YEAR_SEC       31622400

#define NORMAL_YEAR_SEC     31536000

#define A_DAY_SEC           86400

#define A_HOUR_SEC          3600

#define A_MIN_SEC           60

 

#define MAX_DAY             10

#define ONE_DAY_HOURS       24

#define ONE_HOUR_MIN        60

#define ONE_MIN_SEC         60

#define MAX_SEC             (MAX_DAY * ONE_DAY_HOURS * ONE_HOUR_MIN * ONE_MIN_SEC)

 

typedef struct {

    uint32_t day;

    uint32_t hour;

    uint32_t min;

    uint32_t sec;

} SK_TIME_t;

 

SK_TIME_t g_stCurrentTime;

 

static void _setCurrentTime(SK_TIME_t *cur_time)

{

    // Test RTC At 2018.7.13 -- 00:26:00

    RTC_SetCounter(0x00);

    RTC_WaitForLastTask();

}

 

void SK_getCurrentTime(SK_TIME_t *cur_time)

{

    uint32_t secCount = RTC_GetCounter();

    uint32_t sec = secCount % A_DAY_SEC;

 

    cur_time->day   = secCount / A_DAY_SEC ;

    cur_time->hour  = sec / 3600;

    cur_time->min   = (sec % 3600) / 60;

    cur_time->sec   = (sec % 3600) % 60;

}

 

static uint8_t SK_RTCIsConfiged(void)

{

    return ((BKP_ReadBackupRegister(BKP_DR1) == RTC_CFG_DONE) ? 1 : 0);

}

 

static void SK_RTCNVICConfig(void)

{

    NVIC_InitTypeDef NVIC_InitStructure;

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 

    NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

}

 

static void SK_RTC_Configuration(void)

{

    // Step 1 : Open Power & Backup zone Clock

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

 

    // Step 2 : Set Power register to allow to access backup domain

    PWR_BackupAccessCmd(ENABLE);

 

    // Step 3 : Rest BackUp domain

    BKP_DeInit();

 

    // Step 4 : Enable LSE Clock and wait for ready

    RCC_LSEConfig(RCC_LSE_ON);

    while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);

 

    // Step 5 : Configure the LSE as RTC Clock input

    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);

 

    // Step 6 : Enable RTC Clock

    RCC_RTCCLKCmd(ENABLE);

 

    // Step 7 : Because APB1 was reset when power on, follow datasheet, must wait RSF

    RTC_WaitForSynchro();

 

    // Step 8 : Wait until last write was finished

    RTC_WaitForLastTask();

 

    // Step 9 : Set prescaler as 32767

    // RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1)

    RTC_SetPrescaler(LSE_CLK_32768KHZ - 1);

    RTC_WaitForLastTask();

 

    // Step 10 : Enable second interrupt

    RTC_ITConfig(RTC_IT_SEC, ENABLE);

    RTC_WaitForLastTask();

}

 

 

void SK_RTCInit(void)

{

    // First Configure RTC

    if (!SK_RTCIsConfiged())

    {

        SK_RTC_Configuration();

        _setCurrentTime(&stTestRTCTime);

        BKP_WriteBackupRegister(BKP_DR1, RTC_CFG_DONE);

    }

    else

    {

        RTC_WaitForSynchro();

        RTC_ITConfig(RTC_IT_SEC, ENABLE);

        RTC_WaitForLastTask();

    }

    SK_RTCNVICConfig();

    SK_getCurrentTime(&g_stCurrentTime);

}

 

void SK_RTCDeInit(void)

{

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

    PWR_BackupAccessCmd(ENABLE);

    BKP_DeInit();

}

 

void RTC_IRQHandler(void)

{

    if (RTC_GetITStatus(RTC_IT_SEC) != RESET)

    {

        if (RTC_GetCounter() >= MAX_SEC)

        {

            RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

            PWR_BackupAccessCmd(ENABLE);

            RTC_WaitForLastTask();

            RTC_SetCounter(0x0);

            RTC_WaitForLastTask();

        }

        SK_getCurrentTime(&g_stCurrentTime);

    }

    if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)

    {

        RTC_ClearITPendingBit(RTC_IT_ALR);

    }

    RTC_ClearITPendingBit(RTC_IT_SEC | RTC_IT_OW);

    RTC_WaitForLastTask();

}

推荐阅读

史海拾趣

北京人民电器厂公司的发展小趣事

随着北京人民电器产品的不断优化和升级,其生产的GM系列直流断路器在发电、输变电系统中得到了广泛应用。众多电力企业和项目都选择了北京人民电器的产品,这不仅是对其产品质量和技术水平的认可,也进一步推动了公司在电力行业的深入发展。

Dailywell Electronics Co Ltd公司的发展小趣事

随着业务的不断扩展和市场需求的增加,德利威电子在1998年实现了全系列防水开关的生产,并取得了RS33A开关专利。同年,公司还扩大了经营规模,搬入了自购的厂办大楼,并增加了资本额至一千五百万元。这些举措不仅提升了公司的生产能力和产品品质,也为公司未来的发展奠定了坚实的基础。

FLIR公司的发展小趣事

近年来,随着智能化和便携化趋势的兴起,FLIR积极响应市场需求,推出了一系列智能化、便携化的红外热像仪产品。例如,FLIR的I系列和T系列产品就以其小巧轻便、操作简便的特点受到了广大用户的青睐。这些产品不仅具备高性能的红外成像能力,还集成了多种智能化功能,如自动测温、图像分析、报告生成等,极大地提升了用户的使用体验和工作效率。此外,FLIR还推出了适用于智能手机的红外热像仪配件,进一步拓宽了产品的应用领域和市场空间。

启攀微(CHIPHOM)公司的发展小趣事

随着LED背光驱动芯片的成功推出,启攀微电子(CHIPHOM)逐渐在市场上崭露头角。然而,公司并没有满足于现状,而是继续加大研发投入,拓展产品线。在一次国际电子展上,公司展示了音频功率放大芯片和电阻式触摸屏控制芯片,引起了众多客户的关注。通过不懈的市场推广和技术支持,启攀微电子(CHIPHOM)成功打开了国内外市场的大门,实现了销售收入的快速增长。

Apx-Crystal公司的发展小趣事

Apx-Crystal公司起初是一家专注于研发新型晶体振荡器的小型科技公司。在创始人的领导下,团队通过不懈的努力,成功研发出了一款具有高稳定性和长寿命的晶体振荡器,这一技术突破在行业内引起了广泛关注。随着产品性能的不断提升和成本的有效控制,Apx-Crystal开始赢得越来越多客户的青睐,市场份额逐年攀升。公司逐渐扩大生产规模,并在多个国家和地区设立了销售和服务网络,实现了从初创企业到国际知名电子元件供应商的华丽转身。

驰兴电感(Coilank)公司的发展小趣事

驰兴电感自成立之初,就深知技术创新对于企业发展的重要性。公司投入大量资源进行研发,成功推出了一系列全自动、小型化的SMD绕线电感产品。这些产品不仅具有更高的性能和稳定性,而且满足了市场对小型化、轻量化的需求,迅速在市场上获得了广泛的认可。驰兴电感凭借技术创新的优势,逐渐在电子行业中崭露头角。

问答坊 | AI 解惑

游逛车展心得

2008北京国际汽车展,这个世界级的汽车盛宴上,各种新车型、新能源、新技术、新概念集中亮相,展现在民众面前的必将是一个新的“竞”界。值得一看; 最便宜的路线: 坐地铁到天通苑站下车。出战有专车开往车展。 不过票价100,很难找到卖50 ...…

查看全部问答>

snapgear udp接收不了广播包

用原始套接字可以抓到包,但是UDP就是接收不了,不知道在哪里被拦截了。…

查看全部问答>

调查:有用MIPS32做过wince的吗?最新的Au1300 serials

做个调查,有用MIPS32做过wince的吗? 5.0或6.0 Au1100serials,Au1200 serials,最新的Au1300 serials 请高手讲讲在启动,地址(memory,virtual ,physical)上和ARM的区别吧?…

查看全部问答>

各位大侠,如何读取硬盘和CPU的序列号啊?急啊,拜托了...

各位大侠,如何读取硬盘和CPU的序列号啊? 我想做一个加密,想到读取硬盘盒CPU的序列号,加上自己的算法。…

查看全部问答>

抢楼抽到的LM3S811评估板收到啦~~~开始上图咯~~~~~~~~

昨天晚上8点整收到电话问我门牌号,今天早上看到帖子说评估板已经寄出了,手机一查10点已经到威海了....不得不说顺丰还真是给力啊....下午收到短信说已经到了,下了课直奔门口,嘿嘿,废话不多说了,先上开箱图——     要打开了, ...…

查看全部问答>

教你计算Buck降压储能电感

如何计算请看下面介绍   如图:输入20-24VDC,输出12V1.8A  频率Fs=250KHZ  计算储能电感值 1.电感最大峰值压降VL=Vinmax-Vo=24V-12V=12V 2.压比Vd=Vo/Vinmax=12V/24V=0.5 3.纹波电流^I=Io*0.3=1.8A*0.3=0.54A 4.储能电感值Lmin=VL*V ...…

查看全部问答>

Quartus开发环境出现的specify a legal end time的问题

Quartus开发环境出现的specify a legal end time的问题 当输入波形时要想改变时间的长短时,总是出现specify a legal end time的现象,添加一个main Time Bar也会有这个提示。解决的方法是在Edit菜单下,有一个End Time菜单,在这里可以修改时间 ...…

查看全部问答>

无意中找到的查SMD代码的 --很好的资料

无意中找到的查SMD代码的 --很好的资料 …

查看全部问答>

编译时遇到“program will not fit into lnk_msp430g2553.cmd“

ccs里c语言编写是老遇到这个错误! 点击进入后转到汇编优势这样的的。 这是怎么回事,是溢出了,可是程序没几行啊,…

查看全部问答>

诚聘PLC、FPGA、matlab、C++、C编程兼职技术(月薪1W+)

正规工作室,因业务量大,在职技术无法供应。现诚聘PLC、FPGA、matlab、C++、C编程兼职技术(有做电路板条件,在校研究生亦可)!有意者联系QQ:740718010,期待与你合作!…

查看全部问答>