Приветствую всех снова на нашем сайте! И сегодня мы продолжим заниматься программированием STM32, а точнее STM32F4. Казалось бы, мы уже рассмотрели огромное количество различных периферийных модулей этих микроконтроллеров, но еще ни разу не использовали RTC - Real Time CLock (часы реального времени). И в этой статье мы разберемся что же это вообще такое, как и зачем эти часы можно использовать, а также напишем маленькую программу с инициализацией RTC.
Что же делают часы реального времени, встроенные в микроконтроллеры STM32? Тут все понятно, никаких неожиданностей. Они предназначены для того, чтобы вести отсчет текущего времени. То есть по большому счету модуль RTC представляет из себя таймер, но есть одно важное отличие. Часы реального времени могут продолжать работу от резервного источника питания (например, батарейки), подключенной к выводу VBAT микроконтроллера. Что нам это дает? А то, что при выключенном устройстве часы будут тикать от резервного источника, и время будет отсчитываться корректно. Вот структурная схема из даташита:
Серым выделено то, что относится к области резервных данных, то есть то, что может питаться от резервного источника питания в отсутствие основного питания на контроллере.
Для того, чтобы часы реального времени начали отсчет, необходимо подключить источник тактирования. И здесь есть несколько вариантов:
- Во-первых, можно подключить внешний низкочастотный кварцевый резонатор на 32768 Гц. Соответственно, в этом случае при инициализации RTC в качестве источника тактовых импульсов надо выбрать LSE.
- Второй вариант - использовать внутренний низкочастотный генератор (LSI). В этом случае мы получим те же самые 32 КГц. Ну и наконец третий вариант - внешний высокочастотный генератор. В этом случае необходимо использовать предделитель частоты. С этим вроде бы все понятно.
Кроме того, часы реального времени в STM32 можно использовать в качестве будильника. Для этого есть специальный регистр RTCALR. Когда счетный регистр досчитывает до значения, хранящегося в этом регистре, контроллер формирует специальный сигнал, который может вызвать прерывание. Ну а уже в прерывании можно включить подвешенную к контроллеру звонилку-пищалку. Помимо этого есть также прерывание по переполнению счетного регистра.
Время традиционной вставки: поскольку компания STMicroelectronics прекратила поддержку библиотеки SPL, которая использовалась в этом курсе, я создал новый, посвященный работе уже с новыми инструментами, так что буду рад видеть вас там - STM32CubeMx. Кроме того, вот глобальная рубрика по STM32, а также небольшая подборка по таймерам из нового курса:
- STM32 и таймеры. STM32CubeMx. Настройка и использование.
- STM32 и watchdog. STM32CubeMx. Настройка модуля WWDG.
- STM32 и Timer Input Capture. Режим захвата сигнала.
- STM32CubeMx и watchdog. Настройка и использование IWDG.
Как видите, возможностей у RTC вполне достаточно. Минус только один - всего один счетный регистр, который считает секунды. То есть высчитывать из секунд минуты и часы нужно руками. Правда в SPL разработчики поместили специальные функции для удобной работы с временем, так что при желании можно этим и воспользоваться.
Перейдем уже к написанию программы наконец ) Пусть это будет простенькая инициализация. Наша сегодняшняя цель - увидеть отсчет секунд в счетном регистре 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, например, какой-нибудь будильник...
Спасибо Вам за столь доступные и понятные примеры !
=))
Здравствуйте.
Сделал как вы и предлагали, но почему то таймер не одну секунду отсчитывает, а намного больше. Может быть такое, что LSI настроен на другую частоту?
А какая плата?
"Что за волшебное число 0x7FFF? А все просто. У нас есть источник тактирования на 32768 Гц. А нам надо 1 Гц — то есть один импульс в секунду. Значит нужен предделитель, а 0x7FFF — это как раз 32768 =)"
Уточните в статье эти моменты:
1) Строго говоря, 0x7FFF - это как раз 32767, ещё 1 добавляется аппаратно.
2) Например, предделителя в RTC у STM32L152RB 2: асинхронный и синхронный. Притом для каждого прописаны макс. значения. См. App. note 3371.
А так огонёк)
А блок схема точно из серии F4 ? а то похожа на F1.
в F4 по больше наворотили.
http://mcucpu.ru/index.php/platformy-32-bit/stm32/124-rtc-stm32f2xx
да и F4 в регистре времени (RTC_TR) есть отдельно секунды, минуты, часы.
"Далее выполняем Backup Domain Reset — то есть сброс RTC модуля" А что именно сбрасывается по этой команде? Все енергонезависимые регистры? Если это так, то сбрасывание модуля RTC каждый раз по включению питания делает его бесполезным.
До инициализации часов реального времени проверить статусный регистр. Если флаг инициализации взведен, значит, часы работали и продолжают работать. То бишь, можно не настраивать часы. И это значит, что шаг с инициализацией пропадает, то бишь, часы продолжают отщёлкивать секунды, глядя на них свысока.
Здравствуйте, уважаемые. В общем собрал я проект с RTC под stm32f103, и ничего, как водится не работает. При инициализации виснет, тактирование не начинается. Подскажите, а может сначала нужно альтернативную функцию ножек OSC32, ну вроде вот этого что-то прописать: GPIO_Mode_AF_PP. В общем, подскажите, люди добрые
В STM32F4 LSI генерирует 32kHz, а не 32768Hz как обычный часовой кварц. AN3371 рекомендует использовать:
rtc.RTC_AsynchPrediv = 127;
rtc.RTC_SynchPrediv = 249;
Кроме того, "LSI accuracy is not suitable for calendar application". Так что юзайте внешний кварц.
Каким образом через SPL забрать текущее время в переменную для дальнейшего использования в программе?
RTC_GetTime()
так что автор, видимо, пишет о серии F1
Теория про модуль RTC в целом. Пример программы и отладка - F4.
Это в какой версии библиотеки?
У меня только RTC_GetCounter()
@version V3.5.0
Это для F1 SPL? Для F4 больше функций там.
Это очень важный момент, без учета которого RTC не имеет смысла. Автору следовало включить его в статью для тех, кто не читает комменты и даташиты.
Такая вот проблема. Подключил библиотеки, а мне пишет:
Description Resource Path Location Type
conflicting types for 'SDIO_SendCommand' plataDebug line 487 C/C++ Problem
А где в HAL функция для прямой установки RTC->CNTL,RTC->CNTH .
На RTC_WriteTimeCounter(), компилер ругается, а определение самой ф-и не нахожу, хотя она используется в HAL_RTC_SetTime()
В HAL такая концепция, что все функции, работающие непосредственно с регистрами являются локальными. Таким образом, расчет на то, что пользователь будет использовать только одну-две высокоуровневые функции.
А зачем тогда есть биты Bits 11:8 MU: Month units in BCD format?
Расскажите, пожалуйста, какими средствами отладки Вы пользуетесь. Если можно - подробнее. Как посмотреть текущие значения в регистрах работающей программы?
Добрый вечер!
Все зависит от среды разработки (хотя по большому счету везде все одинаково). Я использую IAR. Там в меню View можно выбрать разные инструменты для отладки, к примеру, Watch - для просмотра значений переменных, Live Watch - для вывода значений переменных с обновлением в реальном времени при запущенной программе и т. д.