STM32启用 time.h 弥补RTC的不足

由于STM32F103系列 内部的RTC只是普通的定时器 无法作为断电保存使用,这里将演示一种低成本高兼容性的解决方案,重定向启用time.h头文件,将规范工程结构 节省大量时间

time.h头文件介绍

tm 结构的定义如下:

struct tm {
   int tm_sec;         /* 秒,范围从 0 到 59        */
   int tm_min;         /* 分,范围从 0 到 59        */
   int tm_hour;        /* 小时,范围从 0 到 23        */
   int tm_mday;        /* 一月中的第几天,范围从 1 到 31    */
   int tm_mon;         /* 月,范围从 0 到 11        */
   int tm_year;        /* 自 1900 年起的年数        */
   int tm_wday;        /* 一周中的第几天,范围从 0 到 6    */
   int tm_yday;        /* 一年中的第几天,范围从 0 到 365    */
   int tm_isdst;       /* 夏令时                */
};

关键函数功能介绍


clock_t clock(void)//返回程序执行起(一般为程序的开头),处理器时钟所使用的时间。
double difftime(time_t time1, time_t time2)返回 time1 和 time2 之间相差的秒数 (time1-time2)。
time_t time(time_t *timer)计算当前日历时间,并把它编码成 time_t 格式。
struct tm *localtime(const time_t *timer)timer 的值被分解为 tm 结构,并用本地时区表示。
time_t mktime(struct tm *timeptr)把 timeptr 所指向的结构转换为一个依据本地时区的 time_t 值。

需要重写两个接口

// rtc.c

_ARMABI time_t time(time_t * timer)
{
	uint32_t nTime=RTC_ReadTimeCounter(&hrtc);
	if(timer!=NULL)
	{
		*timer=nTime;
	}
	return nTime;
}
_ARMABI clock_t clock(void)
{
	return HAL_GetTick();
}

//用户增加 设置时间接口
//设置系统时间 返回时间戳 
time_t setTime(struct tm * timeptr)
{
	time_t nTime=0;
	if(timeptr!=NULL)
	{
		nTime=mktime(timeptr);
		RTC_WriteTimeCounter(&hrtc,nTime);
	}
	return nTime;	
}

重写说明 通过翻阅HAL_RTC源码可知 RTC_ReadTimeCounter RTC_WriteTimeCounter 是真正的用于操作RTC计数器的,cloc() 函数在time.h中的定义就是CPU计数,这里为了规范也一并重写了
RTC_WriteTimeCounter RTC_WriteTimeCounter 这两个函数在 stm32f1xx_hal_rtc.c里被定义为static类型 直接拷贝出来放 cubeMX生成的rtc.c里就行了 后续也不需要直接调用它,所以仍然采用static 定义即可

调用使用演示

//test RTC 
		LOG_D("\r\n\r\n time.h test");
		clock_t  ck= clock();
		LOG_D("clock:ck:%d",ck);
		time_t timer= time(NULL);
		LOG_D("time:tm:%d",timer);
		/* Read the time counter*/
		struct tm  st_tm=  *gmtime(&timer);
		LOG_D("localtime:%04d-%02d-%02d %02d:%02d:%02d",st_tm.tm_year+1900,st_tm.tm_mon,st_tm.tm_mday,st_tm.tm_hour,st_tm.tm_min,st_tm.tm_sec);

初始化流程演示

	#define RTC_BKP 0x1235
	if(HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR1)== RTC_BKP)
	{
		LOG_D("RTC ok");
		return ;
	}
	else
	{
		LOG_D("RTC need init");
		HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR1,RTC_BKP);
	}
	struct tm nTime={/*tm_sec*/0,/*tm_min*/0,/*tm_hour*/12,/*tm_mday*/22,
		/*tm_mon*/9,/*tm_year */2022-1900};
		setTime(&nTime);

待解决问题

  1. gmtime 无法使用
  2. 获取到的时间是1970年开始的 不方便直接使用

最后

修改CubeMX生成的rtc.c 完成源码

/**
  ******************************************************************************
  * @file    rtc.c
  * @brief   This file provides code for the configuration
  *          of the RTC instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "rtc.h"

/* USER CODE BEGIN 0 */
static uint32_t RTC_ReadTimeCounter(RTC_HandleTypeDef *hrtc);
static HAL_StatusTypeDef RTC_WriteTimeCounter(RTC_HandleTypeDef *hrtc, uint32_t TimeCounter);
/* USER CODE END 0 */

RTC_HandleTypeDef hrtc;

/* RTC init function */
void MX_RTC_Init(void)
{

  /* USER CODE BEGIN RTC_Init 0 */

  /* USER CODE END RTC_Init 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 */
	#define RTC_BKP 0x1235
	if(HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR1)== RTC_BKP)
	{
		LOG_D("RTC ok");
		return ;
	}
	else
	{
		LOG_D("RTC need init");
		HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR1,RTC_BKP);
	}
	struct tm nTime={/*tm_sec*/0,/*tm_min*/0,/*tm_hour*/12,/*tm_mday*/22,
		/*tm_mon*/9,/*tm_year */2022-1900};
		setTime(&nTime);
  /* USER CODE END Check_RTC_BKUP */

  /** Initialize RTC and set the Time and Date
  */

  /* USER CODE BEGIN RTC_Init 2 */

  /* USER CODE END RTC_Init 2 */

}

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();
  /* USER CODE BEGIN RTC_MspInit 1 */

  /* USER CODE END RTC_MspInit 1 */
  }
}

void HAL_RTC_MspDeInit(RTC_HandleTypeDef* rtcHandle)
{

  if(rtcHandle->Instance==RTC)
  {
  /* USER CODE BEGIN RTC_MspDeInit 0 */

  /* USER CODE END RTC_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_RTC_DISABLE();
  /* USER CODE BEGIN RTC_MspDeInit 1 */

  /* USER CODE END RTC_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
_ARMABI time_t time(time_t * timer)
{
	uint32_t nTime=RTC_ReadTimeCounter(&hrtc);
	if(timer!=NULL)
	{
		*timer=nTime;
	}
	return nTime;
}
_ARMABI clock_t clock(void)
{
	return HAL_GetTick();
}
//设置系统时间 返回时间戳 
time_t setTime(struct tm * timeptr)
{
	time_t nTime=0;
	if(timeptr!=NULL)
	{
		nTime=mktime(timeptr);
		RTC_WriteTimeCounter(&hrtc,nTime);
	}
	return nTime;	
}
/**
  * @brief  Read the time counter available in RTC_CNT registers.
  * @param  hrtc   pointer to a RTC_HandleTypeDef structure that contains
  *                the configuration information for RTC.
  * @retval Time counter
  */
static uint32_t RTC_ReadTimeCounter(RTC_HandleTypeDef *hrtc)
{
  uint16_t high1 = 0U, high2 = 0U, low = 0U;
  uint32_t timecounter = 0U;

  high1 = READ_REG(hrtc->Instance->CNTH & RTC_CNTH_RTC_CNT);
  low   = READ_REG(hrtc->Instance->CNTL & RTC_CNTL_RTC_CNT);
  high2 = READ_REG(hrtc->Instance->CNTH & RTC_CNTH_RTC_CNT);

  if (high1 != high2)
  {
    /* In this case the counter roll over during reading of CNTL and CNTH registers,
       read again CNTL register then return the counter value */
    timecounter = (((uint32_t) high2 << 16U) | READ_REG(hrtc->Instance->CNTL & RTC_CNTL_RTC_CNT));
  }
  else
  {
    /* No counter roll over during reading of CNTL and CNTH registers, counter
       value is equal to first value of CNTL and CNTH */
    timecounter = (((uint32_t) high1 << 16U) | low);
  }

  return timecounter;
}
/**
  * @brief  Enters the RTC Initialization mode.
  * @param  hrtc   pointer to a RTC_HandleTypeDef structure that contains
  *                the configuration information for RTC.
  * @retval HAL status
  */
static HAL_StatusTypeDef RTC_EnterInitMode(RTC_HandleTypeDef *hrtc)
{
  uint32_t tickstart = 0U;

  tickstart = HAL_GetTick();
  /* Wait till RTC is in INIT state and if Time out is reached exit */
  while ((hrtc->Instance->CRL & RTC_CRL_RTOFF) == (uint32_t)RESET)
  {
    if ((HAL_GetTick() - tickstart) >  RTC_TIMEOUT_VALUE)
    {
      return HAL_TIMEOUT;
    }
  }

  /* Disable the write protection for RTC registers */
  __HAL_RTC_WRITEPROTECTION_DISABLE(hrtc);


  return HAL_OK;
}
/**
  * @brief  Exit the RTC Initialization mode.
  * @param  hrtc   pointer to a RTC_HandleTypeDef structure that contains
  *                the configuration information for RTC.
  * @retval HAL status
  */
static HAL_StatusTypeDef RTC_ExitInitMode(RTC_HandleTypeDef *hrtc)
{
  uint32_t tickstart = 0U;

  /* Disable the write protection for RTC registers */
  __HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);

  tickstart = HAL_GetTick();
  /* Wait till RTC is in INIT state and if Time out is reached exit */
  while ((hrtc->Instance->CRL & RTC_CRL_RTOFF) == (uint32_t)RESET)
  {
    if ((HAL_GetTick() - tickstart) >  RTC_TIMEOUT_VALUE)
    {
      return HAL_TIMEOUT;
    }
  }

  return HAL_OK;
}
/**
  * @brief  Write the time counter in RTC_CNT registers.
  * @param  hrtc   pointer to a RTC_HandleTypeDef structure that contains
  *                the configuration information for RTC.
  * @param  TimeCounter: Counter to write in RTC_CNT registers
  * @retval HAL status
  */
static HAL_StatusTypeDef RTC_WriteTimeCounter(RTC_HandleTypeDef *hrtc, uint32_t TimeCounter)
{
  HAL_StatusTypeDef status = HAL_OK;

  /* Set Initialization mode */
  if (RTC_EnterInitMode(hrtc) != HAL_OK)
  {
    status = HAL_ERROR;
  }
  else
  {
    /* Set RTC COUNTER MSB word */
    WRITE_REG(hrtc->Instance->CNTH, (TimeCounter >> 16U));
    /* Set RTC COUNTER LSB word */
    WRITE_REG(hrtc->Instance->CNTL, (TimeCounter & RTC_CNTL_RTC_CNT));

    /* Wait for synchro */
    if (RTC_ExitInitMode(hrtc) != HAL_OK)
    {
      status = HAL_ERROR;
    }
  }

  return status;
}

/* USER CODE END 1 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

为了避免 别人调用HAL_RTC接口 ,头文件也进行必要改动

/**
  ******************************************************************************
  * @file    rtc.h
  * @brief   This file contains all the function prototypes for
  *          the rtc.c file
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __RTC_H__
#define __RTC_H__

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* USER CODE BEGIN Includes */
#define __CLK_TCK 1000
#include <time.h>
/* USER CODE END Includes */

extern RTC_HandleTypeDef hrtc;

/* USER CODE BEGIN Private defines */

//don't use them   
	#define HAL_RTC_SetTime
	#define HAL_RTC_GetTime
	#define HAL_RTC_SetDate
	#define HAL_RTC_GetDate

/* USER CODE END Private defines */

void MX_RTC_Init(void);

/* USER CODE BEGIN Prototypes */
//重写这部分功能
//获得系统滴答时钟 ms
extern _ARMABI clock_t clock(void);
//获得自1900-01-01 00:00:00 秒
extern _ARMABI time_t time(time_t * /*timer*/);

//设置系统时间 返回时间戳 
time_t setTime(struct tm * timeptr);
/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif

#endif /* __RTC_H__ */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值