stm32f407 RTC不更新问题排查

1、问题

在做stm32f407rtc实验时,代码是用cubemx生成的,通过串口打印出时间值,1s打印一次。但是结果与料想中的不一致。

发现打印出来的值一直不更新。按下复位键,后时间会更新一次。
stm32f407 RTC不更新问题排查_第1张图片
一开始一直是51s,按下复位键,发现时间更新了,再按下复位键,时间再次更新。

后来直接在线debug,运行后,一开始时间也是不会更新的,但是后来将hrtc结构体放到观察窗口,并点击了instance成员后,奇迹出现了,发现时间能够正常更新了。
stm32f407 RTC不更新问题排查_第2张图片
这就非常奇怪了,甚至怀疑了单片机出问题了,结果换了一块板子,还是同样的现象基本可以排除是板子的问题。时间能更新说明晶振都没有啥问题。主函数代码如下;

  while (1)
  {
	HAL_RTC_GetTime(&hrtc,&RTC_TimeStruct,RTC_FORMAT_BIN);	printf("Time:%02d:%02d:%02d\r\n",RTC_TimeStruct.Hours,RTC_TimeStruct.Minutes,RTC_TimeStruct.Seconds);
		HAL_Delay(1000);
	HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_10);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

2、问题排查

发现了这个奇怪的现象后,感觉很苦恼,先后怀疑了这些情况

  • keil mdk配置错误,代码编译优化的问题
  • rtc代码配置的问题

后面经过逐一排查,发现没有问题。并且与正点原子的407代码对比了,也没找出问题所在。后来找百度了一下,找到了https://blog.csdn.net/ZLK1214/article/details/103743152这个博客,发现问题现象一致,按照其操作,解决。

3、问题解决

问题的表面原因是,我主要函数里面只读取了time信息,没有读取date信息。当把主函数代码改为如下:

  while (1)
  {
	HAL_RTC_GetTime(&hrtc,&RTC_TimeStruct,RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc,&RTC_DateStruct,RTC_FORMAT_BIN);
	  printf("Time:%02d:%02d:%02d   %02d-%02d-%02d %d \r\n",RTC_TimeStruct.Hours,RTC_TimeStruct.Minutes,RTC_TimeStruct.Seconds,\
								RTC_DateStruct.Year,RTC_DateStruct.Month,RTC_DateStruct.Date,RTC_DateStruct.WeekDay); 
	HAL_Delay(1000);
	HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_10);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

串口输出正常了
stm32f407 RTC不更新问题排查_第3张图片
更改后,时间可以正常显示。

4、原因分析

出现需要读取time 和date后,时间才会更新问题的原因是。为了保证数据读取的准确性,rtc设置了一个影子寄存器,每次读取时间和日期的时候,都是读取的这个影子寄存器,只有当读取了日期后,影子寄存器才会更新数据。具体的在sstm32f4xx中文参考手册的23.3.6中有入下描述。

stm32f407 RTC不更新问题排查_第4张图片

5、只读取rtc时间的方法

那么有没有办法,我只想读取时间值,而不想读取日期值呢。有两种方法:

5.1方法一,参考手册中说明

配置rtc的时候,需要将RTC_CR寄存器的BYPSHAD位设置为1,这样可以直接读取time值。
stm32f407 RTC不更新问题排查_第5张图片
配置方法如下:
添加HAL_RTCEx_EnableBypassShadow(&hrtc);将BYPSHAD置1
初始化rtc;

void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
{

  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
  if(rtcHandle->Instance==RTC)
  {
  /* USER CODE BEGIN RTC_MspInit 0 */
	__HAL_RCC_PWR_CLK_ENABLE();//使能电源时钟PWR
	HAL_PWR_EnableBkUpAccess();//取消备份区域写保护
  /* USER CODE END RTC_MspInit 0 */

  /** Initializes the peripherals clock
  */
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
    PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
    {
      Error_Handler();
    }
	HAL_RTCEx_EnableBypassShadow(&hrtc);
    /* RTC clock enable */
    __HAL_RCC_RTC_ENABLE();
  /* USER CODE BEGIN RTC_MspInit 1 */
  /* USER CODE END RTC_MspInit 1 */
  }
}

主函数值读取time值

  while (1)
  {
	HAL_RTC_GetTime(&hrtc,&RTC_TimeStruct,RTC_FORMAT_BIN);
//	HAL_RTC_GetDate(&hrtc,&RTC_DateStruct,RTC_FORMAT_BIN);
	  printf("Time:%02d:%02d:%02d   %02d-%02d-%02d %d \r\n",RTC_TimeStruct.Hours,RTC_TimeStruct.Minutes,RTC_TimeStruct.Seconds,\
								RTC_DateStruct.Year,RTC_DateStruct.Month,RTC_DateStruct.Date,RTC_DateStruct.WeekDay); 
// printf("%02x:%02x:%02x\r\n", (RTC->TR >> 16) & 0xff, (RTC->TR >> 8) & 0xff, RTC->TR & 0xff);
	HAL_Delay(1000);
	HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_10);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

运行结果
stm32f407 RTC不更新问题排查_第6张图片
可以正常显示。

5.1方法二,直接读取RTC寄存器

按照上面的博客中,可以直接读取RTC值。也可以正常显示。

printf("%02x:%02x:%02x\r\n", (RTC->TR >> 16) & 0xff, (RTC->TR >> 8) & 0xff, RTC->TR & 0xff);

花了将近一天半的时间解决了这个问题。虽然找到了直接读取time值的方法,不过最好还是按照stm要求的,将time和date同时读取。这样准确性会高很多,毕竟影子寄存器里的时间和日期值是同一时刻的。保证了数据的准确性。

你可能感兴趣的:(问题分析,stm32,单片机,c语言,RTC,时间戳)