Почему сбивается дата и календарь STM32F103?

В микроконтроллерах серии STM32F10x (например, STM32F103C8T6 из популярной BluePill) есть часы реального времени, они "тикают" от батарейки после того, как пропадает основное питание. Но в этих RTC нет аппаратного календаря. Это значит, что дата "не идёт". Даже если вы в своем HAL проекте установили галочку "activate calendar", это значит, что дата будет "идти" при наличии основного питания, но после прекращения питания ДАТА СОБЬЕТСЯ до 01.01.00. Это плохая новость... Хорошая новость в том, что на HAL'е мир не сошелся клином. И мы сделаем полноценные часы реально времени с датой на CMSIS.

(обновление статьи 03.05.2024)

В современных микроконтроллерах STM32 (например серии STM32F4) применены современные часы реального времени, версии V2. В них идет счет и даты и времени. В микроконтроллерах STM32F10x используется старый модуль часов реального времени версии V1. При работе от часовой батарейки приращивается один 32-битный регистр RTC->CNTx. Этот регистр по своему алгоритму, HAL разбивает на часы, минуты, секунды и миллисекунды. Этот регистр мы и будем использовать для хранения штампа времени! Мы будем накапливать в него не миллисекунды, а секунды. В 32-битный регистр можно уместить секунд на 136 лет. Даже если вести отсчет от 2024-го года, то часы теоретически могут идти до 2160-го года. Плата сгниет быстрее, чем "кончится время". 

На просторах интернета я нашел примеры кода инициализации часов реального времени, облагородил их таймаутами и написал свой алгоритм преобразования счетчика в год, месяц, день, часы, минуты, секунды.. и обратно.

Готовую библиотеку вы сможете скачать отсюда https://cloud.as.life/s/BGHtZGf5F9PXpcS 

В этой статье я не буду расписывать как что работает, вы это все прочтете в комментариях в коде. Хочу лишь показать как использовать библиотеку.

Сперва необходимо ее разместить в каталоге с проектом, указать компилятору путь к header'ам, подключить #include "stm32f1_rtc.h". Проведите инициализацию сразу после всех сгенеренных инициализаций HAL'а.

Объявите переменную структурного типа для хранения и передачи даты/времени

RTC_UNIT datetime;
/* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  /* USER CODE BEGIN 2 */
  rtc_Init();

Теперь вы можете работать с датой и временем через функции

RTC_UNIT rtc_GetTime(void);
void rtc_SetTime(RTC_UNIT dt);

Пример (внутри main() {})

datetime = rtc_GetTime();
printf("%02i:%02i:%02i\r\n", datetime.hours, datetime.minutes, datetime.seconds);

Копируйте, пользуйтесь свободно. Вы можете обсудить эту статью в нашем Telegram канале. Не забудьте присоединиться, чтобы не пропустить новые статьи.

Tags: ,