STM32-RTC
RTC简介:
- RTC是一个独立的定时器,它可以连续计数和提供了时钟日历功能。使用BKP寄存器存储具有掉电保存功能
- 存粹的计时的,
- 触发中断
——闹钟中断,用来产生一个可编程的闹钟中断。
——秒中断,用来产生一个可编程的周期性中断信号(最快1秒,最慢1秒,只能1秒)
——溢出中断,指示内部可编程计数器溢出并回传为0的状态。
- RTC的特性掉电之后保存数据,但是f1的日期数据是保存到运行寄存器的(掉电丢失)
- 是它是一个 32 位的计数器只能向上计 数。它的时钟来源有三种,分别为高速外部时钟的 128 分频( HSE/128 )、 低速内部时钟 LSI 以及低速外部时钟 LSE。
- 时间寄存器,日期寄存器(32位的)分别存储时分秒,年月日。
启用RTC流程:
开始遇到的问题:
1.
2.
3.
4.
5.
6. 开启串口用于打印时间信息:
STM32CubeMX设置RTC就完成了,以下是代码:
1. 定义结构体变量,获取数据
RTC_TimeTypeDef GET_Time; /* 获取时间结构体 */
RTC_DateTypeDef GET_Date; /* 获取时期结构体 */
2. 打印数据
/* 打印时间结构体数据 */ HAL_RTC_GetDate(&hrtc, &GET_Date, RTC_FORMAT_BIN); HAL_RTC_GetTime(&hrtc, &GET_Time, RTC_FORMAT_BIN); /* 打印时期结构体数据 */ printf("%04d/%02d/%02d/\r\n",2000+GET_Date.Year,GET_Date.Month,GET_Date.Date); printf("%02d:%02d:%02d:\r\n",GET_Time.Hours,GET_Time.Minutes,GET_Time.Seconds); /* 延时 */ HAL_Delay(1000);
打印日历成功
注意:这个是掉电丢失的!,因为f103的RTC功能日期是保存到BKP里面的,但是我门每次复位或掉电之后,都是会重复初始化 void MX_RTC_Init(void)这个函数,所以掉电之后或复位之后重新计时。
怎么掉电不丢失:
1. 掉电丢失的问题一
可以看到图二这里面根据CubeMX里面的配置初始化了存储时期与时间的结构体(变量)如下图一:
图一
/** Initialize RTC and set the Time and Date */ sTime.Hours = 0x20; sTime.Minutes = 0x44; sTime.Seconds = 0x00; if( HAL_RTC_SetTime( &hrtc, &sTime, RTC_FORMAT_BCD ) != HAL_OK ) { Error_Handler(); } DateToUpdate.WeekDay = RTC_WEEKDAY_WEDNESDAY; DateToUpdate.Month = RTC_MONTH_MAY; DateToUpdate.Date = 0x31; DateToUpdate.Year = 0x23;
void MX_RTC_Init(void): 图二
/* RTC init function */ void MX_RTC_Init(void) { /* USER CODE BEGIN RTC_Init 0 */ /* USER CODE END RTC_Init 0 */ RTC_TimeTypeDef sTime = {0}; RTC_DateTypeDef DateToUpdate = {0}; /* USER CODE BEGIN RTC_Init 1 */ /* USER CODE END RTC_Init 1 */ /** Initialize RTC Only */ hrtc.Instance = RTC; hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND; hrtc.Init.OutPut = RTC_OUTPUTSOURCE_ALARM; if (HAL_RTC_Init(&hrtc) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN Check_RTC_BKUP */ /* USER CODE END Check_RTC_BKUP */ /** Initialize RTC and set the Time and Date */ sTime.Hours = 9; sTime.Minutes = 40; sTime.Seconds = 0; if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK) { Error_Handler(); } DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY; DateToUpdate.Month = RTC_MONTH_JUNE; DateToUpdate.Date = 6; DateToUpdate.Year = 23; if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN RTC_Init 2 */ /* USER CODE END RTC_Init 2 */ }
2. 在MX_RTC_Init函数的结尾,把0x7240这段数据写入BKP某个16位的寄存器里面,之后在MX_RTC_Init函数的开始写一个判断BKP某个寄存器是否为0x7240这段数据,如果条件为真则return出函数。这样就达到了初始化一次的效果了。
(BKP的特性掉电不丢失,可以去查看手册)
(0x7240这段数据可以写任意数,别太大了)
以下是代码:
MX_RTC_Init头
/* USER CODE BEGIN Check_RTC_BKUP */ /* 只初始化一次 */ if( HAL_RTCEx_BKUPRead( &hrtc,RTC_BKP_DR1 ) == 0x7240 ) { return ; } /* USER CODE END Check_RTC_BKUP */
MX_RTC_Init尾
HAL_RTCEx_BKUPWrite( &hrtc,RTC_BKP_DR1,0x7240 );
2. 掉电丢失的问题二
f103的RTC日期是不保存的,我门可以利用定时器中断来计数保存数据,代码如下:
1. 开启RTC定时器
2. 在stm32f1xx_it.c里面写,中断后存数据到指定BKP寄存器
/** * @brief This function handles RTC global interrupt. */ void RTC_IRQHandler(void) { /* USER CODE BEGIN RTC_IRQn 0 */ /* USER CODE END RTC_IRQn 0 */ HAL_RTCEx_RTCIRQHandler(&hrtc); /* USER CODE BEGIN RTC_IRQn 1 */ HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR2,hrtc.DateToUpdate.Year); HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR3,hrtc.DateToUpdate.Month); HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR4,hrtc.DateToUpdate.Date); /* USER CODE END RTC_IRQn 1 */ }
3. rtc.c的HAL_RTC_MspInit函数内写
__HAL_RTC_ALARM_ENABLE_IT(&hrtc,RTC_IT_SEC);
4. 读BKP寄存器的日期数据到计时变量内
/* 只初始化一次 */ if( HAL_RTCEx_BKUPRead( &hrtc,RTC_BKP_DR1 ) == 0x7240 ) { /* 读BKP寄存器的日期数据到计时变量内 */ hrtc.DateToUpdate.Year = HAL_RTCEx_BKUPRead( &hrtc,RTC_BKP_DR2 ); hrtc.DateToUpdate.Month = HAL_RTCEx_BKUPRead( &hrtc,RTC_BKP_DR3 ); hrtc.DateToUpdate.Date = HAL_RTCEx_BKUPRead( &hrtc,RTC_BKP_DR4 ); HAL_RTC_GetTime( &hrtc, &sTime, RTC_FORMAT_BIN ); return ; }
这样就达到了日期存储的功能了。
以下是代码下载链接: