Siemens S7-300 SFC0 SET_CLK: Write PLC Clock from WinCC Flexible VB Script
Writing a fixed date and time to a Siemens SIMATIC S7-300 CPU without using the WinCC Flexible panel clock synchronization feature requires two cooperating layers: a STEP 7 block that calls the system function SFC0 SET_CLK, and a WinCC Flexible trigger (rising-edge bit or Date/Time area pointer) that fires the block from a VB script on the panel. This reference documents the BCD payload format, SFC0 return codes, WinCC Flexible area pointer wiring, and the specific behaviour observed on the CPU 315-2 DP when SFC48 is requested but not supported.
1. Overview: Two Valid Clock-Write Paths
The S7-300 family exposes two system functions for clock manipulation in user code:
| System Function | Purpose | Typical Use |
|---|---|---|
| SFC0 SET_CLK | Sets the CPU master clock to an absolute date/time | Forced clock write from application |
| SFC48 SNC_RTCB | Synchronizes slave clocks on a PROFIBUS segment via the bus master | Distributed clock discipline on DP |
For the requirement "write a fixed value to the system time on a rising bit without using the panel and PLC time synchronisation," SFC0 SET_CLK is the correct primitive. SFC48 requires a bus-mastered time transmitter and is not a substitute for an absolute clock write. The CP315-2 DP CPU (6ES7 315-2AFxx / 6ES7 315-2EHxx) supports SFC0 in all firmware revisions; SFC48 availability is firmware-dependent and is documented in the CPU's technical data sheet.
2. Hardware and Software Prerequisites
| Component | Specification |
|---|---|
| CPU | CPU 315-2 DP (6ES7 315-2AFxx / 6ES7 315-2EHxx) or any S7-300 CPU supporting SFC0 |
| Firmware | V2.x or V3.x recommended for full SFC48 support; SFC0 works on all firmware releases |
| STEP 7 | STEP 7 V5.4 SP5 / V5.5 (for S7-300 project) |
| HMI | WinCC Flexible 2007 SP3 or WinCC Flexible 2008 SP5 panel with VB script runtime |
| Connection | MPI/PROFIBUS/Industrial Ethernet between panel and CPU |
| Block container | System data blocks (SDB) with SFC0/SFC48 pre-loaded by STEP 7 |
Verify that the system function blocks SFC0 through SFC7 (and SFC48 if used) appear in the Program > System Blocks folder before writing the calling FB/FC. If the SFCs are missing after opening an existing project, run PLC > Compile and Download Objects to regenerate the SDB container.
3. SFC0 SET_CLK: Mechanism and Parameters
SFC0 writes the date and time passed as input parameter PDT directly into the CPU's real-time clock. The call is synchronous and takes effect within one OB1 cycle. Refer to the Siemens SFC0 SET_CLK reference in the SIMATIC S7-300 System and Standard Functions manual for the authoritative signature.
| Parameter | Declaration | Type | Description |
|---|---|---|---|
| PDT | INPUT | DATE_AND_TIME (8 bytes BCD) | Date/time to be loaded into the CPU clock |
| RET_VAL | OUTPUT | INT | Status / error code (see Section 5) |
3.1 LAD / FBD Call Pattern
In a ladder diagram, instantiate SFC0 from the libraries pane and wire the PDT input to a temporary tag or a data block variable:
+-----------+
| SFC0 |
| SET_CLK |
+-----------+
|
PDT -----+-- (DB100.DBX0.0 .. DB100.DBX7.7) // 8-byte BCD payload
|
RET_VAL ---+-- (MW200) // status word
|
EN ----+-- (Trigger bit, rising edge)
|
ENO ----+-- (optional: status bit for downstream logic)
+-----------+
3.2 STL Call Pattern
// S7-300 STL: call SFC0 with PDT from DB100 and capture RET_VAL
CALL SFC0
PDT := DB100.DB_DATE_TIME // 8-byte BCD
RET_VAL := MW200 // status
// Pattern with rising-edge trigger
A M 100.0 // trigger bit from VB script
FP M 100.1 // edge flag
JCN NO_WRITE
CALL SFC0
PDT := DB100.DB_DATE_TIME
RET_VAL := MW200
NO_WRITE: NOP 0
4. PDT (DATE_AND_TIME) BCD Format Specification
The DATE_AND_TIME data type is an 8-byte BCD-encoded structure. STEP 7 packs this when you write a literal of type DATE_AND_TIME, but when you build the value from scratch (e.g., from a WinCC tag with year/month/day/hour/minute/second), you must BCD-encode each field manually.
| Byte | Content | Range (BCD) | Encoding Example (2024-07-15 14:32:08.250) |
|---|---|---|---|
| 0 | Year | 00-99 (90-99 = 1990-1999, 00-89 = 2000-2089) | 16h (i.e., 22 BCD for 2022, 24 BCD for 2024) |
| 1 | Month | 01-12 | 07h |
| 2 | Day | 01-31 | 15h |
| 3 | Hour | 00-23 | 14h |
| 4 | Minute | 00-59 | 32h |
| 5 | Second | 00-59 | 08h |
| 6 + 7 (high nibble of 6, low 3 nibbles of 7) | Milliseconds (3 BCD digits) + reserved (1 nibble) + Weekday (1 nibble of byte 7) | 000-999 ms / 1-7 (1=Sun) | 250 ms, weekday 1 (Mon) -> 250-1 packed as W#16#2501 in low 16 bits of bytes 6-7 |
4.1 Packing Algorithm for VB / WinCC Script
WinCC Flexible VB scripts cannot construct a BCD DATE_AND_TIME directly. Build eight separate bytes in a DB and let the STEP 7 code pack them, or use a small FC that converts a 7-byte integer array to BCD before the SFC0 call. The simplest field-proven pattern is:
- Define eight byte tags in a DB (DB100.DB_DATE_TIME[0..7]).
- From the panel, write the year as a BCD-coded word using the WinCC function SetValueByBit or a VB script that converts decimal to BCD.
- After all eight bytes are written, set the trigger bit high for one cycle.
' WinCC Flexible VB Script: decimal-to-BCD for year 2024
Dim yr As Integer, hi As Integer, lo As Integer
yr = 24 ' last two digits of year
hi = Int(yr / 10) * 16 ' tens nibble shifted to high nibble of byte
lo = yr Mod 10 ' units nibble stays low
SmartTags("DB100_year_byte") = hi + lo ' -> 16#24
' Repeat for month (1-12), day (1-31), hour (0-23), minute (0-59), second (0-59)
' For ms_weekday, pack ms (0-999) into 3 BCD digits and weekday (1-7) as high nibble of low byte
' Example: 250 ms + Monday (weekday=2) -> 16#2502
SmartTags("DB100_ms_wd_word") = &H2502
' After all eight bytes are written, fire trigger
SmartTags("PLC_trigger_bit") = 1
5. SFC0 Error Codes (RET_VAL)
SFC0 sets RET_VAL to one of the values below. See the SFC0 reference for the canonical list.
| RET_VAL (hex) | Meaning | Field Action |
|---|---|---|
| 0000h | No error; clock accepted | None |
| 8080h | Invalid date/time in PDT (e.g., month=13, day=32, weekday=0) | Validate BCD fields in script |
| 8081h | PDT time is more than one day in the future relative to CPU clock | Reduce forward offset, sync base clock first |
| 8xyyh | General error (x=category, y=detail): typically OB scheduling or SFC availability | Inspect CPU diagnostic buffer |
6. STEP 7 Implementation: FC for Clock Write
Encapsulate SFC0 in an FC that accepts the PDT as an IN_OUT parameter and pulses a one-shot trigger. This decouples the panel interface from the system function and centralises BCD validation.
FUNCTION FC 100 : VOID
VAR_INPUT
Execute : BOOL; // rising edge fires SFC0
END_VAR
VAR_IN_OUT
PDT : DATE_AND_TIME; // 8-byte BCD payload, in a DB or TEMP region
END_VAR
VAR_TEMP
ret : INT;
edge : BOOL;
edge_mem: BOOL;
END_VAR
BEGIN
// rising-edge detection on Execute
edge := Execute AND NOT edge_mem;
edge_mem := Execute;
IF edge THEN
CALL SFC0
PDT := PDT;
RET_VAL := ret;
END_CALL;
END_IF;
// optional: write ret to a status word for WinCC display
"DB100".ret_word := ret;
END_FUNCTION
Place FC100 in OB1 unconditionally. The DB100 instance holds the PDT and a status word. From WinCC Flexible, configure the eight bytes plus the trigger bit as tag connections.
7. WinCC Flexible Area Pointer: Date/Time Synchronization
If the requirement is "push the panel time to the PLC," the WinCC Flexible Date/Time area pointer performs this without any user VB script. Configure it under Connections > Area Pointer in the panel project:
- Open the connection that targets the S7-300 CPU.
- Select Area Pointer.
- Add a pointer of type Date/Time.
- Set the update direction to PLC <- HMI (write from panel to PLC).
- Assign a starting address in the CPU (e.g., DB100.DBX0.0, length 8 bytes matching the PDT layout).
- Enable the pointer; the panel pushes its local time to the CPU at the configured cycle.
Refer to the WinCC Flexible Communication manual for the area pointer field layout.
8. VB Script Implementation on WinCC Flexible
Two patterns are commonly used on WinCC Flexible panels that support VB scripting (e.g., MP 277, TP 277, PC Runtime with VB):
8.1 Pattern A: Trigger SFC0 from a button
' WinCC Flexible VB - OnClick of button "SetPLCClock"
Dim yr As Integer, mo As Integer, dy As Integer
Dim hh As Integer, mm As Integer, ss As Integer
Dim ms As Integer, wd As Integer
' Get values from screen input fields
yr = SmartTags("set_year")
mo = SmartTags("set_month")
dy = SmartTags("set_day")
hh = SmartTags("set_hour")
mm = SmartTags("set_min")
ss = SmartTags("set_sec")
ms = SmartTags("set_ms")
wd = SmartTags("set_weekday") ' 1=Sun..7=Sat
' Pack year BCD
SmartTags("DB100_byte0") = (Int(yr/10) * 16) + (yr Mod 10)
' Pack month
SmartTags("DB100_byte1") = (Int(mo/10) * 16) + (mo Mod 10)
' Pack day
SmartTags("DB100_byte2") = (Int(dy/10) * 16) + (dy Mod 10)
' Pack hour
SmartTags("DB100_byte3") = (Int(hh/10) * 16) + (hh Mod 10)
' Pack minute
SmartTags("DB100_byte4") = (Int(mm/10) * 16) + (mm Mod 10)
' Pack second
SmartTags("DB100_byte5") = (Int(ss/10) * 16) + (ss Mod 10)
' Pack ms/weekday as 16-bit word: high byte = ms BCD (0..999), low byte = weekday + reserved
Dim ms_hi As Integer, ms_lo As Integer
ms_hi = Int(ms/10) * 16 + (Int(ms/100) * 256) ' careful: ms uses 3 BCD digits
SmartTags("DB100_byte6_7") = (ms_hi * 256) + wd
' Fire the rising-edge trigger
SmartTags("PLC_trigger") = 0
SmartTags("PLC_trigger") = 1
8.2 Pattern B: Periodic forced sync using panel system time
' Scheduled VB - every 60 seconds, push panel time to PLC clock via SFC0
Dim n As Date
n = Now ' VB Now returns local system time
' ... pack n into BCD fields as in Pattern A ...
SmartTags("PLC_trigger") = 0
SmartTags("PLC_trigger") = 1
9. SFC48 SNC_RTCB: Alternative Path and Limitations
SFC48 SNC_RTCB reads the CPU master clock and broadcasts a time frame on the connected PROFIBUS segment, allowing DP slaves configured as time slaves to follow. The function:
- Does not write the CPU clock; it distributes it.
- Requires the DP interface of the CPU to be configured as the time master.
- Returns RET_VAL = 8085h if the CPU is not time-master capable or the DP master system is not configured for clock distribution.
If a download error appears when calling SFC48 from FC/FB code on a CPU 315-2 DP, the most likely causes are:
- SFC48 is not in the system block container for the current CPU firmware; STEP 7 will reject the download with "Function not supported by CPU".
- The CPU's hardware configuration has not been recompiled after a firmware upgrade.
- The DP master system is configured for transparent operation, not for clock distribution.
Refer to the S7-300 CPU 315-2 DP manual for the firmware-specific availability matrix.
10. CP315-2 DP Specific Compatibility Notes
The CPU 315-2 DP variants exhibit the following behaviour for clock functions:
| Firmware | SFC0 (SET_CLK) | SFC48 (SNC_RTCB) | Notes |
|---|---|---|---|
| V1.x | Supported | Not supported | Use SFC0 only |
| V2.x | Supported | Supported with restrictions | Check DP master config |
| V3.x | Supported | Supported | Full functionality |
If a download error occurs when including an SFC48 call in the project, recompile the hardware (HW Config) to regenerate the SDB container for the current firmware. STEP 7 will then resolve the SFC48 to a system block or display the unsupported-function warning that prevents download.
11. Verification and Diagnostics
After deploying the FC, trigger the bit from the panel and verify the write through three independent paths:
- PLC diagnostic buffer: Online > CPU > Diagnostic Buffer. Look for event "Clock set by user program" with the new timestamp. Any SFC0 error code is logged as a peripheral fault.
- WinCC tag readback: Read the eight PDT bytes back into WinCC tags and decode them in a VB display. This confirms the round-trip BCD encoding.
- CPU clock read in STEP 7: Online > CPU > Set Time of Day. The displayed date and time should match the value pushed from the panel within one OB1 cycle.
11.1 Online Read of SFC0 RET_VAL
Create a VAT (Variable Table) with the RET_VAL tag. Monitor it online in STEP 7. After the trigger pulse, the value should read 0000h. Persistent 8080h indicates a BCD encoding bug in the VB script; persistent 8081h indicates the target time is more than 24 hours ahead of the current CPU clock.
11.2 Verifying via SFC1 READ_CLK
SFC1 reads the current CPU clock into a PDT. Call it in the same FC immediately after SFC0 to confirm the write took effect:
CALL SFC1
CDT := DB100.DT_readback
RET_VAL := MW202
12. Troubleshooting Matrix
| Symptom | Likely Cause | Resolution |
|---|---|---|
| Download fails: "SFC48 not supported" | SFC48 unavailable on CPU firmware | Switch to SFC0; recompile HW Config |
| SFC0 RET_VAL = 8080h | Invalid BCD field or weekday = 0 | Validate all eight BCD fields, ensure weekday 1-7 |
| SFC0 RET_VAL = 8081h | Target time > 1 day ahead of CPU clock | First call SFC0 with current time to reset base, then write target |
| Clock writes but drifts immediately | Battery-backed RTC not present or discharged | Check BAT LED; replace backup battery (CPU 315-2 DP uses CR2032 type) |
| VB script fires but PLC does not respond | Trigger tag not wired to FC enable input | Verify tag connection in WinCC Flexible connection list |
| Trigger fires repeatedly without rising-edge latch | VB script never clears the trigger | Add a PLC-side edge detection on FC100 as shown in Section 6 |
| Panel area pointer updates DB but SFC0 not called | Area pointer does not invoke SFC0 | Use FC100 wrapper and trigger bit in addition to area pointer |
| PLC clock reads OK in STEP 7 but logs show old timestamps | Diagnostic buffer uses internal counter, not RTC | Expected behaviour; not an SFC0 failure |
13. Quick Reference: SFC0 Call Checklist
- Confirm SFC0 exists in System Blocks after STEP 7 compile.
- Define an 8-byte DATE_AND_TIME tag in a DB.
- Implement an FC that detects a rising edge on the trigger bit and calls SFC0 with the DB tag as PDT.
- Capture RET_VAL to a status word for HMI display.
- Add VB script on the panel that packs each decimal field into BCD and writes the trigger bit.
- Verify by reading back with SFC1 and via STEP 7 online clock view.
- If SFC48 is requested, confirm CPU firmware supports it; otherwise use SFC0 only.
Can WinCC Flexible write the S7-300 clock directly without STEP 7 code?
Yes, via the Date/Time area pointer configured for PLC <- HMI direction. However, the area pointer only writes to a DB; it does not call SFC0. To actually overwrite the CPU master clock, an FC that calls SFC0 must execute in the CPU. Use the area pointer plus an FC wrapper when you need both a record and a real-time clock update.
Why does SFC48 fail to download on a CPU 315-2 DP but SFC0 works?
SFC48 requires the CPU firmware to support PROFIBUS clock distribution and a DP master configuration marked for time-master operation. On CPU 315-2 DP firmware V1.x, SFC48 is not present in the system block container, causing STEP 7 to reject the FC download. SFC0 is supported across all CPU 315-2 DP firmware revisions and is the correct primitive for absolute clock writes.
What causes SFC0 RET_VAL = 8080h even though the values look correct?
The most common cause is a weekday nibble of 0 in byte 7. SFC0 requires weekday 1-7 (1 = Sunday). A VB script that lets the panel calendar control supply the weekday will frequently pass 0 when no day has been explicitly selected. Force weekday 1-7 in the script before packing.
How do I encode milliseconds in the PDT BCD word?
The 16-bit word at bytes 6-7 holds three BCD digits of milliseconds (0-999) in the low 12 bits and the weekday (1-7) in the high nibble of byte 7. Example: 250 ms on Monday (weekday 2) packs to 16#2502. The upper nibble of byte 6 is reserved and must be 0. Building the value as a 32-bit integer and shifting into place in the VB script avoids per-nibble arithmetic errors.
Can a fixed value be written to the PLC clock on every rising edge of a bit?
Yes. Build an FC that latches the rising edge and calls SFC0 with the configured PDT. Wire a WinCC Flexible trigger bit to the FC enable input and assert it from VB. Use STEP 7 online diagnostic buffer to confirm the clock write event. Persist the PDT in a DB so the value survives PLC restart and download.