я делал (в программных часах на Меге 8) просто таблицу чисел марта/октября, соответствующих переходу (с 2000 по 203x год - всего 64 байта, думаю само вычисление числа займет больше).
Функция rtc_increment вызывается каждую секунду в обработчике прерывания часового кварца.
Флаги flag_rtc_sec_pass, flag_rtc_min_pass, flag_rtc_hr_pass используются в других частях программы для синхронизации с секундными, минутными, часовыми событиями (в конце основного цикла обнуляются).
Флаги flag_rtc_corrected и flag_rtc_corrected_forw - для улавливания события коррекции.
ul_rtc.h :
Код
/** \addtogroup group_rtc RTC structure/functions (структура и функции для работы с часами реального времени)
*/
#if ((!defined(ul_c_rtc_included)) || (defined __DOXYGEN__))
#define ul_c_rtc_included 1 /**< \brief module inclusion flag<br />флаг включения модуля \ingroup group_rtc */
#include "ul_misc.h" /*include misc definitions/functions types*/
/** \brief RTC structure<br />структура часов \ingroup group_rtc */
typedef struct
{u8 sec; /**< \brief seconds (0..59) <br />секунды (0..59) \ingroup group_rtc */
u8 min; /**< \brief minutes (0..59) <br />минуты (0..59) \ingroup group_rtc */
u8 hr; /**< \brief hours (0..23) <br />часы (0..23) \ingroup group_rtc */
u8 date; /**< \brief date (1..31) <br />дата (1..31) \ingroup group_rtc */
u8 month; /**< \brief month (1..12) <br />месяц (1..12) \ingroup group_rtc */
u16 year; /**< \brief year (1900..2100) <br />год (1900..2100) \ingroup group_rtc */
u8 flags; /**< \brief RTC flags <br />флаги RTC \ingroup group_rtc */
u16 crc; /**< \brief crc of structure <br />контр.сумма структуры \ingroup group_rtc */
}struct_rtc;
#define flag_rtc_sec_pass 0x01 /**< \brief =1 every second passed <br />=1 каждую секунду \ingroup group_rtc */
#define flag_rtc_min_pass 0x02 /**< \brief =1 every minute passed <br />=1 каждую минуту \ingroup group_rtc */
#define flag_rtc_hr_pass 0x04 /**< \brief =1 every hour passed <br />=1 каждый час \ingroup group_rtc */
#define flag_rtc_corrected 0x20 /**< \brief =1 if was time correction <br />=1 если была коррекция на летнее/зимнее время \ingroup group_rtc */
#define flag_rtc_corrected_forw 0x40 /**< \brief =1 if was hour-forward time correction (otherwise hour-backward)<br />=1 если была коррекция на час вперед (иначе на час назад) \ingroup group_rtc */
#define flag_rtc_correction 0x80 /**< \brief =1 for auto-correction <br />=1 для автоматического перехода на зимнее/летнее время \ingroup group_rtc */
/** \brief increment time of RTC structure by 1 second<br />увеличить время в структуре часов на 1 секунду \ingroup group_rtc */
inline void rtc_increment(void *rtc_data);
#endif
ul_rtc.c :
Код
#include "ul_rtc.h" /*include RTC header*/
#if (defined(ul_c_use_gccavr))
#include <avr/pgmspace.h> /*Program memory usage for AVR-GCC*/
#endif
#if (!defined(rtc_corr_dates_table))
#if (defined(ul_c_use_gccavr))
u8 rtc_corr_dates_table[][32] PROGMEM = {{29,28,27,26,31,30,29,28,26,25,31,30,28,27,26,25,30,29,28,27,25,31,30,29,27,26,
25,31,29,28,27,26},
{26,25,31,30,28,27,26,25,30,29,28,27,25,31,30,29,27,26,25,31,29,28,27,26,31
,30,29,28,26,25,31,30}
};
#else
u8 rtc_corr_dates_table[][32] = {{29,28,27,26,31,30,29,28,26,25,31,30,28,27,26,25,30,29,28,27,25,31,30,29,27,26,
25,31,29,28,27,26},
{26,25,31,30,28,27,26,25,30,29,28,27,25,31,30,29,27,26,25,31,29,28,27,26,31
,30,29,28,26,25,31,30}
};
#endif
#endif
inline void rtc_increment(void *rtc_data)
{u8 u8_01, u8_02;
u8_01 = (*((struct_rtc *)rtc_data)).month;
u8_02 = (*((struct_rtc *)rtc_data)).date;
(*((struct_rtc *)rtc_data)).flags |= flag_rtc_sec_pass; /*set second passed flag*/
if (++((*((struct_rtc *)rtc_data)).sec) == 60) /*process seconds overflow*/
{(*((struct_rtc *)rtc_data)).sec = 0;
(*((struct_rtc *)rtc_data)).flags |= flag_rtc_min_pass; /*set minute passed flag*/
if (++((*((struct_rtc *)rtc_data)).min) == 60) /*process minutes overflow*/
{(*((struct_rtc *)rtc_data)).min = 0;
(*((struct_rtc *)rtc_data)).flags |= flag_rtc_hr_pass; /*set hour passed flag*/
if (++((*((struct_rtc *)rtc_data)).hr) == 24) /*process hours overflow*/
{(*((struct_rtc *)rtc_data)).hr = 0;
u8_02++; /*calculate next date*/
if (u8_02 == 32) {u8_01++; u8_02 = 1;}
else if (u8_02 == 31)
{if ((u8_01 == 4) || (u8_01 == 6) || (u8_01 == 9) || (u8_01 == 11))
{u8_01++;
u8_02 = 1;
}
}else if (u8_02 == 30)
{if (u8_01==2) {u8_01++; u8_02 = 1;}
}else if (u8_02 == 29)
{if ((u8_01 == 2) && (((*((struct_rtc *)rtc_data)).year) & 3))
{u8_01++;
u8_02 = 1;
}
}
/*month overflow*/
if (u8_01 == 13)
{u8_01 = 1;
((*((struct_rtc *)rtc_data)).year)++;
}
}
}
}
(*((struct_rtc *)rtc_data)).month = u8_01;
(*((struct_rtc *)rtc_data)).date = u8_02;
/*if needed, do time auto correction*/
if ((*((struct_rtc *)rtc_data)).flags & flag_rtc_correction)
{/*every last sunday of march (hour++) and october (hour--) at 4 a.m.*/
if (((u8_01 == 10) || (u8_01 == 3)) && (u8_02 > 24) &&
((*((struct_rtc *)rtc_data)).hr == 4) && ((*((struct_rtc *)rtc_data)).min == 0) &&
((*((struct_rtc *)rtc_data)).sec == 0))
{u8 u8_03;
/*get correction date*/
u8_03 = ((u8)((*((struct_rtc *)rtc_data)).year)) & 0x1f; /*table index*/
#if (defined(ul_c_use_gccavr))
u8_03 = pgm_read_byte(&(rtc_corr_dates_table[u8_01 & 1][u8_03]));
#else
u8_03 = rtc_corr_dates_table[u8_01 & 1][u8_03];
#endif
/*if date is correct, do time correction*/
if (u8_02 == u8_03)
{(*((struct_rtc *)rtc_data)).flags |= flag_rtc_corrected; /*set correction flag*/
if (u8_01 == 3)
{(*((struct_rtc *)rtc_data)).hr++;
(*((struct_rtc *)rtc_data)).flags |= flag_rtc_corrected_forw; /*forward correction*/
}else (*((struct_rtc *)rtc_data)).hr--;
}
}
}
}
Сообщение отредактировал umup - Apr 2 2008, 20:36