Сообщение от
drvlas
Никак не могу понять, как получить из структуры SystemTimeDate (библиотека SysLibTime.lib) время в формате POSIX (это которое в секундах от 1970-01-01-00:00:00).
У меня работает ФБ CurTimeEx из этой библиотеки. В нем мирно сосуществуют 64-битное системное время (с разрешающей способностью 1 мкс) и структура ГОД-МЕСЯЦ- и т.д.
Эту структуру я инициализирую, она отсчитывает правильное время и дату, когда нужно - я подрихтовую. Все окей. Имею дату и время.
А 64-битное системное время живет своей жизнью, сбрасываясь в ноль по ресету и не изменяясь при моих манипуляциях со структурой ГОД-МЕСЯЦ- и т.д.
Значит использовать 64-битную структуру для получения POSIX-времени я не могу. А должен как-то из нескольких UINT переменных ГОД, МЕСЯЦ и т.д. посчитать, сколько же секунд отделяет данный временной штамп от 1 января 1970 года.
Неужто действительно считать придется? Не верю... Должна быть какая-то функция преобразования.
myPOSIXtime: DWORD;
mySTD: SystemTimeDate;
...
myPOSIXtime := ФУНКЦИЯ(mySTD);
Или?
Дополнено: поигрался с RTC из Standard.Lib. там кагбэ должно было легко получиться
myPOSIXtime := DT_TO_DWORD( myRTC.CDT);
Однако сам ФБ RTC заставить работать у меня не получилось. Инициализируется, на входе EN даю TRUE, а время застыло...
Есть хорошая статья Игоря Петрова «Программируем временные сложности»
Если функциональный блок RTC не реализован в вашей системе программирования, его не сложно построить самостоятельно
Код:
FUNCTION_BLOCK fbRTC
VAR_INPUT
EN:BOOL;
PDT:DT;
END_VAR
VAR_OUTPUT
Q:BOOL;
CDT:DT;
POSIX:DWORD; (*добавил в оригинальный ФБ*)
END_VAR
VAR
DiffTime:TON:=(PT:=t#20h);
ResDT:DT;
RunTrig:R_TRIG;
END_VAR
RunTrig(CLK:=EN);
IF EN THEN
IF RunTrig.Q THEN (*рестарт часов*)
ResDT:=PDT; (*начало отсчета*)
DiffTime(IN:=FALSE);(*рестарт таймера*)
DiffTime(IN:=TRUE);
ELSE (*норм.режим CDT=DT рестарт+таймер*)
DiffTime;
CDT:=DWORD_TO_DT(DT_TO_DWORD(ResDT)
+TIME_TO_DWORD(DiffTime.ET)/1000);
IF DiffTime.ET>t#1h THEN
(*рестарт таймера каждый час для предотвращения его переполнения*)
ResDT:=CDT; (*начало отсчета*)
DiffTime(IN:=FALSE);(*рестарт таймера*)
DiffTime(IN:=TRUE);
END_IF
END_IF
END_IF
Q:=EN;
POSIX:=DT_TO_DWORD(CDT);(*добавил в оригинальный ФБ*)
Добавил нужный Вам дополнительный выход.
Это RTC работает и в эмуляции.
К стати И. Петров
В живых ПЛК могут быть /могут не быть/ аппаратные часы реального времени. Читаются они обычно через би-бку SysLibTime или подобную. См. мануал на ПЛК.
Часто сама операция чтения аппаратных часов довольно медленная. Поэтому рекомендуется считать их 1 раз. Полученным значением проинициализировать RTC и далее с ним работать.
В любом случае RTC нужно инициализировать при включении ПЛК, по этому, я думаю, что в первом цикле ПЛК нужно только один раз вызывать SystemTimeDate и там же, полученными значениями, инициализировать RTC.
ЗЫ. Я думаю, что Вам понадобится функция для преобразования текущей даты и времени из структуры SystemTimeDate в формат DT. На этот случай функция из OSCAT
Код:
FUNCTION SET_DT : DT
VAR_INPUT
year : INT;
month : INT;
day : INT;
hour : INT;
minute : INT;
second : INT;
END_VAR
SET_DT := DWORD_TO_DT(DATE_TO_DWORD(SET_DATE(YEAR, MONTH, day))
+ INT_TO_DWORD(SECOND) + INT_TO_DWORD(MINUTE) * 60
+ INT_TO_DWORD(HOUR) * 3600);
И используемая здесь SET_DATE()
Код:
FUNCTION SET_DATE : DATE
VAR_INPUT
YEAR : INT;
MONTH : INT;
DAY : INT;
END_VAR
VAR
count : INT;
END_VAR
IF month > 2 THEN
count := (month - 1) * 30;
IF month > 7 THEN count := count + SHR(month - 3,1);
ELSE count := count + SHR(month - 4,1); END_IF;
(* chech for leap year and add one day if true *)
IF SHL(year,14) = 0 THEN count := count + 1; END_IF;
ELSE
count := (month - 1) * 31;
END_IF;
SET_DATE := DWORD_TO_DATE((INT_TO_DWORD(count + day - 1)
+ SHR(INT_TO_DWORD(year) * 1461 - 2878169, 2)) * 86400);