stm32cube 生成RTC时钟

芯片是stm32f407ve
软件 stm32cubemx5.3.0 和keil5
F4的RTC提供了日历时钟和两个可编程闹钟中断,一个周期性可编程唤醒标志。这样很方便设置系统时间,并不会像F1的RTC那样要自己计算年月日时分秒。F4的RTC是一个独立的BCD定时计数器,系统可以自动将月份天数补偿为28、29(闰年)、30、31天。并且还可以进行夏令时补偿。

1、设置RCC

在这里插入图片描述
RTC设备因为其独特的运行方式(即掉电依旧运行)使用HSE分频时钟或者LSI的时候,在主电源VDD掉电的情况下,这两个时钟来源都会受到影响,资源消耗太大,小小的纽扣电池根本吃不消。没法保证RTC正常工作.所以RTC一般都时钟低速外部时钟LSE。

2、设置RTC

在这里插入图片描述
Activate Clock Source 激活时钟源
Activate calendar 激活日历
在这里插入图片描述
设置初始的时间、日期和格式
低速的外部晶振我使用的是32768Hz的,根据计算公式
RTC时钟频率 = RTC时钟源 / ((Asynchronous Predivider value + 1) * (Synchronous Predivider value + 1))
32.768KHz / ((127+1)*(255+1)) = 1Hz,也就是1秒

Binary data format 十进制
BCD data format BCD码进制

3、编写代码

生成工程后就可以读取时间和日期了

	RTC_TimeTypeDef GetTime;
	RTC_DateTypeDef GetData;
	GUI_SetColor(GUI_BLACK);
	GUI_SetBkColor(GUI_WHITE); 
	GUI_SetFont(pFont_22);		
	HAL_RTC_GetTime(&hrtc,&GetTime,RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc,&GetData,RTC_FORMAT_BIN);
	Time2Asc(GetTime,aa);
	GUI_DispStringAt(aa,300,10);
	Date2Asc(GetData,aa);
	GUI_DispStringAt(aa,380,10);

需要注意的是,必须在HAL_RTC_GetTime函数后面使用HAL_RTC_GetDate函数,否则是不能读出数据的。
在这里插入图片描述

4、RTC备份寄存器

修改RTC初始化函数

void MX_RTC_Init(void)
{
  RTC_TimeTypeDef sTime = {0};
  RTC_DateTypeDef sDate = {0};

  /** Initialize RTC Only 
  */
  hrtc.Instance = RTC;
  hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
  hrtc.Init.AsynchPrediv = 127;
  hrtc.Init.SynchPrediv = 255;
  hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
  hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
  hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
  if (HAL_RTC_Init(&hrtc) != HAL_OK)
  {
    Error_Handler();
  }

  /* USER CODE BEGIN Check_RTC_BKUP */
 	__HAL_RCC_PWR_CLK_ENABLE();	//开启后备电源时钟
	HAL_PWR_EnableBkUpAccess();	//允许访问、RTC 备份寄存器
	if (HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1) != 0xA2A2)
	{
		sTime.Hours = 0x0;
		sTime.Minutes = 0x0;
		sTime.Seconds = 0x0;
		sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
		sTime.StoreOperation = RTC_STOREOPERATION_RESET;
		if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
		{
			Error_Handler();
		}
		sDate.WeekDay = RTC_WEEKDAY_FRIDAY;
		sDate.Month = RTC_MONTH_JANUARY;
		sDate.Date = 0x1;
		sDate.Year = 0x00;

		if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
		{
			Error_Handler();
		}
		HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 0xA2A2);
	}
	else
	{

	}
  /* USER CODE END Check_RTC_BKUP */

  /** 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;
//  if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
//  {
//    Error_Handler();
//  }
//  sDate.WeekDay = RTC_WEEKDAY_FRIDAY;
//  sDate.Month = RTC_MONTH_JANUARY;
//  sDate.Date = 0x1;
//  sDate.Year = 0x2000;

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

}

这样断电后或者复位后,时钟会保存下来,不会是复位值

遇到的问题

自己手动修改了日期之后,再读取时,读出来的年份总是错误的,其他的月份什么的没有问题,后来在保存日期之前,把星期也重新设置一下再保存,这样就没有问题
应该是因为用HAL_RTC_SetDate这个函数保存的时候,他是将整个RTC_DR寄存器都进行了赋值再保存的,如果不设置星期,那么对RTC_DR寄存器赋值的时候,WDU[2:0]会是一个未知的值,所以后面读取的时候可能会出现问题
在这里插入图片描述

    assert_param(IS_RTC_YEAR(sDate->Year));
    assert_param(IS_RTC_MONTH(sDate->Month));
    assert_param(IS_RTC_DATE(sDate->Date));

   datetmpreg = (((uint32_t)RTC_ByteToBcd2(sDate->Year) << 16U) | \
                 ((uint32_t)RTC_ByteToBcd2(sDate->Month) << 8U) | \
                 ((uint32_t)RTC_ByteToBcd2(sDate->Date)) | \
                 ((uint32_t)sDate->WeekDay << 13U));

上面是HAL_RTC_SetDate函数中的一段语句,可以看出Week会左移13位,而week是uint8_t类型的数据,左移13位的话,正好会影响年份的值。
包括后面设置时间时,单独设置时间,或者单独设置12小时制再读出来就有问题,一起设置的话就可以,所以现在都是先读取一下,在修改某一项,再整体保存

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值