OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 15745|回复: 12

stm32f103用cubemx生成hal库的RTC程序年月日出错

[复制链接]

4

主题

63

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1194
金钱
1194
注册时间
2017-8-31
在线时间
295 小时
发表于 2017-12-12 14:15:19 | 显示全部楼层 |阅读模式
10金钱
如题,听说以后hal库是主流,于是想用stm32f103c8t6的板子学习一下,结果在RTC这块用cubemx生成hal库的工程,在又一次下载程序或复位后RTC时间不对,年月日为00-01-01,时分秒正常
网上找了一下,也有类似问题出现,但没找到解决方法,所以想问一下到底是什么问题导致这种情况出现。

[mw_shl_code=c,true]//cubemx生成的RTC配置,时钟配置在别处未包含进来
void MX_RTC_Init(void)
{
  RTC_TimeTypeDef sTime;
  RTC_DateTypeDef DateToUpdate;

    /**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();
  }

    /**Initialize RTC and set the Time and Date
    */
  if(HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1) != 0x32F2){
  sTime.Hours = 0x11;
  sTime.Minutes = 0x19;
  sTime.Seconds = 0x2;

  if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
  {
    Error_Handler();
  }

  DateToUpdate.WeekDay = RTC_WEEKDAY_TUESDAY;
  DateToUpdate.Month = RTC_MONTH_DECEMBER;
  DateToUpdate.Date = 0x12;
  DateToUpdate.Year = 0x17;

  if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BCD) != HAL_OK)
  {
    Error_Handler();
  }

    HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR1,0x32F2);
  }

}

//自己写的读RTC时间值并打印的程序
void RTC_Check()
{
        uint8_t time[6];
        RTC_TimeTypeDef sTime;
  RTC_DateTypeDef DateToUpdate;

        HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BCD);
        time[3]=sTime.Hours;
        time[4]=sTime.Minutes;
        time[5]=sTime.Seconds;
        HAL_RTC_GetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BCD);
        time[0]=DateToUpdate.Year;
        time[1]=DateToUpdate.Month;
        time[2]=DateToUpdate.Date;
        printf("Time:%02X-%02X-%02X %02X:%02X:%02X\r\n",time[0],time[1],time[2],time[3],time[4],time[5]);
}[/mw_shl_code]

ps.我用标准库程序时间都很正常,不知道为什么hal库的年月日就保存不了,但调试发现BKP寄存器0x32F2有写入值的
求知道原因的大大告诉我

最佳答案

查看完整内容[请看2#楼]

stm32F1的hal库,RTC设置时间函数HAL_RTC_GetDate不会将日期转换成计数值存进计数器,反而会读计数器值将值减小到时分秒的范围,不保存年月日,也不知道ST出于什么原因考虑这样设置,32位计数器能计数100多年却只用来保存时分秒
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

4

主题

63

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1194
金钱
1194
注册时间
2017-8-31
在线时间
295 小时
 楼主| 发表于 2017-12-12 14:15:20 | 显示全部楼层
stm32F1的hal库,RTC设置时间函数HAL_RTC_GetDate不会将日期转换成计数值存进计数器,反而会读计数器值将值减小到时分秒的范围,不保存年月日,也不知道ST出于什么原因考虑这样设置,32位计数器能计数100多年却只用来保存时分秒
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165377
金钱
165377
注册时间
2010-12-1
在线时间
2111 小时
发表于 2017-12-13 01:01:01 | 显示全部楼层
帮顶
回复

使用道具 举报

4

主题

63

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1194
金钱
1194
注册时间
2017-8-31
在线时间
295 小时
 楼主| 发表于 2017-12-13 15:40:34 | 显示全部楼层
本帖最后由 一起哈皮 于 2017-12-13 15:45 编辑

找到原因了,分析HAL_RTC_SetTime和HAL_RTC_SetDate函数,发现SETTime将时分秒存进RTC计数寄存器,但SetDate函数只是将年月日填进句柄hrtc的时间变量中,并没有转换成计数值填入RTC计数寄存器,断电自然像普通变量那样重启初始化值了
[mw_shl_code=c,true]HAL_StatusTypeDef HAL_RTC_SetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format)
{
  uint32_t counter_time = 0, counter_alarm = 0;
  
  /* 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;
  
       //转换填充32位计数值
  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 * 3600) + \
                        ((uint32_t)sTime->Minutes * 60) + \
                        ((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)) * 3600) + \
              ((uint32_t)(RTC_Bcd2ToByte(sTime->Minutes)) * 60) + \
              ((uint32_t)(RTC_Bcd2ToByte(sTime->Seconds))));   
  }

  /* 写数据到RTC_CNTH 和 RTC_CNTL寄存器*/
  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_BIT(hrtc->Instance->CRL, (RTC_FLAG_SEC | RTC_FLAG_OW));
   
    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)(24 * 3600);
        
        /* 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_StatusTypeDef HAL_RTC_SetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format)
{
  uint32_t counter_time = 0, counter_alarm = 0, hours = 0;
  
  /* Check input parameters */
  if((hrtc == NULL) || (sDate == NULL))
  {
     return HAL_ERROR;
  }
  
  /* Check the parameters */
  assert_param(IS_RTC_FORMAT(Format));
  
/* Process Locked */
__HAL_LOCK(hrtc);
  
  hrtc->State = HAL_RTC_STATE_BUSY;
  
        //RTC年月日值存句柄的变量DateToUpdate中
  if(Format == RTC_FORMAT_BIN)
  {   
    assert_param(IS_RTC_YEAR(sDate->Year));
    assert_param(IS_RTC_MONTH(sDate->Month));
    assert_param(IS_RTC_DATE(sDate->Date));

    /* Change the current date */
    hrtc->DateToUpdate.Year  = sDate->Year;
    hrtc->DateToUpdate.Month = sDate->Month;
    hrtc->DateToUpdate.Date  = sDate->Date;
  }
  else
  {   
    assert_param(IS_RTC_YEAR(RTC_Bcd2ToByte(sDate->Year)));
    assert_param(IS_RTC_MONTH(RTC_Bcd2ToByte(sDate->Month)));
    assert_param(IS_RTC_DATE(RTC_Bcd2ToByte(sDate->Date)));
   
    /* Change the current date */
    hrtc->DateToUpdate.Year  = RTC_Bcd2ToByte(sDate->Year);
    hrtc->DateToUpdate.Month = RTC_Bcd2ToByte(sDate->Month);
    hrtc->DateToUpdate.Date  = RTC_Bcd2ToByte(sDate->Date);
  }

  /* WeekDay set by user can be ignored because automatically calculated */
  hrtc->DateToUpdate.WeekDay = RTC_WeekDayNum(hrtc->DateToUpdate.Year, hrtc->DateToUpdate.Month, hrtc->DateToUpdate.Date);
  sDate->WeekDay = hrtc->DateToUpdate.WeekDay;

  /* Reset time to be aligned on the same day */
  /* 读RTC计数寄存器值*/
  counter_time = RTC_ReadTimeCounter(hrtc);

  /* Fill the structure fields with the read parameters */
  hours = counter_time / 3600;//根据计数器值计算共多少小时
  if (hours > 24)             //计数器值大于一天
  {
    /* Set updated time in decreasing counter by number of days elapsed */
    counter_time -= ((hours / 24) * 24 * 3600);//去掉年月日
    /* 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;
    }

    /* 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)(24 * 3600);
        
        /* 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 ;
  
  /* Process Unlocked */
  __HAL_UNLOCK(hrtc);
  
  return HAL_OK;   
}[/mw_shl_code]
回复

使用道具 举报

2

主题

62

帖子

0

精华

高级会员

Rank: 4

积分
711
金钱
711
注册时间
2019-5-17
在线时间
273 小时
发表于 2020-6-6 12:22:31 | 显示全部楼层
这个问题可以解决吗?  是不是要自己设置寄存器
回复

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
7
金钱
7
注册时间
2019-7-12
在线时间
1 小时
发表于 2021-3-6 22:37:24 | 显示全部楼层
我也发现同样的问题,请问大侠有找到解决办法吗?
回复

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
7
金钱
7
注册时间
2019-7-12
在线时间
1 小时
发表于 2021-3-6 22:40:10 | 显示全部楼层
一起哈皮 发表于 2017-12-13 15:40
找到原因了,分析HAL_RTC_SetTime和HAL_RTC_SetDate函数,发现SETTime将时分秒存进RTC计数寄存器,但SetDat ...

我也发现这个问题,只是把时间(时分秒)写入寄存器RTC_CNT,但是日期(年月日)没有存入寄存器,也就是保存的是不含年月日的时间戳,请问有什么解决办法吗?
回复

使用道具 举报

0

主题

6

帖子

0

精华

初级会员

Rank: 2

积分
67
金钱
67
注册时间
2021-1-19
在线时间
24 小时
发表于 2021-4-12 15:03:09 | 显示全部楼层
techtide 发表于 2021-3-6 22:40
我也发现这个问题,只是把时间(时分秒)写入寄存器RTC_CNT,但是日期(年月日)没有存入寄存器,也就是 ...

同求解决办法,难道要自己实现一个吗?
回复

使用道具 举报

0

主题

10

帖子

0

精华

初级会员

Rank: 2

积分
175
金钱
175
注册时间
2019-5-2
在线时间
50 小时
发表于 2021-7-27 22:22:19 | 显示全部楼层
同求解决方法
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165377
金钱
165377
注册时间
2010-12-1
在线时间
2111 小时
发表于 2021-8-17 13:40:14 | 显示全部楼层
ST根本就没设置年月日,只设置了时分秒
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

0

主题

10

帖子

0

精华

初级会员

Rank: 2

积分
133
金钱
133
注册时间
2017-5-5
在线时间
36 小时
发表于 2022-3-16 17:23:31 | 显示全部楼层
我也是这个问题,CUbeMX生成的代码,掉电第二天通电时间准确,日期不更新,也就星期也不更新,求解决办法或者发我邮箱,十分感谢,85968011@qq.com
回复

使用道具 举报

0

主题

5

帖子

0

精华

新手入门

积分
15
金钱
15
注册时间
2016-9-3
在线时间
1 小时
发表于 2022-4-2 11:47:18 | 显示全部楼层
回复

使用道具 举报

0

主题

5

帖子

0

精华

新手入门

积分
15
金钱
15
注册时间
2016-9-3
在线时间
1 小时
发表于 2022-4-2 11:51:11 | 显示全部楼层
85968011 发表于 2022-3-16 17:23
我也是这个问题,CUbeMX生成的代码,掉电第二天通电时间准确,日期不更新,也就星期也不更新,求解决办法或 ...

改造RTC_HAL库函数,让STM32F1XX也具有完美的日历功能

搜上面这个
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-27 17:24

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表