|
@@ -0,0 +1,864 @@
|
|
|
|
+/**
|
|
|
|
+ * |----------------------------------------------------------------------
|
|
|
|
+ * | 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 <http://www.gnu.org/licenses/>.
|
|
|
|
+ * |----------------------------------------------------------------------
|
|
|
|
+ */
|
|
|
|
+#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);
|
|
|
|
+}
|