STM32L151 RTC Аварийное прерывание

У меня проблема с прерыванием сигнала тревоги RTC STM32L151. Я хочу, чтобы моя программа каждую секунду переходила в прерывание сигнала тревоги RTC, но это не работает. Моя основная функция:

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_IWDG_Init();
  MX_RTC_Init();
  MX_SPI1_Init();
  MX_USART1_UART_Init();

  __HAL_RTC_ALARM_ENABLE_IT(&hrtc, RTC_IT_ALRA);

  while (1)
  {

  }
}

Функция настраивает RTC: MX_RTC_Init ():

void MX_RTC_Init(void)
{
  RTC_TimeTypeDef sTime;
  RTC_DateTypeDef sDate;
  RTC_AlarmTypeDef sAlarm;

  hrtc.Instance = RTC;
  hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
  hrtc.Init.AsynchPrediv = 127;
  hrtc.Init.SynchPrediv = 255;
  hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
  hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
  hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
  HAL_RTC_Init(&hrtc);

  sTime.Hours = 0x14;
  sTime.Minutes = 0;
  sTime.Seconds = 0;
  sTime.TimeFormat = RTC_HOURFORMAT12_AM;
  sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  sTime.StoreOperation = RTC_STOREOPERATION_RESET;
  HAL_RTC_SetTime(&hrtc, &sTime, FORMAT_BCD);

  sDate.WeekDay = RTC_WEEKDAY_WEDNESDAY;
  sDate.Month = RTC_MONTH_AUGUST;
  sDate.Date = 0x24;
  sDate.Year = 0x16;

  HAL_RTC_SetDate(&hrtc, &sDate, FORMAT_BCD);

    /**Enable the Alarm A 
    */
  sAlarm.AlarmTime.Hours = 0;
  sAlarm.AlarmTime.Minutes = 0;
  sAlarm.AlarmTime.Seconds = 0;
  sAlarm.AlarmTime.TimeFormat = RTC_HOURFORMAT12_AM;
  sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
  sAlarm.AlarmMask = RTC_ALARMMASK_SECONDS;
  sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
  sAlarm.AlarmDateWeekDay = 1;
  sAlarm.Alarm = RTC_ALARM_A;
  HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, FORMAT_BCD);

}

Я создал проект с помощью CubeMX. У вас есть какие-нибудь идеи или советы для меня? Спасибо


person uv_utna    schedule 06.09.2016    source источник
comment
Вероятно, вам нужно включить прерывание в NVIC. Это может быть скрыто частью этого кода, так что это может быть уже сделано. Проверьте и посмотрите, включен ли он в NVIC, и если это так, проверьте и посмотрите, правильно ли разрешены прерывания RTC (также проверьте и посмотрите, есть ли ожидающее прерывание).   -  person rjp    schedule 06.09.2016


Ответы (2)


Если поле замаскировано, оно не будет сравниваться при проверке даты срабатывания сигнализации. Поэтому, когда вы маскируете СЕКУНДЫ, сравниваются только поля ДЕНЬ, ЧАС и МИНУТА. Правильный способ получения прерываний в 1 секунду с помощью RTC - использовать всю маску аварийных сигналов, потому что в этом случае ни одно из полей не сравнивается, и когда RTC увеличивает значение поля SECOND, будет сгенерировано аварийное прерывание.

sAlarm.AlarmMask = RTC_ALARMMASK_ALL;

Также все это описано ST в их Использование аппаратных часов реального времени (RTC) в STM32 F0, F2, F3, F4 и примечания к применению для микроконтроллеров серии L1.

введите описание изображения здесь

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

person Bence Kaulics    schedule 18.09.2016
comment
как можно, например, делать это каждые 5 секунд? - person Kennet Celeste; 06.04.2019
comment
@KennetCeleste Я боюсь, что вам придется маскировать все, кроме поля секунд, и перенастраивать сигнал тревоги при каждом прерывании. Что-то вроде другого ответа. Что упростило бы переход от HAL к подходу с голым регистром, потому что HAl имеет огромные накладные расходы. - person Bence Kaulics; 07.04.2019

Поскольку вы установили sAlarm.AlarmMask = RTC_ALARMMASK_SECONDS, RTC будет генерировать прерывание, когда значение секунд времени совпадет с sAlarm.AlarmTime.Seconds, что в вашем случае равно 0. Таким образом, если вы оставите код как есть, у вас будет прерывание каждую минуту.

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

void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
    RTC_TimeTypeDef sTime;
    HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
    uint8_t next_second = sTime.Seconds++;
    if (next_second > 59) next_second = 0;

    RTC_AlarmTypeDef sAlarm;
    sAlarm.AlarmTime.Hours = 0;
    sAlarm.AlarmTime.Minutes = 0;
    sAlarm.AlarmTime.Seconds = RTC_ByteToBcd2(next_second);
    sAlarm.AlarmTime.TimeFormat = RTC_HOURFORMAT12_AM;
    sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
    sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
    sAlarm.AlarmMask = RTC_ALARMMASK_SECONDS;
    sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
    sAlarm.AlarmDateWeekDay = 1;
    sAlarm.Alarm = RTC_ALARM_A;
    HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, FORMAT_BCD);
}

Чтобы это работало, вы должны убедиться, что вы правильно настроили часы RTC (внутренние или внешние 32K).

В качестве альтернативы вы можете использовать функцию пробуждения RTC, я думаю, это было бы более подходящим. Или в своем основном цикле вы можете использовать HAL_GetTick, чтобы проверить, что с момента последней обработки прошла 1 секунда, например:

static uint32_t last_second = 0;
void main(void)
{
   uint32_t current_second = HAL_GetTick();
   if (current_second - last_second > 1000)
   {
       last_second = current_second;

       //1 second has elapsed, do something
   }
}
person Guillaume Michel    schedule 07.09.2016
comment
это законный подход? или это обходной путь? - person Kennet Celeste; 06.04.2019