Overview
WinCC Flexible (versions 2005, 2007, 2008 SP2/SP3/SP4/SP5) ships with a VBScript runtime that lets a WinCC Flexible Runtime panel or PC runtime read comma-separated files from a local or mapped network drive and write the parsed values into internal tags. Those internal tags can then be transferred to the PLC over MPI/PROFIBUS, PROFINET, or EtherNet/IP. The runtime implements the Microsoft Scripting Runtime (Scripting.FileSystemObject) and the standard Split() / Replace() / UBound() VBScript functions, so any CSV with a fixed delimiter can be parsed with a 30-line script.
This article documents the working pattern for reading .csv and .txt data into a two-dimensional array, the exact meaning of the OpenTextFile(filename, iomode, create, format) parameters, the classic 3-field-vs-7-field array overflow that breaks the original Siemens sample, and the recommended method for writing modified values back to the connected S7 PLC.
Prerequisites
- WinCC Flexible 2008 SP2 or later installed on the engineering station. Confirm version in Help → About or read
HmiES.exefile version. - A configured WinCC Flexible project with at least one connection to the target PLC (S7-200, S7-300, S7-400, S7-1200, or LOGO!).
- Internal tags of matching data type declared in the tag editor:
nValue_1throughnValue_7asIntegerorReal;szString_1asString. See WinCC Flexible 2008 Manual, Chapter 4 - Working with Tags. - For panel targets: a storage card or USB stick with the CSV file, or for PC Runtime: a fixed file path the runtime account can read.
- A trigger event (button press, value change on a tag, or scheduled task using the Scheduler object).
CSV File Format Requirements
The runtime does not use a CSV parser — it treats each line as a raw string and relies on Split(line, ","). The file must therefore obey three rules:
| Rule | Detail |
|---|---|
| Delimiter | Use a single character that never appears in the data. Comma is the default; semicolon is preferred on German locales where the decimal separator is also a comma. |
| No quoted fields | VBScript Split() cannot strip " quotes. Values like "123,45" will be split across two columns. Pre-process the file or replace commas in numeric fields before split. |
| Fixed line count | Dimension the receiving array to a known maximum (e.g. 100 rows × 7 columns) and stop when f.AtEndOfStream = True. |
Example CSV saved as \Storage Card\Application\recipe.csv:
RecipeNo;Name;Setpoint1;Setpoint2;Setpoint3;Setpoint4;Setpoint5
1;Mixer_A;120;240;36.5;0;1
2;Mixer_B;115;230;35.0;0;1
3;Mixer_C;130;250;38.2;1;0
The FileSystemObject Model
WinCC Flexible exposes the Microsoft Scripting Runtime through COM. The objects used in the script are:
| Object | Role |
|---|---|
Scripting.FileSystemObject |
Root object. Created with CreateObject("Scripting.FileSystemObject"). |
File |
Represents a file on disk. Returned by GetFile(path). |
TextStream |
Sequential read/write access. Returned by OpenTextFile(), OpenAsTextStream(), or created via CreateTextFile(). |
Folder / Drive
|
Used for directory listings and path validation. |
For the CSV-read pattern only FileSystemObject and TextStream are needed. See the Microsoft Scripting Runtime reference for full method listings.
OpenTextFile Parameters Explained
The signature is:
object.OpenTextFile(filename[, iomode[, create[, format]]])
Each argument in the original Siemens sample (OpenTextFile(Path, 1, 0, -2)) has a fixed meaning:
| Argument | Value in sample | Constant | Effect |
|---|---|---|---|
filename |
Path |
— | Required. Fully qualified path including drive, folder, and extension. On panels use \Storage Card\Application\... or \USB\Storage01\.... |
iomode |
1 |
ForReading = 1ForWriting = 2ForAppending = 8 |
1 opens for read-only, 2 overwrites the file from byte 0, 8 appends at end. For a read-only CSV always use 1. |
create |
0 |
False = 0True = -1 |
If True a new file is created when the path is missing. False (0) returns an error on a missing file — preferred for recipes to fail loud. |
format |
-2 |
TristateUseDefault = -2TristateTrue = -1 (Unicode)TristateFalse = 0 (ASCII) |
-2 opens the file in the system's default code page (UTF-8 on modern panels, ANSI on legacy OP 77A). Use -1 only when the CSV was saved explicitly as UTF-16 LE / Unicode. |
Split(MyZf, ";"), not Split(MyZf, ","). Detect automatically with InStr(line, ";") or expose a flag tag to the operator.
Step-by-Step: Read CSV to Internal Tags
- Open the WinCC Flexible project and declare seven internal tags in the tag editor:
nValue_1tonValue_7(Integer), and optionally one string tagszString_1. See WinCC Flexible 2008 - Working with Tags. - Create a new VBScript action. In the screen, insert a button, open Properties → Events → Click, and add a Add script. Name it
ReadCSV. - Paste the corrected script (full version below). The script is the canonical Siemens sample, with the array bound fixed for seven fields per line.
- Compile / check syntax from the script editor. The editor underlines undeclared variables; resolve all warnings.
- Compile the project: Project → Compiler → All. The output window must show zero errors and zero warnings.
- Transfer the project to the panel or start PC Runtime.
- Copy
recipe.csvto\Storage Card\Application\on the panel, or to the configured path on the PC runtime host. - Trigger the script (press the button) and observe the alarm line; the script raises
ShowSystemAlarm "Readout of the data was successful!"on success.
Corrected Script (7 Fields per Line)
The original Siemens sample declares Dim HiField(2,2) and loops For i = 0 To 5. The array has indices 0,1,2 — index 5 raises runtime error 9 ("Subscript out of range") and the script silently aborts because On Error Resume Next is active. The corrected version below redimensions the array, validates the split count, and writes only the first valid row into the HMI tags. A more useful pattern reads the requested row from a numeric tag iRecipeRow:
'////////////////////////////////////////////////////////////////
' en: Read a 7-field CSV file into internal tags
' Project: WinCC Flexible 2008 SP5
' Trigger: Button "Load Recipe"
'////////////////////////////////////////////////////////////////
Option Explicit
Dim fso, f, ts, Path, field, MyZf
Dim i, j, iRow, iMaxRow, iMaxCol
Dim HiField(99, 6) ' 100 rows x 7 columns (0..6)
i = 0
j = 0
iMaxRow = 99
iMaxCol = 6
' Path: on a panel use the storage card; on PC Runtime use a local path.
Path = "\Storage Card\Application\recipe.csv"
' --- Error handling --------------------------------------------------
On Error Resume Next
' 1. Create the FSO
Set fso = CreateObject("Scripting.FileSystemObject")
If Err.Number <> 0 Then
ShowSystemAlarm "Error #" & CStr(Err.Number) & " " & Err.Description
Err.Clear
Exit Sub
End If
' 2. Check existence to give a friendlier message
If Not fso.FileExists(Path) Then
ShowSystemAlarm "File not found: " & Path
Exit Sub
End If
' 3. Open for read, do not create, system default encoding
Set f = fso.OpenTextFile(Path, 1, 0, -2)
If Err.Number <> 0 Then
ShowSystemAlarm "Open error #" & CStr(Err.Number) & " " & Err.Description
Err.Clear
Exit Sub
End If
' 4. Read all rows into HiField. Skip header line if first char is alpha.
j = 0
Do While f.AtEndOfStream <> True
MyZf = f.ReadLine
If j = 0 And Not IsNumeric(Left(Trim(MyZf), 1)) Then
' Header line — skip
j = j - 1
Else
field = Split(MyZf, ";")
For i = 0 To iMaxCol
If i <= UBound(field) Then
field(i) = Replace(Trim(field(i)), Chr(34), "")
HiField(j, i) = field(i)
End If
Next
End If
j = j + 1
If j > iMaxRow Then Exit Do
Loop
f.Close
Set f = Nothing
Set fso = Nothing
' 5. Surface a row count tag for downstream use
SmartTags("iRecipeCount") = j
' 6. Write the requested row to the internal tags
iRow = CInt(SmartTags("iRecipeRow"))
If iRow < 0 Or iRow >= j Then
ShowSystemAlarm "Recipe row " & iRow & " out of range (0.." & j-1 & ")"
Exit Sub
End If
SmartTags("szString_1") = HiField(iRow, 0) ' RecipeNo / name
SmartTags("nValue_1") = CDbl(HiField(iRow, 1)) ' Setpoint1
SmartTags("nValue_2") = CDbl(HiField(iRow, 2)) ' Setpoint2
SmartTags("nValue_3") = CDbl(HiField(iRow, 3)) ' Setpoint3
SmartTags("nValue_4") = CDbl(HiField(iRow, 4)) ' Setpoint4
SmartTags("nValue_5") = CDbl(HiField(iRow, 5)) ' Setpoint5
SmartTags("nValue_6") = CDbl(HiField(iRow, 6)) ' Setpoint6
ShowSystemAlarm "Readout of row " & iRow & " was successful!"
On Error Resume Next is dangerous: The original Siemens example silently masks the out-of-range write into HiField(j, 5). The first ShowSystemAlarm never fires, the loop terminates early, and the operator sees "Readout successful!" while only the first three fields of the first line are written. The fix is Option Explicit + bound checking, as shown above.
Writing Modified Internal Tags Back to the PLC
Internal tags are local to the HMI. To push the modified nValue_* values to the PLC, declare the same tag name as a connection tag pointing to an S7 DB or M address. The runtime will mirror the value automatically on the configured acquisition cycle.
- In Connections, ensure a working connection to the S7 PLC is configured. Acquire WinCC Flexible Communication for the S7-300/400 setup notes.
- Add connection tags with the same name as the internal tags (e.g.
nValue_1asDB10.DBD0,nValue_2asDB10.DBD4, ...). - Set the acquisition mode to Cyclic continuous with a 1 s update cycle, or trigger with a button ("Send to PLC") that copies the internal tags back to connection tags via a second script.
- Alternative: in the same script, after the CSV read, set connection tags directly with
SmartTags("nValue_1_PLC") = SmartTags("nValue_1")— the PLC will pick them up on the next scan.
Performance and Limits
| Panel class | Max file size | Rows/s parsed | Notes |
|---|---|---|---|
| OP 177B / TP 177B | ≤ 200 KB | ~40 | Limited RAM; keep < 500 rows. |
| MP 277 / MP 377 | ≤ 4 MB | ~200 | Card reader on MP 277; CF on MP 377. |
| PC Runtime | Limited by disk | ~10 000 | Use SSD; consider reading in chunks via separate scripts. |
For files larger than 1000 rows on a panel, switch from Split() + 2-D array to a streaming parser that pushes one row at a time directly into the connection tag — this avoids materialising the full array in memory.
Error Codes and Troubleshooting Matrix
| VBScript error # | Message | Likely cause | Fix |
|---|---|---|---|
| 53 | File not found | Path wrong; card not mounted | Verify path with fso.FileExists(); on panels use \Storage Card\...
|
| 52 | Bad file name or number | UNC path on a non-networked panel | Use local paths only on OP/TP; map a drive letter on PC Runtime |
| 9 | Subscript out of range |
HiField(j, i) exceeds dimension |
Redim array to match the largest expected row size |
| 13 | Type mismatch | CSV cell empty or non-numeric in CDbl()
|
Wrap conversion in If IsNumeric(...) Then
|
| 70 | Permission denied | Runtime user cannot read network share | Use a local copy refreshed on connection, or run service as user with share read rights |
| 800A01A8 | Object required |
Set fso = ... failed silently |
Check Err.Number after CreateObject
|
Edge Cases and Field Tips
-
Header lines. If the first CSV row contains alpha characters in the first field, the script above skips it. To force a header count, declare an internal tag
iHeaderLines= 1 and incrementjby that value before the loop. -
Trailing empty columns.
Split("1;2;", ";")returns an array of length 3 where the last element is the empty string.CDbl("")raises error 13 — guard withIf Len(field(i)) = 0 Then field(i) = "0". -
Decimal comma vs decimal point. A German CSV with
3,5as a number will be split into two columns if you use;as the delimiter but,as the decimal separator. Pre-process withReplace(text, ",", ".")in a single-pass string substitution before splitting — but only if the file uses no comma thousands separator. -
BOM handling. Excel on Windows 10+ writes a UTF-8 BOM (
EF BB BF) as the first three bytes. WithTristateUseDefault (-2)the BOM is read as the first three characters of the first cell. Open withformat = -1(Unicode) and skip the first three characters withMid(line, 4), or strip the BOM during file preparation. -
Atomic update of PLC values. A common defect is partial updates: the operator changes row 1, presses send, and the PLC sees
nValue_1change butnValue_7is still the previous cycle's value. Wrap the write in a handshake: set abUpdateBusytag to TRUE, write all values, pulsebUpdateDonefor the PLC's edge-triggered FC. -
Logging failures. Add a call to
SmartTags("szLastError") = Err.Descriptionat everyExit Subso the operator can read the last error from an I/O field without scrolling the alarm history.
Verification Procedure
- From the engineering station, start WinCC Flexible Runtime with the simulator. The simulator gives you a software HMI on the PC; no panel required.
- Create a test CSV with 3 rows × 7 columns. Save it to the path the script expects.
- Trigger
ReadCSV. The system alarm should read "Readout of row N was successful!". - Open an I/O field bound to
nValue_1throughnValue_6. Each field must display the value of the corresponding column in row 0. - Set
iRecipeRowto 1, retrigger. The values must update to row 1's data. - Set
iRecipeRowto 99, retrigger. The script must alarm "out of range" and leave the tags unchanged. - Rename the CSV to
recipe.csv.bak, retrigger. The script must alarm "File not found" and exit cleanly. - From the PLC side, monitor
DB10.DBD0...DB10.DBD20in the STEP 7 watch table. After a successful read the DBs must mirror the I/O field values within one acquisition cycle.
Related Siemens Documentation
- WinCC Flexible 2008 Manual (entry ID 18796052)
- Communication WinCC Flexible <-> S7-300/400 (entry ID 26106418)
- WinCC Flexible Runtime operator controls and VBScript (entry ID 22700159)
- Microsoft Scripting Runtime - FileSystemObject
Frequently Asked Questions
Why does the original Siemens sample only read three fields when the CSV has seven?
The sample declares Dim HiField(2,2) (a 3×3 array, valid indices 0..2) and loops For i = 0 To 5. The write to HiField(j, 3) raises runtime error 9 ("Subscript out of range"), which the script masks with On Error Resume Next. Only the first three fields of the first row are written to the HMI tags. Redimension the array to HiField(99, 6) and check UBound(field) before each assignment.
What does OpenTextFile(Path, 1, 0, -2) mean?
It opens Path in read-only mode (iomode=1), refuses to create a new file if missing (create=0), and uses the system default code page for text encoding (format=-2). Use iomode=2 for write, iomode=8 for append, create=-1 to allow auto-creation, and format=-1 for UTF-16 LE Unicode.
How do I detect the CSV delimiter automatically?
Read the first line, then check If InStr(line, ";") > InStr(line, ","). If the semicolon count wins, use Split(line, ";"); otherwise use the comma. On German, Italian, and French Windows, Excel exports with semicolons by default.
Can WinCC Flexible Runtime read a CSV from a network share?
Yes, on PC Runtime only. Panels (OP/TP/MP) do not support UNC paths. Use a mapped drive letter, e.g. Z:\Recipes\recipe.csv, and ensure the runtime Windows service runs as a user that has read access to the share. The script syntax is identical.
How do I write the modified internal tag values back to the S7 PLC?
Declare connection tags with the same name (e.g. nValue_1 as DB10.DBD0) and set acquisition mode to cyclic continuous. The runtime will mirror every internal-tag change to the S7 address. For atomic updates use a handshake tag pair: set bUpdateBusy=1, copy all values, then pulse bUpdateDone=1 for the PLC to latch the block.
Does this pattern work in TIA Portal WinCC?
No. TIA Portal WinCC uses JavaScript (not VBScript) and exposes files through the FileSystem JavaScript API. The logic is identical but the object model and event bindings differ. See the TIA Portal WinCC Scripting manual, chapter "File system access" for the modern equivalent.