STM32F030R8Tx HAL库实现RTC 1秒中断

  • 工程准备,在以下链接工程的基础上添加的RTC功能

https://blog.csdn.net/mygod2008ok/article/details/106750657

  • 在工程中添加stm32f0xx_hal_rtc.c

STM32F030R8Tx HAL库实现RTC 1秒中断_第1张图片

  • 在stm32f0xx_hal_conf.h中打开HAL_RTC_MODULE_ENABLED宏

STM32F030R8Tx HAL库实现RTC 1秒中断_第2张图片

  • 新建BSP_rtc.c和BSP_rtc.h文件并加入工程

STM32F030R8Tx HAL库实现RTC 1秒中断_第3张图片

  • 初时化RTC,由于使用内部40KHz LSI时钟源,如果AsynchPrediv的分频值为128分频,则SynchPrediv的理论分频值

    为40000Hz/128 = 312.5,本例程中暂时使用311分频,等会进行实

    际测量进行校准

/* RTC init function */
void MX_RTC_Init(void)
{
  RTC_TimeTypeDef sTime;
  RTC_DateTypeDef sDate;
  RTC_AlarmTypeDef sAlarm;

    /**Initialize RTC Only 
    */
  hrtc.Instance = RTC;
  hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
  hrtc.Init.AsynchPrediv = 127;
  hrtc.Init.SynchPrediv = 310;
  hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
  hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
  hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
  HAL_StatusTypeDef err_code = HAL_RTC_Init(&hrtc);
  APP_ERROR_CHECK(err_code);

    /**Initialize RTC and set the Time and Date 
    */
  sTime.Hours = 0x0;
  sTime.Minutes = 0x0;
  sTime.Seconds = 0x0;
  sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  sTime.StoreOperation = RTC_STOREOPERATION_RESET;
  err_code = HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
  APP_ERROR_CHECK(err_code);

  sDate.WeekDay = RTC_WEEKDAY_MONDAY;
  sDate.Month = RTC_MONTH_JUNE;
  sDate.Date = 0x1;
  sDate.Year = 0x0;

  err_code = HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
  APP_ERROR_CHECK(err_code);

    /**Enable the Alarm A 
    */
  sAlarm.AlarmTime.Hours = 0;
  sAlarm.AlarmTime.Minutes = 0;
  sAlarm.AlarmTime.Seconds = 1;
  sAlarm.AlarmTime.SubSeconds = 0;
  sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
  sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS
                              |RTC_ALARMMASK_MINUTES;
  sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
  sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
  sAlarm.AlarmDateWeekDay = 1;
  sAlarm.Alarm = RTC_ALARM_A;
  err_code = HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN);
  APP_ERROR_CHECK(err_code);

}
  • RTC重置函数,保证秒钟到达1产生一次中断

/* USER CODE BEGIN 1 */
void TimeRsset(void)
{
	  RTC_TimeTypeDef sTime;
	  sTime.Hours = 0x0;
    sTime.Minutes = 0x0;
    sTime.Seconds = 0x0;
    sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
    sTime.StoreOperation = RTC_STOREOPERATION_RESET;
    HAL_StatusTypeDef err_code = HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD);
	  APP_ERROR_CHECK(err_code);
   
}
  • 重写HAL_RTC_MspInit和HAL_RTC_MspDeInit两个函数


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 */
	  HAL_NVIC_SetPriority(RTC_IRQn, 2, 0);
    HAL_NVIC_EnableIRQ(RTC_IRQn);
  /* 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();

    /* RTC interrupt Deinit */
    HAL_NVIC_DisableIRQ(RTC_IRQn);
  /* USER CODE BEGIN RTC_MspDeInit 1 */

  /* USER CODE END RTC_MspDeInit 1 */
  }
} 
  • 重写HAL_RTC_AlarmAEventCallback回调函数,并在函数内调用重置RTC函数

void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
	TimeRsset();
}
  • RTC校准函数,校准参数由实际硬件测量出 

/**
* @brief 校验1HZ RTC频率
*/
void cali_rtc(uint32_t ms)
{
  uint32_t t	= hrtc.Init.SynchPrediv+1;
  t = t * 1000000/ms;
	
  hrtc.Init.SynchPrediv = t;
  NRF_LOG_INFO("cali=%d\n",hrtc.Init.SynchPrediv );
  HAL_StatusTypeDef err_code = HAL_RTC_Init(&hrtc);
  APP_ERROR_CHECK(err_code);
}
  • 在stm32f0xx_it.h中,自定义一个校准状态的枚举变量类型

typedef enum
{
	CALI_RTC_BEGING_TIME,
	CALI_RTC_END_TIME,
	CALI_RTC_FINISH,
}E_CALI_RTC_PROGRESS;
  • 在RTC_IRQHandler中进行时间测量,每秒中断进入后计算实际的时间,得出的时间进行RTC校准

/**
  * @brief  This function handles RTC Alarm interrupt request.
  * @param  None
  * @retval None
  */
void RTC_IRQHandler(void)
{
 HAL_RTC_AlarmIRQHandler(&hrtc);

 s_wakeup_flag |= TICK_FOR_1HZ;
// NRF_LOG_INFO("RTC_IRQHandler");

	if(cali_rtc_flag == CALI_RTC_BEGING_TIME)
	{
		cali_rtc_flag = CALI_RTC_END_TIME;
		BSP_tim14_init();
	}
	else if(cali_rtc_flag==CALI_RTC_END_TIME)
	{
		cali_rtc_flag = CALI_RTC_FINISH;
		uint32_t t = BSP_tim14_deinit();
		cali_rtc(t);
//		NRF_LOG_INFO("RTC_IRQHandler %d\n",t);
	}

校准步骤:

    首先第一次进入RTC中断启动TIM14,第二次中断进入后停止TIM14,2次中断所花的时间作为参数进行RTC 1秒校准参数

  • 如果要定时进行校准,则用如下函数进行定时校

#define CALI_RTC_INTERVAL   6   // 测试6秒钟校验一次,一般1小时以上检验一次
/**
* @brief 每天校验一次
* @note 此函数在1HZ中调用
*/
void start_cali_rtc(void)
{
	static uint32_t tick_cnt;
	if(++tick_cnt > CALI_RTC_INTERVAL)
	{
		tick_cnt = 0;
		cali_rtc_flag = 0;
	}
}
  • 在1Hz中调用start_cali_rtc函数,这里每6秒会触发一次RTC校准

/**
* @brief 1Hz handler
*
*/
static void tick_1hz_handler(void)
{
	if((s_wakeup_flag & TICK_FOR_1HZ) == 0)
	  return;
	s_wakeup_flag &= CLEAR_TICK_FOR_1HZ;
	//####################################################################################
	//---------TODO this to add 1hz event handler-----------
	start_cali_rtc();
	
}

 

  • 在main函数中调用1Hz处理函数

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
	RTT_INIT();
  HAL_Init();
  SystemClock_Config();
 
  BSP_wdt_init(5000);
   
  delay_init();

	
  MX_RTC_Init();
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
     if(s_wakeup_flag)  //任务处理模式
     {
	BSP_wdt_feed();
	tick_25hz_handler();
	tick_1hz_handler();
     }
     else  // 省电模式
    {
    }
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
  • 运行结果,校准后的LSI实际频率为

               128*(291+1)= 37376Hz 

STM32F030R8Tx HAL库实现RTC 1秒中断_第4张图片

  • 例程下载链接

https://download.csdn.net/download/mygod2008ok/12522792

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(STM32,HAL库)