Микроконтроллеры STM32: использование встроенных RTC
11 июля 2018
Ранее в посте Микроконтроллеры 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 действительно используется:
В Makefile понадобится добавить пару файлов к списку C_SOURCES:
$(FIRMWARE)/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rtc_ex.c \
Теперь можно спокойно использовать RTC в коде. Например, получение даты и времени осуществляется так:
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;
}
А так происходит их изменение:
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:
Для вывода времени, даты, дня недели и выбранных цветов интерфейса я использовал TFT-экранчик на базе ST7735. Для изменения даты, времени, и всего остального используются четыре кнопки. Действия кнопок сверху вниз: переход назад, перех вперед, уменьшить значение, увеличить значение.
Интересно, что при отсутствии основного питания батарейка питает не только часы, но и небольшое количество SRAM, так называемую backup memory (она же backup registers). Для доступа к ней при инициализации устройства нужно сказать:
/* ... (пропущено) ... */
HAL_PWR_EnableBkUpAccess();
}
После чего можно осуществлять чтение и запись памяти. Я решил хранить в ней выбранный пользователем цвет интерфейса:
// ... (пропущено) ...
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.
Метки: STM32, Электроника.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.