前言
硬件开发板:
STM32F429
软件链接:
编译调试工具 Mbed Studio
参考 Mbed RTC Api
根据Mbed RTC Api获得的时间戳只能精确到秒,并且在中断中无法使用time(NULL),无法满足实际需要,故设法直接使用Hal库获得毫秒级时间戳,并总结记录此文。
加载相关Hal库
#include “stm32f4xx_hal.h”
mbed-os\targets\TARGET_STM\TARGET_STM32F4\STM32Cube_FW\STM32F4xx_HAL_Driver目录下,主要使用HAL_RTC_GetDate与HAL_RTC_GetTime两个函数。
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
| /**
* @brief Gets 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
* @note You must call HAL_RTC_GetDate() after HAL_RTC_GetTime() to unlock the values
* in the higher-order calendar shadow registers to ensure consistency between the time and date values.
* Reading RTC current time locks the values in calendar shadow registers until Current date is read.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_RTC_GetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format);
/**
* @brief Gets 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 RTC_FORMAT_BIN: Binary data format
* @arg RTC_FORMAT_BCD: BCD data format
* @note You can use SubSeconds and SecondFraction (sTime structure fields returned) to convert SubSeconds
* value in second fraction ratio with time unit following generic formula:
* Second fraction ratio * time_unit= [(SecondFraction-SubSeconds)/(SecondFraction+1)] * time_unit
* This conversion can be performed only if no shift operation is pending (ie. SHFP=0) when PREDIV_S >= SS
* @note You must call HAL_RTC_GetDate() after HAL_RTC_GetTime() to unlock the values
* in the higher-order calendar shadow registers to ensure consistency between the time and date values.
* Reading RTC current time locks the values in calendar shadow registers until current date is read.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_RTC_GetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format);
|
调用顺序应该是先调用HAL_RTC_GetTime,再调用HAL_RTC_GetDate,否则不能解锁,会被锁死。
#include “rtc_api_hal.h”
mbed-os\targets\TARGET_STM目录下,主要是获取PREDIV_S_VALUE相关定义。
1
2
3
4
5
6
7
| /* PREDIV_A : 7-bit asynchronous prescaler */
/* PREDIV_A is set to the maximum value to improve the consumption */
#define PREDIV_A_VALUE 127
/* PREDIV_S : 15-bit synchronous prescaler */
/* PREDIV_S is set in order to get a 1 Hz clock */
#define PREDIV_S_VALUE (RTC_CLOCK / (PREDIV_A_VALUE + 1) - 1)
|
Mbed 默认PREDIV_A_VALUE为3,PREDIV_S_VALUE为8191,RTC_PRER_PREDIV_S为32767
若调整同步/异步预分频值,需要重新初始化。
1
2
3
4
5
6
7
8
9
| PREDIV_A_VALUE = 0x1F; //31
PREDIV_S_VALUE = 0x3FF; //1023
RtcHandle.Instance = RTC;
RtcHandle.Init.HourFormat = RTC_HOURFORMAT_24;
RtcHandle.Init.AsynchPrediv = PREDIV_A_VALUE; //默认RtcHandle.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
RtcHandle.Init.SynchPrediv = PREDIV_S_VALUE;
if (HAL_RTC_Init(&RtcHandle) != HAL_OK) {
error("RTC initialization failed\n");
}
|
获得秒级时间戳
1
2
3
4
5
6
7
8
9
10
11
| uint32_t get_timestamp() {
uint32_t Result;
if (HAL_OK == HAL_RTC_GetTime(&hRTC, &RTC_Time, RTC_FORMAT_BIN) && HAL_OK == HAL_RTC_GetDate(&hRTC, &RTC_Date, RTC_FORMAT_BIN)) {
uint16_t Year = RTC_Date.Year + 1900 + 68; //使Year获得值为当前年份
Result = (Year - 1970) * 365 * 24 * 3600 +(monDays[RTC_Date.Month - 1] + RTC_Date.Date) * 24 * 3600 +(RTC_Time.Hours) * 3600 + RTC_Time.Minutes * 60 + RTC_Time.Seconds;
Result += (RTC_Date.Month > 2 && (Year % 4 == 0) &&(Year % 100 != 0 || Year % 400 == 0)) *24 * 3600; //闰月
Year -= 1970;
Result += (Year / 4 - Year / 100 + Year / 400) * 24 * 3600; //闰年
}
return Result;
}
|
获得毫秒级时间戳
亚秒转化为毫秒 (PREDIV_S_VALUE - 亚秒) * 999 / PREDIV_S_VALUE,返回 0 ~ 999。
1
2
3
4
5
6
7
8
9
10
11
12
| uint64_t get_timestamp_ms() {
uint64_t Result;
if (HAL_OK == HAL_RTC_GetTime(&hRTC, &RTC_Time, RTC_FORMAT_BIN) && HAL_OK == HAL_RTC_GetDate(&hRTC, &RTC_Date, RTC_FORMAT_BIN)) {
uint16_t Year = RTC_Date.Year + 1900 + 68; //使Year获得值为当前年份
Result = (Year - 1970) * 365 * 24 * 3600 +(monDays[RTC_Date.Month - 1] + RTC_Date.Date) * 24 * 3600 +(RTC_Time.Hours) * 3600 + RTC_Time.Minutes * 60 + RTC_Time.Seconds;
Result += (RTC_Date.Month > 2 && (Year % 4 == 0) &&(Year % 100 != 0 || Year % 400 == 0)) *24 * 3600; //闰月
Year -= 1970;
Result += (Year / 4 - Year / 100 + Year / 400) * 24 * 3600; //闰年
Result = Result * 1000 + uint64_t((PREDIV_S_VALUE - RTC_Time.SubSeconds) * 999 / PREDIV_S_VALUE);
}
return Result;
}
|
RTC时间戳扩展
mbed-os\targets\TARGET_STM\TARGET_STM32F4\STM32Cube_FW\STM32F4xx_HAL_Driver目录下stm32f4xx_hal_rtc_ex.h
RTC的时间戳,通过PC13引脚的上升沿或者下降沿可以触发时间戳的中断函数。
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
| /**
* @brief Sets TimeStamp with Interrupt.
* @param hrtc pointer to a RTC_HandleTypeDef structure that contains
* the configuration information for RTC.
* @note This API must be called before enabling the TimeStamp feature.
* @param TimeStampEdge Specifies the pin edge on which the TimeStamp is
* activated.
* This parameter can be one of the following values:
* @arg RTC_TIMESTAMPEDGE_RISING: the Time stamp event occurs on the
* rising edge of the related pin.
* @arg RTC_TIMESTAMPEDGE_FALLING: the Time stamp event occurs on the
* falling edge of the related pin.
* @param RTC_TimeStampPin Specifies the RTC TimeStamp Pin.
* This parameter can be one of the following values:
* @arg RTC_TIMESTAMPPIN_DEFAULT: PC13 is selected as RTC TimeStamp Pin.
* @arg RTC_TIMESTAMPPIN_PI8: PI8 is selected as RTC TimeStamp Pin. (not applicable in the case of STM32F446xx, STM32F412xx, STM32F413xx and STM32F423xx devices)
* @arg RTC_TIMESTAMPPIN_PA0: PA0 is selected as RTC TimeStamp Pin only for STM32F446xx devices
* @retval HAL status
*/
HAL_StatusTypeDef HAL_RTCEx_SetTimeStamp_IT(RTC_HandleTypeDef *hrtc, uint32_t TimeStampEdge, uint32_t RTC_TimeStampPin);
/**
* @brief This function handles TimeStamp interrupt request.
* @param hrtc pointer to a RTC_HandleTypeDef structure that contains
* the configuration information for RTC.
* @retval None
*/
void HAL_RTCEx_TamperTimeStampIRQHandler(RTC_HandleTypeDef *hrtc);
|
结束语
因为硬件引脚触发中断获得时间戳的通用性不强,所以通常还是使用计算获得RTC时间戳。