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

Приветствую всех снова на нашем сайте!

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

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

rtc

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

Для того, чтобы часы реального времени начали отсчет, необходимо подключить источник тактирования. И здесь есть несколько вариантов:

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

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

Как видите, возможностей у RTC вполне достаточно. Минус только один – всего один счетный регистр, который считает секунды. То есть высчитывать из секунд минуты и часы нужно руками. Правда в Standard Peripheral Library разработчики засунули специальные функции для удобной работы с временем, так что при желании можно этим и воспользоваться.

Перейдем уже к написанию программы наконец! Пусть это будет простенькая инициализация. Наша сегодняшняя цель – увидеть отсчет секунд в счетном регистре RTC. Я буду использовать для этого отладочную плату STM32F4Discovery, ну а программу, как обычно, будем писать в 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, например, какой-нибудь будильник

Поделиться!

Подписаться
Уведомление о
guest
24 Комментарий
старее
новее большинство голосов
Inline Feedbacks
View all comments
Александр
Александр
6 лет назад

Спасибо Вам за столь доступные и понятные примеры !

NERV
NERV
6 лет назад

Здравствуйте.
Сделал как вы и предлагали, но почему то таймер не одну секунду отсчитывает, а намного больше. Может быть такое, что LSI настроен на другую частоту?

Alex Bond
Alex Bond
6 лет назад

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

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

А так огонёк)

Макс
Макс
6 лет назад

А блок схема точно из серии F4 ? а то похожа на F1.
в F4 по больше наворотили.
http://mcucpu.ru/index.php/platformy-32-bit/stm32/124-rtc-stm32f2xx

Сергей
Сергей
Reply to  Макс
5 лет назад

да и F4 в регистре времени (RTC_TR) есть отдельно секунды, минуты, часы.

Антон
Антон
6 лет назад

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

Тест
Тест
6 лет назад

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

Дмитрий
Дмитрий
6 лет назад

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

kyb
kyb
5 лет назад

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

Василий
Василий
5 лет назад

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

Сергей
Сергей
5 лет назад

так что автор, видимо, пишет о серии F1

Антон
Антон
5 лет назад

Это в какой версии библиотеки?

У меня только RTC_GetCounter()
@version V3.5.0

Marcusska
Marcusska
5 лет назад

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

Макс
Макс
4 лет назад

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

lex
lex
4 лет назад

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

Doka
Doka
3 лет назад

А зачем тогда есть биты Bits 11:8 MU: Month units in BCD format?

Andriy
Andriy
1 год назад

Расскажите, пожалуйста, какими средствами отладки Вы пользуетесь. Если можно – подробнее. Как посмотреть текущие значения в регистрах работающей программы?

Присоединяйтесь!

Profile Profile Profile Profile Profile
Vkontakte
Twitter

Язык сайта

Июнь 2020
Пн Вт Ср Чт Пт Сб Вс
« Май    
1234567
891011121314
15161718192021
22232425262728
2930  

© 2013-2020 MicroTechnics.ru