Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

stm32f030. как считать день недели ?

Вт апр 11, 2017 23:20:47

Здравствуйте уважаемые коты!

устройство: таймер с различным поведением по будням и выходным
встроенная клавиатура и дисплей

проблемы с конфигурацией и запуском нет
всё хорошо настраивается и работает
секунды, минуты, часы, дни, месяцы и годы изменяются автоматически как положено

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

а хочется получить функционал как в любых самых примитивных электронных часах с датой:
меняешь дату - день недели меняется автоматически

кроме того, хочется защитится от тупых ошибок ввода даты типа 29/02/17

для сотой серии вроде всё проще, там ртц имеет одну большую чиселку, с которой как мне кажется проще работать
даже дату можно увеличить просто увеличив эту чиселку, и она преобразуется корректно
а вот в 030 серии всё это хранится отдельными значениями

подозреваю что я не первый столкнулся с такой задачей, но поиск к сожалению не дал ответов
Буду благодарен если подскажите решения, или хотя бы направления куда смотреть

Использую HAL, но другие решения тоже рассматриваю :)

Re: stm32f030. как считать день недели ?

Ср апр 12, 2017 00:46:30

Преобразовываешь дату в количество дней относительно начала какого-то года, если 1 января было понедельником, остается лишь взять остаток от деления на 7...

Re: stm32f030. как считать день недели ?

Ср апр 12, 2017 07:20:27

Решение очевидное, но как это сделать с учётом високосных годов ? Да и просто учесть что в разных месяцах разное количество дней ?

Re: stm32f030. как считать день недели ?

Ср апр 12, 2017 08:25:50

Насколько мне помнится в формуле учтен высокосный год. Гуглится на ура..

// формула для вычисления дня недели по дате (ru.wikipedia.org)
// a = (14 - месяц) / 12
// y = год - a
// m = месяц + 12 * a - 2
//ДеньНедели = (7000 + (день + y + y / 4 - y / 100 + y / 400 + (31 * m) / 12)) ОСТАТОК 7

Вот еще одна формула вычисления дня недели.
dayOfWeek = (year+(int)(year4)+ mounth + day) % 7;

где - dayOfWeek - число от нуля до 7, соответсвует дню недели
(0 - вс,1-пн, ...)
year - год
(int)(year/4) - целая часть от четверти года(математики, простите за int)
mounth - число, соответствующее месяцу
январь - 4(високосный) 5(невисокосный)
февраль - 0(високосный) 1(невисокосный)
март - 1
апрель - 4
май - 6
июнь - 2
июль - 4
август - 0
сентябрь - 3
октябрь - 5
ноябрь - 1
декабрь - 3
day - число дня в месяце

Итак, в моем примере
dayOfWeek = (1980 + 495 + 0 + 17 ) % 7 = 0(воскресенье)

Re: stm32f030. как считать день недели ?

Ср апр 12, 2017 08:34:54

RoboC писал(а):январь - 4(високосный) 5(невисокосный)
февраль - 0(високосный) 1(невисокосный)

А как это учитывать? По таблице ?

Re: stm32f030. как считать день недели ?

Ср апр 12, 2017 09:04:33

В первой формуле он учтен.

Как узнать что год высокосный?

Или по таблице :) Все зависит насколько вечный Вы делаете календарь и сколько флеша у вас осталось.

Re: stm32f030. как считать день недели ?

Вт май 02, 2017 10:37:44

#define SEC_A_DAY 86400
typedef struct
{
uint16_t year;
uint8_t mon;
uint8_t mday;
uint8_t hour;
uint8_t min;
uint8_t sec;
uint8_t wday;
} RTC_cal;



// Функция переводит счетный регистр RTC в дату и время
void timer_to_cal (uint32_t timer, RTC_cal * RTC_time)
{
uint32_t a;
uint8_t b;
uint8_t c;
uint8_t d;
uint32_t time;
time = timer%SEC_A_DAY; // секунд с начала суток
a = ((timer+43200)/(86400>>1)) + (2440587<<1) + 1; // 86400 - сек в сутках
a>>=1; // а - кол-во суток от 1970г + 2440587.5
RTC_time->wday = a%7;
a+=32044; // а - кол-во суток от 1970г + 2472631.5
b=(4*a+3)/146097; // 146097 - кол-во суток за 400 лет. b - кол-во веков от 1 марта -4800 года
a=a-(146097*b)/4;
c=(4*a+3)/1461; // c - лет после 1 марта 1900-го года, 2100-го и др невисокосных Григ.
a=a-(1461*c)/4; // 1461 - кол-во дней за 4 года. a - кол-во дней с 1-го марта
d=(5*a+2)/153; // месяц, начиная с марта
RTC_time->mday=a-(153*d+2)/5+1;
RTC_time->mon=d+3-12*(d/10);
RTC_time->year=100*b+c-4800+(d/10);
RTC_time->hour=time/3600;
RTC_time->min=(time%3600)/60;
RTC_time->sec=(time%3600)%60;
}

// Аргументы: дата и время, результат - в счетный регистр RTC
uint32_t cal_to_timer (RTC_cal * RTC_time) // учесть пояс и летнее время
{
uint8_t a;
uint16_t y;
uint8_t m;
uint32_t Uday;
uint32_t time;

a=((14-RTC_time->mon)/12);
y=RTC_time->year+4800-a;
m=RTC_time->mon+(12*a)-3;
Uday=(RTC_time->mday+((153*m+2)/5)+365*y+(y/4)-(y/100)+(y/400)-32045)-2440588;
time=Uday*86400;
time+=RTC_time->sec+RTC_time->min*60+RTC_time->hour*3600;
return time;
}
//**************************************************************************


Да, большая чиселка, как в 100-й серии гораздо удобнее. Но имея набор отдельных минут, часов итд, как в stm32f030 или ds3107 итп, можно используя данные функции, конвертнуть эти данные в большую чиселку (uint32_t) и обратно и на выходе у вас будет правильный день недели. Проверено - работает.

Re: stm32f030. как считать день недели ?

Пт фев 02, 2018 06:22:50

В функции: void timer_to_cal (uint32_t timer, RTC_cal * RTC_time)
Точно нет ошибки вычисления дня недели?
Вчера решил применить ее в будильнике который должен сробатывать только по будням но утром обнаружил, что он перепрыгнул с четверга на субботу. Я вечером еще конечно проверю у себя код.

Re: stm32f030. как считать день недели ?

Пт фев 02, 2018 07:00:05

Извиняюсь ошибка была у меня )) функция работает правильно.
Ответить