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. У вас есть идея или совет для меня? Спасибо
3 ответа
Если поле замаскировано, оно не будет сравниваться при проверке даты тревоги. Поэтому, когда вы маскируете SECONDS, сравниваются только поля DAY, HOUR и MINUTE. Надлежащим способом достижения прерываний в 1 секунду с помощью RTC является использование всей маски сигналов тревоги, поскольку таким образом ни одно из полей не сравнивается, и когда RTC увеличивает значение поля ВТОРОЕ, генерируется прерывание сигнала тревоги.
sAlarm.AlarmMask = RTC_ALARMMASK_ALL;
Также все это описано ST в их Использовании аппаратных часов реального времени (RTC) в STM32 F0, F2, F3, F4 и L1 серии MCU.
Это очень удобное решение, так как вам не нужно сбрасывать сигнал тревоги после всех прерываний.
Как вы установили 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
}
}
- Не звони
__HAL_RTC_ALARM_ENABLE_IT()
напрямую. Это называетсяHAL_RTC_SetAlarm_IT()
. - Включить будильник B. Почему? Потому что иногда, как я испытал, один будильник не работает. «Иногда» приходится включать оба будильника.
- Для маскировки необходимо замаскировать все биты:
sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS|RTC_ALARMMASK_MINUTES|RTC_ALARMMASK_SECONDS;
Таким образом, вы просите ST использовать только секунды. Вы также можете использовать
RTC_ALARMMASK_ALL
.