解决STM32F1 系列复位后RTC日期为2000-01-01

问题:

STM32F1中RTC 不像 F4中,是一个单独模块。其就是一个计数器,查看HAL库中时间和日期的设置发现,在日期设置的时候,HAL库并没有将日期换算为计数器的值。

库源码如下

日期设置:

HAL_StatusTypeDef HAL_RTC_SetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format)
{
  uint32_t counter_time = 0U, counter_alarm = 0U;
  
  /* Check input parameters */
  if((hrtc == NULL) || (sTime == NULL))
  {
     return HAL_ERROR;
  }
  
 /* Check the parameters */
  assert_param(IS_RTC_FORMAT(Format));
  
  /* Process Locked */ 
  __HAL_LOCK(hrtc);
  
  hrtc->State = HAL_RTC_STATE_BUSY;
  
  if(Format == RTC_FORMAT_BIN)
  {
    assert_param(IS_RTC_HOUR24(sTime->Hours));
    assert_param(IS_RTC_MINUTES(sTime->Minutes));
    assert_param(IS_RTC_SECONDS(sTime->Seconds));


    counter_time = (uint32_t)(((uint32_t)sTime->Hours * 3600U) + \   //HAL库这里计算的时间,后面写入计数器的
                        ((uint32_t)sTime->Minutes * 60U) + \                         //也就是这个值
                        ((uint32_t)sTime->Seconds));  
  }
  else
  {
    assert_param(IS_RTC_HOUR24(RTC_Bcd2ToByte(sTime->Hours)));
    assert_param(IS_RTC_MINUTES(RTC_Bcd2ToByte(sTime->Minutes)));
    assert_param(IS_RTC_SECONDS(RTC_Bcd2ToByte(sTime->Seconds)));


    counter_time = (((uint32_t)(RTC_Bcd2ToByte(sTime->Hours)) * 3600U) + \
              ((uint32_t)(RTC_Bcd2ToByte(sTime->Minutes)) * 60U) + \
              ((uint32_t)(RTC_Bcd2ToByte(sTime->Seconds))));   
  }


  /* Write time counter in RTC registers */
  if (RTC_WriteTimeCounter(hrtc, counter_time) != HAL_OK)  //更新计数器,并没设计到日期
  {
    /* Set RTC state */
    hrtc->State = HAL_RTC_STATE_ERROR;
    
    /* Process Unlocked */ 
    __HAL_UNLOCK(hrtc);
    
    return HAL_ERROR;
  }
  else
  {
    /* Clear Second and overflow flags */
    CLEAR_BIT(hrtc->Instance->CRL, (RTC_FLAG_SEC | RTC_FLAG_OW));
    
    /* Read current Alarm counter in RTC registers */
    counter_alarm = RTC_ReadAlarmCounter(hrtc);


    /* Set again alarm to match with new time if enabled */
    if (counter_alarm != RTC_ALARM_RESETVALUE)
    {
      if(counter_alarm < counter_time)
      {
        /* Add 1 day to alarm counter*/
        counter_alarm += (uint32_t)(24U * 3600U);
        
        /* Write new Alarm counter in RTC registers */
        if (RTC_WriteAlarmCounter(hrtc, counter_alarm) != HAL_OK)
        {
          /* Set RTC state */
          hrtc->State = HAL_RTC_STATE_ERROR;
          
          /* Process Unlocked */ 
          __HAL_UNLOCK(hrtc);
          
          return HAL_ERROR;
        }
      }
    }
    
    hrtc->State = HAL_RTC_STATE_READY;
  
   __HAL_UNLOCK(hrtc); 
     
   return HAL_OK;
  }

}

HAL日期设置:

HAL_StatusTypeDef HAL_RTC_GetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format)
{
  uint32_t counter_time = 0U, counter_alarm = 0U, days_elapsed = 0U, hours = 0U;
  
  /* Check input parameters */
  if((hrtc == NULL) || (sTime == NULL))
  {
     return HAL_ERROR;
  }


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


  /* Check if counter overflow occurred */
  if (__HAL_RTC_OVERFLOW_GET_FLAG(hrtc, RTC_FLAG_OW))
  {
      return HAL_ERROR;
  }


  /* Read the time counter*/
  counter_time = RTC_ReadTimeCounter(hrtc);


  /* Fill the structure fields with the read parameters */
  hours = counter_time / 3600U;
  sTime->Minutes  = (uint8_t)((counter_time % 3600U) / 60U);
  sTime->Seconds  = (uint8_t)((counter_time % 3600U) % 60U);


  if (hours >= 24U)
  {
    /* Get number of days elapsed from last calculation */
    days_elapsed = (hours / 24U);


    /* Set Hours in RTC_TimeTypeDef structure*/
    sTime->Hours = (hours % 24U);    


    /* Read Alarm counter in RTC registers */
    counter_alarm = RTC_ReadAlarmCounter(hrtc);


    /* Calculate remaining time to reach alarm (only if set and not yet expired)*/
    if ((counter_alarm != RTC_ALARM_RESETVALUE) && (counter_alarm > counter_time))
    {
      counter_alarm -= counter_time;
    }
    else 
    {
      /* In case of counter_alarm < counter_time */
      /* Alarm expiration already occurred but alarm not deactivated */
      counter_alarm = RTC_ALARM_RESETVALUE;
    }


    /* Set updated time in decreasing counter by number of days elapsed */
    counter_time -= (days_elapsed * 24U * 3600U);
    
    /* Write time counter in RTC registers */
    if (RTC_WriteTimeCounter(hrtc, counter_time) != HAL_OK)
    {
      return HAL_ERROR;
    }


    /* Set updated alarm to be set */
    if (counter_alarm != RTC_ALARM_RESETVALUE)
    {
      counter_alarm += counter_time;
      
      /* Write time counter in RTC registers */
      if (RTC_WriteAlarmCounter(hrtc, counter_alarm) != HAL_OK)
      {
        return HAL_ERROR;
      }
    }
    else
    {
      /* Alarm already occurred. Set it to reset values to avoid unexpected expiration */
      if (RTC_WriteAlarmCounter(hrtc, counter_alarm) != HAL_OK)
      {
        return HAL_ERROR;
      }
    }
    
    /* Update date */
    RTC_DateUpdate(hrtc, days_elapsed);
  }
  else 
  {
    sTime->Hours = hours;    
  }


  /* Check the input parameters format */
  if(Format != RTC_FORMAT_BIN)
  {
    /* Convert the time structure parameters to BCD format */
    sTime->Hours    = (uint8_t)RTC_ByteToBcd2(sTime->Hours);
    sTime->Minutes  = (uint8_t)RTC_ByteToBcd2(sTime->Minutes);
    sTime->Seconds  = (uint8_t)RTC_ByteToBcd2(sTime->Seconds);  
  }
  
  return HAL_OK;

}

HAL在对日期设置的时候,只对RTC计数器进行减,就不谈加了。减的意思是,把大于一天的值去掉(days_elapsed * 24U * 3600U),只留下不满一天的时间

解决办法:

    现在我们已经知道了问题出在HAL库在设置RTC计数器的时候,没有计算日期,所以这里我们就不用HAL的时间和日期设置。当然,获取的方法也要改变

RTC 初始化:

void RTC_Init(void) 
{
rtc_handle.Instance = RTC;
rtc_handle.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
rtc_handle.Init.OutPut = RTC_OUTPUTSOURCE_NONE;
if(HAL_RTC_Init(&rtc_handle) != HAL_OK)
{
while(1 == 1)
{
;
}
}
if(HAL_RTCEx_BKUPRead(&rtc_handle, RTC_BKP_DR1) != 0x32F2)
{
rtc_time.Hours = 8;
rtc_time.Minutes = 0x01;
rtc_time.Seconds = 0x01;
if(HAL_RTC_SetTime(&rtc_handle, &rtc_time, RTC_FORMAT_BIN) != HAL_OK)
{
while(1 == 1)
{
;
}
}
rtc_date.WeekDay = RTC_WEEKDAY_MONDAY;
rtc_date.Month   = RTC_MONTH_MAY;
rtc_date.Date    = 0x01;
rtc_date.Year    = 0x12;
if(HAL_RTC_SetDate(&rtc_handle, &rtc_date, RTC_FORMAT_BIN) != HAL_OK)
{
while(1 == 1)
{
;
}
}
HAL_RTCEx_BKUPWrite(&rtc_handle, RTC_BKP_DR1, 0x32F2);
}
}


void HAL_RTC_MspInit(RTC_HandleTypeDef* hrtc)
{


RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;


__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWR_EnableBkUpAccess();
__HAL_RCC_BKP_CLK_ENABLE();


RCC_OscInitStruct.OscillatorType=RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.PLL.PLLState=RCC_PLL_NONE;
RCC_OscInitStruct.LSEState=RCC_LSE_ON;                 
HAL_RCC_OscConfig(&RCC_OscInitStruct);


PeriphClkInitStruct.PeriphClockSelection=RCC_PERIPHCLK_RTC;
PeriphClkInitStruct.RTCClockSelection=RCC_RTCCLKSOURCE_LSE;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);

__HAL_RCC_RTC_ENABLE();

}

实现自己的RTC 关于时间日期的获取和设置.这里用到了HAL库中的RTC计数器读(RTC_ReadTimeCounter)和写(RTC_WriteTimeCounter)函数。在库中,两个函数是静态函数,把static去掉,在头文件申明,以便我们使用

#define RTC_BASE_YEAR 2000

static const uint32_t day_sec = 86400;
static const uint32_t leap_y_s = 31622400;

static const uint32_t norm_y_s = 31536000;

static const int month_days[]={0,31,59,90,120,151,181,212,243,273,304,334,365};

//功能:获取传入的日期与基准日期的时间差,单位秒

uint32_t getSecformBase(int y,int m,int d)
{
int days =0;
uint32_t sec;
if(isLeapyear(y) > 0)
{
if( m > 2)
{
days = 1;
}
}
days += month_days[m-1];
days = days + d -1;
sec = ((uint32_t)days)*day_sec;
y--;
while(y >= 2000)
{
if(isLeapyear(y) > 0)
{
sec += leap_y_s;
}
else
{
sec += norm_y_s;
}
y--;
}
return sec;

}

//闰年判断

uint8_t isLeapyear(int year)
{
if(year%4==0) 

if(year%100==0) 

if(year%400==0)
{
return 1; 
}
else
{
return 0;   
}
}
else
{
return 1;   
}
}
else
{
return 0;
}
}

//时间设置

void RTC_setTime(RTC_TimeTypeDef * time) 
{
uint32_t t_c = RTC_ReadTimeCounter(&rtc_handle);
t_c = t_c - t_c%day_sec;
t_c += time->Hours*3600;
t_c += time->Minutes*60;
t_c += time->Seconds;
RTC_WriteTimeCounter(&rtc_handle,t_c);

}

//日期设置

void RTC_setDate(RTC_DateTypeDef * date) 
{
uint32_t diff_sec;
uint32_t t_c = RTC_ReadTimeCounter(&rtc_handle);
t_c %= day_sec;
diff_sec = getSecformBase(date->Year + RTC_BASE_YEAR,date->Month, date->Date);
t_c = t_c + diff_sec;
RTC_WriteTimeCounter(&rtc_handle,t_c);
}

//获取时间

void RTC_getTime(RTC_TimeTypeDef * time) {
uint32_t t_c = RTC_ReadTimeCounter(&rtc_handle);
t_c %= day_sec;
time->Hours = (uint8_t)(t_c /3600);
t_c %= 3600;
time->Minutes = (uint8_t)(t_c /60);
t_c %= 60;
time->Seconds = t_c;
}

//获取日期

void RTC_getDate(RTC_DateTypeDef * date) {
int year,yday,mon,mday,wday;
uint32_t t_c = RTC_ReadTimeCounter(&rtc_handle);
int days =(int)(t_c / day_sec);
days = days - (31 + 28) + 730484;  // 730484 为0 到 2000-1-1的天数
year = (days + 2) * 400 / (365 * 400 + 100 - 4 + 1);
  yday = days - (365 * year + year / 4 - year / 100 + year / 400);
if (yday < 0)
{
if((year % 4 == 0) && (year % 100 || (year % 400 == 0)))
{
yday = 366 + yday;
}
else
{
yday = 365 + yday;
}
year--;
}
mon = (yday + 31) * 10 / 306;
mday = yday - (367 * mon / 12 - 30) + 1;
if (yday >= 306) 
{
year++;
mon -= 10;
}
else 
{
mon += 2;
}
wday = (6 + days) % 7; //2000-1-1 是星期六
date->Date =(uint8_t) mday;
date->Month =(uint8_t) mon;
date->Year = (uint8_t)(year - RTC_BASE_YEAR);
date->WeekDay =(uint8_t) wday;
}


你可能感兴趣的:(经验)