/** * |---------------------------------------------------------------------- * | Copyright (C) Tilen Majerle, 2014 * | * | This program is free software: you can redistribute it and/or modify * | it under the terms of the GNU General Public License as published by * | the Free Software Foundation, either version 3 of the License, or * | any later version. * | * | This program is distributed in the hope that it will be useful, * | but WITHOUT ANY WARRANTY; without even the implied warranty of * | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | GNU General Public License for more details. * | * | You should have received a copy of the GNU General Public License * | along with this program. If not, see . * |---------------------------------------------------------------------- */ #include "rtc.h" /* Private macros */ /* Internal status registers for RTC */ #define RTC_STATUS_REG RTC_BKP_DR19 /* Status Register */ #define RTC_STATUS_INIT_OK 0x1234 /* RTC initialised */ #define RTC_STATUS_TIME_OK 0x4321 /* RTC time OK */ #define RTC_STATUS_ZERO 0x0000 /* Internal RTC defines */ #define TM_RTC_LEAP_YEAR(year) ((((year) % 4 == 0) && ((year) % 100 != 0)) || ((year) % 400 == 0)) #define TM_RTC_DAYS_IN_YEAR(x) TM_RTC_LEAP_YEAR(x) ? 366 : 365 #define TM_RTC_OFFSET_YEAR 1970 #define TM_RTC_SECONDS_PER_DAY 86400 #define TM_RTC_SECONDS_PER_HOUR 3600 #define TM_RTC_SECONDS_PER_MINUTE 60 #define TM_RTC_BCD2BIN(x) ((((x) >> 4) & 0x0F) * 10 + ((x) & 0x0F)) #define TM_RTC_CHAR2NUM(x) ((x) - '0') #define TM_RTC_CHARISNUM(x) ((x) >= '0' && (x) <= '9') /* Internal functions */ void TM_RTC_Config(TM_RTC_ClockSource_t source); /* Default RTC status */ uint32_t TM_RTC_Status = RTC_STATUS_ZERO; /* RTC declarations */ RTC_TimeTypeDef RTC_TimeStruct; RTC_InitTypeDef RTC_InitStruct; RTC_DateTypeDef RTC_DateStruct; NVIC_InitTypeDef NVIC_InitStruct; EXTI_InitTypeDef EXTI_InitStruct; RTC_InitTypeDef RTC_InitStructure; RTC_TimeTypeDef RTC_TimeStructure; RTC_DateTypeDef RTC_DateStructure; #define RTC_CLOCK_SOURCE_LSE /* LSE used as RTC source clock */ #define FIRST_DATA 0x32F2 #define RTC_BKP_DR_NUMBER 0x14 __IO uint32_t uwAsynchPrediv = 0; __IO uint32_t uwSynchPrediv = 0; __IO uint32_t uwTimeDisplay = 0; uint32_t uwErrorIndex = 0; uint32_t uwIndex = 0; uint32_t aBKPDataReg[RTC_BKP_DR_NUMBER] = { RTC_BKP_DR0, RTC_BKP_DR1, RTC_BKP_DR2, RTC_BKP_DR3, RTC_BKP_DR4, RTC_BKP_DR5, RTC_BKP_DR6, RTC_BKP_DR7, RTC_BKP_DR8, RTC_BKP_DR9, RTC_BKP_DR10, RTC_BKP_DR11, RTC_BKP_DR12, RTC_BKP_DR13, RTC_BKP_DR14, RTC_BKP_DR15, RTC_BKP_DR16, RTC_BKP_DR17, RTC_BKP_DR18, RTC_BKP_DR19 }; /* Days in a month */ uint8_t TM_RTC_Months[2][12] = { {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, /* Not leap year */ {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} /* Leap year */ }; /** * @brief Writes data to all Backup data registers. * @param FirstBackupData: data to write to first backup data register. * @retval None */ static void WriteToBackupReg(uint16_t FirstBackupData) { uint32_t index = 0; for (index = 0; index < RTC_BKP_DR_NUMBER; index++) { RTC_WriteBackupRegister(aBKPDataReg[index], FirstBackupData + (index * 0x5A)); } } uint32_t TM_RTC_Init(TM_RTC_ClockSource_t source) { uint32_t status; uint8_t stat = 1; TM_RTC_t datatime; /* Enable PWR peripheral clock */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); /* Allow access to BKP Domain */ PWR_BackupAccessCmd(ENABLE); /* Get RTC status */ status = RTC_ReadBackupRegister(RTC_STATUS_REG); if (status == RTC_STATUS_TIME_OK) { TM_RTC_Status = RTC_STATUS_TIME_OK; /* Start internal clock if we choose internal clock */ if (source == TM_RTC_ClockSource_Internal) TM_RTC_Config(TM_RTC_ClockSource_Internal); /* Wait for RTC APB registers synchronisation (needed after start-up from Reset) */ RTC_WaitForSynchro(); /* Clear interrupt flags */ RTC_ClearITPendingBit(RTC_IT_WUT); EXTI->PR = 0x00400000; /* Get date and time */ TM_RTC_GetDateTime(&datatime, TM_RTC_Format_BIN); } else if (status == RTC_STATUS_INIT_OK) { TM_RTC_Status = RTC_STATUS_INIT_OK; /* Start internal clock if we choose internal clock */ if (source == TM_RTC_ClockSource_Internal) TM_RTC_Config(TM_RTC_ClockSource_Internal); /* Wait for RTC APB registers synchronisation (needed after start-up from Reset) */ RTC_WaitForSynchro(); /* Clear interrupt flags */ RTC_ClearITPendingBit(RTC_IT_WUT); EXTI->PR = 0x00400000; /* Get date and time */ //TM_RTC_GetDateTime(&datatime, TM_RTC_Format_BIN); } else { TM_RTC_Status = RTC_STATUS_ZERO; /* Return status = 0 -> RTC Never initialized before */ stat = RTC_STATUS_ZERO; /* Config RTC */ TM_RTC_Config(source); /* Set date and time */ datatime.date = 1; datatime.day = 1; datatime.month = 1; datatime.year = 0; datatime.hours = 0; datatime.minutes = 0; datatime.seconds = 0; /* Set date and time */ TM_RTC_SetDateTime(&datatime, TM_RTC_Format_BIN); /* Initialized OK */ TM_RTC_Status = RTC_STATUS_INIT_OK; } /* If first time initialized */ if (stat == RTC_STATUS_ZERO) return 0; return TM_RTC_Status; } void TM_RTC_SetDataTimeUnix(uint32_t unixTime) { TM_RTC_t data; TM_RTC_GetDateTimeFromUnix(&data, unixTime); TM_RTC_SetDateTime(&data, TM_RTC_Format_BIN); } /** * @brief Кореектировака времени. * @param Часовой пояс * @retval */ void TM_RTC_Correction(float utc) { TM_RTC_t data; TM_RTC_t newData; int utcSec; uint32_t unixTime; /* Получаем текущее время */ TM_RTC_GetDateTime(&data, TM_RTC_Format_BIN); /* Рассчитываем поправку */ utcSec = (int)(3600.0*utc); unixTime = data.unix + utcSec; /* Устанавливаем новое время */ TM_RTC_GetDateTimeFromUnix(&newData, unixTime); TM_RTC_SetDateTime(&newData, TM_RTC_Format_BIN); } TM_RTC_Result_t TM_RTC_SetDateTime(TM_RTC_t* data, TM_RTC_Format_t format) { TM_RTC_t tmp; /* Check date and time validation */ if (format == TM_RTC_Format_BCD) { tmp.date = TM_RTC_BCD2BIN(data->date); tmp.month = TM_RTC_BCD2BIN(data->month); tmp.year = TM_RTC_BCD2BIN(data->year); tmp.hours = TM_RTC_BCD2BIN(data->hours); tmp.minutes = TM_RTC_BCD2BIN(data->minutes); tmp.seconds = TM_RTC_BCD2BIN(data->seconds); tmp.day = TM_RTC_BCD2BIN(data->day); } else { tmp.date = data->date; tmp.month = data->month; tmp.year = data->year; tmp.hours = data->hours; tmp.minutes = data->minutes; tmp.seconds = data->seconds; tmp.day = data->day; } /* Check year and month */ if ( tmp.year > 99 || tmp.month == 0 || tmp.month > 12 || tmp.date == 0 || tmp.date > TM_RTC_Months[TM_RTC_LEAP_YEAR(2000 + tmp.year) ? 1 : 0][tmp.month - 1] || tmp.hours > 23 || tmp.minutes > 59 || tmp.seconds > 59 || tmp.day == 0 || tmp.day > 7 ) { /* Invalid date */ return TM_RTC_Result_Error; } /* Fill time */ RTC_TimeStruct.RTC_Hours = data->hours; RTC_TimeStruct.RTC_Minutes = data->minutes; RTC_TimeStruct.RTC_Seconds = data->seconds; /* Fill date */ RTC_DateStruct.RTC_Date = data->date; RTC_DateStruct.RTC_Month = data->month; RTC_DateStruct.RTC_Year = data->year; RTC_DateStruct.RTC_WeekDay = data->day; /* Set the RTC time base to 1s and hours format to 24h */ RTC_InitStruct.RTC_HourFormat = RTC_HourFormat_24; RTC_InitStruct.RTC_AsynchPrediv = RTC_ASYNC_PREDIV; RTC_InitStruct.RTC_SynchPrediv = RTC_SYNC_PREDIV; RTC_Init(&RTC_InitStruct); /* Set time */ if (format == TM_RTC_Format_BCD) { RTC_SetTime(RTC_Format_BCD, &RTC_TimeStruct); } else { RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct); } /* Set date */ if (format == TM_RTC_Format_BCD) { RTC_SetDate(RTC_Format_BCD, &RTC_DateStruct); } else { RTC_SetDate(RTC_Format_BIN, &RTC_DateStruct); } if (TM_RTC_Status != RTC_STATUS_ZERO) { /* Write backup registers */ RTC_WriteBackupRegister(RTC_STATUS_REG, RTC_STATUS_TIME_OK); } /* Return OK */ return TM_RTC_Result_Ok; } TM_RTC_Result_t TM_RTC_SetDateTimeString(char* str) { TM_RTC_t tmp; uint8_t i = 0; /* Get date */ tmp.date = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.date = tmp.date * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } i++; /* Get month */ tmp.month = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.month = tmp.month * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } i++; /* Get year */ tmp.year = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.year = tmp.year * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } i++; /* Get day in a week */ tmp.day = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.day = tmp.day * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } i++; /* Get hours */ tmp.hours = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.hours = tmp.hours * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } i++; /* Get minutes */ tmp.minutes = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.minutes = tmp.minutes * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } i++; /* Get seconds */ tmp.seconds = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.seconds = tmp.seconds * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } i++; /* Return status from set date time function */ return TM_RTC_SetDateTime(&tmp, TM_RTC_Format_BIN); } void TM_RTC_GetDateTime(TM_RTC_t* data, TM_RTC_Format_t format) { uint32_t unix; /* Get time */ if (format == TM_RTC_Format_BIN) { RTC_GetTime(RTC_Format_BIN, &RTC_TimeStruct); } else { RTC_GetTime(RTC_Format_BCD, &RTC_TimeStruct); } /* Format hours */ data->hours = RTC_TimeStruct.RTC_Hours; data->minutes = RTC_TimeStruct.RTC_Minutes; data->seconds = RTC_TimeStruct.RTC_Seconds; /* Get subseconds */ data->subseconds = RTC->SSR; /* Get date */ if (format == TM_RTC_Format_BIN) { RTC_GetDate(RTC_Format_BIN, &RTC_DateStruct); } else { RTC_GetDate(RTC_Format_BCD, &RTC_DateStruct); } /* Format date */ data->year = RTC_DateStruct.RTC_Year; data->month = RTC_DateStruct.RTC_Month; data->date = RTC_DateStruct.RTC_Date; data->day = RTC_DateStruct.RTC_WeekDay; /* Calculate unix offset */ unix = TM_RTC_GetUnixTimeStamp(data); data->unix = unix; } uint8_t TM_RTC_GetDaysInMonth(uint8_t month, uint8_t year) { /* Check input data */ if ( month == 0 || month > 12 ) { /* Error */ return 0; } /* Return days in month */ return TM_RTC_Months[TM_RTC_LEAP_YEAR(2000 + year) ? 1 : 0][month - 1]; } uint16_t TM_RTC_GetDaysInYear(uint8_t year) { /* Return days in year */ return TM_RTC_DAYS_IN_YEAR(2000 + year); } void TM_RTC_Config(TM_RTC_ClockSource_t source) { if (source == TM_RTC_ClockSource_Internal) { /* Enable the LSI OSC */ RCC_LSICmd(ENABLE); /* Wait till LSI is ready */ while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET); /* Select the RTC Clock Source */ RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); } else if (source == TM_RTC_ClockSource_External) { /* Enable the LSE OSC */ RCC_LSEConfig(RCC_LSE_ON); /* Wait till LSE is ready */ while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET); /* Select the RTC Clock Source */ RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); } /* Enable the RTC Clock */ RCC_RTCCLKCmd(ENABLE); /* Wait for register synchronization */ RTC_WaitForSynchro(); /* Write status */ RTC_WriteBackupRegister(RTC_STATUS_REG, RTC_STATUS_INIT_OK); } void TM_RTC_Interrupts(TM_RTC_Int_t int_value) { uint32_t int_val; /* Clear pending bit */ EXTI->PR = 0x00400000; /* Disable wakeup interrupt */ RTC_WakeUpCmd(DISABLE); /* Disable RTC interrupt flag */ RTC_ITConfig(RTC_IT_WUT, DISABLE); /* NVIC init for RTC */ NVIC_InitStruct.NVIC_IRQChannel = RTC_WKUP_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = RTC_PRIORITY; NVIC_InitStruct.NVIC_IRQChannelSubPriority = RTC_WAKEUP_SUBPRIORITY; NVIC_InitStruct.NVIC_IRQChannelCmd = DISABLE; NVIC_Init(&NVIC_InitStruct); /* RTC connected to EXTI_Line22 */ EXTI_InitStruct.EXTI_Line = EXTI_Line22; EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStruct.EXTI_LineCmd = DISABLE; EXTI_Init(&EXTI_InitStruct); if (int_value != TM_RTC_Int_Disable) { /* Enable NVIC */ NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); /* Enable EXT1 interrupt */ EXTI_InitStruct.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStruct); /* First disable wake up command */ RTC_WakeUpCmd(DISABLE); if (int_value == TM_RTC_Int_60s) { int_val = 0x3BFFF; /* 60 seconds = 60 * 4096 / 1 = 245760 */ } else if (int_value == TM_RTC_Int_30s) { int_val = 0x1DFFF; /* 30 seconds */ } else if (int_value == TM_RTC_Int_15s) { int_val = 0xEFFF; /* 15 seconds */ } else if (int_value == TM_RTC_Int_10s) { int_val = 0x9FFF; /* 10 seconds */ } else if (int_value == TM_RTC_Int_5s) { int_val = 0x4FFF; /* 5 seconds */ } else if (int_value == TM_RTC_Int_2s) { int_val = 0x1FFF; /* 2 seconds */ } else if (int_value == TM_RTC_Int_1s) { int_val = 0x0FFF; /* 1 second */ } else if (int_value == TM_RTC_Int_500ms) { int_val = 0x7FF; /* 500 ms */ } else if (int_value == TM_RTC_Int_250ms) { int_val = 0x3FF; /* 250 ms */ } else if (int_value == TM_RTC_Int_125ms) { int_val = 0x1FF; /* 125 ms */ } /* Clock divided by 8, 32768 / 8 = 4096 */ /* 4096 ticks for 1second interrupt */ RTC_WakeUpClockConfig(RTC_WakeUpClock_RTCCLK_Div8); /* Set RTC wakeup counter */ RTC_SetWakeUpCounter(int_val); /* Enable wakeup interrupt */ RTC_ITConfig(RTC_IT_WUT, ENABLE); /* Enable wakeup command */ RTC_WakeUpCmd(ENABLE); } } uint32_t TM_RTC_GetUnixTimeStamp(TM_RTC_t* data) { uint32_t days = 0, seconds = 0; uint16_t i; uint16_t year = (uint16_t) (data->year + 2000); /* Year is below offset year */ if (year < TM_RTC_OFFSET_YEAR) { return 0; } /* Days in back years */ for (i = TM_RTC_OFFSET_YEAR; i < year; i++) { days += TM_RTC_DAYS_IN_YEAR(i); } /* Days in current year */ for (i = 1; i < data->month; i++) { days += TM_RTC_Months[TM_RTC_LEAP_YEAR(year)][i - 1]; } /* Day starts with 1 */ days += data->date - 1; seconds = days * TM_RTC_SECONDS_PER_DAY; seconds += data->hours * TM_RTC_SECONDS_PER_HOUR; seconds += data->minutes * TM_RTC_SECONDS_PER_MINUTE; seconds += data->seconds; /* seconds = days * 86400; */ return seconds; } void TM_RTC_GetDateTimeFromUnix(TM_RTC_t* data, uint32_t unix) { uint16_t year; /* Store unix time to unix in struct */ data->unix = unix; /* Get seconds from unix */ data->seconds = unix % 60; /* Go to minutes */ unix /= 60; /* Get minutes */ data->minutes = unix % 60; /* Go to hours */ unix /= 60; /* Get hours */ data->hours = unix % 24; /* Go to days */ unix /= 24; /* Get week day */ /* Monday is day one */ data->day = (unix + 3) % 7 + 1; /* Get year */ year = 1970; while (1) { if (TM_RTC_LEAP_YEAR(year)) { if (unix >= 366) { unix -= 366; } else { break; } } else if (unix >= 365) { unix -= 365; } else { break; } year++; } /* Get year in xx format */ data->year = (uint8_t) (year - 2000); /* Get month */ for (data->month = 0; data->month < 12; data->month++) { if (TM_RTC_LEAP_YEAR(year) && unix >= (uint32_t)TM_RTC_Months[1][data->month]) { unix -= TM_RTC_Months[1][data->month]; } else if (unix >= (uint32_t)TM_RTC_Months[0][data->month]) { unix -= TM_RTC_Months[0][data->month]; } else { break; } } /* Get month */ /* Month starts with 1 */ data->month++; /* Get date */ /* Date starts with 1 */ data->date = unix + 1; } void TM_RTC_SetAlarm(TM_RTC_Alarm_t Alarm, TM_RTC_AlarmTime_t* DataTime, TM_RTC_Format_t format) { RTC_AlarmTypeDef RTC_AlarmStruct; /* Disable alarm first */ TM_RTC_DisableAlarm(Alarm); /* Set RTC alarm settings */ /* Set alarm time */ RTC_AlarmStruct.RTC_AlarmTime.RTC_Hours = DataTime->hours; RTC_AlarmStruct.RTC_AlarmTime.RTC_Minutes = DataTime->minutes; RTC_AlarmStruct.RTC_AlarmTime.RTC_Seconds = DataTime->seconds; RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay; /* Alarm type is every week the same day in a week */ if (DataTime->alarmtype == TM_RTC_AlarmType_DayInWeek) { /* Alarm trigger every week the same day in a week */ RTC_AlarmStruct.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_WeekDay; /* Week day can be between 1 and 7 */ if (DataTime->day == 0) { RTC_AlarmStruct.RTC_AlarmDateWeekDay = 1; } else if (DataTime->day > 7) { RTC_AlarmStruct.RTC_AlarmDateWeekDay = 7; } else { RTC_AlarmStruct.RTC_AlarmDateWeekDay = DataTime->day; } } else { /* Alarm type is every month the same day */ /* Alarm trigger every month the same day in a month */ RTC_AlarmStruct.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_Date; /* Month day can be between 1 and 31 */ if (DataTime->day == 0) { RTC_AlarmStruct.RTC_AlarmDateWeekDay = 1; } else if (DataTime->day > 31) { RTC_AlarmStruct.RTC_AlarmDateWeekDay = 31; } else { RTC_AlarmStruct.RTC_AlarmDateWeekDay = DataTime->day; } } switch (Alarm) { case TM_RTC_Alarm_A: /* Configure the RTC Alarm A */ RTC_SetAlarm(format, RTC_Alarm_A, &RTC_AlarmStruct); /* Enable Alarm A */ RTC_AlarmCmd(RTC_Alarm_A, ENABLE); /* Enable Alarm A interrupt */ RTC_ITConfig(RTC_IT_ALRA, ENABLE); /* Clear Alarm A pending bit */ RTC_ClearFlag(RTC_IT_ALRA); break; case TM_RTC_Alarm_B: /* Configure the RTC Alarm B */ RTC_SetAlarm(format, RTC_Alarm_B, &RTC_AlarmStruct); /* Enable Alarm B */ RTC_AlarmCmd(RTC_Alarm_B, ENABLE); /* Enable Alarm B interrupt */ RTC_ITConfig(RTC_IT_ALRB, ENABLE); /* Clear Alarm B pending bit */ RTC_ClearFlag(RTC_IT_ALRB); break; default: break; } } void TM_RTC_DisableAlarm(TM_RTC_Alarm_t Alarm) { switch (Alarm) { case TM_RTC_Alarm_A: /* Disable Alarm A */ RTC_AlarmCmd(RTC_Alarm_A, DISABLE); /* Disable Alarm A interrupt */ RTC_ITConfig(RTC_IT_ALRA, DISABLE); /* Clear Alarm A pending bit */ RTC_ClearFlag(RTC_IT_ALRA); break; case TM_RTC_Alarm_B: /* Disable Alarm B */ RTC_AlarmCmd(RTC_Alarm_B, DISABLE); /* Disable Alarm B interrupt */ RTC_ITConfig(RTC_IT_ALRB, DISABLE); /* Clear Alarm B pending bit */ RTC_ClearFlag(RTC_IT_ALRB); break; default: break; } /* Clear RTC Alarm pending bit */ EXTI->PR = 0x00020000; /* Configure EXTI 17 as interrupt */ EXTI_InitStruct.EXTI_Line = EXTI_Line17; EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStruct.EXTI_LineCmd = ENABLE; /* Initialite Alarm EXTI interrupt */ EXTI_Init(&EXTI_InitStruct); /* Configure the RTC Alarm Interrupt */ NVIC_InitStruct.NVIC_IRQChannel = RTC_Alarm_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = RTC_PRIORITY; NVIC_InitStruct.NVIC_IRQChannelSubPriority = RTC_ALARM_SUBPRIORITY; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; /* Initialize RTC Alarm Interrupt */ NVIC_Init(&NVIC_InitStruct); } void TM_RTC_WriteBackupRegister(uint8_t location, uint32_t value) { /* Check input, 0 to 18 registers are allowed */ if (location > 18) { return; } /* Write data to backup register */ *(uint32_t *)((&RTC->BKP0R) + 4 * location) = value; } uint32_t TM_RTC_ReadBackupRegister(uint8_t location){ /* Check input, 0 to 18 registers are allowed */ if (location > 18) { return 0; } /* Read data from backup register */ return *(uint32_t *)((&RTC->BKP0R) + 4 * location); } /* Callbacks */ __weak void TM_RTC_RequestHandler(void) { /* If user needs this function, then they should be defined separatelly in your project */ } __weak void TM_RTC_AlarmAHandler(void) { /* If user needs this function, then they should be defined separatelly in your project */ } __weak void TM_RTC_AlarmBHandler(void) { /* If user needs this function, then they should be defined separatelly in your project */ } /* Private RTC IRQ handlers */ void RTC_WKUP_IRQHandler(void) { /* Check for RTC interrupt */ if (RTC_GetITStatus(RTC_IT_WUT) != RESET) { /* Clear interrupt flags */ RTC_ClearITPendingBit(RTC_IT_WUT); /* Call user function */ TM_RTC_RequestHandler(); } /* Clear EXTI line 22 bit */ EXTI->PR = 0x00400000; } void RTC_Alarm_IRQHandler(void) { /* RTC Alarm A check */ if (RTC_GetITStatus(RTC_IT_ALRA) != RESET) { /* Clear RTC Alarm A interrupt flag */ RTC_ClearITPendingBit(RTC_IT_ALRA); /* Call user function for Alarm A */ TM_RTC_AlarmAHandler(); } /* RTC Alarm B check */ if (RTC_GetITStatus(RTC_IT_ALRB) != RESET) { /* Clear RTC Alarm A interrupt flag */ RTC_ClearITPendingBit(RTC_IT_ALRB); /* Call user function for Alarm B */ TM_RTC_AlarmBHandler(); } /* Clear EXTI line 17 bit */ EXTI->PR = 0x00020000; } /** * @brief Установливает время срабатывания профилактики сульфатации для отладки * @retval */ void RTC_SetDebugProfTime(void) { TM_RTC_t currentTime; uint32_t unixTime; TM_RTC_GetDateTime(¤tTime, TM_RTC_Format_BIN); unixTime = TM_RTC_GetUnixTimeStamp(¤tTime); unixTime += 30; TM_RTC_WriteBackupRegister(RTC_BKP_DR0, unixTime); } /** * @brief Установливает время срабатывания профилактики сульфатации */ void RTC_SetProfTime(char *str) { TM_RTC_t tmp; uint32_t unixTime; uint8_t i = 0; /* Get date */ tmp.date = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.date = tmp.date * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } i++; /* Get month */ tmp.month = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.month = tmp.month * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } //i++; i+=3; /* Get year */ tmp.year = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.year = tmp.year * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } i++; i++; /* Get hours */ tmp.hours = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.hours = tmp.hours * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } i++; /* Get minutes */ tmp.minutes = 0; while (TM_RTC_CHARISNUM(*(str + i))) { tmp.minutes = tmp.minutes * 10 + TM_RTC_CHAR2NUM(*(str + i)); i++; } i++; /* Get seconds */ tmp.seconds = 0; /* Устанавливаем +1 для профилактики */ tmp.year += 1; unixTime = TM_RTC_GetUnixTimeStamp(&tmp); TM_RTC_WriteBackupRegister(RTC_BKP_DR0, unixTime); } /** * @brief * @retval */ uint32_t RTC_GetUnixTime(void) { TM_RTC_t currentTime; TM_RTC_GetDateTime(¤tTime, TM_RTC_Format_BIN); return TM_RTC_GetUnixTimeStamp(¤tTime); }