WinCC Flexible: Read CSV Data to Internal Tags via VB Script

David Krause13 min read
HMI ProgrammingSiemensTutorial / How-to
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

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.

Scope: The procedure below applies to WinCC Flexible 2008 SP5 and earlier on Panels (OP 177B, TP 177B, OP 277, TP 277, MP 277, MP 377) and on the WinCC Flexible Runtime / PC Runtime. TIA Portal WinCC (V13/V14/V15/V16/V17/V18/V19) uses a different scripting host — see the TIA Portal WinCC Scripting manual for the modern equivalent.

Prerequisites

  1. WinCC Flexible 2008 SP2 or later installed on the engineering station. Confirm version in Help → About or read HmiES.exe file version.
  2. A configured WinCC Flexible project with at least one connection to the target PLC (S7-200, S7-300, S7-400, S7-1200, or LOGO!).
  3. Internal tags of matching data type declared in the tag editor: nValue_1 through nValue_7 as Integer or Real; szString_1 as String. See WinCC Flexible 2008 Manual, Chapter 4 - Working with Tags.
  4. 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.
  5. 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 = 1
ForWriting = 2
ForAppending = 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 = 0
True = -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 = -2
TristateTrue = -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.
Locale trap: If the CSV is exported from Excel on a German/Italian/French Windows and the panel runs with the same locale, Excel writes a semicolon-delimited file. The script must therefore use 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

  1. Open the WinCC Flexible project and declare seven internal tags in the tag editor: nValue_1 to nValue_7 (Integer), and optionally one string tag szString_1. See WinCC Flexible 2008 - Working with Tags.
  2. Create a new VBScript action. In the screen, insert a button, open Properties → Events → Click, and add a Add script. Name it ReadCSV.
  3. Paste the corrected script (full version below). The script is the canonical Siemens sample, with the array bound fixed for seven fields per line.
  4. Compile / check syntax from the script editor. The editor underlines undeclared variables; resolve all warnings.
  5. Compile the project: Project → Compiler → All. The output window must show zero errors and zero warnings.
  6. Transfer the project to the panel or start PC Runtime.
  7. Copy recipe.csv to \Storage Card\Application\ on the panel, or to the configured path on the PC runtime host.
  8. 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!"
Why 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.

  1. In Connections, ensure a working connection to the S7 PLC is configured. Acquire WinCC Flexible Communication for the S7-300/400 setup notes.
  2. Add connection tags with the same name as the internal tags (e.g. nValue_1 as DB10.DBD0, nValue_2 as DB10.DBD4, ...).
  3. 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.
  4. 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 increment j by 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 with If Len(field(i)) = 0 Then field(i) = "0".
  • Decimal comma vs decimal point. A German CSV with 3,5 as a number will be split into two columns if you use ; as the delimiter but , as the decimal separator. Pre-process with Replace(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. With TristateUseDefault (-2) the BOM is read as the first three characters of the first cell. Open with format = -1 (Unicode) and skip the first three characters with Mid(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_1 change but nValue_7 is still the previous cycle's value. Wrap the write in a handshake: set a bUpdateBusy tag to TRUE, write all values, pulse bUpdateDone for the PLC's edge-triggered FC.
  • Logging failures. Add a call to SmartTags("szLastError") = Err.Description at every Exit Sub so the operator can read the last error from an I/O field without scrolling the alarm history.

Verification Procedure

  1. From the engineering station, start WinCC Flexible Runtime with the simulator. The simulator gives you a software HMI on the PC; no panel required.
  2. Create a test CSV with 3 rows × 7 columns. Save it to the path the script expects.
  3. Trigger ReadCSV. The system alarm should read "Readout of row N was successful!".
  4. Open an I/O field bound to nValue_1 through nValue_6. Each field must display the value of the corresponding column in row 0.
  5. Set iRecipeRow to 1, retrigger. The values must update to row 1's data.
  6. Set iRecipeRow to 99, retrigger. The script must alarm "out of range" and leave the tags unchanged.
  7. Rename the CSV to recipe.csv.bak, retrigger. The script must alarm "File not found" and exit cleanly.
  8. From the PLC side, monitor DB10.DBD0...DB10.DBD20 in 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

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.

Back to blog