8/18/2011 11:26 AM | |
Joined: 1/17/2007 Last visit: 8/21/2024 Posts: 1545 Rating: (537) |
Actually, it is not as bad as I originally thought. The difficult way is to go from DT -> individual date and time components. Making a DT from individual time and date components is a lot easier. Unfortunately, it still needs a purpose built block as it is just too complex to do using the standard CFC blocks. But do not worry, the following code will do the trick for you. I have tested it and it seems to work. If any of the date / time component inputs are invalid (e.g. month=13) then the block will set the DT output to the epoch date / time of 1990-01-01-00:00:00.000. It also caters for leap years. Only took me a couple of hours to develop . You will need to add the following symbol to your symbol table before compilation:- Symbol Address Data type MAKE_DT FBXXX FBXXX The 'XXX' is a function block number of your choice. Pick a number that does not clash with any of the standard blocks you might be using. Here is the code... I hope it works for you! [code] FUNCTION_BLOCK MAKE_DT TITLE = 'MAKE DT' VERSION : '1.0' AUTHOR : SMIFFY NAME : MAKE_DT FAMILY : TIME //****************************************************** // Declare block inputs *** //****************************************************** VAR_INPUT MSECOND {S7_link:='true'; S7_dynamic:='true'} : INT; // Milliseconds input (0 - 999) SECOND {S7_link:='true'; S7_dynamic:='true'} : INT; // Seconds input (0 - 59) MINUTE {S7_link:='true'; S7_dynamic:='true'} : INT; // Minutes input (0 - 59) HOUR {S7_link:='true'; S7_dynamic:='true'} : INT; // Hours input (0 - 23) DAY {S7_link:='true'; S7_dynamic:='true'} : INT; // Days input (1 - 31) MONTH {S7_link:='true'; S7_dynamic:='true'} : INT; // Months input (1 - 12) YEAR {S7_link:='true'; S7_dynamic:='true'} : INT; // Years input YYYY format (1990 - 2089) END_VAR //****************************************************** // Declare block outputs *** //****************************************************** VAR_OUTPUT DATETIME {S7_dynamic:='true'} : DT; // Date and Time output END_VAR //****************************************************** // Declare static variables *** //****************************************************** VAR DateTable : ARRAY [0..11] OF INT := 0,3,2,5,0,3,5,1,4,6,2,4; // Data for Sakamoto's day of week algorithm MonthDays : ARRAY [1..12] OF INT := 31,28,31,30,31,30,31,31,30,31,30,31; // Numbers of days in each month END_VAR //****************************************************** // Declare temporary (stack) variables *** //****************************************************** VAR_TEMP RetVal : INT; // General temporary variable for holding FC/FB return codes DateAndTime : DT; // Date and time structure pointer to allow structure address below to be set DaT AT DateAndTime : STRUCT // Date and time structure to allow DT type to be disassembled Year : BYTE; // Current year (1990 to 2089 - 2 digits) Month : BYTE; // Current month (1 to 12) Day : BYTE; // Current day (1 to 31) Hour : BYTE; // Current hour (0 to 23) Minute : BYTE; // Current minute (0 to 59) Second : BYTE; // Current second (0 to 59) MSD : BYTE; // Most significant decade of current ms (0 to 99) LSD_Weekday : BYTE; // MSB = Least significant decade of current ms (0 to 9), LSB = Current weekday (1=Sunday to 7=Saturday) END_STRUCT; Weekday : INT; // Weekday temproray store LeapYear : BOOL; // TRUE if year is a leap year END_VAR //****************************************************** // Start of code *** //****************************************************** BEGIN IF (((YEAR MOD 4) = 0) AND ((YEAR MOD 100) = 0)) OR ((YEAR MOD 400) = 0) THEN // Detect leap year LeapYear := TRUE; ELSE LeapYear := FALSE; END_IF; IF YEAR >= 1990 AND YEAR <= 2168 AND // If valid year, month, day, hour, minute, second and millisecond inputs MONTH >= 1 AND MONTH <= 12 AND DAY >= 1 AND DAY <= 31 AND HOUR >= 0 AND HOUR <= 23 AND MINUTE >= 0 AND MINUTE <= 59 AND SECOND >= 0 AND SECOND <= 59 AND MSECOND >=0 AND MSECOND <= 999 AND (DAY <= MonthDays[MONTH]) OR ((MONTH = 2) AND (DAY <= 29) AND (LeapYear = TRUE)) THEN // and also valid day of month valid - note February! IF YEAR >= 2000 THEN // Adjust year to 2 digits DaT.Year := WORD_TO_BYTE(INT_TO_BCD(YEAR - 2000)); ELSE DaT.Year := WORD_TO_BYTE(INT_TO_BCD(YEAR - 1900)); END_IF; DaT.Month := WORD_TO_BYTE(INT_TO_BCD(MONTH)); DaT.Day := WORD_TO_BYTE(INT_TO_BCD(DAY)); DaT.Hour := WORD_TO_BYTE(INT_TO_BCD(HOUR)); DaT.Minute := WORD_TO_BYTE(INT_TO_BCD(MINUTE)); DaT.Second := WORD_TO_BYTE(INT_TO_BCD(SECOND)); DaT.MSD := WORD_TO_BYTE(INT_TO_BCD(MSECOND DIV 10)); // Calulate day of week using Sakamoto's algorithm - I have no idea how this works, but it is a known proven technique Weekday := (YEAR + (YEAR / 4) - (YEAR / 100) + (YEAR / 400) + DateTable[MONTH - 1] + DAY) MOD 7; // Build up ms LSB and day of week byte (both use a nibble each). Note Sakamoto's algorithm has 0=Sunday so we adjust it here to 1=Sunday DaT.LSD_Weekday := INT_TO_BYTE(BYTE_TO_INT(SHL(IN := INT_TO_BYTE(MSECOND - (BYTE_TO_INT(DaT.MSD) * 10)), N := 4)) + (Weekday + 1)); DATETIME := DateAndTime; // Store converted DT to output ELSE // Invalid date/time input values DATETIME := DT#1990-01-01-00:00:00.000; // So store EPOCH date END_IF; END_FUNCTION_BLOCK [/code] |
Programming today is the race between software engineers building bigger and better idiot proof programs, and the universe producing bigger and better idiots. |
|
This contribution was helpful to4 thankful Users |
8/19/2011 12:33 PM | |
Joined: 1/17/2007 Last visit: 8/21/2024 Posts: 1545 Rating: (537) |
Oops! Sorry. Just found a slight buglett in my code. The input validation is not working as good as it might. The fix is simple and is a one-liner. The line:- [code] (DAY <= MonthDays[MONTH]) OR ((MONTH = 2) AND (DAY <= 29) AND (LeapYear = TRUE)) THEN [/code] Should actually be:- (extra paranthesis round the month check) [code] ((DAY <= MonthDays[MONTH]) OR ((MONTH = 2) AND (DAY <= 29) AND (LeapYear = TRUE))) THEN [/code] |
Programming today is the race between software engineers building bigger and better idiot proof programs, and the universe producing bigger and better idiots. |
|
Follow us on