OpenEdv-开源电子网

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

STM32F103 RTC简单日历功能

[复制链接]

0

主题

1

帖子

0

精华

新手入门

积分
17
金钱
17
注册时间
2019-10-22
在线时间
5 小时
发表于 2021-7-8 09:29:18 | 显示全部楼层 |阅读模式
本帖最后由 qianxilin 于 2021-7-8 09:36 编辑

STM32F103 RTC简单日历功能,这个只是日历功能,没有闹钟的功能。


STM32F103的RTC只有计数功能,虽然使用STM32CUBE可以配置日历功能,但是年月日,断电后就不能保存了。
大多折中的方法是把年月日保存到BKUP寄存器中。RTC开启秒中断,读取date然后保存年月日。
这种方法,如果断电太久,日期就会对比上。原子大哥的例程有实现日历的功能,并且带了闹钟。
实现原理都一样。
借用了<time.h>中的函数,保存到RTC计数器里面的值是时间戳。因此使用localtime()和mktime()函数来相互转换。
就不需要自己写代码去做年月日时分秒的计算了,如果要保存日期的话,直接用一个U32保存时间戳就行,用的时候用localtime()来转换就可以了。
操作RTC的一些函数在库里面是静态的,不能直接调用,我把代码考出来用。


主要代码:
  1. static void MX_RTC_Init(void)
  2. {

  3.   /* USER CODE BEGIN RTC_Init 0 */

  4.   /* USER CODE END RTC_Init 0 */

  5.   RTC_TimeTypeDef sTime = {0};
  6.   RTC_DateTypeDef DateToUpdate = {0};

  7.   /* USER CODE BEGIN RTC_Init 1 */

  8.   /* USER CODE END RTC_Init 1 */
  9.   /** Initialize RTC Only
  10.   */
  11.   hrtc.Instance = RTC;
  12.   hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
  13.   hrtc.Init.OutPut = RTC_OUTPUTSOURCE_NONE;
  14.   if (HAL_RTC_Init(&hrtc) != HAL_OK)
  15.   {
  16.     Error_Handler();
  17.   }

  18.   /* USER CODE BEGIN Check_RTC_BKUP */
  19. if(HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR1)!= 0x5051)
  20. {      
  21. #if 0
  22.   /* USER CODE END Check_RTC_BKUP */

  23.   /** Initialize RTC and set the Time and Date
  24.   */
  25.   sTime.Hours = 0;
  26.   sTime.Minutes = 0;
  27.   sTime.Seconds = 0;

  28.   if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
  29.   {
  30.     Error_Handler();
  31.   }
  32.   DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY;
  33.   DateToUpdate.Month = RTC_MONTH_JANUARY;
  34.   DateToUpdate.Date = 1;
  35.   DateToUpdate.Year = 21;

  36.   if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK)
  37.   {
  38.     Error_Handler();
  39.   }
  40.   /* USER CODE BEGIN RTC_Init 2 */
  41. #endif  
  42.    DateTimeSet(2021,7,7,18,55,40);
  43.    HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 0x5051);//向指定的后备区域寄存器写入数据
  44. }
复制代码


#include "MyRtc.h"


#define TIME_UTC_DF (8*60*60)  //和格林威治时间相差8小时-北京时间要减去8小时


extern RTC_HandleTypeDef hrtc;


static HAL_StatusTypeDef RTC_EnterInitMode(RTC_HandleTypeDef *hrtc)
{
  uint32_t tickstart = 0U;


  tickstart = HAL_GetTick();
  /* Wait till RTC is in INIT state and if Time out is reached exit */
  while ((hrtc->Instance->CRL & RTC_CRL_RTOFF) == (uint32_t)RESET)
  {
    if ((HAL_GetTick() - tickstart) >  RTC_TIMEOUT_VALUE)
    {
      return HAL_TIMEOUT;
    }
  }


  /* Disable the write protection for RTC registers */
  __HAL_RTC_WRITEPROTECTION_DISABLE(hrtc);




  return HAL_OK;
}


static HAL_StatusTypeDef RTC_ExitInitMode(RTC_HandleTypeDef *hrtc)
{
  uint32_t tickstart = 0U;


  /* Disable the write protection for RTC registers */
  __HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);


  tickstart = HAL_GetTick();
  /* Wait till RTC is in INIT state and if Time out is reached exit */
  while ((hrtc->Instance->CRL & RTC_CRL_RTOFF) == (uint32_t)RESET)
  {
    if ((HAL_GetTick() - tickstart) >  RTC_TIMEOUT_VALUE)
    {
      return HAL_TIMEOUT;
    }
  }


  return HAL_OK;
}


static HAL_StatusTypeDef My_RTC_WriteTimeCounter(RTC_HandleTypeDef *hrtc, uint32_t TimeCounter)
{
  HAL_StatusTypeDef status = HAL_OK;


   __HAL_LOCK(hrtc);
       
  /* Set Initialization mode */
  if (RTC_EnterInitMode(hrtc) != HAL_OK)
  {
    status = HAL_ERROR;
  }
  else
  {
    /* Set RTC COUNTER MSB word */
    WRITE_REG(hrtc->Instance->CNTH, (TimeCounter >> 16U));
    /* Set RTC COUNTER LSB word */
    WRITE_REG(hrtc->Instance->CNTL, (TimeCounter & RTC_CNTL_RTC_CNT));


    /* Wait for synchro */
    if (RTC_ExitInitMode(hrtc) != HAL_OK)
    {
      status = HAL_ERROR;
    }
  }
  
  __HAL_UNLOCK(hrtc);
  return status;
}




uint32_t My_RTC_ReadTimeCounter(RTC_HandleTypeDef *hrtc)
{
  uint16_t high1 = 0U, high2 = 0U, low = 0U;
  uint32_t timecounter = 0U;


  high1 = READ_REG(hrtc->Instance->CNTH & RTC_CNTH_RTC_CNT);
  low   = READ_REG(hrtc->Instance->CNTL & RTC_CNTL_RTC_CNT);
  high2 = READ_REG(hrtc->Instance->CNTH & RTC_CNTH_RTC_CNT);


  if (high1 != high2)
  {
    /* In this case the counter roll over during reading of CNTL and CNTH registers,
       read again CNTL register then return the counter value */
    timecounter = (((uint32_t) high2 << 16U) | READ_REG(hrtc->Instance->CNTL & RTC_CNTL_RTC_CNT));
  }
  else
  {
    /* No counter roll over during reading of CNTL and CNTH registers, counter
       value is equal to first value of CNTL and CNTH */
    timecounter = (((uint32_t) high1 << 16U) | low);
  }


  return timecounter;
}


//初始化系统时间 也就是把时间转换为时间戳
void DateTimeSet(int year, int month, int day, int hour, int min, int sec)
{
    time_t rawtime;
    struct tm * timeinfo;


    rawtime = 1577808000; //2020-1-1 00:00:00
    timeinfo = localtime ( &rawtime );
    timeinfo->tm_year = year - 1900;
    timeinfo->tm_mon  = month - 1;
    timeinfo->tm_mday = day;
    timeinfo->tm_hour = hour;
    timeinfo->tm_min  = min;
    timeinfo->tm_sec  = sec;
   
    rawtime=mktime(timeinfo);
    rawtime-=TIME_UTC_DF;  
   
        //LL_RTC_TIME_SetCounter(RTC,rawtime);  
        My_RTC_WriteTimeCounter(&hrtc,rawtime);
}


struct tm * GetDateTime(void)
{
    time_t rawtime;
        rawtime=My_RTC_ReadTimeCounter(&hrtc)+TIME_UTC_DF;//LL_RTC_TIME_Get(RTC)+TIME_UTC_DF;
    return localtime(&rawtime);
}

调用方法:
struct tm * timeinfo;
  for(;;)
  {
        timeinfo = GetDateTime();
        timeinfo->tm_year+=1900;
        timeinfo->tm_mon+=1;
         
    osDelay(1000);
  }

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

6

主题

890

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1481
金钱
1481
注册时间
2020-8-19
在线时间
336 小时
发表于 2021-7-8 11:33:11 | 显示全部楼层
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-5-23 16:05

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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