Получение времени безотказной работы от RTC

Я хотел получить время безотказной работы системы от RTC за секунды. Дело в том, что, хотя я могу суммировать значения из регистра времени RTC (RTC_TR), он работает только до 24 часов, а затем переполняется, пока один день добавляется в регистр даты RTC (RTC_DR).

Как отсчитать секунды с момента запуска системы? Мне не нужен календарь.

Ниже поясняется, что я имею в виду под "переполнением"

Я настроил RTC в соответствии с примером STM RTC_LSI для StdPeriph и установил только время, а не дату.

Однако, когда я получаю время от RTC_TR с помощью функции RTC_GetTime, после 23h59m59s время возвращается к 0h0m0s.

Конечно, RTC_TR хранит время в формате BCD в десятках и единицах текущего часа, минуты и секунды, а дни подсчитываются в RTC_DR. В любом случае я бы хотел, чтобы он продолжал добавлять часы, а не добавлять дни в регистр дат, поскольку я хочу рассчитывать только время безотказной работы, и я боюсь, что если я начну считать месяцы и дни, у меня возникнут проблемы.

void RtcConfig(void)
{
  RTC_InitTypeDef   RTC_InitStructure;
  RTC_TimeTypeDef   RTC_TimeStructure;
  RTC_DateTypeDef RTC_DateStructure;
  uint32_t LSIFreq = 0;

  /* Enable the PWR clock */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);

  /* Allow access to Backup Domain */
  PWR_BackupAccessCmd(ENABLE);

  /* Disable wake-up source(ALARM) to guarantee free access to WUT level-OR input */
  RTC_ITConfig(RTC_IT_ALRA, DISABLE);

  /* Clear Wakeup flag */
  PWR_ClearFlag(PWR_FLAG_WU);

  /* Enable wake-up source(ALARM) to guarantee free access to WUT level-OR input */
  RTC_ITConfig(RTC_IT_ALRA, ENABLE);

  /* Enable the LSI OSC */
  RCC_LSICmd(ENABLE);

  /* Wait till LSI is ready */
  while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
  {}

  /* Check if the StandBy flag is set (leaving stand-by) */
  if (PWR_GetFlagStatus(PWR_FLAG_SB) != RESET)
  {
    /* Clear StandBy flag */
    PWR_ClearFlag(PWR_FLAG_SB);

    /* Check if the StandBy flag is cleared */
    if (PWR_GetFlagStatus(PWR_FLAG_SB) != RESET)
    {
      while(1);
    }

    RTC_WaitForSynchro();

    /* No need to configure the RTC as the RTC config(clock source, enable,
    prescaler,...) are kept after wake-up from STANDBY */
  }
  else
  {
    /* RTC Configuration ******************************************************/
    /* Reset Backup Domain */
    RCC_BackupResetCmd(ENABLE);
    RCC_BackupResetCmd(DISABLE);

    /* Select the RTC Clock Source */
    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);

    /* Enable the RTC Clock */
    RCC_RTCCLKCmd(ENABLE);

    /* Wait for RTC APB registers synchronisation */
    RTC_WaitForSynchro();

    /* Get the LSI frequency:  TIM14 is used to measure the LSI frequency */
    LSIFreq = GetLSIFrequency();

    RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;
    RTC_InitStructure.RTC_AsynchPrediv = 99;
    RTC_InitStructure.RTC_SynchPrediv =  (LSIFreq/100) - 1;

    RTC_Init(&RTC_InitStructure);

    /* Set the time to 00h 00mn 00s AM */
    RTC_TimeStructure.RTC_H12     = RTC_H12_PM;
    RTC_TimeStructure.RTC_Hours   = 0;
    RTC_TimeStructure.RTC_Minutes = 0;
    RTC_TimeStructure.RTC_Seconds = 0;
    RTC_SetTime(RTC_Format_BIN, &RTC_TimeStructure);
  }
}

uint32 GetLSIFrequency(void)
{
  NVIC_InitTypeDef   NVIC_InitStructure;
  TIM_ICInitTypeDef  TIM_ICInitStructure;
  RCC_ClocksTypeDef  RCC_ClockFreq;

  /* TIM14 configuration *******************************************************/
  /* Enable TIM14 clock */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE);

  /* Reset TIM14 registers */
  TIM_DeInit(TIM14);

  /* Configure TIM14 prescaler */
  TIM_PrescalerConfig(TIM14, 0, TIM_PSCReloadMode_Immediate);

  /* Connect internally the TIM14_CH1 to the RTC clock output */
  TIM_RemapConfig(TIM14, TIM14_RTC_CLK);

  /* TIM14 configuration: Input Capture mode ---------------------
     The reference clock(LSE or external) is connected to TIM14 CH1
     The Rising edge is used as active edge,
     The TIM14 CCR1 is used to compute the frequency value
  ------------------------------------------------------------ */
  TIM_ICInitStructure.TIM_Channel     = TIM_Channel_1;
  TIM_ICInitStructure.TIM_ICPolarity  = TIM_ICPolarity_Rising;
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV8;
  TIM_ICInitStructure.TIM_ICFilter = 0x0;
  TIM_ICInit(TIM14, &TIM_ICInitStructure);

  /* Enable the TIM14 global Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM14_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  /* Enable TIM14 counter */
  TIM_Cmd(TIM14, ENABLE);

  /* Reset the flags */
  TIM14->SR = 0;

  /* Enable the CC1 Interrupt Request */
  TIM_ITConfig(TIM14, TIM_IT_CC1, ENABLE);


  /* Wait until the TIM14 get 2 LSI edges (refer to TIM14_IRQHandler() in
    stm32F0xx_it.c file) ******************************************************/
  while(CaptureNumber != 2)
  {
  }
  /* Deinitialize the TIM14 peripheral registers to their default reset values */
  TIM_DeInit(TIM14);


  /* Compute the LSI frequency, depending on TIM14 input clock frequency (PCLK1)*/
  /* Get SYSCLK, HCLK and PCLKx frequency */
  RCC_GetClocksFreq(&RCC_ClockFreq);

  /* Disable TIM14 counter */
  TIM_Cmd(TIM14, DISABLE);
  TIM_ITConfig(TIM14, TIM_IT_CC1, DISABLE);

  /* PCLK1 prescaler equal to 1 => TIMCLK = PCLK1 */
  return ((RCC_ClockFreq.PCLK_Frequency / PeriodValue) * 8);
}

void RTC_GetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct)
{
  uint32_t tmpreg = 0;

  /* Check the parameters */
  assert_param(IS_RTC_FORMAT(RTC_Format));

  /* Get the RTC_TR register */
  tmpreg = (uint32_t)(RTC->TR & RTC_TR_RESERVED_MASK); 

  /* Fill the structure fields with the read parameters */
  RTC_TimeStruct->RTC_Hours = (uint8_t)((tmpreg & (RTC_TR_HT | RTC_TR_HU)) >> 16);
  RTC_TimeStruct->RTC_Minutes = (uint8_t)((tmpreg & (RTC_TR_MNT | RTC_TR_MNU)) >>8);
  RTC_TimeStruct->RTC_Seconds = (uint8_t)(tmpreg & (RTC_TR_ST | RTC_TR_SU));
  RTC_TimeStruct->RTC_H12 = (uint8_t)((tmpreg & (RTC_TR_PM)) >> 16);  

  /* Check the input parameters format */
  if (RTC_Format == RTC_Format_BIN)
  {
    /* Convert the structure parameters to Binary format */
    RTC_TimeStruct->RTC_Hours = (uint8_t)RTC_Bcd2ToByte(RTC_TimeStruct->RTC_Hours);
    RTC_TimeStruct->RTC_Minutes = (uint8_t)RTC_Bcd2ToByte(RTC_TimeStruct->RTC_Minutes);
    RTC_TimeStruct->RTC_Seconds = (uint8_t)RTC_Bcd2ToByte(RTC_TimeStruct->RTC_Seconds);
  }
}

uint32 RtcGetTimeSec(void)
{
  RTC_TimeTypeDef  RTC_TimeStructure;

  uint32 currenttimesec = 0;

  /* Get the Current time in second */
  RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure);
  currenttimesec = ((RTC_TimeStructure.RTC_Hours * 3600) +(RTC_TimeStructure.RTC_Minutes * 60) +
    RTC_TimeStructure.RTC_Seconds);

  return currenttimesec;
}

person Paweł J    schedule 19.06.2017    source источник


Ответы (1)


Что значит переполнение. Покажи свой код и математику

В 32-битном формате вы можете хранить:

Seconds         Hours            Days              Years
4294967295      1193046.471      49710.26962       136.1925195

Если ваше прогнозируемое время безотказной работы составляет более 136,2 года, используйте 64-битное целое число без знака, и вы сможете сосчитать до:

Seconds                 Hours               Days            Years           Decades     Centuries   Millenniums Aeons (10e9 years)
18446744073709600000    5124095576030430    213503982334601 584942417355    58494241736 5849424174  584942417   585

Надеюсь, вам этого будет достаточно.

person 0___________    schedule 19.06.2017
comment
Спасибо за ваш ответ. Код добавлен к вопросу. - person Paweł J; 20.06.2017