五.STM32F030C8T6 MCU开发之RTC模块基础例程

五.STM32F030C8T6 MCU开发之RTC模块基础例程

0.总体功能概述

使用STD库–en.stm32f0_stdperiph_lib_v1.6.0。

如果需要年月日时分秒的时间记录,之前开发51单片机上面外挂一个类似DS1302的时钟芯片,再加上时间芯片的外围电路。但现在MCU不再需要这么干了。因为在STM32的内部就已经集成了年月日时分秒的时钟电路–也就是实时时钟(RTC)。

本例程将RTC时间调整为当前时间,并特定格式从串口输出,每1s输出一次;

1.RTC硬件介绍

RTC (Real Time Clock):实时时钟
实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。
RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒后, RTC的设置和时间维持不变。
在这里插入图片描述

系统复位后,对后备寄存器和RTC的访问被禁止,这是为了防止对后备区域(BKP)的意外写操作。执行以下操作将使能对后备寄存器和RTC的访问:
● 设置寄存器RCC_APB1ENR的PWREN和BKPEN位,使能电源和后备接口时钟
● 设置寄存器PWR_CR的DBP位,使能对后备寄存器和RTC的访问。

在这里插入图片描述

实时时钟(RTC)是一个独立的定时器。

1.1日历的功能

STM32 的 RTC 模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。

1.2 闹钟输出

当 RTC 运行的时间跟预设的闹钟时间相同的时候,相应的标志位 ALRAF(在 RTC_ISR 寄存器中)和 ALRBF 会置 1。可以作为备忘提醒功能。
如果使能了闹钟输出(由 RTC_CR 的 OSEL[0:1]位控制),则 ALRAF 和 ALRBF 会连接到闹钟输出引RTC_ALARM.

RTC_ALARM 最终连接到 RTC 的外部引脚 RTC_AF1(即 PC13),输出的极性由 RTC_CR 寄存器的 POL 位配置,可以是高电平或者低电平。

1.3 入侵检测

RTC 自带两个入侵检测引脚RTC_TAMP1 的RTC_AF1(PC13)和 RTC__TAMP2的RTC_AF2(PA0)。这两个输入既可配置为边沿检测,也可配置为带过滤的电平检测。当检测到外部事件时,可复位备份寄存器,共80个字节,可用于记录用户数据。备份寄存器不会在系统复位或电源复位时复位,也不会在器件从待机模式唤醒时复位。

1.4 时间戳事件检测

为了记录外部紧急事件触发的时间。时间戳复用功能 (RTC_TS) 可映射到 RTC_AF1 或 RTC_AF2,当发生外部的入侵事件时,即发生时间戳事件时, RTC_ISR 寄存器中的时间戳标志位 (TSF) 将置 1,日历会保存到时间戳寄存器( RTC_TSSSR、RTC_TSTR 和RTC_TSDR)中。

2.RTC软件配置

配置当前时间:时间可以采取24小时格式,也可以采用12小时格式,默认采用24小时格式。

配置时间时,还会设置日期格式,是采用BCD或者二进制。

建议采用二进制即可,可以直接填入时间数值。

第一,定义一个时间的起点,比如2000年1月1日,0点0分0秒。这里要多说一句,其实这个起点可以随便定义,0也没关系。但网络上通常的做法是1970年的1月1日,至于为什么,可以了解时间戳的概念。

第二,STM32并没有专门的记录分钟、小时、日、月、年的寄存器,换句话说,他只是记录了从时间起点(计数器的初值)到当前时间的总秒数,并且能在掉电情况下持续计数运行。要想得到年、月、日信息,是需要我们自己写函数实现的。这里总感觉STM32干得有猛,很粗鲁的样子,上电的时候直接给年、月、日的变量赋值,想要哪年哪月哪日,就直接赋值,然后在这个基础上累加时间,并不断更新,这样就确定了年、月、日的信息。

但别忘了,这是在CPU上电程序运行的情况下进行的,一旦CPU掉电,程序也不再运行,年、月、日信息就不再更新。此时在工作的,只有那个32位的秒计数器。

第三,要想再次上电后正确显示年、月、日等信息,就需要上电后重新调用自己写的这个函数,根据初始化时的年、月、日初值和计数器的当前值,输出当前时间信息。

RTC一般有单独的外部电池供电。

2.1.RTC 模块初始化配置

可以选择以下三种RTC的时钟源:
— HSE时钟除以128;
— LSE振荡器时钟;
— LSI振荡器时钟(详见6.2.8节RTC时钟)。

RTC_CLOCK_SOURCE_LSE 使用外部 32.768 时钟源

RTC_CLOCK_SOURCE_LSI 使用内部RC 32.768 时钟源

	/**
  * @brief  Configure the RTC peripheral by selecting the clock source.
  * @param  None
  * @retval None
  */
static void RTC_Config(void)
{
  /* Enable the PWR clock */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);

  /* Allow access to RTC */
  PWR_BackupAccessCmd(ENABLE);
    
#if defined (RTC_CLOCK_SOURCE_LSI)  /* LSI used as RTC source clock*/
/* The RTC Clock may varies due to LSI frequency dispersion. */   
  /* Enable the LSI OSC */ 
  RCC_LSICmd(ENABLE);

  /* Wait till LSI is ready */  
  while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
  {
  }

  /* Select the RTC Clock Source */
  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
  
  SynchPrediv = 0x18F;
  AsynchPrediv = 0x63;

#elif defined (RTC_CLOCK_SOURCE_LSE) /* LSE used as RTC source clock */
  /* Enable the LSE OSC */
  RCC_LSEConfig(RCC_LSE_ON);

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

  /* Select the RTC Clock Source */
  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
  
  SynchPrediv = 0xFF;
  AsynchPrediv = 0x7F;

#else
  #error Please select the RTC Clock source inside the main.c file
#endif /* RTC_CLOCK_SOURCE_LSI */
  
  /* Enable the RTC Clock */
  RCC_RTCCLKCmd(ENABLE);

  /* Wait for RTC APB registers synchronisation */
  RTC_WaitForSynchro();
}

2.2 RTC 开始时间配置

    /* Configure the RTC data register and RTC prescaler */
    RTC_InitStructure.RTC_AsynchPrediv = AsynchPrediv;
    RTC_InitStructure.RTC_SynchPrediv = SynchPrediv;
    RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;
   printf("rtc init\r\n");
    /* Check on RTC init */
    if (RTC_Init(&RTC_InitStructure) == ERROR)
    {
    }
	printf("rtc RTC_TimeRegulate\r\n");
    RTC_TimeRegulate(); 
2.2.1RTC 年月日 时分秒配置
static void RTC_TimeRegulate(void)
{
  RTC_TimeTypeDef RTC_TimeStructure;
  RTC_DateTypeDef RTC_DateStructure;
  
  /* Set Time hh:mm:ss */
  RTC_TimeStructure.RTC_H12     = RTC_H12_AM;
  RTC_TimeStructure.RTC_Hours   = 0x08;  
  RTC_TimeStructure.RTC_Minutes = 0x10;
  RTC_TimeStructure.RTC_Seconds = 0x00;
  RTC_SetTime(RTC_Format_BCD, &RTC_TimeStructure);

  /* Set Date Week/Date/Month/Year */
  RTC_DateStructure.RTC_WeekDay = 01;
  RTC_DateStructure.RTC_Date = 0x31;
  RTC_DateStructure.RTC_Month = 0x12;
  RTC_DateStructure.RTC_Year = 0x12;
  RTC_SetDate(RTC_Format_BCD, &RTC_DateStructure);
  
  /* Write BkUp DR0 */
  RTC_WriteBackupRegister(RTC_BKP_DR0, 0x32F2);
}

2.3 RTC时间获取

void RTC_TimeShow(void)
{

  /* Get the current Time */
	RTC_GetTime(RTC_Format_BIN, &aShowTime);
	RTC_GetDate(RTC_Format_BIN, &RTC_DateStructure);

}

3.RTC 验证例程

每隔1秒获取RTC时间,查看RTC时间实际变化

int rtc_main(void)
{

    unsigned int s_time = 0;
    unsigned int e_time = 0;
    RTC_Config();

    /* Configure the RTC data register and RTC prescaler */
    RTC_InitStructure.RTC_AsynchPrediv = AsynchPrediv;
    RTC_InitStructure.RTC_SynchPrediv = SynchPrediv;
    RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;
   printf("rtc init\r\n");
    /* Check on RTC init */
    if (RTC_Init(&RTC_InitStructure) == ERROR)
    {
    }
	printf("rtc RTC_TimeRegulate\r\n");
    RTC_TimeRegulate(); 

	printf("rtc start\r\n");
  while(1)
  {	   
   
		s_time = get_curtime();
		while(1)
		{
			e_time = get_curtime();	
			if(e_time>s_time )
			{
				if((e_time - s_time) >=1000)
				{
					break;
				}
			}
		}
	printf("RTC_TimeShow\r\n");
    RTC_TimeShow();
		printf("RTC_Hours=%d:%d:%d\r\n",aShowTime.RTC_Hours,aShowTime.RTC_Minutes,aShowTime.RTC_Seconds);
		printf("y m d=%d %d %d\r\n",RTC_DateStructure.RTC_Year,RTC_DateStructure.RTC_Month,RTC_DateStructure.RTC_Date);
  }		
}

4.总结

4.1RTC模块只是用于时间计算可以不需要开中断。

如果需要用alarm功能 才需要开.

4.2 rtc只初始化一次即可?

每次上电后会读取BKP_DR1的值,判断是否为第一次启动,如果是,则配置RTC。换句话说,出现问题时,这个判断肯定出现问题,也就是备份寄存器的值丢失,导致重复配置RTC!

备份寄存器的值丢失原因:

1》 VDD和VBAT同时掉电

2》 客户代码意外修改

3》 检测到入侵事件

;
}
}


## 4.总结

### 4.1RTC模块只是用于时间计算可以不需要开中断。

如果需要用alarm功能 才需要开.

### 4.2 rtc只初始化一次即可?

每次上电后会读取BKP_DR1的值,判断是否为第一次启动,如果是,则配置RTC。换句话说,出现问题时,这个判断肯定出现问题,也就是备份寄存器的值丢失,导致重复配置RTC!

备份寄存器的值丢失原因:

1》 VDD和VBAT同时掉电

2》 客户代码意外修改

3》 检测到入侵事件

首先怀疑是VBAT引脚。要是VBAT再现异常,RTC重新配置就很正常。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

悟空胆好小

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值