ARM

Старт ARM. Часы реального времени RTC. HAL

Доброе время суток, продолжаем изучать микроконтроллеры ARM stm32f4, сегодня речь пойдет о часах реального времени RTC, а поставим мы себе задачу по времени переключать светодиод и сделаем себе будильник по которому нехотя будем вставать утром. И как всегда мы это будет делать на HAL-е, и тут нас ждет 2 бага со стороны хала. Начнем по порядку:
1. RTC имеет Alarm A и Alarm B (EXTI line 17)
2. RTC может проснуться по линии PA0(EXTI line 20)
3. RTC может сработать по метке (EXTI line 21)
Тактирование для RTC можно задать с помощью:
1. LSE – внешний часовой кварцевый генератор 32.738 kHz
2. LSI – внутренний генератор на 32 kHz
3. HSE – внешний кварцевой генератор для работы микроконтроллера, вход для RTC это частота HSE/Пред делитель.
И переходим непосредственно к самой программе.
stm32f4xx_hal_msp.c

void HAL_RTC_MspInit(RTC_HandleTypeDef* hrtc)
{
  if(hrtc->Instance==RTC)
  {
		HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);
    HAL_NVIC_SetPriority(RTC_Alarm_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
  }
}

void HAL_RTC_MspDeInit(RTC_HandleTypeDef* hrtc)
{

  if(hrtc->Instance==RTC)
  {
 HAL_NVIC_DisableIRQ(RTC_Alarm_IRQn);
  }
}

main.c

RTC_HandleTypeDef hrtc;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_RTC_Init(void);

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
  MX_GPIO_Init();
  MX_RTC_Init();
if(!(*(volatile uint32_t *) (BDCR_RTCEN_BB)))__HAL_RCC_RTC_ENABLE();
  while (1)
  {
	}
}

void SystemClock_Config(void)
{

  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
  RCC_OscInitTypeDef RCC_OscInitStruct;
	
  __PWR_CLK_ENABLE();
	
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
                              |RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
  PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
  HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);

}

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 = 0;
  sTime.Minutes = 0;
  sTime.Seconds = 0;
  sTime.TimeFormat = RTC_HOURFORMAT12_AM;
  sTime.DayLightSaving = RTC_DAYLIGHTSAVING_SUB1H;
  sTime.StoreOperation = RTC_STOREOPERATION_RESET;
  HAL_RTC_SetTime(&hrtc, &sTime, FORMAT_BIN);
  sDate.WeekDay = RTC_WEEKDAY_MONDAY;
  sDate.Month = RTC_MONTH_JANUARY;
  sDate.Date = 1;
  sDate.Year = 0;
  HAL_RTC_SetDate(&hrtc, &sDate, FORMAT_BIN);
  sAlarm.AlarmTime.Hours = sTime.Hours;
  sAlarm.AlarmTime.Minutes = sTime.Minutes;
  sAlarm.AlarmTime.Seconds = sTime.Seconds + 5;
  sAlarm.AlarmTime.TimeFormat = RTC_HOURFORMAT12_AM;
  sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_SUB1H;
  sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
  sAlarm.AlarmMask = RTC_ALARMMASK_NONE;
  sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
  sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
  sAlarm.AlarmDateWeekDay = 1;
  sAlarm.Alarm = RTC_ALARM_A;
  HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, FORMAT_BIN);
}

void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;
  __GPIOC_CLK_ENABLE();
  __GPIOH_CLK_ENABLE();
  __GPIOA_CLK_ENABLE();
  __GPIOG_CLK_ENABLE();
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_EVT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

}

1-ый баг необходимо добавить после MX_RTC_Init(), следующую строку
if(!(*(volatile uint32_t *) (BDCR_RTCEN_BB)))__HAL_RCC_RTC_ENABLE();
2-ой баг в файле smt32f4xx_hal_rtc.c необходимо закомментировать данную строку
//sTime->SubSeconds = (uint32_t)(hrtc->Instance->SSR);
Будильник делается аналогично, для этого в функции MX_RTC-Init() ставим текущее время и выставляем время через которое будильник должен зазвенеть (например через 10 секунд).

main.c

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 = 9;
  sTime.Minutes = 26;
  sTime.Seconds = 0;
  sTime.TimeFormat = RTC_HOURFORMAT12_AM;
  sTime.DayLightSaving = RTC_DAYLIGHTSAVING_SUB1H;
  sTime.StoreOperation = RTC_STOREOPERATION_RESET;
  HAL_RTC_SetTime(&hrtc, &sTime, FORMAT_BIN);
  sDate.WeekDay = RTC_WEEKDAY_MONDAY;
  sDate.Month = RTC_MONTH_JANUARY;
  sDate.Date = 1;
  sDate.Year = 0;
  HAL_RTC_SetDate(&hrtc, &sDate, FORMAT_BIN);
  sAlarm.AlarmTime.Hours = sTime.Hours;
  sAlarm.AlarmTime.Minutes = sTime.Minutes;
  sAlarm.AlarmTime.Seconds = sTime.Seconds + 10;
  sAlarm.AlarmTime.TimeFormat = RTC_HOURFORMAT12_AM;
  sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_SUB1H;
  sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
  sAlarm.AlarmMask = RTC_ALARMMASK_NONE;
  sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
  sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
  sAlarm.AlarmDateWeekDay = 1;
  sAlarm.Alarm = RTC_ALARM_A;
  HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, FORMAT_BIN);
}

stm32f4xx_it.c

void RTC_Alarm_IRQHandler(void)
{
  HAL_NVIC_ClearPendingIRQ(RTC_Alarm_IRQn);
		
		if(i%2){
		HAL_GPIO_WritePin(GPIOG, GPIO_PIN_13, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOG, GPIO_PIN_14, GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET); i++;
	}
	else{
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOG, GPIO_PIN_14, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOG, GPIO_PIN_13, GPIO_PIN_SET); i++;
	}
	if(i >= 10) i = 0;
	HAL_RTC_GetTime(&hrtc, &sTime, FORMAT_BIN);
	sAlarm.AlarmTime.Hours = sTime.Hours;
  sAlarm.AlarmTime.Minutes = sTime.Minutes;
  sAlarm.AlarmTime.Seconds = (sTime.Seconds + 1 ) % 60;
  sAlarm.AlarmTime.TimeFormat = RTC_HOURFORMAT12_AM;
  sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_SUB1H;
  sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
  sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS|RTC_ALARMMASK_MINUTES;
  sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
  sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
  sAlarm.AlarmDateWeekDay = 0x31;
  sAlarm.Alarm = RTC_ALARM_A;
	HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, FORMAT_BIN);
	HAL_RTC_AlarmIRQHandler(&hrtc);
}

Так же добавляем в MX_GPIO_Init() следующие строки кода

__GPIOB_CLK_ENABLE();	
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);


В следующий раз поговорим про энергосберегающий режим, на сегодня все, всем пока, увидимся на просторах mcu.by.

Старт ARM. Часы реального времени RTC. HAL: 8 комментариев

  1. Здравствуйте! Недавно для себя начал изучать STM32F429I-DISCO и соответственно программирование , вот хочу подключить через HAL часы реального времени DS3231 (интерфейс I2C).
    Подскажите как можно это все подключить.
    Хочу сделать светильник с будильником!
    Среда разработки EmBitz 0.42
    Заранее благодарю за ответ!

  2. как проверить шли часы до нашей инициализации от батарейки или нет? чтобы не выставлять их при каждом включении прибора

  3. Нужно запись в BKUP область любое число HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR0, < ваше значение>), и при старте прочитать HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0), если значения совпали? значит часы продолжают отсчитывать время.

    1. какие-то костыли. а нельзя проверить установку каких нибуть битов готовности например

      1. К сожалению нету, только так.

        /*##-2- Check if Data stored in BackUp register1: No Need to reconfigure RTC#*/
        /* Read the Back Up Register 1 Data */
        if (HAL_RTCEx_BKUPRead(&RtcHandle, RTC_BKP_DR1) != 0x32F2)
        {
        /* Configure RTC Calendar */
        RTC_CalendarConfig();
        }
        else
        {
        /* Check if the Power On Reset flag is set */
        if (__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST) != RESET)
        {
        /* Turn on LED2: Power on reset occured */
        BSP_LED_On(LED2);
        }
        /* Check if Pin Reset flag is set */
        if (__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST) != RESET)
        {
        /* Turn on LED4: External reset occured */
        BSP_LED_On(LED4);
        }
        /* Clear source Reset Flag */
        __HAL_RCC_CLEAR_RESET_FLAGS();
        }

        /*##-3- Writes a data in a RTC Backup data Register1 #######################*/
        HAL_RTCEx_BKUPWrite(&RtcHandle, RTC_BKP_DR1, 0x32F2);

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.