5

STM32CubeMX之RTC电子钟

 1 year ago
source link: https://blog.51cto.com/u_15688123/5885574
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

STM32CubeMX之RTC电子钟

1.RTC简介

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

      RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒后, RTC的设置和时间维持不变。

 ● 可编程的预分频系数:分频系数最高为220。

 ● 32位的可编程计数器,可用于较长时间段的测量。

 ● 2个分离的时钟:用于APB1接口的PCLK1和RTC时钟(RTC时钟的频率必须小于PCLK1时钟频率的四分之一以上)。

 ● 可以选择以下三种RTC的时钟源:

      ─ HSE时钟除以128;

      ─ LSE振荡器时钟;

      ─ LSI振荡器时钟;

  ● 3个专门的可屏蔽中断:

     ─ 闹钟中断,用来产生一个软件可编程的闹钟中断。

     ─ 秒中断,用来产生一个可编程的周期性中断信号(最长可达1秒)。

     ─ 溢出中断,指示内部可编程计数器溢出并回转为0的状态。

3.功能概述

      RTC由两个主要部分组成(见下图)。第一部分(APB1 接口 )用来和APB1 总线相连。此单元还包含一组16位寄存器,可通过APB1 总线对其进行读写操作。 APB1 接口由APB1 总线时钟驱动,用来与APB1 总线接口。另一部分(RTC核心)由一组可编程计数器组成,分成两个主要模块。第一个模块是RTC的预分频模块,它可编程产生最长为1 秒的RTC时间基准TR_CLK。 RTC的预分频模块包含了一个20位的可编程分频器(RTC 预分频器) 。如果在 RTC_CR寄存器中设置了相应的允许位,则在每个TR_CLK周期中RTC产生一个中断(秒中断)。第二个模块是一个32位的可编程计数器,可被初始化为当前的系统时间。系统时间按TR_CLK周期累加并与存储在RTC_ALR寄存器中的可编程时间相比较,如果RTC_CR控制寄存器中设置了相应允许位,比较匹配时将产生一个闹钟中断。

STM32CubeMX之RTC电子钟_HAL库

4.RTC配置过程

      必须设置RTC_CRL寄存器中的CNF位 ,使RTC进入配置模式后 ,才能写入RTC_PRL 、RTC_CNT、 RTC_ALR寄存器。另外,对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF状态位是’1’时,才可以写入RTC寄存器。

  • 配置过程:
  1. 选择RTC时钟源
  2. 查询RTOFF位,直到RTOFF的值变为’1’;
  3. 置CNF值为1 ,进入配置模式;
  4. 对一个或多个RTC寄存器进行写操作;
  5. 清除CNF标志位,退出配置模式;
  6. 查询RTOFF,直至RTOFF位变为’1’以确认写操作已经完成。仅当CNF标志位被清除时,写操作才能进行,这个过程至少需要3个RTCCLK周期;

5.软件设计

 5.1 选择RTC时钟源

STM32CubeMX之RTC电子钟_RTC电子钟_02

 5.2 RTC配置

开启RTC功能,开启日历功能,设置时间和日期,设置预分频系数,产生秒中断。

STM32CubeMX之RTC电子钟_RTC电子钟_03
STM32CubeMX之RTC电子钟_HAL库_04

 5.3 配置RTC时钟源

RTC时钟产生可配置三种时钟源:

      外部高速时钟HSE(8MHZ)进行128分频(HSE/128);

外部低速时钟LSE(32.768KHZ);

内部低速时钟LSI(40KHZ);

下面配置选择为外部低速时钟LSE,32.768KHZ作为RTC时钟源。

STM32CubeMX之RTC电子钟_RTC电子钟_05

6.生成代码

 6.1 RTC初始化

    由于RTC部分配置寄存器是处于后备区域,在有后备电池供电情况下,为了保证掉电后电子钟数据持续更新,我们需要开启后备驱动。

/* RTC init function */
void MX_RTC_Init(void)
{
RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef DateToUpdate = {0};

/** 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 */
/*检查后备区域是否写入数据*/
if(HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR1)==0x12)
{
return ;
}
else HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR1,0x12);//写入标志位,表示RTC时间配置好,防止重置时间
/* USER CODE END Check_RTC_BKUP */

/** Initialize RTC and set the Time and Date
*/
sTime.Hours = 0;
sTime.Minutes = 0;
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 = 30;
DateToUpdate.Year = 21;

if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK)//设置日期
{
Error_Handler();
}

}

 6.2 开启RTC开时钟,开RTC中断

void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
{
if(rtcHandle->Instance==RTC)
{
/* USER CODE BEGIN RTC_MspInit 0 */

/* USER CODE END RTC_MspInit 0 */
HAL_PWR_EnableBkUpAccess();//电源接口时钟
/* Enable BKP CLK enable for backup registers */
__HAL_RCC_BKP_CLK_ENABLE();//后备域时钟
/* RTC clock enable */
__HAL_RCC_RTC_ENABLE();//RTC时钟

/* RTC interrupt Init */
HAL_NVIC_SetPriority(RTC_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(RTC_IRQn);
/* USER CODE BEGIN RTC_MspInit 1 */
HAL_RTCEx_SetSecond_IT(rtcHandle);//开启RTC中断
/* USER CODE END RTC_MspInit 1 */
}
}

 6.3 配置RTC中断

extern u8 flag;
void RTC_IRQHandler(void)
{
/* USER CODE BEGIN RTC_IRQn 0 */
u8 buff[30];
RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef DateToUpdate = {0};
/* USER CODE END RTC_IRQn 0 */
HAL_RTCEx_RTCIRQHandler(&hrtc);
/* USER CODE BEGIN RTC_IRQn 1 */
if(flag==1)
{
if(HAL_RTC_GetTime(&hrtc,&sTime,RTC_FORMAT_BIN)==HAL_OK)
{
// printf("%d:%d:%d ",sTime.Hours,sTime.Minutes,sTime.Seconds);
snprintf((char *)buff,sizeof(buff),"%02d:%02d:%02d",sTime.Hours,sTime.Minutes,sTime.Seconds);
OLED_Display_str(32,0,8,16,buff);
}
if(HAL_RTC_GetDate(&hrtc,&DateToUpdate,RTC_FORMAT_BIN)==HAL_OK)
{
printf("%d/%d/%d 星期:%d\r\n",DateToUpdate.Year,DateToUpdate.Month,DateToUpdate.Date,DateToUpdate.WeekDay);
snprintf((char *)buff,sizeof(buff),"%02d/%02d/%02d week:%d",DateToUpdate.Year,DateToUpdate.Month,DateToUpdate.Date,DateToUpdate.WeekDay);
OLED_Display_str(0,2,8,16,buff);
}
}
/* USER CODE END RTC_IRQn 1 */
}

 6.4 主体功能

     主函数中实现OLED屏幕初始化、RTC电子钟初始化等;实现实时时间显示,可通过串口进行时间校准。

int main(void)
{
/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* MCU Configuration--------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM4_Init();
MX_USART1_UART_Init();
MX_RTC_Init();
/* USER CODE BEGIN 2 */
OLED_Init();
OLED_Displey_Imag(48,0,32,32,(u8 *)android);
Delay_Ms(500);
Delay_Ms(500);
OLED_Clear();//清屏
flag=1;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)//轮询
{
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
if(usart1_flag)
{
printf("%s\r\n",usart1_buff_rx);
if(usart1_buff_rx[0]== '*')
{
DateToUpdate.Year=(usart1_buff_rx[3]-'0')*10+(usart1_buff_rx[4]-'0')*1;//年
DateToUpdate.Month=(usart1_buff_rx[5]-'0')*10+(usart1_buff_rx[6]-'0')*1;//月
DateToUpdate.Date=(usart1_buff_rx[7]-'0')*10+(usart1_buff_rx[8]-'0')*1;//日

sTime.Hours=(usart1_buff_rx[9]-'0')*10+(usart1_buff_rx[10]-'0')*1;
sTime.Minutes=(usart1_buff_rx[11]-'0')*10+(usart1_buff_rx[12]-'0')*1;
sTime.Seconds=(usart1_buff_rx[13]-'0')*10+(usart1_buff_rx[14]-'0')*1;
printf("%d/%d/%d -- %d:%d:%d\r\n",DateToUpdate.Year,DateToUpdate.Month,DateToUpdate.Date,sTime.Hours,sTime.Minutes,sTime.Seconds);
HAL_RTC_SetDate(&hrtc, &DateToUpdate,RTC_FORMAT_BIN);
HAL_RTC_SetTime(&hrtc,&sTime,RTC_FORMAT_BIN);
}
usart1_flag=0;
usart1_count=0;
}
}
/* USER CODE END 3 */
}

7.运行效果

STM32CubeMX之RTC电子钟_RTC电子钟_06
STM32CubeMX之RTC电子钟_STM32_07

8.相关接口函数

//读取和写入后备域数据
uint32_t HAL_RTCEx_BKUPRead(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister)
HAL_RTCEx_BKUPWrite(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister, uint32_t Data)

//设置和获获取时间
HAL_StatusTypeDef HAL_RTC_SetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format)
HAL_StatusTypeDef HAL_RTC_GetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format)

//设置和获取日期
HAL_StatusTypeDef HAL_RTC_SetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format)
HAL_StatusTypeDef HAL_RTC_GetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format)

//设置RTC秒中断
HAL_StatusTypeDef HAL_RTCEx_SetSecond_IT(RTC_HandleTypeDef *hrtc)

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK