STM32F4. Часы реального времени (RTC).

Приветствую всех снова на нашем сайте! И сегодня мы продолжим заниматься программированием STM32, а точнее STM32F4. Казалось бы, мы уже рассмотрели огромное количество различных периферийных модулей этих микроконтроллеров, но еще ни разу не использовали RTC — Real Time CLock (часы реального времени). Будем исправлять это досадное недоразумение ) В этой статье мы разберемся что же это вообще такое, как и зачем эти часы можно использовать, а также напишем маленькую программу с инициализацией RTC.

Что же делают часы реального времени, встроенные в микроконтроллеры STM32? Тут все понятно, никаких неожиданностей. Они предназначены для того, чтобы вести отсчет текущего времени. То есть по большому счету модуль RTC представляет из себя таймер, но есть одно важное отличие. Часы реального времени могут продолжать работу от резервного источника питания (например, батарейки), подключенной к выводу Vbat микроконтроллера. Что нам это дает? А то, что при выключенном устройстве часы будут тикать от резервной батарейки, и время будет отсчитываться корректно. Вот структурная схемка из даташита:

rtc

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

Для того, чтобы часы реального времени начали отсчет, необходимо подключить источник тактирования. И здесь есть несколько вариантов. Во-первых, можно подключить внешний низкочастотный кварцевый резонатор на 32768 Гц. Соответственно, в этом случае при инициализации RTC в качестве источника тактовых импульсов надо выбрать LSE. Второй вариант — использовать внутренний низкочастотный генератор (LSI). В этом случае  мы получим те же самые 32 КГц. Ну и наконец третий вариант — внешний высокочастотный генератор. В этом случае необходимо использовать предделитель частоты. С этим вроде бы все понятно 😉

Кроме того, часы реального времени в STM32 можно использовать в качестве будильника. Для этого есть специальный регистр RTCALR. Когда счетный регистр досчитывает до значения, хранящегося в этом регистре, контроллер формирует специальный сигнал, который может вызвать прерывание. Ну а уж в прерывании можно включить подвешенную к контроллеру звонилку-пищалку =) Помимо этого есть также прерывание по переполнению счетного регистра. Как видите, возможностей у RTC вполне достаточно. Минус только один — всего один счетный регистр, который считает секунды. То есть высчитывать из секунд минуты и часы нужно ручками. Правда в Standard Peripheral Library разработчики засунули специальные функции для удобной работы с временем, так что при желании можно этим воспользоваться 😉

Перейдем уже к написанию программы наконец! Пусть это будет простенькая инициализация. Наша сегодняшняя цель — увидеть отсчет секунд в счетном регистре RTC. Я буду использовать для этого отладочную плату STM32F4 Discovery, ну а программу, как обычно, будем писать в Keil’е. Итак, для начала создадим новый проект (создание нового проекта для STM32F4).

Подключаем необходимые файлы:

/*************************************************************************************/
#include "stm32f4xx.h"
#include "stm32f4xx_rtc.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_pwr.h"
#include "stm32f4xx_conf.h"
#include "system_stm32f4xx.h"
 
/*************************************************************************************/

Для инициализации нам понадобится переменная:

/*************************************************************************************/
RTC_InitTypeDef rtc;
 
/*************************************************************************************/

Функция инициализации:

/*************************************************************************************/
void initRTC()
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
 
    PWR_BackupAccessCmd(ENABLE);
 
    RCC_BackupResetCmd(ENABLE);
    RCC_BackupResetCmd(DISABLE);
 
    RCC_LSICmd(ENABLE);
    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
    RCC_RTCCLKCmd(ENABLE);
 
    RTC_StructInit(&rtc);
    rtc.RTC_HourFormat = RTC_HourFormat_24;
    rtc.RTC_SynchPrediv = 0x7FFF;
    RTC_Init(&rtc);
}
 
/*************************************************************************************/

Тут надо разобраться подробнее 😉

Включаем тактирование (PWR — Power Control):

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);

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

PWR_BackupAccessCmd(ENABLE);

Далее выполняем Backup Domain Reset — то есть сброс RTC модуля:

RCC_BackupResetCmd(ENABLE);
RCC_BackupResetCmd(DISABLE);

Включаем внутренний низкочастотный источник тактирования и выбираем его в качестве источника тактирования для часов реального времени:

RCC_LSICmd(ENABLE);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
RCC_RTCCLKCmd(ENABLE);

Ну и под конец настройка RTC:

rtc.RTC_HourFormat = RTC_HourFormat_24;
rtc.RTC_SynchPrediv = 0x7FFF;
RTC_Init(&rtc);

Что за волшебное число 0x7FFF? А все просто. У нас есть источник тактирования на 32768 Гц. А нам надо 1 Гц — то есть один импульс в секунду. Значит нужен предделитель, а 0x7FFF — это как раз 32767 и единичка добавляется аппаратно =) Не хватает в нашей программке только функции main:

/*************************************************************************************/
int main()
{
    initRTC();
    while(1);
}
 
/*************************************************************************************/

Вот и все )

Давайте посмотрим на результаты. Запускаем под отладчиком программу и смотрим на счетный регистр RTC:
Часы реального времени

Значение регистра увеличивается каждую секунду! ) Собственно, так и задумывалось. Поэтому на сегодня мы заканчиваем, скоро замутим что-нибудь еще на RTC, например, какой-нибудь будильник….

Понравилась статья? Поделись с друзьями!

STM32F4. Часы реального времени (RTC).: 21 комментарий
  1. Здравствуйте.
    Сделал как вы и предлагали, но почему то таймер не одну секунду отсчитывает, а намного больше. Может быть такое, что LSI настроен на другую частоту?

  2. «Что за волшебное число 0x7FFF? А все просто. У нас есть источник тактирования на 32768 Гц. А нам надо 1 Гц — то есть один импульс в секунду. Значит нужен предделитель, а 0x7FFF — это как раз 32768 =)»

    Уточните в статье эти моменты:
    1) Строго говоря, 0x7FFF — это как раз 32767, ещё 1 добавляется аппаратно.
    2) Например, предделителя в RTC у STM32L152RB 2: асинхронный и синхронный. Притом для каждого прописаны макс. значения. См. App. note 3371.

    А так огонёк)

  3. «Далее выполняем Backup Domain Reset — то есть сброс RTC модуля» А что именно сбрасывается по этой команде? Все енергонезависимые регистры? Если это так, то сбрасывание модуля RTC каждый раз по включению питания делает его бесполезным.

  4. До инициализации часов реального времени проверить статусный регистр. Если флаг инициализации взведен, значит, часы работали и продолжают работать. То бишь, можно не настраивать часы. И это значит, что шаг с инициализацией пропадает, то бишь, часы продолжают отщёлкивать секунды, глядя на них свысока.

  5. Здравствуйте, уважаемые. В общем собрал я проект с RTC под stm32f103, и ничего, как водится не работает. При инициализации виснет, тактирование не начинается. Подскажите, а может сначала нужно альтернативную функцию ножек OSC32, ну вроде вот этого что-то прописать: GPIO_Mode_AF_PP. В общем, подскажите, люди добрые

  6. В STM32F4 LSI генерирует 32kHz, а не 32768Hz как обычный часовой кварц. AN3371 рекомендует использовать:
    rtc.RTC_AsynchPrediv = 127;
    rtc.RTC_SynchPrediv = 249;
    Кроме того, «LSI accuracy is not suitable for calendar application». Так что юзайте внешний кварц.

  7. Каким образом через SPL забрать текущее время в переменную для дальнейшего использования в программе?

  8. Это очень важный момент, без учета которого RTC не имеет смысла. Автору следовало включить его в статью для тех, кто не читает комменты и даташиты.

  9. Такая вот проблема. Подключил библиотеки, а мне пишет:
    Description Resource Path Location Type
    conflicting types for ‘SDIO_SendCommand’ plataDebug line 487 C/C++ Problem

  10. А где в HAL функция для прямой установки RTC->CNTL,RTC->CNTH .
    На RTC_WriteTimeCounter(), компилер ругается, а определение самой ф-и не нахожу, хотя она используется в HAL_RTC_SetTime()

    • В HAL такая концепция, что все функции, работающие непосредственно с регистрами являются локальными. Таким образом, расчет на то, что пользователь будет использовать только одну-две высокоуровневые функции.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *