:::: MENU ::::

RTC

В данной серии статей будут приведены примеры работы с периферией STM32L с помощью библиотеки, предоставляемой ST — StdPeriph. Перед использованием примеров не забывайте включать, соответствующие файлы библиотеки в проект.

RTC

Доступ к RTC

После сброса RTC регистры защищены от случайной записи. Разрешение доступа к регистру доступа к **RTC(я знаю звучит как тавтология, но это так — см. ReferenceManual):

  • Включение тактирования power interface установкой PWREN в RCC_APB1ENR.
  • Установка DBP бита в PWR_CR регистре (разрешает доступ к регистрам RTC)
  • Выбираем источник тактирования RTC через RTCSEL[1:0] биты RCC_CSR регистра.
  • Включение RTC тактирования, RTCEN бит в регистре RCC_CSR.

Тактирование RTC

RTC может тактироваться от LSE, LSI или **HSE. Для получения 1 Гц на RTC — используют 2 предделителя частоты(асинхронный 7 бит, простой 13/15 бит). Для изменения источника тактирования RTC необходимо установить RTCRST бит в RCCCSR регистре и сбросить его обратно в 0. Бит RTCEN в регистре RCCCSR включает/отключает тактирование RTC(кроме того данный бит сбрасывается установкой RTCRST — см. выше).

note: Для тактирования от 32.768 kHz — предделители должны быть настроены на 128 и 256(в регистрах 127 и 255). Частота после всех предделителей рассчитывается как F_rtcclk/ ((асинхронный предделитель + 1)x(простой предделитель + 1)).

Инициализация RTC

Вначале мы снимаем запрет на доступ к регистру доступа к RTC(описано выше).

  • Снимаем защиту записи в регистры RTC. Для этого пишем 0xCA и 0x53 в RTC_WPR регистр.
  • Устанавливаем INIT бит в RTC_ISR регистре для входа в режим инициализации. В этом режиме календарь остановлен и его значение может быть изменено.
  • Ждем подтверждения входа в режим инициализации RTC. Для этого ждем установки INITF бита в регистре RTC_ISR. Это длится примерно два такта RTCCLK.
  • Программируем предделители для получения 1 Гц.
  • Заполняем календарь датой и временем в регистрах RTCTR и RTCDR. Настраиваем 12 или 24 часовой формат в RTC_CRрегистре.
  • Выход из режима инициализации. Для этого очищаем INIT бит в RTC_ISR регистре.
  • Устанавливаем защиту на запись в регистры. Для этого пишем 0xFF в RTC_WPR регистр.

RTC_table

Пример:

void RTC_init(void)
{
    RTC_TimeTypeDef RTC_Time;   
    RTC_InitTypeDef RTCInit;

    // разрешенме доступа к регистру доступа RTC
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
    PWR_RTCAccessCmd(ENABLE);

    // настройка тактирования RTC
    RCC_LSICmd(ENABLE);
    while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);
    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
    RCC_RTCCLKCmd(ENABLE);
    RTC_WaitForSynchro();

    // настройка предделителя и вкл. RTC
    // все необходимыве настройки (описанные выше) в RTC_Init()  
    // 1 Hz = 37000 Hz / (127+1)x(288+1) 
    RTCInit.RTC_HourFormat = RTC_HourFormat_24;
    RTCInit.RTC_AsynchPrediv = 127; 
    RTCInit.RTC_SynchPrediv = 288; 
    RTC_Init(&RTCInit); 

    //RTC_Time.RTC_H12 = RTC_H12_AM; // не важно т.к. RTC_HourFormat_24
    RTC_Time.RTC_Hours = 0x01;
    RTC_Time.RTC_Minutes = 0x00;
    RTC_Time.RTC_Seconds = 0x00;
    RTC_SetTime(RTC_Format_BIN, &RTC_Time);
}

Для получения данных из RTC:

RTC_TimeTypeDef RTC_Time;
RTC_GetTime(RTC_Format_BIN, &RTC_Time);

 

Настройка и использование RTC ALARM

RTC ALARM прерывание происходит когда календарь укажет на определенную (заданную вами) дату и время.

Настройка RTC ALARM:

void RTC_alarm_config(void)
{
  EXTI_InitTypeDef EXTI_InitStructure;
  RTC_AlarmTypeDef RTC_AlarmStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  
  RTC_AlarmCmd(RTC_Alarm_A, DISABLE);
  
  EXTI_ClearITPendingBit(EXTI_Line17);
  EXTI_InitStructure.EXTI_Line = EXTI_Line17;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
    
  NVIC_InitStructure.NVIC_IRQChannel = RTC_Alarm_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
 
  // маска позволяет использовать не всю дату целиком, а только ее часть
  // например в этом примере срабатывает каждый день (дата, день и число не проверяются)
  RTC_AlarmStructure.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay; 

  RTC_AlarmStructure.RTC_AlarmTime.RTC_H12 = RTC_HourFormat_24;
  RTC_AlarmStructure.RTC_AlarmTime.RTC_Hours = 15;
  RTC_AlarmStructure.RTC_AlarmTime.RTC_Minutes = 0;
  RTC_AlarmStructure.RTC_AlarmTime.RTC_Seconds = 5;

  // следующие два параметра в нашем примере не имеют значения - см. маску
  RTC_AlarmStructure.RTC_AlarmDateWeekDay = 1; // день недели или месяца
  RTC_AlarmStructure.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_WeekDay; // неделя или месяц

  RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_A, &RTC_AlarmStructure);
    
  //RTC_AlarmSubSecondConfig(RTC_Alarm_A, 0xFF, RTC_AlarmSubSecondMask_SS14_5);
  // настраиваем вывод сигнала о срабатывание alarm на RTC_OUT (stm32l - RC13)
  RTC_OutputConfig(RTC_Output_AlarmA, RTC_OutputPolarity_High);
  RTC_OutputTypeConfig(RTC_OutputType_PushPull);

  /* Enable AlarmA interrupt */
  RTC_ITConfig(RTC_IT_ALRA, ENABLE);
  RTC_AlarmCmd(RTC_Alarm_A, ENABLE);
  RTC_ClearITPendingBit(RTC_IT_ALRA);
}

Кроме того, если хотите, чтобы на RTC_OUT выводился сигнал о срабатывание RTC ALARM — надо настроить этот pin (PC13):

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //(_OUT, _AF, _AN)
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_400KHz; //(_2MHz, _10MHz, 40MHz)
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //(_NOPULL, _UP)
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //(_0 ... _15)
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //(_PP - push/pull, _OD - open drain)
  GPIO_Init(GPIOC, &GPIO_InitStructure);

  GPIO_PinAFConfig(GPIOC, GPIO_PinSource13, GPIO_AF_RTC_AF1);

И само прерывание:

void RTC_Alarm_IRQHandler()
{
  if(RTC_GetITStatus(RTC_IT_ALRA) != RESET)
  {
    RTC_ClearITPendingBit(RTC_IT_ALRA);
    EXTI_ClearITPendingBit(EXTI_Line17);
  }
}