STM32的实时时钟RTC编程详解

发布者:Chunjie2022最新更新时间:2023-08-31 来源: elecfans关键字:STM32  实时时钟  RTC  编程 手机看文章 扫描二维码
随时随地手机看文章

在STM32里,一个CPU已经足够,不需要像DS1302这样的实时时钟芯片。实际上,RTC就只一个定时器而已,掉电之后所有信息都会丢失,因此我们需要找一个地方来存储这些信息,于是就找到了备份寄存器。因为它掉电后仍然可以通过纽扣电池供电,所以能时刻保存这些数据。


STM32的RTC模块

RTC模块之所以具有实时时钟功能,是因为它内部维持了一个独立的定时器,通过配置,可以让它准确地每秒钟中断一次。



1.1 RTC的组成


RTC由两个部分组成:APB1接口部分以及RTC核心部分。 STM32所有的外设默认时钟无效,使用某个外设时,再开启时钟,用这样的方式来降低功耗。 这里的RTC,APB1 接口由APB1总线时钟来驱动。为了突出时钟吧?不过据说APB1接口部分还包括一组16 位寄存器。


RTC核心部分又分为预分频模块和一个32位的可编程计数器。前者可使每个TR_CLK 周期中RTC产生一个秒中断,后者可被初始化为当前系统时间。此后系统时间会按照TR_CLK周期进行累加,实现时钟功能。


1.2 对RTC的操作


我们对RTC的访问,是通过APB1接口来进行的。注意,APB1刚被开启的时候(比如刚上电,或刚复位后),从APB1上读出来的RTC寄存器的第一个值有可能是被破坏了的(通常读到0)。这个不幸,STM32是如何预防的呢?我们在程序中,会先等待RTC_CRL寄存器中的RSF位(寄存器同步标志)被硬件置1,然后才开始读操作,这时候读出来的值就是OK的。


那么对RTC寄存器的写操作会不会有类似的情况呢?对于写操作,我们只要注意, 每一次写操作,必须确保在前一次写操作完成后进行。 这个“确保”,是通过查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。只有当RTOFF状态位是1,才可以写RTC寄存器。


RTC的编程

RTC的例程,主要是设置RTC时钟,使得其在超级终端上显示出当前的时钟。这个时钟的显示是“不停地走”。而且掉电后,重新上电,时钟仍然在走,仍然显示当前的时间。当然,如果感兴趣,您可以让它在LCD上显示—— 那就是一个名副其实的电子钟了。


编程的时候,首先要注意备份寄存器BKP_DR1,它做了一件关键的事情:判断RTC是否已经被设置过。 因为RTC跟其他计时器不同,它是使用纽扣电池单独供电工作,所以它不会每次上电或者复位都被重置。判断RTC是否已经被设置过,可以决定当前是否需要去设置RTC。如果刚安装电池,第一次上电,自然需要去设置。否则的话,我们只要让它显示当前时钟即可。


当第一次使用RTC的时候(第一次配置),需要做的工作总结下:


1、打开电源管理和备份寄存器时钟。注意,一定要打开备份寄存器的时钟。


我们正是通过在备份寄存器写固定的数据来判断芯片是否第一次使用RTC,从而在系统运行RTC 时提示配置时钟的。


2、使能RTC 和备份寄存器的访问(复位默认是关闭的,以防止可能存在的意外的写操作)。


3、选择外部低速晶体为RTC时钟,并使能时钟。笔者当初调试RTC 的时候,犯了一个低级错误:由于没有定义如下:


#define RTCClockSource_LSE

导致程序一直停留在这里:


/* Wait till LSE is ready */while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET){}

希望大家能避免这个错误。


4、使能秒中断,程序里在秒中断里置位标志位来通知主程序显示时间数据,同时在32 位计数器到23:59:59时清零;


5 、设置RTC 预分频器值产生1秒信号计算公式fTR_CLK = fRTCCLK/(PRL+1),我们设置32767来产生秒信号。


我们再次强调:所有在对RTC寄存器操作之前都要判断读写操作是否完成,即内部是否有读写操作。


下面来看代码:


/* System Clocks Configuration */RCC_Configuration();

/* NVIC configuration */NVIC_Configuration();

/* Configure the GPIOs */GPIO_Configuration();

/* Configure the USART1 */USART_Configuration();

注意时钟,为避免遗漏,笔者将其代码放在第一位:


RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_PWR,ENABLE);

接着我们读取备份寄存器BKP_DR1 中的值来判断是否是第一次上电,如果不是则直接显示时钟,否则进行时间设置。当BKP_DR1的值不为0xAAAA,说明是第一次上电,此时需要对RTC进行初始化。注意初始化的实现函数RTC_Configuration();,为什么那么写,请参考我们之前给出的“第一次使用RTC的配置工作总结”,然后进行时钟设置。


注意,因为我们需要进行写操作,所以根据固件库手册,要先调用RTC_WaitForLastTask(),等待标志位RTOFF被设置,保证在前一次写操作结束后才能进行。调用RTC_SetCounter(Time_Regulate());,将计数值写入RTC计数器。


由于后面要通过BKP_WriteBackupRegister()函数对BKP_DR1写操作,因此之前还需要进行一次RTC_WaitForLastTask(),这样,对时间的设置就完成了。


剩下的代码,比较简单,主要是注意如下:


RTCCount = RTC_GetCounter(); //获得计数值并计算当前时钟

/* Compute hours */THH = RTCCount/3600;

/* Compute minutes */TMM = (RTCCount % 3600)/60;

/* Compute seconds */TSS = (RTCCount % 3600)% 60;

这是通过RTC_GetCounter();函数获取计数值,然后把这个计数值分别用小时、分钟、秒来表示的过程。最后还需要调用printf 函数把它显示出来。


关键字:STM32  实时时钟  RTC  编程 引用地址:STM32的实时时钟RTC编程详解

上一篇:STM32C0开发(1)----概述
下一篇:基于STM32的无人售货机系统设计

推荐阅读最新更新时间:2024-11-08 11:21

51单片机编程实例讲解
通过前面的学习,我们已经掌握了相当一部份的单片机指令,大家对这些枯燥的单片机指令可能也有些厌烦了,下面让我们轻松一下,做个实验。 实验(注意本程序可以在C51单片机实验台上或在Keil C51仿真软件上运行,仿真软件可以在本站下载): ORG 0000H LJMP START ORG 30H START: MOV SP,#5FH MOV A,#80H LOOP: MOV P1,A RL A LCALL DELAY LJMP LOOP delay: mov r7,#255 d1: mov r6,#255 d2: nop nop nop nop djnz r6,d2 djnz r7,d1 r
[单片机]
用数组的指针控制LED流水灯--C语言编程
//实例28: 用数组的指针控制P0 口8 位LED流水点亮--配套51单片机开发板 // #include reg51.h /************************************************* 函数功能:延时约150ms (3*200*250=150 000 s=150ms *************************************************/ void delay150ms(void) { unsigned char m,n; for(m=0;m 200;m++) for(n=0;n 250;n++) ; } /*********************
[单片机]
STM32官方固件库简析
STM32固件库目录结构如下图所示: 我们主要关注的是 Libraries这个文件夹。 1、_htmresc 是ST图标,Project是一些列子和模板可以参考学习,Utilities是ST官方评估板的例程。 2、Libraries 中 CMSIS(Cortex Microcontroller Software Interface Standand)为Cortex微控制器软件接口标准。 CoreSupport 中包含内核文件 core_cm3.h, core_cm3.c 用于访问CortexM3内核 设备驱动文件 stm32f10x.h, system_stm32f10
[单片机]
从零开始一起学stm32(十二)---SPI协议
SPI通信 -- W25Q64 -- flash芯片的使用 1、通信协议 2、SPI通信 3、STM32中SPI控制器的使用 4、W25Q64的操作过程以及软件编程 1.通信协议: 协议:两个相互通信的设备之间,进行数据传输的一种规定! 1.串口通信-- 物理层 所接管脚:TX(发送管脚) RX(接收管脚) GND(接地) 数据链接层---RS232协议 开始位+数据位+奇偶校验位+停止位 1 5~8 1 1 1.总线在发送或接收前应处于空闲状态--没有数据传输时,总线处于高电平状态! 2.开始位:要发送数据时,先发送一个低电平信号,这个信号叫开始信号,表示开
[单片机]
从零开始一起学<font color='red'>stm32</font>(十二)---SPI协议
STM32F0xx_FLASH编程(片内)配置详细过程
Ⅰ、概述 关于数据的储存,我觉得编程的人基本上都会使用到,只是看你储存在哪里。STM32的芯片内部FLASH都是可以进行编程的,也就是说可以拿来储存数据。但是,很多做一些小应用程序开发的人都没有利用好这个功能,而是单独外接一个EEPROM或者FLASH,我觉得有些情况下(小数据、不常改动)这是对资源的一种极大浪费。 关于使用内部FLASH进行编程,网上也有很多人这么说:1、内部FLASH的读写次数有限;2、内部FLASH会破坏程序。这些说法确实存在一定道理,对于次数,10W次,我想这个次数除非你经常写FLASH,正常情况下你打不到这个值。对于破坏程序,如果你编程严谨,这个不是问题。综上,我觉得这些都不是担心的问题,只要你用心编好程
[单片机]
STM32F0xx_FLASH<font color='red'>编程</font>(片内)配置详细过程
stm32 dac 配置过程
DAC模块的通道1来输出模拟电压,其详细设置步骤如下: 1)开启PA口时钟,设置PA4为模拟输入。 STM32F103ZET6的DAC通道1是接在PA4上的,所以,我们先要使能PORTA的时钟,然后设置PA4为模拟输入(虽然是输入,但是STM32内部会连接在DAC模拟输出上)。 2)使能DAC1时钟。 同其他外设一样,要想使用,必须先开启相应的时钟。STM32的DAC模块时钟是由APB1提供的,所以我们先要在APB1ENR寄存器里面设置DAC模块的时钟使能。 3)设置DAC的工作模式。 该部分设置全部通过DAC_CR设置实现,包括:DAC通道1使能、DAC通道1输出缓存关闭、不使用触发、不使用波形发生器等设置。 4)设置DAC的
[单片机]
STM32—cubeMX+DMA+USART 接收任意长度的数据
前言     之前的一篇文章中我为了可以实现USART接收任意长度的数据,对HAL的库进行了修改,可以实现接收以0x0a结尾的任意长度数据,即认为接收到0x0a时接收结束,见链接:HAL USART接收任意长度。   然而,上述这种方法并不合适,原则上HAL库一般不去修改,不便于其他人移植程序,降低了程序中库的适用性,这是很不好的习惯,所以这种方法并不可取。   后查资料得知STM32中还可以利用DMA的方式实现串口的任意长度数据的接收,故开始学习DMA+串口接收任意长度的数据这种方式。 cubeMX软件配置过程 首先,第一步都是进行时钟树的配置,配置好系统的时钟,不同的芯片配置不同的时钟频率,如图。
[单片机]
<font color='red'>STM32</font>—cubeMX+DMA+USART 接收任意长度的数据
6.6410和210的按键中断编程
首先是打开6410底板原理图: 可以看到OK6410有六个按键: 可以看到OK6410的六个按键对应的引脚是KEYINT1、KEYINT2、KEYINT3、KEYINT4、KEYINT5和KEYINT6。接着在核心板的原理图里搜索这个词: 可以看到按键中断与GPN系列寄存器的引脚是互用的,接着就是在芯片手册里查看有关GPN系列寄存器的信息,重点是关注GPN控制寄存器:GPNCON: 这里我们使用到的按键对应的中断,需要配置成中断的方式,对应的GPN位设置为10,中断功能,即需要将KEYINT1-6设置为中断功能的,即是将GPNCON对应的前12位设置为101010101010即可。这样就把对应的GPN0-5设置
[单片机]
6.6410和210的按键中断<font color='red'>编程</font>
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved