← На главную

Микроконтроллеры STM32: использование встроенных RTC

Ранее в посте Микроконтроллеры AVR: пример работы с часами реального времени DS1302 отмечалось, что DS1302 было бы довольно глупо использовать с микроконтроллерами STM32, так как у них есть встроенные часы реального времени. Давайте же попробуем разобраться, как происходит работа с этими встроенными RTC, и что они умеют.

Как обычно, для экспериментов я использовал плату Nucleo-F411RE, но описанные далее шаги можно повторить и для любой другой отладочной платы. Обратите внимание, что в мире STM32 встречаются микроконтроллеры с RTC, но без функции календаря. Их RTC умеет работать со временем, но не с датами. В качестве примера можно привести используемый в Blue Pill микроконтроллер STM32F103C8T6. Чтобы определить, есть ли в микроконтроллере хардварный календарь, внимательно читайте даташит.

Итак, для включения RTC следует открыть STM32CubeMX и произвести следующие изменения в проекте:

  • Во вкладке Pinout перейдите в Configuration → Peripherals → RCC. В выпадающем списке Low Speed Clock (LSE) выберите «Crystal/Ceramic Resonator». Этим мы говорим микроконтроллеру использовать внешний часовой кварц на 32768 Гц. Разумеется, предполагается, что он есть на вашей плате. Можно обойтись и внутренним генератором (LSI). Однако точность часов в этом случае будет оставлять желать лучшего.
  • В той же вкладке Pinout перейдите в Configuration → Peripherals → RTC, поставьте галочки «Activate Clock Source» и «Activate Calendar». Этим мы, собственно, включаем RTC.
  • Во вкладке Configuration появится кнопка RTC. Нажмите на нее и проверьте, что используется 24-х часовое время (Hour Format) и бинарный формат (Data Format).

Важно! При проектировании собственной платы нужно серьезно отнестись к выбору конденсаторов рядом с часовым кварцем. Если переборщить с емкостью этих конденсаторов, часы будут идти слишком медленно. На практике неплохо работают конденсаторы на 10 пФ.

Наконец, во вкладке Clock Configuration будет не лишним перепроверить, что LSE действительно используется:

Настройка LSE в STM32CubeMX

В Makefile понадобится добавить пару файлов к списку C_SOURCES:

$(FIRMWARE)/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rtc.c \ $(FIRMWARE)/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rtc_ex.c \

Теперь можно спокойно использовать RTC в коде. Например, получение даты и времени осуществляется так:

RTC_TimeTypeDef time; RTC_DateTypeDef date; HAL_StatusTypeDef res; res = HAL_RTC_GetTime(&hrtc, &time, RTC_FORMAT_BIN); if(res != HAL_OK) { UART_Printf("HAL_RTC_GetTime failed: %d\r\n", res); return; } res = HAL_RTC_GetDate(&hrtc, &date, RTC_FORMAT_BIN); if(res != HAL_OK) { UART_Printf("HAL_RTC_GetDate failed: %d\r\n", res); return; }

А так происходит их изменение:

int RTC_Set( uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec, uint8_t dow) { HAL_StatusTypeDef res; RTC_TimeTypeDef time; RTC_DateTypeDef date; memset(&time, 0, sizeof(time)); memset(&date, 0, sizeof(date)); date.WeekDay = dow; date.Year = year; date.Month = month; date.Date = day; res = HAL_RTC_SetDate(&hrtc, &date, RTC_FORMAT_BIN); if(res != HAL_OK) { UART_Printf("HAL_RTC_SetDate failed: %d\r\n", res); return -1; } time.Hours = hour; time.Minutes = min; time.Seconds = sec; res = HAL_RTC_SetTime(&hrtc, &time, RTC_FORMAT_BIN); if(res != HAL_OK) { UART_Printf("HAL_RTC_SetTime failed: %d\r\n", res); return -2; } return 0; }

Заметьте, что структура RTC_TimeTypeDef помимо самого времени хранит ряд дополнительных полей. Они могут не очень аккуратно заполняться процедурой HAL_RTC_GetTime. Поэтому при изменении времени структуру лучше заполнить самостоятельно. Иначе можно увидеть, как часы показывают 27 часов, и налететь на прочие потрясающие баги.

Следует также иметь в виду, что в RTC не предусмотрено защиты от дурака, что позволяет выставить дату вроде 31 февраля. Если пользователь вашего устройства может изменять дату, вы должны предусмотреть в коде валидацию вводимых данных, знающую про високосные года и всякое такое. Эта тема уже поднималась в данном блоге, поэтому снова на ней я останавливаться не буду. Пример валидации вы найдете в полной версии исходников к данному посту (ищите в конце текста).

Для питания RTC нужно подать от 1.6 В до 3.6 В на пины микроконтроллера VBAT и GND. Я использовал батарейку CR2032:

Пример использования встроенных RTC микроконтроллеров STM32

Для вывода времени, даты, дня недели и выбранных цветов интерфейса я использовал TFT-экранчик на базе ST7735. Для изменения даты, времени, и всего остального используются четыре кнопки. Действия кнопок сверху вниз: переход назад, перех вперед, уменьшить значение, увеличить значение.

Интересно, что при отсутствии основного питания батарейка питает не только часы, но и небольшое количество SRAM, так называемую backup memory (она же backup registers). Для доступа к ней при инициализации устройства нужно сказать:

void init() { /* ... (пропущено) ... */ HAL_PWR_EnableBkUpAccess(); }

После чего можно осуществлять чтение и запись памяти. Я решил хранить в ней выбранный пользователем цвет интерфейса:

uint8_t chosen_color = (uint8_t)HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1); // ... (пропущено) ... if( /* ... */ ) { // color changed HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, (uint32_t)chosen_color); }

Как видите, backup memory поделена на 32-х битные регистры. Количество регистров зависит от микроконтроллера, их точное число можно узнать из даташита. Например, использованный мной STM32F411RE имеет 20 регистров. То есть, суммарно в backup memory он может хранить до 80 байт данных. Учитывая, что большинство микроконтроллеров STM32 не имеют встроенного EEPROM, наличие у них backup memory оказывается весьма кстати.

В целом, я не нашел серьезных дефектов во встроенных RTC. Время они показывают весьма точно, дату и день недели обновляют правильно, отключение основного питания переживают. RTC имеют и другие возможности, которые не были рассмотрены выше. Например, есть настройки для дополнительной калибровки часов. А еще RTC могут генерировать прерывания, выводящие микроконтроллер из энергосберегающего режима по расписанию. Однако эти моменты уже выходят за рамки данного поста. В качестве источника дополнительной информации можно порекомендовать книгу Mastering STM32.

Полную версию исходников к этому посту вы найдете на GitHub.