This commit is contained in:
olikraus 2017-06-10 23:56:02 +02:00
parent a30824ba71
commit 2e000ed456
5 changed files with 239 additions and 22 deletions

View File

@ -59,6 +59,12 @@
/* Large values reduce power consumtion, but displayed time and alarm might be later than the actual RTC time. */
#define WAKEUP_PERIOD 14
/* DST (daylight savings time) rules */
/* 0: DST not applied */
/* 1: EU */
/* 2: US */
#define DST_RULE 1
/* Contrast value for the display in normal mode (u8g2_SetContrast). */
/* 208: default value for the SSD1306 */
@ -79,6 +85,8 @@ volatile unsigned long DisplayStandbyMode = DISPLAY_STANDBY_MODE_OFF;
/*=======================================================================*/
/* external functions */
uint8_t u8x8_gpio_and_delay_stm32l0(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
int is_dst_by_date(uint8_t region);
void adjustDST(uint8_t region);
/*=======================================================================*/
@ -107,6 +115,8 @@ const uint8_t *AlarmSeqPtr = NULL;
const uint8_t *AlarmSeqStart = NULL;
volatile unsigned long AlarmSeqTime = 0;
volatile unsigned long RTCUpdateCount = 0; // decremented in SysTick IRQ if not 0
volatile unsigned long NextDSTAdjustment = 0;
//rtc_t rtc;
@ -808,6 +818,7 @@ int main()
SystemCoreClockUpdate(); /* Update variable SystemCoreClock, must be executed after each reset */
startUp(); /* basic system setup + make a backup of PWR_CSR (PWR_CSR_Backup), must be executed after each reset */
startSysTick(); /* start the sys tick interrupt, must be executed after each reset */
adjustDST(DST_RULE); /* adjust DST... ok,this is only done after reset, hopefully this is often enough. This must be called before readRTC() */
/* LED output line */
@ -917,7 +928,8 @@ int main()
/* get current voltage level of the battery */
adc = readADC(5);
/* start user loop */
for(;;)

View File

@ -2,12 +2,14 @@
summer.c
stm32l0 daylight savings time calculation
stm32l0 daylight savings time (DST) calculation
US:
Der Energy Policy Act of 2005 (Public Law 109-58) bestimmt in Sec. 110 mit dem Titel Daylight Savings, dass ab 2007 die Sommerzeit am zweiten Sonntag im März beginnt und am ersten Sonntag im November endet.
Der Energy Policy Act of 2005 (Public Law 109-58) bestimmt in Sec. 110 mit dem Titel Daylight Savings,
dass ab 2007 die Sommerzeit am zweiten Sonntag im März beginnt und am ersten Sonntag im November endet.
EU:
Central European Summer Time (CEST, britisch) oder Central European Daylight Saving Time
(applies to almost all european countries)
@ -16,25 +18,98 @@
3:00 Uhr MESZ, indem die Stundenzählung um eine Stunde von 3:00 Uhr auf 2:00 Uhr zurückgestellt wird. Die Stunde von 2:00 Uhr bis 3:00 Uhr erscheint im Herbst also zweimal.
*/
#ifdef __unix
#include <stdio.h>
#include <stdint.h>
static uint8_t is_leap_year(uint16_t y)
{
if (
((y % 4 == 0) && (y % 100 != 0)) ||
(y % 400 == 0)
)
return 1;
return 0;
}
uint16_t get_year_day_number(uint16_t y, uint8_t m, uint8_t d)
{
uint8_t tmp1;
uint16_t tmp2;
tmp1 = 0;
if ( m >= 3 )
tmp1++;
tmp2 = m;
tmp2 +=2;
tmp2 *=611;
tmp2 /= 20;
tmp2 += d;
tmp2 -= 91;
tmp1 <<=1;
tmp2 -= tmp1;
if ( tmp1 != 0 )
tmp2 += is_leap_year(y);
return tmp2;
}
uint8_t get_weekday_by_year_day_number(uint16_t y, uint16_t ydn)
{
uint8_t j, c, tmp8;
uint16_t tmp16;
y--;
j = y % 100;
c = y / 100;
tmp16 = c;
tmp16 *= 5;
tmp16 += ydn;
tmp8 = j;
j >>= 2;
c >>= 2;
tmp8 += j;
tmp8 += c;
tmp8 += 28;
tmp16 += tmp8;
tmp16 %= 7;
return tmp16;
}
uint16_t year;
uint16_t month;
uint16_t day;
uint16_t hour;
#else
#include "datecalc.h"
#include "stm32l031xx.h"
#endif
/*
this function does not require gui_date_adjust() to be called
0: Summertime
1: Wintertime
-1: unknown (last sunday in oct, between 2am and 3am
0: no DST (Wintertime)
1: DST (Summertime)
-1: unknown (last sunday in oct, between 2am and 3am )
region
0: do nothing
1: EU
2: US
*/
int is_summer_time(void)
int is_dst_by_date(uint8_t region)
{
uint16_t ydn;
uint16_t ydn_change_to_wintertime;
uint16_t ydn_change_to_summertime;
#ifndef __unix
uint16_t year;
uint16_t month;
uint16_t day;
uint16_t hour;
uint16_t ydn_change_to_wintertime;
uint16_t ydn_change_to_summertime;
/* read date from date register */
@ -57,31 +132,140 @@ int is_summer_time(void)
hour *= 10;
hour += ((RTC->TR >> 16) & 15);
#endif
/* convert all dates to date numbers of the current year*/
ydn = get_year_day_number(year, month, day);
ydn_change_to_wintertime = get_year_day_number(year, 10, 31);
ydn_change_to_wintertime -= get_weekday_by_year_day_number(year, ydn_change_to_wintertime);
ydn_change_to_summertime = get_year_day_number(year, 3, 31);
if ( region == 1 ) /* EU */
{
/* European Summer Time: Last Sunday in March and last Sunday in October */
ydn_change_to_summertime = get_year_day_number(year, 3, 31);
ydn_change_to_wintertime = get_year_day_number(year, 10, 31);
}
else if ( region == 2 ) /* US */
{
/* US DST rules: Second Sunday in March and First Sunday in November */
ydn_change_to_summertime = get_year_day_number(year, 2, 28+is_leap_year(year));
ydn_change_to_summertime += 14;
ydn_change_to_wintertime = get_year_day_number(year, 10, 31);
ydn_change_to_wintertime += 7;
}
else
{
return 0;
}
ydn_change_to_summertime -= get_weekday_by_year_day_number(year, ydn_change_to_summertime);
ydn_change_to_wintertime -= get_weekday_by_year_day_number(year, ydn_change_to_wintertime);
ydn = get_year_day_number(year, month, day);
if ( ydn == ydn_change_to_summertime )
if ( hour >= 2 )
return 1; /* vorstellen */
return 1; /* yes, it is DST */
if ( ydn == ydn_change_to_wintertime )
{
if ( hour < 2 )
return 1; /* vorstellen, immer noch sommerzeit */
return 1; /* still DST */
if ( hour > 3 )
return 0; /* jetzt ist wieder Winterzeit */
return -1; /* zwischen 2 und 3 Uhr wissen wir nichts... */
return 0; /* not DST any more */
return -1; /* not sure whether DST or not */
}
if ( ydn > ydn_change_to_summertime && ydn < ydn_change_to_wintertime )
return 1;
return 1; /* within DST */
return 0;
}
#ifdef __unix
int main()
{
int dd;
int d = -2;
for( year = 2000; year < 2030; year++ )
{
printf("%d: ", year);
for( month = 3; month <= 11; month ++ )
{
for( day = 1; day<= 31; day++ )
{
hour = 2;
dd = is_dst_by_date(1);
if ( d == 0 && dd == 1 )
{
printf("%d.%d.%d", day, month, year);
}
switch(dd)
{
//case -1: printf("%d.%d.%d", day, month, year); break;
//case 0: printf("w"); break;
//case 1: printf("s"); break;
}
d = dd;
}
}
printf("\n");
}
}
#else
/*
region
0: do nothing
1: EU
2: US
*/
void adjustDST(uint8_t region)
{
int is_dst;
int dst_state;
is_dst = is_dst_by_date(region);
if ( is_dst >= 0 )
{
dst_state = 0;
if ( RTC->CR & RTC_CR_BCK ) /* BKP flag in the CR register */
dst_state = 1;
if ( is_dst != dst_state )
{
__disable_irq();
PWR->CR |= PWR_CR_DBP; /* disable write protection (step 1) */
RTC->WPR = 0x0ca; /* disable RTC write protection (step 2) */
RTC->WPR = 0x053;
if ( is_dst != 0 )
{
RTC->CR |= RTC_CR_BCK; /* the RTC will now run in summer time (set DST flag) */
RTC->CR |= RTC_CR_ADD1H; /* change to DST (Summertime): add one hour */
}
else
{
RTC->CR &= ~RTC_CR_BCK; /* the RTC will now run in winter time (turn off DST flag) */
RTC->CR |= RTC_CR_SUB1H; /* change back to none DST (Wintertime): subtract one hour */
}
RTC->WPR = 0; /* enable RTC write protection (step 2) */
RTC->WPR = 0;
__enable_irq();
}
}
}
#endif

View File

@ -208,3 +208,21 @@ http://www.hilltop-cottage.info/blogs/adam/model-watt-governor-cad-plans-and-con
http://www.stuartmodels.com/products/fittings--tools---accessories/governor---spring-belt ... teuer
Alles zu teuer.
Glocke mit servo dran...
---------------
A) short description of the STM32L0 RTC
- date/time register
- CR register with special DST features (BKP, SUB1H and ADD1H flags)
- two step write protection:
PWR->CR |= PWR_CR_DBP;
RTC->WPR = 0x0ca; /* disable RTC write protection */
RTC->WPR = 0x053;
B) algorithm
- basic idea
- special case for winter time change (double hour)
C) Date calculation
D) Code

View File

@ -70,7 +70,7 @@
0 not a leap year
1 leap year
*/
static uint8_t is_leap_year(uint16_t y)
uint8_t is_leap_year(uint16_t y)
{
if (
((y % 4 == 0) && (y % 100 != 0)) ||
@ -85,7 +85,7 @@ static uint8_t is_leap_year(uint16_t y)
uint16_t get_year_day_number(uint16_t y, uint8_t m, uint8_t d)
Description:
Calculate the day number within a year. 1st of Jan has the number 1.
"Robertson" Algorithm
"Robertson" Algorithm IDAY (CACM Vol 15/#10/Oct 1972)
Arguments:
y year, e.g. 2011 for year 2011
m month with 1 = january to 12 = december
@ -121,7 +121,7 @@ uint16_t get_year_day_number(uint16_t y, uint8_t m, uint8_t d)
uint8_t get_month_by_year_day_number(uint16_t y, uint16_t ydn)
Description:
Get the month from year and day number within a year.
"R. A. Stone" Algorithm
"R. A. Stone" Algorithm (CACM Vol 13/#10/Oct 1970)
Arguments:
y year, e.g. 2011 for year 2011
ydn year day number (1st of Jan has the number 1)
@ -160,7 +160,7 @@ uint8_t get_month_by_year_day_number(uint16_t y, uint16_t ydn)
uint8_t get_day_by_year_day_number(uint16_t y, uint16_t ydn)
Description:
Get the day within month from year and day number within a year.
"R. A. Stone" Algorithm
"R. A. Stone" Algorithm (CACM Vol 13/#10/Oct 1970)
Arguments:
y year, e.g. 2011 for year 2011
ydn year day number (1st of Jan has the number 1)
@ -189,6 +189,8 @@ uint8_t get_day_by_year_day_number(uint16_t y, uint16_t ydn)
Description:
Get the day within week from year and day number within a year.
"Zeller" Algorithm
https://de.wikisource.org/wiki/Index:Acta_Mathematica_vol._009_(1886)
https://ia801407.us.archive.org/8/items/actamathematica09upps/actamathematica09upps.pdf
Arguments:
y year, e.g. 2011 for year 2011
ydn year day number (1st of Jan has the number 1)

View File

@ -62,6 +62,7 @@
#include <stdint.h>
uint8_t is_leap_year(uint16_t y);
uint16_t get_year_day_number(uint16_t y, uint8_t m, uint8_t d);
uint8_t get_month_by_year_day_number(uint16_t y, uint16_t ydn);
uint8_t get_day_by_year_day_number(uint16_t y, uint16_t ydn);