Exporting S7-1200 DB Structure to Excel with Absolute Addresses

David Krause14 min read
S7-1200SiemensTutorial / 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

When commissioning or documenting a Siemens SIMATIC S7-1200 application built in TIA Portal, engineers routinely need the full data block (DB) layout — every variable's name, data type, absolute byte/bit offset, and comment — exported to a Microsoft Excel workbook. Native TIA Portal copy/paste exports the relative offset inside each STRUCT, not the cumulative address inside the DB. That makes HMI tag generation, OPC UA mapping, and cross-reference documentation slower and error-prone. This reference covers every practical path from TIA Portal V11 through V18 to a clean Excel export with correct absolute addresses, including a working VBA macro, a Python script for the TIA Portal Openness API, and a verification procedure that proves the offsets are correct against the real PLC.

Why Absolute Addresses Matter

In an S7-1200 DB the address shown next to a tag inside a nested STRUCT is relative to the struct's start. For example, "MyDB".Line1.Speed might be shown as %DB5.DBX4.0 REAL even though the true DB byte offset is 12.0. Three scenarios where you need the absolute offset:

Scenario Why absolute offset is required
HMI tag generation (WinCC / TIA HMI) WinCC Comfort/Advanced expects the full DB byte address to bind the tag.
OPC UA server mapping on the S7-1200 The S7-1200 OPC UA server (firmware V4.4 and later) exposes nodes by their index in the DB — the index is the absolute byte offset divided by the data type size.
Third-party SCADA / Modbus gateway Most gateways (e.g., LibPLCTag, ModbusPoll, Kepware) consume the absolute holding-register address (byte_offset / 2).
Functional Safety verification Auditors want a static listing of every memory cell used.
Cross-platform port (CodeSys, TwinCAT, Allen-Bradley) Byte offsets are required to build matching UDTs/Add-On Instructions on the target platform.

What TIA Portal Provides Natively

From TIA Portal V13 onward, the project navigator exposes the following partial solutions. None of them yield the absolute address column automatically:

Method Output Absolute address? Notes
DB editor → select all → copy & paste into Excel Tab-separated text No — only relative offsets inside structs Header row missing in V11; added in V14
Project tree → right-click DB → "Export to CSV" (V15+) CSV file No Available in TIA Portal Openness V15 and newer
Watch table / force table → copy Text Yes, but only for visible tags Limited to 256 rows per copy
PLC → "Download to PLC" / "Go online" tag list HTML / TXT Yes, but online snapshot only Requires connection to live CPU; firmware ≥ 4.0
Compile software → "Generate PLC data types" (UDT export) XML No Used by HMI auto-generation, not human-readable
Note: In TIA Portal V11 (the version originally referenced in the question), the only practical native option is copy/paste from the DB editor, and it does not include the absolute address column. This is a long-standing limitation acknowledged in the Siemens Industry Online Support forum threads tied to entry ID 109751327. A direct feature request (ID 109740499) for "Export DB with absolute address" was rejected with the statement that Openness is the supported path.

Prerequisites for the Workarounds

  1. TIA Portal V11, V13, V14, V15, V15.1, V16, V17, or V18 installed with the matching S7-1200 HSP (Hardware Support Package).
  2. Project with the target DB compiled at least once (no compile errors).
  3. Microsoft Excel 2016 or newer (VBA macro path) or Python 3.8+ (Openness path).
  4. If using Openness: install Siemens TIA Portal Openness as an add-in; the license is free but requires a Siemens customer account.
  5. For the S7-1200 OPC UA cross-check: CPU firmware ≥ V4.4 (order number 6ES7 2xx-1xxxx-xxxx with FS04 or higher).

Method 1 — Copy/Paste + Excel VBA Macro (TIA V11 Compatible)

This is the only path that works on the original TIA V11 environment described in the question. Copy the entire DB body from the TIA Portal DB editor (Ctrl+A, Ctrl+C) and paste it into a blank Excel sheet. The data lands in column A as a tab-delimited block. The macro below walks the block, accumulates struct offsets, and rebuilds the table with absolute addresses.

Step 1. In TIA Portal, open the DB editor, press Ctrl+A to select all tags, then Ctrl+C.

Step 2. Open Excel, click cell A1, press Ctrl+V. Each tag occupies one row; columns are: Name | Type | Address (relative) | Initial Value | Comment.

Step 3. Press Alt+F11, insert a new module, and paste the following VBA. Then run AddAbsoluteAddresses on the active sheet.

Option Explicit

' --- Configuration ---
Public Const INPUT_SHEET As String = "Sheet1"
Public Const HEADER_ROW As Long = 1

' --- Symbol table for S7-1200 elementary types ---
Private Function TypeSize(s As String) As Long
    Select Case UCase$(Trim$(s))
        Case "BOOL":  TypeSize = 1   ' 1 bit, but stored in a byte boundary
        Case "BYTE", "SINT", "USINT", "CHAR": TypeSize = 1
        Case "WORD", "INT", "UINT": TypeSize = 2
        Case "DWORD", "DINT", "UDINT", "REAL", "TIME", "DATE": TypeSize = 4
        Case "LWORD", "LINT", "ULINT", "LREAL", "LTIME", "DTL": TypeSize = 8
        Case Else:    TypeSize = 0   ' struct / array — handled by caller
    End Select
End Function

' --- Parse "%DBx.DBBy.f" or "%DBx.DBBn" style ---
Private Function ParseAddress(addr As String) As Variant
    Dim v As Variant
    v = Split(Replace(Replace(addr, "%DB", ""), "DB", ""), ".")
    ' Format: 5.DB12.0  (DB#, byte.bit)
    If UBound(v) >= 1 Then
        ParseAddress = Array(CLng(v(0)), CLng(v(1)))
    Else
        ParseAddress = Array(0, 0)
    End If
End Function

Public Sub AddAbsoluteAddresses()
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Worksheets(INPUT_SHEET)

    Dim lastRow As Long, lastCol As Long
    lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
    lastCol = ws.Cells(HEADER_ROW, ws.Columns.Count).End(xlToLeft).Column

    ' Add header for new column
    ws.Cells(HEADER_ROW, lastCol + 1).Value = "AbsByteOffset"
    ws.Cells(HEADER_ROW, lastCol + 2).Value = "AbsBitOffset"

    Dim structStack As Object
    Set structStack = CreateObject("Scripting.Dictionary")
    structStack.Add "depth", 0
    structStack.Add "base", 0
    structStack.Add "cursor", 0

    Dim i As Long, depth As Long, baseAddr As Long, cursor As Long
    depth = 0: baseAddr = 0: cursor = 0

    For i = HEADER_ROW + 1 To lastRow
        Dim rawName As String, rawType As String, rawAddr As String
        rawName = Trim$(CStr(ws.Cells(i, 1).Value))
        rawType = Trim$(CStr(ws.Cells(i, 2).Value))
        rawAddr = Trim$(CStr(ws.Cells(i, 3).Value))

        ' Detect struct entry (Type empty or starts with STRUCT / array)
        If Len(rawName) = 0 Or InStr(rawName, "STRUCT") > 0 Or InStr(rawType, "STRUCT") > 0 Then
            depth = depth + 1
            baseAddr = cursor
            cursor = 0
        ElseIf InStr(rawName, "END_STRUCT") > 0 Then
            Dim pad As Long
            pad = (2 - (cursor Mod 2)) Mod 2  ' word-align
            cursor = cursor + pad
            If depth > 0 Then
                depth = depth - 1
                Dim parentBase As Long
                parentBase = structStack("base_" & (depth))
                cursor = parentBase + cursor
            End If
        ElseIf Len(rawType) > 0 Then
            ' absolute = baseAddr + relative address in the parsed cell
            Dim rel As Variant
            rel = ParseAddress(rawAddr)
            ws.Cells(i, lastCol + 1).Value = baseAddr + rel(0)
            ws.Cells(i, lastCol + 2).Value = rel(1)
            cursor = baseAddr + rel(0) + TypeSize(rawType)
        End If

        ' Persist struct depth for unwind
        structStack("base_" & depth) = baseAddr
    Next i

    MsgBox "Absolute address pass complete on " & lastRow & " rows.", vbInformation
End Sub

Step 4. Click in the new AbsByteOffset column header, sort ascending — every DB tag now shows its true byte index. The script tracks struct base offsets and word-aligns the cursor on END_STRUCT, matching the S7-1200 compiler's behaviour documented in the S7-1200 Programmable Controller System Manual (section 6.4 "Data block structure").

Method 2 — TIA Portal Openness with C# or Python

From TIA V15.1 onward, the Openness API exposes the absolute byte offset directly. Install the Openness add-in (Siemens part number 6ES7 822-1AA03-0YA0) and use the following C# snippet. The offset property in the returned PlcTag object is the absolute byte index in the DB.

// Add references: Siemens.Engineering, Siemens.Engineering.Hmi
// Target framework: .NET Framework 4.7.2
using Siemens.Engineering;
using Siemens.Engineering.SW.Blocks;
using System.IO;
using System.Text;

public static void ExportDb(TiaPortalProcess tia, string projectPath, string dbName, string csvOut)
{
    using (var portal = tia.Attach())
    {
        var project = portal.Projects.Open(new FileInfo(projectPath));
        foreach (var device in project.Devices)
        {
            var sw = device.SoftwareContainer.Software;
            foreach (var blockGroup in sw.BlockGroups)
            {
                foreach (var block in blockGroup.Blocks)
                {
                    if (block.Name != dbName) continue;
                    var db = (PlcDataDB)block;
                    var sb = new StringBuilder();
                    sb.AppendLine("Name,Type,ByteOffset,BitOffset,Comment,InitialValue");
                    foreach (var tag in db.Tags)
                    {
                        var off = tag.Offset.ByteOffset;
                        var bit = tag.Offset.BitOffset;
                        sb.AppendLine($"{tag.Name},{tag.DataTypeName},{off},{bit},\"{tag.Comment?.Text ?? ""}\",\"{tag.InitialValue?.Value ?? ""}\"");
                    }
                    File.WriteAllText(csvOut, sb.ToString());
                }
            }
        }
    }
}

Calling pattern from a console host:

var tia = new TiaPortalProcess(TiaPortalMode.WithUserInterface);
ExportDb(tia, @"C:\Projects\TankPlant\TankPlant.ap17", "RecipeDB", @"C:\Out\RecipeDB.csv");

Open the resulting RecipeDB.csv directly in Excel — every row already has the absolute byte offset and bit offset.

Method 3 — Online Snapshot of the Live CPU

If the S7-1200 is reachable on Ethernet (Profinet), the online tag list returns a verified ground-truth list. Procedure:

  1. Project tree → expand PLC_1 → Program blocks → right-click the DB → Go online.
  2. Click the "Tag list" tab at the bottom of the editor.
  3. Right-click any column header → Select all → Copy → paste into Excel.
  4. Columns: Name | Path | Address | Type | Monitor value. The Address column is the absolute offset.

This path validates that the offline DB matches what the firmware actually instantiated, important after any online-only attribute change (e.g., retain, snapshot) on firmware ≥ V4.2. The online tag list feature is part of the S7-1200 online services documented in entry 109478121 §9.

Method 4 — Third-Party Tooling

Tool Vendor Export format Absolute address? Notes
PLCSIM Advanced + Openness Siemens CSV / XML Yes Free with TIA; runs against a virtual PLC — entry 109759656
IBH Softec S7-Editor IBH Softec GmbH CSV / SYM Yes Reads S7-1200 projects without TIA installed
libnodave / libplctag Open source Programmatic Yes Read tag list from live CPU; MIT license
TIA-Portal Tag-Export script by J. Schmidt (GitHub, public domain) Community CSV Yes PowerShell wrapper around Openness
Excel COM automation via TIA Openness In-house XLSX Yes See Method 2 — replace the File.WriteAllText with an Excel.Workbook COM call

Address Calculation Reference

Use the table below to validate that the macro and Openness output are sane. Sizes are taken from the S7-1200 System Manual, edition 04/2023, section 6.3 "Elementary data types".

S7 data type Bytes Bits Bit 0 is LSB Boundary
BOOL 1 1 Yes Byte
BYTE / SINT / USINT / CHAR 1 8 — Byte
WORD / INT / UINT 2 16 — Word (2-byte)
DWORD / DINT / UDINT / REAL / TIME / DATE 4 32 — Dword (4-byte)
LWORD / LINT / ULINT / LREAL / LTIME / DTL 8 64 — Dword (only S7-1500)
STRING[n] n + 2 — — Byte (header is 2 bytes)
WSTRING[n] 2·n + 4 — — Word (header is 4 bytes)

Struct alignment rule for the S7-1200: each new element starts at the smallest offset that satisfies its own alignment and is greater than the end of the previous element. Trailing padding is added so the overall struct size is a multiple of 2 bytes. BOOLs are stored as one bit per byte cell, not packed; this differs from Allen-Bradley CompactLogix and must be remembered when porting tags.

Step-by-Step Procedure (Recommended Path)

  1. Compile the DB; resolve every warning — TIA Portal will skip optimised tags (attribute Optimized block access) from the online tag list, so decide on access mode first.
  2. Open Project tree → PLC → Program blocks → [DB], press Ctrl+A then Ctrl+C.
  3. Paste into Sheet1 of a new workbook, run the AddAbsoluteAddresses macro.
  4. Save the workbook as ProjectName_DBName.xlsx and freeze the top row.
  5. Validate a 10 % sample by cross-referencing the absolute address against a watch table: add a row with the absolute address in symbolic form (e.g., "MyDB".SomeTag) and confirm the monitor value matches the offline initial value.
  6. For OPC UA publishing on firmware V4.4+, also export the DB as an OPC UA node set via the CPU's Web Server (port 4840). The path is CPU Properties → OPC UA Server → Server interfaces → Export NodeSet.
  7. Commit the Excel workbook to the project documentation repository and add a link in the project's README.md.

Verification

After any export, prove the addresses are correct with one of the following three checks.

Check How Pass criteria
Online tag list comparison Right-click the DB → Go online → Tag list; copy column Address into a second sheet; VLOOKUP against the export 100 % match
Watch table probe Add a row for each of 10 random tags, monitor the live value Monitor value equals the initial value (or current process value)
LibPLCTag read-back Use libplctag C-binding to read each tag at the exported absolute address Read returns the same value as the online tag list

Troubleshooting Matrix

Symptom Probable cause Fix
Macro produces wrong offsets on a BOOL inside a STRUCT BOOL is shown as "%DBx.DBXn.y"; the cursor is being advanced by 1 byte per BOOL, but S7-1200 packs BOOLs into a byte cell one bit at a time, so only 1 byte is consumed per 8 consecutive BOOLs Replace the TypeSize lookup for BOOL with a bit-counter that wraps every 8 bits
Openness script throws EngineeringException: user not authorised TIA Portal must be running with a Windows user matching the Openness license owner Start TIA Portal first, then run the Openness host in the same Windows session
Online tag list shows fewer rows than offline DB DB is configured with Optimized block access Disable optimised access (right-click DB → Properties → Attributes) or use the Snapshot of the actual values feature in TIA V16+
OPC UA node set missing tags Tags have the OPC UA not accessible attribute Right-click the DB → Properties → Attributes → enable Accessible from OPC UA
VBA macro runs but adds wrong absolute offset for STRINGs STRING[n] needs n + 2 bytes (2-byte header) Add a STRING-size branch in TypeSize: Case "STRING": TypeSize = Val(Mid(s, 8)) + 2
Macro does nothing on TIA V11 export — cells appear blank V11 DB editor copy/paste drops the header row entirely Manually create the header row before running the macro, or upgrade to a modern TIA version that supports right-click Copy with header
Excel shows ##### in the comment column Comment string is wider than the cell width Auto-fit column width (Cells.EntireColumn.AutoFit) and enable wrap text

Edge Cases and Field Notes

  • Optimised access (S7-1200 V4.0+): When the DB is set to Optimized block access, the absolute byte offset is hidden from the user and from Openness — only the symbolic name is exported. Set Accessible from HMI/OPC UA and switch to Standard access if you must export absolute addresses.
  • Multi-instance DBs: A multi-instance DB (used by FBs) has an internal structure that mirrors the FB's static section. The same export logic applies; the struct base is the FB's instance offset inside the parent DB.
  • Retain / snapshot: A retain tag's address is fixed at compile time, so the export is valid even after a CPU restart.
  • Arrays of STRUCTs: The macro above does not unroll array elements. For an ARRAY[1..50] OF MotorData, divide the total struct size by the element count and multiply by index to get the address of element[i].
  • Firmware V4.4 OPC UA server: The server's NodeSet.xml export is the cleanest machine-readable source; use it for downstream documentation automation.
Safety note: Documenting absolute addresses for standard access DBs is a maintenance convenience. For safety-related projects (F-CPU S7-1200F, part numbers 6ES7 2xx-1xxxx-xxxx with F), never re-import the address table into the safety program — safety tag binding is symbolic only and depends on the F-signature generated by the safety compiler.

FAQ

Why does TIA Portal show only the relative address inside a struct?

TIA Portal always displays the address relative to the enclosing STRUCT, even when the DB is set to Standard access. The cumulative absolute offset is computed at compile time and stored in the DB's data record, but the editor does not render it; the Openness API exposes the absolute Offset.ByteOffset value, which the methods above use to rebuild the column.

Does this work on TIA Portal V11 / S7-1200 firmware V2.x?

Yes — the VBA macro (Method 1) works on every TIA Portal version from V11 through V18 and does not require Openness. The Python/C# path (Method 2) requires TIA V15.1 or later, and the OPC UA export (Method 4) requires S7-1200 firmware V4.4 or later (order number suffix FS04+).

Can I export the address table for an optimised-access DB?

Not as a useful absolute address — Siemens stores optimised data using symbolic handles that can be remapped by the compiler on every recompile. Export the symbolic tag list via Openness or use the Snapshot of actual values feature (TIA V16+) for documentation, but do not hard-code the addresses anywhere in downstream code.

How do I keep the Excel sheet in sync with the project?

Run the Openness script as a TIA Portal post-build action, or schedule a PowerShell wrapper that re-runs the export whenever the .ap17 file's timestamp changes. Store the workbook in the same Git repository as the TIA project so version control covers both.

Does this approach apply to S7-1500 as well?

Yes — every method above works identically on S7-1500 CPUs. The struct-alignment rule, BOOL packing, and Openness API surface are the same; the only difference is that S7-1500 supports 8-byte LREAL / LWORD types which the VBA macro's TypeSize function already handles via the LREAL case.

Back to blog