江科大RTC实时时钟hal库实现

发布于:2025-06-03 ⋅ 阅读:(18) ⋅ 点赞:(0)

首先,因为的LSE无法启振,所以我使用LSI当作RTCCLK,LSI无法由备用电源供电,故主电源掉电时,RTC走时会暂停。

hal库相关函数

时分秒

typedef struct
{
  uint8_t Hours;            /*!< Specifies the RTC Time Hour.
                                 This parameter must be a number between Min_Data = 0 and Max_Data = 23 */

  uint8_t Minutes;          /*!< Specifies the RTC Time Minutes.
                                 This parameter must be a number between Min_Data = 0 and Max_Data = 59 */

  uint8_t Seconds;          /*!< Specifies the RTC Time Seconds.
                                 This parameter must be a number between Min_Data = 0 and Max_Data = 59 */

} RTC_TimeTypeDef;

闹钟结构体 

typedef struct
{
  RTC_TimeTypeDef AlarmTime;     /*!< Specifies the RTC Alarm Time members */

  uint32_t Alarm;                /*!< Specifies the alarm ID (only 1 alarm ID for STM32F1).
                                      This parameter can be a value of @ref RTC_Alarms_Definitions */
} RTC_AlarmTypeDef;

初始化结构体 

typedef struct
{
  uint32_t AsynchPrediv;    /*异步预分频器,对RTC时钟源进行分频*/

  uint32_t OutPut;          /*时钟输出*/

} RTC_InitTypeDef;

 日期结构体

typedef struct
{
  uint8_t WeekDay;  /*!< Specifies the RTC Date WeekDay (not necessary for HAL_RTC_SetDate).
                         This parameter can be a value of @ref RTC_WeekDay_Definitions */

  uint8_t Month;    /*!< Specifies the RTC Date Month (in BCD format).
                         This parameter can be a value of @ref RTC_Month_Date_Definitions */

  uint8_t Date;     /*!< Specifies the RTC Date.
                         This parameter must be a number between Min_Data = 1 and Max_Data = 31 */

  uint8_t Year;     /*!< Specifies the RTC Date Year.
                         This parameter must be a number between Min_Data = 0 and Max_Data = 99 */

} RTC_DateTypeDef;

句柄

#if (USE_HAL_RTC_REGISTER_CALLBACKS == 1)
typedef struct __RTC_HandleTypeDef
#else
typedef struct
#endif /* (USE_HAL_RTC_REGISTER_CALLBACKS) */
{
  RTC_TypeDef                 *Instance;  /*外设地址*/

  RTC_InitTypeDef             Init;       /*初始化结构体*/

  RTC_DateTypeDef             DateToUpdate;       /*初始化上电时间*/

  HAL_LockTypeDef             Lock;       /*配置锁存*/

  __IO HAL_RTCStateTypeDef    State;      /*当前状态*/

#if (USE_HAL_RTC_REGISTER_CALLBACKS == 1)
  void (* AlarmAEventCallback)(struct __RTC_HandleTypeDef *hrtc);           /*!< RTC Alarm A Event callback         */

  void (* Tamper1EventCallback)(struct __RTC_HandleTypeDef *hrtc);          /*!< RTC Tamper 1 Event callback        */

  void (* MspInitCallback)(struct __RTC_HandleTypeDef *hrtc);               /*!< RTC Msp Init callback              */

  void (* MspDeInitCallback)(struct __RTC_HandleTypeDef *hrtc);             /*!< RTC Msp DeInit callback            */

#endif /* (USE_HAL_RTC_REGISTER_CALLBACKS) */

} RTC_HandleTypeDef;

 初始化函数

HAL_StatusTypeDef HAL_RTC_Init(RTC_HandleTypeDef *hrtc);
HAL_StatusTypeDef HAL_RTC_DeInit(RTC_HandleTypeDef *hrtc);
void              HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc);
void              HAL_RTC_MspDeInit(RTC_HandleTypeDef *hrtc);

设置日期时间

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);

闹钟相关函数

HAL_StatusTypeDef HAL_RTC_SetAlarm(RTC_HandleTypeDef *hrtc, RTC_AlarmTypeDef *sAlarm, uint32_t Format);
HAL_StatusTypeDef HAL_RTC_SetAlarm_IT(RTC_HandleTypeDef *hrtc, RTC_AlarmTypeDef *sAlarm, uint32_t Format);
HAL_StatusTypeDef HAL_RTC_DeactivateAlarm(RTC_HandleTypeDef *hrtc, uint32_t Alarm);
HAL_StatusTypeDef HAL_RTC_GetAlarm(RTC_HandleTypeDef *hrtc, RTC_AlarmTypeDef *sAlarm, uint32_t Alarm, uint32_t Format);
void              HAL_RTC_AlarmIRQHandler(RTC_HandleTypeDef *hrtc);
HAL_StatusTypeDef HAL_RTC_PollForAlarmAEvent(RTC_HandleTypeDef *hrtc, uint32_t Timeout);
void              HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc);

hal库实现江科大 

首先就是对RTC的初始化,得开启BKP和PWR先关时钟,CubeMx帮我们开启了。

开启RTC时钟源,在时钟树那边设置RTC的时钟源,我选择的是LSI.

 BKP的相关函数在RTC和RTC_EX里面,没有专门的hal_BKP文件。

读写BKP函数

void HAL_RTCEx_BKUPWrite(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister, uint32_t Data)
uint32_t HAL_RTCEx_BKUPRead(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister)

对于江科大的相关函数,首先标准库里面很多的函数hal库里面都没有,所以得找个替换的方式,有些相关函数对于hal库是不起作用的,我们也得将他们删去。

//江科大RTC初始化函数
void MyRTC_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);//开启BKP,PWR时钟
	
	PWR_BackupAccessCmd(ENABLE);//使能通道
	
	if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)//判断BKP_DR1内容
	{
		RCC_LSICmd(ENABLE);//开启LSI时钟
		while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) != SET);//等待时钟就绪
		
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);//配置LSI到RTC的时钟
		RCC_RTCCLKCmd(ENABLE);
		
		RTC_WaitForSynchro();//等待时钟同步
		RTC_WaitForLastTask();
		
		RTC_SetPrescaler(40000 - 1);//配置预分频值
		RTC_WaitForLastTask();//等待上个工作完成
		
		MyRTC_SetTime();//设置时间
		
		BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);//写入BKP_DR1
	}
	else
	{
		RCC_LSICmd(ENABLE);				//即使不是第一次配置,也需要再次开启LSI时钟
		while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) != SET);
		
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
		RCC_RTCCLKCmd(ENABLE);
		
		RTC_WaitForSynchro();
		RTC_WaitForLastTask();
	}
}

这段代码里面,对于LSI和RTC的时钟是不需要我们进行配置的,CubeMX里面已经直接帮我们配置好且开启时钟了,我们只需要先开启BKP和PWR时钟,再对BKP进行读写和设置时间即可。

对于时分秒的计算,RTC的相关函数HAL_RTC_GetTime在函数里面对时间戳进行计算得到对应的时分秒,我们开启秒中断让他的时间戳一秒自增一次就行了。(内部自动进行自增)

秒中断 __HAL_RTC_SECOND_ENABLE_IT(&hrtc,RTC_IT_SEC);也在rtc_ex文件里面

hal库的日期读写则是通过读取RTC内部的寄存器内容来获取日期,日期也是在外面写入之后RTC内部自己进行维护的。

  RTC_DateTypeDef GetData;  //获取日期结构体
  RTC_TimeTypeDef GetTime;   //获取时间结构体
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  OLED_Init();
  MX_GPIO_Init();
  MX_RTC_Init();
    OLED_ShowString(1, 1, "Date:XXXX-XX-XX");
    OLED_ShowString(2, 1, "Time:XX:XX:XX");
//    OLED_ShowString(3, 1, "CNT :");
//    OLED_ShowString(4, 1, "DIV :");
  while (1)
  {
      HAL_RTC_GetTime(&hrtc,&GetTime,RTC_FORMAT_BIN);
      HAL_RTC_GetDate(&hrtc,&GetData,RTC_FORMAT_BIN);
    OLED_ShowNum(1, 6,(2000+GetData.Year), 4);		//显示MyRTC_Time数组中的时间值,年
    OLED_ShowNum(1, 11,GetData.Month, 2);		//月
    OLED_ShowNum(1, 14, GetData.Date, 2);		//日
    OLED_ShowNum(2, 6, GetTime.Hours, 2);		//时
    OLED_ShowNum(2, 9, GetTime.Minutes, 2);		//分
    OLED_ShowNum(2, 12, GetTime.Seconds, 2);		//秒
    HAL_Delay(1000);
    
//    OLED_ShowNum(3, 6, RTC_GetCounter(), 10);	//显示32位的秒计数器,没有相关函数,但是可以通过读写寄存器,或者对时间进行逻辑推导来实现
//    OLED_ShowNum(4, 6, RTC_GetDivider(), 10);	//显示余数寄存器
  }
}

日期的存入读取有问题,我们把日期存入BKP里面,第一次上电初始化的时候写入,其他时间上电从BKP里面读取,这样也能实现日期的正常读写。

void MX_RTC_Init(void)
{
  RTC_TimeTypeDef sTime = {0};
  RTC_DateTypeDef DateToUpdate = {0};
  __HAL_RCC_BKP_CLK_ENABLE();       //开启后备区域时钟
  __HAL_RCC_PWR_CLK_ENABLE();		  //开启电源时钟
  hrtc.Instance = RTC;
  hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
  hrtc.Init.OutPut = RTC_OUTPUTSOURCE_NONE;
  if (HAL_RTC_Init(&hrtc) != HAL_OK)
  {
    Error_Handler();
  }
  if(HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR1) != 0xA5A5){
      sTime.Hours = 15;
      sTime.Minutes = 51;
      sTime.Seconds = 0;
      
      if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
      {
        Error_Handler();
      }
      __HAL_RTC_SECOND_ENABLE_IT(&hrtc,RTC_IT_SEC);
      HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR1, 0xA5A5);//写入DR1的判断数据
      DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY;
      DateToUpdate.Month = RTC_MONTH_JUNE;
      DateToUpdate.Date = 02;
      DateToUpdate.Year = 25;
      if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK)
      {
        Error_Handler();
      }
      HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, (uint16_t)DateToUpdate.Year);
      HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR3, (uint16_t)DateToUpdate.Month);
      HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR4, (uint16_t)DateToUpdate.Date);
      HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR5, (uint16_t)DateToUpdate.WeekDay);
  }
  else{
      DateToUpdate.Year    = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR2);
      DateToUpdate.Month   = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR3);
      DateToUpdate.Date    = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR4);
      DateToUpdate.WeekDay = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR5);
      if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK)
      {
          Error_Handler();
      }
      __HAL_RTC_SECOND_ENABLE_IT(&hrtc,RTC_IT_SEC);	 //开启RTC时钟秒中断	
  }
}

代码参考了小璇的相关代码

这样也能实现江科大的RTC时钟了 


网站公告

今日签到

点亮在社区的每一天
去签到