当前位置:   article > 正文

STM32 RTC学习笔记_stm32 取消 备份域 写保护

stm32 取消 备份域 写保护

RTC是一个独立的定时器,系统断电后仍然可以计时,配置其参数的寄存器RCC_BDCR是在后备区域,系统复位后,会自动禁止访问后备区域,所以在设置时间之前,要先取消备份区域(BKP)的写保护。

RTC框图
时钟源RTCCLK: 高速外部晶振的128分频,低速外部晶振,低速内部RC振荡器(一般不用它,时间不准)

RTC_PRL: RTC_PRL是预分频装载寄存器,用来配置RTC的分频数,其值可由软件设置。比如,使用外部的32.768K的晶振作为时钟输入,那么要设置它的值为32767,就可以得到一秒的计数频率。RTCCLK,RTC_PRL,TR_CLK的关系如下:
T R _ C L K = R T C _ C L K R T C _ P R L TR\_CLK=\dfrac{RTC\_CLK}{RTC\_PRL} TR_CLK=RTC_PRLRTC_CLK
RTC_DIV 只读,RTC_DIV的初始值和RTC_PRL的值是相同的,其值在RTCCLK的时钟控制下减少(每一个RTCCLK脉冲就减1),而这个减少的过程是由硬件控制的。当其减少到0时,产生一个TR_CLK脉冲。并且在TR_CLK这个脉冲的作用下,再次被赋值为RTC_PRL的值。

TR_CLK RTC的时间基准,每个TR_CLK周期都可以产生一个秒中断。

RTC_CNT 32位可编程计数器,可以被初始化为当前时间。计数TR_CLK的脉冲数,当其值和RTC_ALR相等时,就会产生一个闹钟中断。

以上是RTC的核心部分,接下来是关于控制寄存器的介绍,需要注意的是,在配置控制寄存器之前,首先需要等待其同步标志位被硬件置1(RTC_CRL 寄存器的 RSF).
这是参考手册关于RTC_CRH的介绍,该寄存器用于控制中断。
在这里插入图片描述
以下是参考手册关于RTC_CRL的介绍。
在这里插入图片描述
在这里插入图片描述
这里介绍0、3~5这几个位。

第0位是秒钟标志位,进入闹钟中断的时候,由这个位来判断是否发生了秒钟中断,然后必须通过软件将该位清零。

第3位RSF是寄存器同步标志位,在修改控制寄存器之前,必须先通过该位来判断是否已经同步,如果没有同步则不能修改控制寄存器RTC_CRH/CRL的值

第4位是配置标位,软件修改计数器值RTC_CNT、闹钟值RTC_ALR,预分频值RTC_PRL的时候,必须先用软件配置该位,以允许进入配置模式

第5位RCOFF,用于判断上一次的写操作是否完成,如果未完成,则不能进行下一次的写操作。

RTC_PRLH和RTC_PRLL 预分频值存在这两个寄存器中,其中,RTC_PRLL存储低16位,RTC_PRLH存储高4位,总共20位。
在这里插入图片描述
在这里插入图片描述
RCC_BDCR寄存器
RTC的时钟源选择、使能设置都是通过该寄存器实现的。在RTC操作之前,先要通过该寄存器选择RTC时钟源,然后才能开始其它操作。

重点:库函数配置RTC步骤
需要用到的文件:stm32f10x_rtc.c 和 stm32f10x_rtc.h,为RTC相关,stm32f10x_bkp.c 和文件 stm32f10x_bkp.h为BKP相关

1:使能电源时钟和备份区时钟

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
  • 1

2:取消备份区写保护
每次硬复位后都会使能写保护,取消写保护才能访问RTC和后备寄存器

PWR_BackupAccessCmd(ENABLE); //使能 RTC 和后备寄存器访问
  • 1

3:复位备份区域

BKP_DeInit();//复位备份区域
  • 1

4:开启外部低速振荡器

RCC_LSEConfig(RCC_LSE_ON);// 开启外部低速振荡器
  • 1

5:RTC时钟源设置

RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //选择 LSE 作为 RTC 时钟
RCC_RTCCLKCmd(ENABLE); //使能 RTC 时钟
  • 1
  • 2

对于 RTC 时钟的选择,还有 RCC_RTCCLKSource_LSI 和 RCC_RTCCLKSource_HSE_Div128两个,顾名思义,前者为 LSI,后者为 HSE 的 128 分频

6:设置RTC的分频,配置RTC时钟
注意,这里仅仅介绍需要用到的库函数,具体的使用见后文的完整配置代码

在进行配置前,打开允许配置位(CNF)

RTC_EnterConfigMode();/// 允许配置
  • 1

设置 RTC 时钟分频数。这个函数只有一个入口参数,就是 RTC 时钟的分频数,很好理解。

void RTC_SetPrescaler(uint32_t PrescalerValue);
  • 1

RTC使能中断函数:

void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState)
  • 1

使能秒中断

RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC 秒中断
  • 1

设置RTC的计数值,也就是RTC_CNT。注意,这也就是设置时间,时间和计数值是需要换算的。

void RTC_SetCounter(uint32_t CounterValue)
  • 1

更新配置同时退出配置模式

RTC_ExitConfigMode();//退出配置模式,更新配置
  • 1

在退出配置模式更新配置之后我们在备份区域 BKP_DR1 中写入 0X5050 代表我们已经初始化过时钟了,下次开机(或复位)的时候,先读取 BKP_DR1 的值,然后判断是否是0X5050 来决定是不是要配置。接着我们配置 RTC 的秒钟中断,并进行分组。

往备份区域写用户数据的函数是:

void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data)
  • 1

这个函数的第一个参数就是寄存器的标号了,这个是通过宏定义定义的。比如我们要往BKP_DR1 写入 0x5050,方法是:

BKP_WriteBackupRegister(BKP_DR1, 0X5050);
  • 1

同时,有写便有读,读取备份区域指定寄存器的用户数据的函数是:

uint16_t BKP_ReadBackupRegister(uint16_t BKP_DR)
  • 1

最后需要调用NVIC_Init函数进行中断分组,并且编写中断服务函数


static void RTC_NVIC_Config(void)
{	
    NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;//RTC全局中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;	
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;	
	NVIC_Init(&NVIC_InitStructure);		//根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}



u8 RTC_Init(void)
{
	u8 temp=0;//计数变量,用于判断外部晶振是否有问题
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);	//使能PWR和BKP时钟
	PWR_BackupAccessCmd(ENABLE);	//使能后备寄存器访问
	if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050)		//如果需要重新配置以下值,需要将5050修改成任意其它四位数字
	{	 			
		BKP_DeInit();	//复位备份区域
		RCC_LSEConfig(RCC_LSE_ON);	//设置外部低速晶振
		while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)		//检查指定的RCC标志位是否设置,等待低速晶振就绪
		{
			temp++;
			delay_ms(10);
		}
		if(temp>=250)return 1;//初始化晶振失败,晶振有问题    
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);		//设置RTC时钟(RTCCLK),选择LSE作为RTC时钟   
		RCC_RTCCLKCmd(ENABLE);	//使能RTC时钟
		RTC_WaitForLastTask();	//等待最近一次RTC寄存器写操作完成
		RTC_WaitForSynchro();		//等待RTC寄存器同步  
		RTC_ITConfig(RTC_IT_SEC, ENABLE);		//使能RTC秒中断
		RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
		RTC_EnterConfigMode();//允许配置
		//RTC_SetPrescaler(32767); //设置RTC预分频值,中断时间为1s
		RTC_SetPrescaler(3277);//根据自己的需要将中断时间修改为0.1s
		RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
		RTC_SetCounter(100);	//设置RTC计数器的初始值(这里随便设置的,这里对我来说并不重要)
		RTC_ExitConfigMode(); //退出配置模式
		BKP_WriteBackupRegister(BKP_DR1, 0X5050);//向指定后备寄存器中写入用户程序数据
	}
	else//系统继续计时
	{
		RTC_WaitForSynchro();	
		RTC_ITConfig(RTC_IT_SEC, ENABLE);	//使能RTC秒中断
		RTC_WaitForLastTask();	
	}
	RTC_NVIC_Config();//RTC中断分组的设置    				     	
	return 0; //ok
}	

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

需要把stm32f10x_rtc.c, stm32f10x_bkp.c, 这两个文件加进来,还需要stm32f10x_pwr.c,否则就会出现下面的报错。
在这里插入图片描述
也就是说,如果要使用rtc,就需要添加上面的三个文件,如果出现如图类似的报错,说明是少了文件。
这里解释一下pwr,使用rtc需要用到后备寄存器,pwr和后备寄存器的访问控制有关,例如下面这个函数
在这里插入图片描述

Reference:
链接: STM32-RTC时钟学习笔记
链接: STM32的RTC时钟及其相关寄存器
链接: STM32F10x_PWR
正点原子的《STM32不完全手册_库函数版本》
《STM32中文参考手册》

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/737322
推荐阅读
相关标签
  

闽ICP备14008679号