1.RTC初始化 (为了兼容有无外部晶振程序都可正常运行,增加和更改了初始化相关函数)
void hal_rtc_init(void)
{
uint32_t tickstart = 0;
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
HAL_PWR_EnableBkUpAccess(); //使能后备域访问
__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);设置外部低速晶振驱动能力
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
__HAL_RCC_LSE_CONFIG(RCC_OscInitStruct.LSEState); ///打开外部低速晶振
tickstart = HAL_GetTick();
while (READ_BIT(RCC->BDCR, RCC_BDCR_LSERDY) == 0U) /*读取LSE晶振准备状态*/
{
lse_check_flag = 1;
if ((HAL_GetTick() - tickstart) > LSE_CHECK_TIME) ///当准备时间大于LSE_CHECK_TIME时间 那么外部低速晶振检测失败 rtc使用内部低速晶振
{
lse_check_flag = 0;
break;
}
}
if(lse_check_flag) ///检测成功
{
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) ///设置外部晶振
{
Error_Handler();
}
}
MX_RTC_Init(); /初始化rtc
}
2.lse_check_flag主要用在下面函数中进行RTC的时钟配置,
void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
{
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
if(rtcHandle->Instance==RTC)
{
/* USER CODE BEGIN RTC_MspInit 0 */
if(lse_check_flag == 0) ///外部低速时钟检测失败 那么将内部低速时钟作为RTC时钟源
{
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
/* RTC clock enable */
__HAL_RCC_RTC_ENABLE();
__HAL_RCC_RTCAPB_CLK_ENABLE();
}
else ///检测成功 那么将外部低速时钟作为时钟源
{
/* USER CODE END RTC_MspInit 0 */
/** Initializes the peripherals clocks
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
/* RTC clock enable */
__HAL_RCC_RTC_ENABLE();
__HAL_RCC_RTCAPB_CLK_ENABLE();
/* USER CODE BEGIN RTC_MspInit 1 */
}
/* USER CODE END RTC_MspInit 1 */
}
}
3.时间戳和日期之间的相互转换
时间戳计算调用了头文件"time.h"函数,刚开始调用了gmtime这个函数,但是返回指针一直是NULL,后来参考在Keil MDK中无法使用gmtime函数进行时间戳转换_keil 5 时间戳-CSDN博客文章浏览阅读2.3k次,点赞4次,收藏11次。硬件平台STM32,软件平台Keil MDK 5.18由于项目中需要用到UNIX时间戳和日历的来回转换,于是想到C库函数里面有现成的函数可以使用。于直接使用mktime和gmtime两个函数进行时间戳转换,前者把日历转为时间戳,后者把时间戳转为日历。但是程序运行起来发现,gmtime得到的日历数据为乱码!!!经过调试才发现,这个函数返回值是NULL啊!!!查看反汇编代码,简直惊呆,这是什么鬼操作?汇编代码没有函数跳转,取而代之的是MOVS R0, #0_keil 5 时间戳https://blog.csdn.net/qq446252221/article/details/111625957,调用了localtime这个函数,gmtime和localtime的区别就是,gmtime返回的是GMT标准时间,而localtime返回的是本地时间。
何为本地时间?那就是带时区转换的时间,比如北京时间是东8区,与GMT时间相差8小时。
然而MDK库函数并没有直接设置时区的函数,因此locatime返回的仍然是GMT时间。
所以在使时localtime的时候,要先把时间戳加上28800秒(8小时)再进行转换,就能得到北京时间。
1)时间戳转换为日期:
/**
* @brief timestamp_set_clock 将时间戳转化为时间
* @param timestamp 需要转化的时间戳
* @param t 指向获取时间变量的指针
* @retval null
*/
static void timestamp_to_data(uint32_t timestamp,ts_rtc *t)
{
struct tm *timeinfo = NULL;
time_t t_stamp = 0;
t_stamp = (time_t)(timestamp + 28800);
timeinfo = localtime(&t_stamp);
t->Year = timeinfo->tm_year + 1900 - 2000; timeinfo得到的年份是从1900年开始 t.Year是从2000年开始
t->Month = timeinfo->tm_mon + 1; ///timeinfo的月份是从0开始 所以加一
t->Date = timeinfo->tm_mday;
t->Hours = timeinfo->tm_hour;
t->Minutes = timeinfo->tm_min;
t->Seconds = timeinfo->tm_sec;
}
timestamp + 28800,时间戳在原有的基础上加了28800也就是8小时,因为北京时间比标准时间快了8小时,
2)日期转换为时间戳:
/**
* @brief get_timestamp_value 将当前时间转化为时间戳
* @param timestamp 指向获取时间戳变量指针
* @retval null
*/
static void get_timestamp_value(uint32_t *timestamp)
{
ts_rtc date = {0};
time_t times;
struct tm tms;
hal_get_DateTime(&date); 获取当前时间
tms.tm_year = date.Year + 2000 - 1900; //C库函数的年份是从1900开始计算 date.Year是从2000年开始的,所以加上2000-1900
tms.tm_mon = date.Month - 1; //C库函数的月份是用0表示1月
tms.tm_mday = date.Date;
tms.tm_hour = date.Hours;
tms.tm_min = date.Minutes;
tms.tm_sec = date.Seconds;
times = mktime(&tms);
*timestamp = times - 28800; //北京时间:东8区偏移值
}