STM32Cube STM32L053配置RTC时钟详解

本文介绍了如何在STM32L053上配置RTC时钟,使用内部32KHz LSE振荡器,并启用RTC中断进行休眠唤醒。在没有外部32.768KHz晶振的情况下,需要根据公式重新计算RTC分频值以确保1Hz精度。同时,探讨了RTC的数据格式,包括月份和星期的定义,以及RTC_FORMAT_BIN和RTC_FORMAT_BCD的实际含义。文中还展示了如何使用STM32CubeMX生成工程,以及RTC的初始化、设置和读取函数,最后提供了测试代码来验证RTC的时间设置和读取功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先看下STM32L053的RTC时钟,这里没有外部晶振用的是内部LSE,频率37KHz

 通过Cube配置RTC,启用日历和时钟,我这里开启了一个RTC中断,用来唤醒休眠中的单片机

STM32CubeMX默认填入的分频是使用32.768KHz的,但是内部振荡器是32KHz的,所以估计都是推荐使用外部晶振,使用内部振荡器的自己按公式重新计算分频值

公式如下:

RTC时钟频率 = RTC时钟源 / ((Asynchronous Predivider value + 1) * (Synchronous Predivider value + 1))

使用公式

32.768KHz / ((127+1)*(255+1)) = 1Hz,也就是1秒

年是从1970年算起的,其他月日时分秒以及24或者12小时制没什么好说的

数据格式Data Format,我使用Binary data format

stm32定义了RTC_FORMAT_BIN和RTC_FORMAT_BCD两种格式

RTC_FORMAT_BIN:为10进制,RTC_FORMAT_BCD为16进制,开始我也是这样认为的,然后并不是

看一下stm32l0xx_II_rtc.h头文件中对月份的定义:

/** @defgroup RTC_LL_EC_WEEKDAY  WEEK DAY
  * @{
  */
#define LL_RTC_WEEKDAY_MONDAY              ((uint8_t)0x01U) /*!< Monday    */
#define LL_RTC_WEEKDAY_TUESDAY             ((uint8_t)0x02U) /*!< Tuesday   */
#define LL_RTC_WEEKDAY_WEDNESDAY           ((uint8_t)0x03U) /*!< Wednesday */
#define LL_RTC_WEEKDAY_THURSDAY            ((uint8_t)0x04U) /*!< Thrusday  */
#define LL_RTC_WEEKDAY_FRIDAY              ((uint8_t)0x05U) /*!< Friday    */
#define LL_RTC_WEEKDAY_SATURDAY            ((uint8_t)0x06U) /*!< Saturday  */
#define LL_RTC_WEEKDAY_SUNDAY              ((uint8_t)0x07U) /*!< Sunday    */
/**
  * @}
  */

/** @defgroup RTC_LL_EC_MONTH  MONTH
  * @{
  */
#define LL_RTC_MONTH_JANUARY               ((uint8_t)0x01U)  /*!< January   */
#define LL_RTC_MONTH_FEBRUARY              ((uint8_t)0x02U)  /*!< February  */
#define LL_RTC_MONTH_MARCH                 ((uint8_t)0x03U)  /*!< March     */
#define LL_RTC_MONTH_APRIL                 ((uint8_t)0x04U)  /*!< April     */
#define LL_RTC_MONTH_MAY                   ((uint8_t)0x05U)  /*!< May       */
#define LL_RTC_MONTH_JUNE                  ((uint8_t)0x06U)  /*!< June      */
#define LL_RTC_MONTH_JULY                  ((uint8_t)0x07U)  /*!< July      */
#define LL_RTC_MONTH_AUGUST                ((uint8_t)0x08U)  /*!< August    */
#define LL_RTC_MONTH_SEPTEMBER             ((uint8_t)0x09U)  /*!< September */
#define LL_RTC_MONTH_OCTOBER               ((uint8_t)0x10U)  /*!< October   */
#define LL_RTC_MONTH_NOVEMBER              ((uint8_t)0x11U)  /*!< November  */
#define LL_RTC_MONTH_DECEMBER              ((uint8_t)0x12U)  /*!< December  */

比如12月份RTC_MONTH_DECEMBER的值是等于0x12的,转成10进制等于18,也就是RTC_FORMAT_BCD也不是16进制,只是用了16进制的样式,0x12不看0x直接看数字部分,就是12月份

再来看看stm32内部的两种格式的转换函数

/**
  * @brief  Helper macro to convert a value from 2 digit decimal format to BCD format
  * @param  __VALUE__ Byte to be converted
  * @retval Converted byte
  */
#define __LL_RTC_CONVERT_BIN2BCD(__VALUE__) (uint8_t)((((__VALUE__) / 10U) << 4U) | ((__VALUE__) % 10U))

/**
  * @brief  Helper macro to convert a value from BCD format to 2 digit decimal format
  * @param  __VALUE__ BCD value to be converted
  * @retval Converted byte
  */
#define __LL_RTC_CONVERT_BCD2BIN(__VALUE__) (uint8_t)((((uint8_t)((__VALUE__) & (uint8_t)0xF0U) >> (uint8_t)0x4U) * 10U ) + ((__VALUE__) & (uint8_t)0x0FU))

配置完成,生成工程

找到static void MX_RTC_Init(void)函数,在MX_RTC_Init后,使用RTC的后备寄存器保存是否初始化过时间的标志,RTC的后备寄存器也是后备电源供电的,所以主电源断电后数据还在,也可以用这些寄存器保存数据,读写函数如下:

#define RTC_BKP_DATE_TIME_UPDTATED ((uint32_t)0x32F2)
unsigned char const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表   
unsigned char rtc_get_week(unsigned short int year,unsigned char month, unsigned char day)
{
	unsigned short int temp2;
	unsigned char yearH, yearL;

	yearH = year/100; yearL = year%100;
	
	// 如果为21世纪,年份数加100
	if (yearH>19) yearL+=100;
	
	// 所过闰年数只算1900年之后的
	temp2 = yearL + yearL/4;
	temp2 = temp2 % 7;
	temp2 = temp2 + day + table_week[month-1];
	
	if (yearL%4 == 0&&month<3) temp2--;
	
	return(temp2 % 7);
}

void rtc_set(LL_RTC_DateTypeDef *date,LL_RTC_TimeTypeDef *time)
{	
	LL_RTC_TIME_Init(RTC, LL_RTC_FORMAT_BIN, time);
	LL_RTC_DATE_Init(RTC, LL_RTC_FORMAT_BIN, date);	
	LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, RTC_BKP_DATE_TIME_UPDTATED);
}

void rtc_get(LL_RTC_DateTypeDef *date,LL_RTC_TimeTypeDef *time)
{
	time->Hours   = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_TIME_GetHour(RTC));
	time->Minutes = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_TIME_GetMinute(RTC));
	time->Seconds = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_TIME_GetSecond(RTC));
	date->Year  = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_DATE_GetYear(RTC));
	date->Month = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_DATE_GetMonth(RTC));
	date->Day   = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_DATE_GetDay(RTC));
}

需要屏蔽2个函数

//LL_RCC_ForceBackupDomainReset();
//LL_RCC_ReleaseBackupDomainReset();

测试代码

void rtc_read(void)
{	
	LL_RTC_DateTypeDef curData;
	LL_RTC_TimeTypeDef curTime;
		
	rtc_get(&curData, &curTime);
#ifdef ENABLE_PRINT
	printf("MX_RTC_Init:Date time: %d-%02d-%02d weekData:%d %02d:%02d:%02d\r\n"                   
                   , 1970 + curData.Year, curData.Month, curData.Day, curData.WeekDay
                   , curTime.Hours, curTime.Minutes, curTime.Seconds);
#endif
	curData.WeekDay = rtc_get_week((curData.Year+2000), curData.Month, curData.Day );
	
	curData.Year = 51;
	curData.Month = 7;
	curData.Day = 4;	
	curData.WeekDay = rtc_get_week((curData.Year+2000), curData.Month, curData.Day );
	
	curTime.Hours = 9;
	curTime.Minutes = 29;
	curTime.Seconds = 1;	
	
	rtc_set(&curData, &curTime);	
	#ifdef ENABLE_PRINT
	printf("MX_RTC_Init:Date time: %d-%02d-%02d weekData:%d %02d:%02d:%02d\r\n"                   
                   , 1970 + curData.Year, curData.Month, curData.Day, curData.WeekDay
                   , curTime.Hours, curTime.Minutes, curTime.Seconds);
#endif
	rtc_get(&curData, &curTime);	
	#ifdef ENABLE_PRINT
	printf("MX_RTC_Init:Date time: %d-%02d-%02d weekData:%d %02d:%02d:%02d\r\n"                   
                   , 1970 + curData.Year, curData.Month, curData.Day, curData.WeekDay
                   , curTime.Hours, curTime.Minutes, curTime.Seconds);
#endif
	rtc_get(&curData, &curTime);
	#ifdef ENABLE_PRINT
	printf("MX_RTC_Init:Date time: %d-%02d-%02d weekData:%d %02d:%02d:%02d\r\n"                   
                   , 1970 + curData.Year, curData.Month, curData.Day, curData.WeekDay
                   , curTime.Hours, curTime.Minutes, curTime.Seconds);
#endif
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

花开花落的个人博客

你的鼓励是我最大的动力

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

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

打赏作者

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

抵扣说明:

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

余额充值