STM32F767 RTC的基本用法

 本文介绍STM32F767 RTC(Real-time clock)的基本用法。

开发环境

硬件环境

  • 电脑:Windows 10 Home x64
  • Apollo STM32F767开发板(ST-LINK V2仿真器)

软件环境

  • Keil Version 5.24.1 (Pack Installer:Keil.STM32F7xx_DFP.2.9.0.pack)
  • STM32CubeMX Version 4.25.0(Packages Manager:STM32CubeF7)

RTC功能介绍

RTC主要特性

  • 包含亚秒、秒、分钟、小时(12/24 小时制)、星期几、日期、月份和年份的日历;
  • 软件可编程的夏令时补偿;
  • 具有中断功能的可编程闹钟。可通过任意日历字段的组合触发闹钟;
  • 自动唤醒单元,可周期性地生成标志以触发自动唤醒中断;
  • 参考时钟检测:可使用更加精确的第二时钟源(50 Hz 或 60 Hz)来提高日历的精确度;
  • 利用亚秒级移位特性与外部时钟实现精确同步;
  • 数字校准电路(周期性计数器调整):精度为 0.95 ppm,在数秒钟的校准窗口中获得;
  • 用于事件保存的时间戳功能;
  • 带可配置过滤器和内部上拉的入侵检测事件;
  • 可屏蔽中断/事件:闹钟A、闹钟B、唤醒中断、时间戳、入侵检测
  • 32备份寄存器。

RTC系统框图

 本例中仅使用RTC的基本功能:设置RTC事件后进行读取操作,故不再对框图进行说明。

RTC的基本用法

RTC时钟设置

 本例中,使用外部低速时钟LSE作为时钟源,其频率为32.768kHz

 RTC的时钟设置函数如下所示。

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
/**
* @brief RTC Clock Configuration
* @retval None
*/
void RTC_Clock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
/**Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/**初始化LSE时钟:32.768kHz
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE; /* LSE配置 */
RCC_OscInitStruct.LSEState = RCC_LSE_ON; /* LSE使能 */
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; /* LSE无PLL */
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC; /* 外设为RTC */
PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; /* RTC时钟源为LSE */
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}

 RTC时钟初始化函数的主要功能如下:

  • 使能外部LSE时钟,LSE无PLL功能;
  • 设置RTC的时钟源为LSE。

RTC初始化函数

 RTC初始化函数如下所示。

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
RTC_HandleTypeDef hrtc;
#define RTC_BKP_Mask 0x5051
/* RTC init function */
void MX_RTC_Init(void)
{
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
/**Initialize RTC Only
*/
hrtc.Instance = RTC;
if(HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0) != RTC_BKP_Mask){
hrtc.Init.HourFormat = RTC_HOURFORMAT_24; /* 24小时制 */
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255; /* 分频系数 = 128 * 256 = 32768 */
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE; /* 禁用RTC output输出 */
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**初始化RTC时间与日期
*/
sTime.Hours = 23;
sTime.Minutes = 8;
sTime.Seconds = 50;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; /* 关闭夏令时 */
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sDate.WeekDay = RTC_WEEKDAY_WEDNESDAY;
sDate.Month = RTC_MONTH_MAY;
sDate.Date = 30;
sDate.Year = 18;
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR0,RTC_BKP_Mask);
}
}

 初始化函数的功能如下:

  • 设置RTC为24小时制;
  • 设置RTC分频系数,32.768kHz时钟分频后为1Hz;
  • 初始化RTC;
  • 设置RTC时分秒,关闭夏令时;
  • 设置RTC年月日星期;
  • 初始化RTC时间与日期。

HAL_RTC_Init()函数实现

HAL_RTC_Init()函数用于初始化RTC,其实现如下。

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/**
* @brief Initializes the RTC peripheral
* @param hrtc pointer to a RTC_HandleTypeDef structure that contains
* the configuration information for RTC.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_RTC_Init(RTC_HandleTypeDef *hrtc)
{
/* Check the RTC peripheral state */
if(hrtc == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_RTC_ALL_INSTANCE(hrtc->Instance));
assert_param(IS_RTC_HOUR_FORMAT(hrtc->Init.HourFormat));
assert_param(IS_RTC_ASYNCH_PREDIV(hrtc->Init.AsynchPrediv));
assert_param(IS_RTC_SYNCH_PREDIV(hrtc->Init.SynchPrediv));
assert_param (IS_RTC_OUTPUT(hrtc->Init.OutPut));
assert_param (IS_RTC_OUTPUT_POL(hrtc->Init.OutPutPolarity));
assert_param(IS_RTC_OUTPUT_TYPE(hrtc->Init.OutPutType));
if(hrtc->State == HAL_RTC_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hrtc->Lock = HAL_UNLOCKED;
/* Initialize RTC MSP */
HAL_RTC_MspInit(hrtc); /* 使能RTC时钟 */
}
/* Set RTC state */
hrtc->State = HAL_RTC_STATE_BUSY;
/* Disable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_DISABLE(hrtc); /* 解锁RTC寄存器的写保护 */
/* Set Initialization mode */
if(RTC_EnterInitMode(hrtc) != HAL_OK) /* 进入RTC初始化模式 */
{
/* Enable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
/* Set RTC state */
hrtc->State = HAL_RTC_STATE_ERROR;
return HAL_ERROR;
}
else
{
/* Clear RTC_CR FMT, OSEL and POL Bits */
hrtc->Instance->CR &= ((uint32_t)~(RTC_CR_FMT | RTC_CR_OSEL | RTC_CR_POL)); /* 配置RTC模式 */
/* Set RTC_CR register */
hrtc->Instance->CR |= (uint32_t)(hrtc->Init.HourFormat | hrtc->Init.OutPut | hrtc->Init.OutPutPolarity);
/* Configure the RTC PRER */ /* 配置RTC分频系数 */
hrtc->Instance->PRER = (uint32_t)(hrtc->Init.SynchPrediv);
hrtc->Instance->PRER |= (uint32_t)(hrtc->Init.AsynchPrediv << 16);
/* Exit Initialization mode */
hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT; /* 跳出初始化模式 */
hrtc->Instance->OR &= (uint32_t)~RTC_OR_ALARMTYPE; /* ALARM TIMESTAMP IO设置 */
hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType);
/* Enable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_ENABLE(hrtc); /* 上锁RTC寄存器的写保护 */
/* Set RTC state */
hrtc->State = HAL_RTC_STATE_READY;
return HAL_OK;
}
}

HAL_RTC_MspInit()函数仅用于使能RTC时钟,具体如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
{
if(rtcHandle->Instance==RTC)
{
/* USER CODE BEGIN RTC_MspInit 0 */
/* USER CODE END RTC_MspInit 0 */
/* RTC clock enable */
__HAL_RCC_RTC_ENABLE();
/* USER CODE BEGIN RTC_MspInit 1 */
/* USER CODE END RTC_MspInit 1 */
}
}

 RTC具有寄存器写保护功能,进行寄存器写入之前必须首先进行解锁。解锁的操作为:按顺序写入0xCA0x53即可解锁所有RTC寄存器;写入一个错误的关键字会再次激活写保护

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* @brief Disable the write protection for RTC registers.
* @param __HANDLE__ specifies the RTC handle.
* @retval None
*/
#define __HAL_RTC_WRITEPROTECTION_DISABLE(__HANDLE__) \
do{ \
(__HANDLE__)->Instance->WPR = 0xCAU; \
(__HANDLE__)->Instance->WPR = 0x53U; \
} while(0U)
/**
* @brief Enable the write protection for RTC registers.
* @param __HANDLE__ specifies the RTC handle.
* @retval None
*/
#define __HAL_RTC_WRITEPROTECTION_ENABLE(__HANDLE__) \
do{ \
(__HANDLE__)->Instance->WPR = 0xFFU; \
} while(0U)

RTC_EnterInitMode()函数用于将RTC设置为初始化模式。通过将RTC RTC_ISR寄存器INIT位置位实现。

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
/**
* @brief Enters the RTC Initialization mode.
* @note The RTC Initialization mode is write protected, use the
* __HAL_RTC_WRITEPROTECTION_DISABLE() before calling this function.
* @param hrtc pointer to a RTC_HandleTypeDef structure that contains
* the configuration information for RTC.
* @retval HAL status
*/
HAL_StatusTypeDef RTC_EnterInitMode(RTC_HandleTypeDef* hrtc)
{
uint32_t tickstart = 0;
/* Check if the Initialization mode is set */
if((hrtc->Instance->ISR & RTC_ISR_INITF) == (uint32_t)RESET)
{
/* Set the Initialization mode */
hrtc->Instance->ISR = (uint32_t)RTC_INIT_MASK;
/* Get tick */
tickstart = HAL_GetTick();
/* Wait till RTC is in INIT state and if Time out is reached exit */
while((hrtc->Instance->ISR & RTC_ISR_INITF) == (uint32_t)RESET)
{
if((HAL_GetTick() - tickstart ) > RTC_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
return HAL_OK;
}

 之后进入主配置环节,具体配置如下:

  • 通过RTC_CR寄存器FMTOSELPOL位分别设置小时格式输出选择输出极性,本例设置为24小时制,输出禁用;
  • 通过RTC_PRER寄存器设置预分频系数;
  • 跳出初始化模式;
  • 设置ALARM与TIMESTAMP,本例中不使用;
  • 上锁RTC寄存器写保护。

HAL_RTC_SetTime()函数实现

HAL_RTC_SetTime()函数用于设置RTC时间,具体实现如下。该函数的核心功能为通过向RTC时间寄存器RTC_TR写入时分秒时间实现,本例中不启用夏令时。

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/**
* @brief Sets RTC current time.
* @param hrtc pointer to a RTC_HandleTypeDef structure that contains
* the configuration information for RTC.
* @param sTime Pointer to Time structure
* @param Format Specifies the format of the entered parameters.
* This parameter can be one of the following values:
* @arg FORMAT_BIN: Binary data format
* @arg FORMAT_BCD: BCD data format
* @retval HAL status
*/
HAL_StatusTypeDef HAL_RTC_SetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format)
{
uint32_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_RTC_FORMAT(Format));
assert_param(IS_RTC_DAYLIGHT_SAVING(sTime->DayLightSaving));
assert_param(IS_RTC_STORE_OPERATION(sTime->StoreOperation));
/* Process Locked */
__HAL_LOCK(hrtc);
hrtc->State = HAL_RTC_STATE_BUSY;
if(Format == RTC_FORMAT_BIN)
{
if((hrtc->Instance->CR & RTC_CR_FMT) != (uint32_t)RESET)
{
assert_param(IS_RTC_HOUR12(sTime->Hours));
assert_param(IS_RTC_HOURFORMAT12(sTime->TimeFormat));
}
else
{
sTime->TimeFormat = 0x00;
assert_param(IS_RTC_HOUR24(sTime->Hours));
}
assert_param(IS_RTC_MINUTES(sTime->Minutes));
assert_param(IS_RTC_SECONDS(sTime->Seconds));
tmpreg = (uint32_t)(((uint32_t)RTC_ByteToBcd2(sTime->Hours) << 16) | \
((uint32_t)RTC_ByteToBcd2(sTime->Minutes) << 8) | \
((uint32_t)RTC_ByteToBcd2(sTime->Seconds)) | \
(((uint32_t)sTime->TimeFormat) << 16));
}
else
{
if((hrtc->Instance->CR & RTC_CR_FMT) != (uint32_t)RESET)
{
tmpreg = RTC_Bcd2ToByte(sTime->Hours);
assert_param(IS_RTC_HOUR12(tmpreg));
assert_param(IS_RTC_HOURFORMAT12(sTime->TimeFormat));
}
else
{
sTime->TimeFormat = 0x00;
assert_param(IS_RTC_HOUR24(RTC_Bcd2ToByte(sTime->Hours)));
}
assert_param(IS_RTC_MINUTES(RTC_Bcd2ToByte(sTime->Minutes)));
assert_param(IS_RTC_SECONDS(RTC_Bcd2ToByte(sTime->Seconds)));
tmpreg = (((uint32_t)(sTime->Hours) << 16) | \
((uint32_t)(sTime->Minutes) << 8) | \
((uint32_t)sTime->Seconds) | \
((uint32_t)(sTime->TimeFormat) << 16));
}
/* Disable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_DISABLE(hrtc);
/* Set Initialization mode */
if(RTC_EnterInitMode(hrtc) != HAL_OK)
{
/* Enable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
/* Set RTC state */
hrtc->State = HAL_RTC_STATE_ERROR;
/* Process Unlocked */
__HAL_UNLOCK(hrtc);
return HAL_ERROR;
}
else
{
/* Set the RTC_TR register */
hrtc->Instance->TR = (uint32_t)(tmpreg & RTC_TR_RESERVED_MASK);
/* Clear the bits to be configured */
hrtc->Instance->CR &= (uint32_t)~RTC_CR_BKP;
/* Configure the RTC_CR register */
hrtc->Instance->CR |= (uint32_t)(sTime->DayLightSaving | sTime->StoreOperation);
/* Exit Initialization mode */
hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT;
/* If CR_BYPSHAD bit = 0, wait for synchro else this check is not needed */
if((hrtc->Instance->CR & RTC_CR_BYPSHAD) == RESET)
{
if(HAL_RTC_WaitForSynchro(hrtc) != HAL_OK)
{
/* Enable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
hrtc->State = HAL_RTC_STATE_ERROR;
/* Process Unlocked */
__HAL_UNLOCK(hrtc);
return HAL_ERROR;
}
}
/* Enable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
hrtc->State = HAL_RTC_STATE_READY;
__HAL_UNLOCK(hrtc);
return HAL_OK;
}
}

HAL_RTC_SetDate()函数实现

HAL_RTC_SetDate()函数用于设置RTC日期,具体实现如下。该函数的核心功能为通过向RTC时间寄存器RTC_DR写入年月日以及周时间实现。

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/**
* @brief Sets RTC current date.
* @param hrtc pointer to a RTC_HandleTypeDef structure that contains
* the configuration information for RTC.
* @param sDate Pointer to date structure
* @param Format specifies the format of the entered parameters.
* This parameter can be one of the following values:
* @arg RTC_FORMAT_BIN: Binary data format
* @arg RTC_FORMAT_BCD: BCD data format
* @retval HAL status
*/
HAL_StatusTypeDef HAL_RTC_SetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format)
{
uint32_t datetmpreg = 0;
/* Check the parameters */
assert_param(IS_RTC_FORMAT(Format));
/* Process Locked */
__HAL_LOCK(hrtc);
hrtc->State = HAL_RTC_STATE_BUSY;
if((Format == RTC_FORMAT_BIN) && ((sDate->Month & 0x10U) == 0x10U))
{
sDate->Month = (uint8_t)((sDate->Month & (uint8_t)~(0x10U)) + (uint8_t)0x0AU);
}
assert_param(IS_RTC_WEEKDAY(sDate->WeekDay));
if(Format == RTC_FORMAT_BIN)
{
assert_param(IS_RTC_YEAR(sDate->Year));
assert_param(IS_RTC_MONTH(sDate->Month));
assert_param(IS_RTC_DATE(sDate->Date));
datetmpreg = (((uint32_t)RTC_ByteToBcd2(sDate->Year) << 16) | \
((uint32_t)RTC_ByteToBcd2(sDate->Month) << 8) | \
((uint32_t)RTC_ByteToBcd2(sDate->Date)) | \
((uint32_t)sDate->WeekDay << 13));
}
else
{
assert_param(IS_RTC_YEAR(RTC_Bcd2ToByte(sDate->Year)));
assert_param(IS_RTC_MONTH(sDate->Month));
assert_param(IS_RTC_DATE(sDate->Date));
datetmpreg = ((((uint32_t)sDate->Year) << 16) | \
(((uint32_t)sDate->Month) << 8) | \
((uint32_t)sDate->Date) | \
(((uint32_t)sDate->WeekDay) << 13));
}
/* Disable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_DISABLE(hrtc);
/* Set Initialization mode */
if(RTC_EnterInitMode(hrtc) != HAL_OK)
{
/* Enable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
/* Set RTC state*/
hrtc->State = HAL_RTC_STATE_ERROR;
/* Process Unlocked */
__HAL_UNLOCK(hrtc);
return HAL_ERROR;
}
else
{
/* Set the RTC_DR register */
hrtc->Instance->DR = (uint32_t)(datetmpreg & RTC_DR_RESERVED_MASK);
/* Exit Initialization mode */
hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT;
/* If CR_BYPSHAD bit = 0, wait for synchro else this check is not needed */
if((hrtc->Instance->CR & RTC_CR_BYPSHAD) == RESET)
{
if(HAL_RTC_WaitForSynchro(hrtc) != HAL_OK)
{
/* Enable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
hrtc->State = HAL_RTC_STATE_ERROR;
/* Process Unlocked */
__HAL_UNLOCK(hrtc);
return HAL_ERROR;
}
}
/* Enable the write protection for RTC registers */
__HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
hrtc->State = HAL_RTC_STATE_READY ;
/* Process Unlocked */
__HAL_UNLOCK(hrtc);
return HAL_OK;
}
}

HAL_RTCEx_BKUPRead/Write()函数实现

 RTC有32个备份寄存器,可以用于存储一些特征变量。本例中RTC初始化函数展示了备份寄存器的一个用法:用于标记是否进行过RTC初始化,防止重新上电对RTC进行重复初始化。RTC初始化函数首先读取本分寄存器0存储的数值,如果与比对值不一致则初始化RTC;当初始化完成重新上电后,寄存器值与比对值一致,所以不再重新初始化。

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
/**
* @brief Reads data from the specified RTC Backup data Register.
* @param hrtc pointer to a RTC_HandleTypeDef structure that contains
* the configuration information for RTC.
* @param BackupRegister RTC Backup data Register number.
* This parameter can be: RTC_BKP_DRx where x can be from 0 to 19 to
* specify the register.
* @retval Read value
*/
uint32_t HAL_RTCEx_BKUPRead(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister)
{
uint32_t tmp = 0;
/* Check the parameters */
assert_param(IS_RTC_BKP(BackupRegister));
tmp = (uint32_t)&(hrtc->Instance->BKP0R);
tmp += (BackupRegister * 4);
/* Read the specified register */
return (*(__IO uint32_t *)tmp);
}
/**
* @brief Writes a data in a specified RTC Backup data register.
* @param hrtc pointer to a RTC_HandleTypeDef structure that contains
* the configuration information for RTC.
* @param BackupRegister RTC Backup data Register number.
* This parameter can be: RTC_BKP_DRx where x can be from 0 to 19 to
* specify the register.
* @param Data Data to be written in the specified RTC Backup data register.
* @retval None
*/
void HAL_RTCEx_BKUPWrite(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister, uint32_t Data)
{
uint32_t tmp = 0;
/* Check the parameters */
assert_param(IS_RTC_BKP(BackupRegister));
tmp = (uint32_t)&(hrtc->Instance->BKP0R);
tmp += (BackupRegister * 4);
/* Write the specified register */
*(__IO uint32_t *)tmp = (uint32_t)Data;
}

实验验证

 RTC初始化完成后可以对RTC时间进行读取,具体方法如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
while (1)
{
mainloop++;
oled_putuint32(0, 2, mainloop);
HAL_RTC_GetTime(&hrtc, &rtcTime, RTC_FORMAT_BIN);
LCD_P6x8Num3(0, 5, rtcTime.Hours);
LCD_P6x8Num3(4, 5, rtcTime.Minutes);
LCD_P6x8Num3(8, 5, rtcTime.Seconds);
HAL_RTC_GetDate(&hrtc, &rtcData, RTC_FORMAT_BIN);
LCD_P6x8Num3(0, 4, rtcData.Year);
LCD_P6x8Num3(4, 4, rtcData.Month);
LCD_P6x8Num3(8, 4, rtcData.Date);
SYS_Delay_US(500000);
}

 运行程序后,可以看到时间、日期读取正确;断电后由于后备电池的存在RTC依然可以计时。

有一点需要注意的是,HAL_RTC_GetTime()函数必须先于HAL_RTC_GetDate()函数调用,ST对此的解释如下:

关于这个问题,读日历时间时有两种模式。

一种是通过影子寄存器来读取,一种是直接日历计数器中读。你谈到的情况是前者。

在该情形下,建议先读时分秒寄存器即TR寄存器,然后读日期寄存器,即DR寄存器。

在读取TR/SSR寄存器后,DR影子寄存器的数据会被锁定而不被更新,直到你来读它,这

样是为了保持数据的一致性。

比如你在5月29日的23:59:59秒去读该时间【TR/SSR】,此时29日就会被锁定,这样你

可以悠然地去读日期,日期还是正确的29日,否则1秒过后去读的话,你读到日期就是30日

了,显然整个读进来的时间就不对了。

 本例中RTC_CR寄存器的BYPSHAD位设置为0,即日历值(从 RTC_SSR、RTC_TR 和 RTC_DR 读取时)取自影子寄存器,该影子寄存器每两个 RTCCLK 周期更新一次,对应了上述情况,所以应该按照先读TR寄存器,再读DR寄存器的方式。

文章目录
  1. 1. 开发环境
    1. 1.1. 硬件环境
    2. 1.2. 软件环境
  2. 2. RTC功能介绍
    1. 2.1. RTC主要特性
    2. 2.2. RTC系统框图
  3. 3. RTC的基本用法
    1. 3.1. RTC时钟设置
    2. 3.2. RTC初始化函数
    3. 3.3. HAL_RTC_Init()函数实现
    4. 3.4. HAL_RTC_SetTime()函数实现
    5. 3.5. HAL_RTC_SetDate()函数实现
    6. 3.6. HAL_RTCEx_BKUPRead/Write()函数实现
  4. 4. 实验验证
|