Put the selected byte number in "HMI_Status".Card_No. In ladder, one branch per byte compares Card_No and runs SCATTER from %IBn into "HMI_Status".DI.Inp[0..7]. On the HMI, eight rows of symbolic I/O fields use text lists indexed by Card_No for address, description and NO/NC, and the DI.Inp bits for live status. An FC adds NC-fault, change and filter bits for the animations.
- One screen and about twenty HMI tags cover 60 inputs and 20 outputs.
- Text lists carry the descriptions, so a rename never touches the PLC.
- NC contacts are shown as NC and turn the row red when they open.
I/O plan and hardware
The example is a sealed quench heat-treatment furnace. The I/O count is fixed at 60 digital inputs, 20 analog inputs, 20 digital outputs and 10 analog outputs, with the digital descriptions taken from the project text lists. Every card keeps spares for later changes.
| Signal type | Used | Modules | Addresses | Terminal strip |
|---|---|---|---|---|
| Digital inputs | 60 | 2 × DI 32x24VDC HF | %I0.0 – %I7.3 (spare %I7.4 – %I7.7) | X10 |
| Digital outputs | 20 | 1 × DQ 32x24VDC/0.5A HF | %Q0.0 – %Q2.3 (spare %Q2.4 – %Q3.7) | X20 |
| Analog inputs | 20 | 3 × AI 8xU/I/RTD/TC ST | %IW100 – %IW138 (spare 4 ch) | X30 |
| Analog outputs | 10 | 3 × AQ 4xU/I ST | %QW100 – %QW118 (spare 2 ch) | X40 |
Set the analog start addresses by hand (Device view → module → Properties → I/O addresses) to 100, 116 and 132 for the AI cards and 100, 108 and 116 for the AQ cards. Fixed addresses keep the tag list valid when a card is added later. The same approach is shown step by step in Siemens device configuration and tag creation.
Stage 1Terminal wiring drawings (EPLAN style)
Twelve drawing sheets in the layout an EPLAN P8 PLC overview uses: column grid, title block, terminal strip numbers, device tags and the PLC channel with its address. Use the selector to page through the rack, the four DI sheets, two DQ sheets, three AI sheets and two AQ sheets.
Loading drawing…
Full digital input list – 64 channels
| Address | Description | Contact | PLC tag | Terminal |
|---|---|---|---|---|
%I0.0 | Charge Fork Backward | NC | DI_0_0_Charge_Fork_Backward | X10:1 |
%I0.1 | Discharge Fork Backward | NC | DI_0_1_Discharge_Fork_Backward | X10:2 |
%I0.2 | Fork Base Down | NC | DI_0_2_Fork_Base_Down | X10:3 |
%I0.3 | Fork Base Up | NO | DI_0_3_Fork_Base_Up | X10:4 |
%I0.4 | Charge Fork Forward | NO | DI_0_4_Charge_Fork_Forward | X10:5 |
%I0.5 | Discharge Fork Forward | NC | DI_0_5_Discharge_Fork_Forward | X10:6 |
%I0.6 | Charge Fork Half Way Back | NO | DI_0_6_Charge_Fork_Half_Way_Back | X10:7 |
%I0.7 | Discharge Fork Halfway Back | NO | DI_0_7_Discharge_Fork_Halfway_Back | X10:8 |
%I1.0 | Discharge Fork Backward | NC | DI_1_0_Discharge_Fork_Backward | X10:9 |
%I1.1 | Front Door Open Switch | NC | DI_1_1_Front_Door_Open_Switch | X10:10 |
%I1.2 | Front Door Close Limit Switch | NC | DI_1_2_Front_Door_Close_Limit_Switch | X10:11 |
%I1.3 | Intermediate Door Open Limit Switch | NO | DI_1_3_Intermediate_Door_Open_Limit_Switch | X10:12 |
%I1.4 | Intermediate Door Close Limit Switch | NO | DI_1_4_Intermediate_Door_Close_Limit_Switch | X10:13 |
%I1.5 | Elevator Up Limit Switch | NO | DI_1_5_Elevator_Up_Limit_Switch | X10:14 |
%I1.6 | Elevator Down Limit Switch | NO | DI_1_6_Elevator_Down_Limit_Switch | X10:15 |
%I1.7 | Charge Ready On Elevator Deck Limit Switch | NO | DI_1_7_Charge_Ready_On_Elevator_Deck_Limit_Switch | X10:16 |
%I2.0 | Rear Door Open Limit Switch | NC | DI_2_0_Rear_Door_Open_Limit_Switch | X10:17 |
%I2.1 | Rear Door Close Limit Switch | NC | DI_2_1_Rear_Door_Close_Limit_Switch | X10:18 |
%I2.2 | Charge On Exit Traverser Trolley | NC | DI_2_2_Charge_On_Exit_Traverser_Trolley | X10:19 |
%I2.3 | Emergency Stop For Front Panel | NO | DI_2_3_Emergency_Stop_For_Front_Panel | X10:20 |
%I2.4 | Emergency Stop For Rear Panel | NO | DI_2_4_Emergency_Stop_For_Rear_Panel | X10:21 |
%I2.5 | Spare(2) | NO | DI_2_5_Spare_2 | X10:22 |
%I2.6 | Spare(3) | NO | DI_2_6_Spare_3 | X10:23 |
%I2.7 | Heating Chamber Fan In Operation(1) | NO | DI_2_7_Heating_Chamber_Fan_In_Operation_1 | X10:24 |
%I3.0 | Fresh Charge Entry Safe Cp(1) | NC | DI_3_0_Fresh_Charge_Entry_Safe_Cp_1 | X10:25 |
%I3.1 | Vestibule Oil Cooling Pump On(1) | NC | DI_3_1_Vestibule_Oil_Cooling_Pump_On_1 | X10:26 |
%I3.2 | Alarm Accept | NO | DI_3_2_Alarm_Accept | X10:27 |
%I3.3 | Bell Accept | NO | DI_3_3_Bell_Accept | X10:28 |
%I3.4 | Carb Boosting In Progress | NO | DI_3_4_Carb_Boosting_In_Progress | X10:29 |
%I3.5 | Carb Diffusion In Progress | NO | DI_3_5_Carb_Diffusion_In_Progress | X10:30 |
%I3.6 | Hardening Soak In Progress | NO | DI_3_6_Hardening_Soak_In_Progress | X10:31 |
%I3.7 | Process End | NO | DI_3_7_Process_End | X10:32 |
%I4.0 | Charge Fork Fwd & Discharge Fork Rvs | NC | DI_4_0_Charge_Fork_Fwd_Discharge_Fork_Rvs | X10:33 |
%I4.1 | Discharge Fork Fwd & Charge Fork Rvs | NC | DI_4_1_Discharge_Fork_Fwd_Charge_Fork_Rvs | X10:34 |
%I4.2 | Oil Agitator Auto Selection | NO | DI_4_2_Oil_Agitator_Auto_Selection | X10:35 |
%I4.3 | Charge Entry Self Temp | NO | DI_4_3_Charge_Entry_Self_Temp | X10:36 |
%I4.4 | Rear Door Flame Curtain Auto | NO | DI_4_4_Rear_Door_Flame_Curtain_Auto | X10:37 |
%I4.5 | Quench Oil Cooling Pump On | NO | DI_4_5_Quench_Oil_Cooling_Pump_On | X10:38 |
%I4.6 | Charge Entry Site Temp | NO | DI_4_6_Charge_Entry_Site_Temp | X10:39 |
%I4.7 | Oil Agitator Manually Slow Mode Selection | NO | DI_4_7_Oil_Agitator_Manually_Slow_Mode_Selection | X10:40 |
%I5.0 | Auto Oper Selection In Rear Oper Panel | NC | DI_5_0_Auto_Oper_Selection_In_Rear_Oper_Panel | X10:41 |
%I5.1 | Manual Oper Selection In Rear Oper Panel | NC | DI_5_1_Manual_Oper_Selection_In_Rear_Oper_Panel | X10:42 |
%I5.2 | Rear Door Open | NO | DI_5_2_Rear_Door_Open | X10:43 |
%I5.3 | Elevator Chain Drive On | NO | DI_5_3_Elevator_Chain_Drive_On | X10:44 |
%I5.4 | Rear Door Close | NO | DI_5_4_Rear_Door_Close | X10:45 |
%I5.5 | Acknowledge Front Oper Panel | NO | DI_5_5_Acknowledge_Front_Oper_Panel | X10:46 |
%I5.6 | Acknowledge Rear Oper Panel | NO | DI_5_6_Acknowledge_Rear_Oper_Panel | X10:47 |
%I5.7 | Oil Agitator Manually Fast | NO | DI_5_7_Oil_Agitator_Manually_Fast | X10:48 |
%I6.0 | Auto Oper Selection In Front Oper Panel | NC | DI_6_0_Auto_Oper_Selection_In_Front_Oper_Panel | X10:49 |
%I6.1 | Manual Oper Selection In Front Oper Panel | NC | DI_6_1_Manual_Oper_Selection_In_Front_Oper_Panel | X10:50 |
%I6.2 | Charge Fork Forward(1) | NO | DI_6_2_Charge_Fork_Forward_1 | X10:51 |
%I6.3 | Discharge Fork Forward | NO | DI_6_3_Discharge_Fork_Forward | X10:52 |
%I6.4 | Charge Pusher Fork Reversing | NO | DI_6_4_Charge_Pusher_Fork_Reversing | X10:53 |
%I6.5 | Front Door Open Push Button | NO | DI_6_5_Front_Door_Open_Push_Button | X10:54 |
%I6.6 | Front Door Close Push Button | NO | DI_6_6_Front_Door_Close_Push_Button | X10:55 |
%I6.7 | Intermediate Door Open Push Button | NO | DI_6_7_Intermediate_Door_Open_Push_Button | X10:56 |
%I7.0 | Intermediate Door Close Push Button | NC | DI_7_0_Intermediate_Door_Close_Push_Button | X10:57 |
%I7.1 | Elevator Up Push Button | NC | DI_7_1_Elevator_Up_Push_Button | X10:58 |
%I7.2 | Elevator Down Push Button | NO | DI_7_2_Elevator_Down_Push_Button | X10:59 |
%I7.3 | Auto Start Push Button | NO | DI_7_3_Auto_Start_Push_Button | X10:60 |
%I7.4 | Spare | – | DI_7_4_Spare | X10:61 |
%I7.5 | Spare | – | DI_7_5_Spare | X10:62 |
%I7.6 | Spare | – | DI_7_6_Spare | X10:63 |
%I7.7 | Spare | – | DI_7_7_Spare | X10:64 |
Full digital output list – 32 channels
| Address | Description | PLC tag | Terminal |
|---|---|---|---|
%Q0.0 | Charge Fork Forward Discharge Fork Backward | DQ_0_0_Charge_Fork_Forward_Discharge_Fork_Backward | X20:1 |
%Q0.1 | Discharge Fork Forward Charge Fork Backward | DQ_0_1_Discharge_Fork_Forward_Charge_Fork_Backward | X20:2 |
%Q0.2 | Elevator Chain Drive On | DQ_0_2_Elevator_Chain_Drive_On | X20:3 |
%Q0.3 | Ring Burner On | DQ_0_3_Ring_Burner_On | X20:4 |
%Q0.4 | Pusher Base Table Up(1) | DQ_0_4_Pusher_Base_Table_Up_1 | X20:5 |
%Q0.5 | Pusher Base Table Down(1) | DQ_0_5_Pusher_Base_Table_Down_1 | X20:6 |
%Q0.6 | Front Door Open | DQ_0_6_Front_Door_Open | X20:7 |
%Q0.7 | Front Door Close | DQ_0_7_Front_Door_Close | X20:8 |
%Q1.0 | Intermediate Door Open | DQ_1_0_Intermediate_Door_Open | X20:9 |
%Q1.1 | Intermediate Door Close | DQ_1_1_Intermediate_Door_Close | X20:10 |
%Q1.2 | Elevator Up | DQ_1_2_Elevator_Up | X20:11 |
%Q1.3 | Elevator Down | DQ_1_3_Elevator_Down | X20:12 |
%Q1.4 | Rear Door Open | DQ_1_4_Rear_Door_Open | X20:13 |
%Q1.5 | Rear Door Close(1) | DQ_1_5_Rear_Door_Close_1 | X20:14 |
%Q1.6 | Exit Roller Drive On | DQ_1_6_Exit_Roller_Drive_On | X20:15 |
%Q1.7 | Tray In Position (To Confirm) | DQ_1_7_Tray_In_Position | X20:16 |
%Q2.0 | Agitator Rotation High Speed Ind | DQ_2_0_Agitator_Rotation_High_Speed_Ind | X20:17 |
%Q2.1 | Agitator Rotation Low Ind | DQ_2_1_Agitator_Rotation_Low_Ind | X20:18 |
%Q2.2 | Agitator High Speed | DQ_2_2_Agitator_High_Speed | X20:19 |
%Q2.3 | Agitator Low Speed | DQ_2_3_Agitator_Low_Speed | X20:20 |
%Q2.4 | Spare | DQ_2_4_Spare | X20:21 |
%Q2.5 | Spare | DQ_2_5_Spare | X20:22 |
%Q2.6 | Spare | DQ_2_6_Spare | X20:23 |
%Q2.7 | Spare | DQ_2_7_Spare | X20:24 |
%Q3.0 | Spare | DQ_3_0_Spare | X20:25 |
%Q3.1 | Spare | DQ_3_1_Spare | X20:26 |
%Q3.2 | Spare | DQ_3_2_Spare | X20:27 |
%Q3.3 | Spare | DQ_3_3_Spare | X20:28 |
%Q3.4 | Spare | DQ_3_4_Spare | X20:29 |
%Q3.5 | Spare | DQ_3_5_Spare | X20:30 |
%Q3.6 | Spare | DQ_3_6_Spare | X20:31 |
%Q3.7 | Spare | DQ_3_7_Spare | X20:32 |
Analog input list – 24 channels
| Address | Tag | Signal | Range | Type | PLC tag |
|---|---|---|---|---|---|
%IW100 | TT101 | Heating chamber temperature zone 1 | 0–1200 °C | 4–20 mA, 2-wire | AI_00_TT101_Raw |
%IW102 | TT102 | Heating chamber temperature zone 2 | 0–1200 °C | 4–20 mA, 2-wire | AI_01_TT102_Raw |
%IW104 | TT103 | Heating chamber temperature zone 3 | 0–1200 °C | 4–20 mA, 2-wire | AI_02_TT103_Raw |
%IW106 | TT104 | Vestibule temperature | 0–600 °C | 4–20 mA, 2-wire | AI_03_TT104_Raw |
%IW108 | TT105 | Quench oil temperature | 0–200 °C | 4–20 mA, 2-wire | AI_04_TT105_Raw |
%IW110 | TT106 | Oil cooler outlet temperature | 0–200 °C | 4–20 mA, 2-wire | AI_05_TT106_Raw |
%IW112 | AT201 | Carbon potential (oxygen probe) | 0–1.6 %C | 4–20 mA, 2-wire | AI_06_AT201_Raw |
%IW114 | AT202 | Atmosphere dew point | -20–+20 °C | 4–20 mA, 2-wire | AI_07_AT202_Raw |
%IW116 | PT301 | LPG supply pressure | 0–2 bar | 4–20 mA, 2-wire | AI_08_PT301_Raw |
%IW118 | PT302 | Carrier (endo) gas pressure | 0–100 mbar | 4–20 mA, 2-wire | AI_09_PT302_Raw |
%IW120 | PT303 | Compressed air pressure | 0–10 bar | 4–20 mA, 2-wire | AI_10_PT303_Raw |
%IW122 | FT401 | Endo gas flow | 0–30 m³/h | 4–20 mA, 2-wire | AI_11_FT401_Raw |
%IW124 | FT402 | Enrichment gas flow | 0–2 m³/h | 4–20 mA, 2-wire | AI_12_FT402_Raw |
%IW126 | FT403 | Dilution air flow | 0–2 m³/h | 4–20 mA, 2-wire | AI_13_FT403_Raw |
%IW128 | LT501 | Quench oil tank level | 0–100 % | 4–20 mA, 2-wire | AI_14_LT501_Raw |
%IW130 | TT107 | Exhaust gas temperature | 0–600 °C | 4–20 mA, 2-wire | AI_15_TT107_Raw |
%IW132 | IT601 | Heating fan motor current | 0–50 A | 4–20 mA, 2-wire | AI_16_IT601_Raw |
%IW134 | IT602 | Agitator 1 motor current | 0–30 A | 4–20 mA, 2-wire | AI_17_IT602_Raw |
%IW136 | IT603 | Agitator 2 motor current | 0–30 A | 4–20 mA, 2-wire | AI_18_IT603_Raw |
%IW138 | PT304 | Furnace chamber pressure | 0–25 mmWC | 4–20 mA, 2-wire | AI_19_PT304_Raw |
%IW140 | – | SPARE | – | – | AI_20_Spare |
%IW142 | – | SPARE | – | – | AI_21_Spare |
%IW144 | – | SPARE | – | – | AI_22_Spare |
%IW146 | – | SPARE | – | – | AI_23_Spare |
Analog output list – 12 channels
| Address | Tag | Signal | Range | Type | PLC tag |
|---|---|---|---|---|---|
%QW100 | TCV101 | Zone 1 burner control valve | 0–100 % | 4–20 mA | AQ_00_TCV101_Out |
%QW102 | TCV102 | Zone 2 burner control valve | 0–100 % | 4–20 mA | AQ_01_TCV102_Out |
%QW104 | TCV103 | Zone 3 burner control valve | 0–100 % | 4–20 mA | AQ_02_TCV103_Out |
%QW106 | FCV401 | Endo gas flow control valve | 0–100 % | 4–20 mA | AQ_03_FCV401_Out |
%QW108 | FCV402 | Enrichment gas control valve | 0–100 % | 4–20 mA | AQ_04_FCV402_Out |
%QW110 | FCV403 | Dilution air control valve | 0–100 % | 4–20 mA | AQ_05_FCV403_Out |
%QW112 | SIC601 | Heating fan VFD speed reference | 0–50 Hz | 4–20 mA | AQ_06_SIC601_Out |
%QW114 | SIC602 | Agitator VFD speed reference | 0–50 Hz | 4–20 mA | AQ_07_SIC602_Out |
%QW116 | TCV104 | Oil cooler water valve | 0–100 % | 4–20 mA | AQ_08_TCV104_Out |
%QW118 | AY201 | Carbon potential retransmission to recorder | 0–1.6 %C | 4–20 mA | AQ_09_AY201_Out |
%QW120 | – | SPARE | – | – | AQ_10_Spare |
%QW122 | – | SPARE | – | – | AQ_11_Spare |
Stage 2PLC tags – copy and paste
144 tags: 8 DI byte tags and 4 DQ byte tags for SCATTER, then every bit and analog channel. The byte tags replace names such as Tag_1, which tell a maintenance engineer nothing.
- Fast way: click Copy for TIA tag table, open the
IO_Listtag table, click the first empty Name cell and press Ctrl+V. Name, data type and address fill in. - With comments: click Copy for Excel import, paste into cell A1 of a sheet named
PLC Tags, save as .xlsx, then in the tag table use Import. This version also brings the comments and HMI access flags.
DI_Byte_0 Byte %IB0 DI_Byte_1 Byte %IB1 DI_Byte_2 Byte %IB2 DI_Byte_3 Byte %IB3 DI_Byte_4 Byte %IB4 DI_Byte_5 Byte %IB5 DI_Byte_6 Byte %IB6 DI_Byte_7 Byte %IB7 DQ_Byte_0 Byte %QB0 DQ_Byte_1 Byte %QB1 DQ_Byte_2 Byte %QB2 DQ_Byte_3 Byte %QB3 DI_0_0_Charge_Fork_Backward Bool %I0.0 DI_0_1_Discharge_Fork_Backward Bool %I0.1 … (144 rows in total – use the copy button)
Stage 3The HMI_Status DB – copy and paste
The DB matches the addresses in the ladder: Card_No at DBB0 and DI.Inp at DBX2.0. It is a standard (not optimized) DB so those absolute addresses stay fixed. DI_NC_Mask holds one bit per NC contact, already filled from the text list Input Add C.
- Copy the source, save it as
HMI_Status.db. - Project tree → External source files → Add new external file → pick the file.
- Right-click it → Generate blocks from source. Set the DB number to 1 in its properties if TIA chose another.
DATA_BLOCK "HMI_Status"
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
STRUCT
Card_No : Byte; // DI byte shown on HMI (0..7) -> %DB1.DBB0
Card_No_DQ : Byte; // DQ byte shown on HMI (0..2) -> %DB1.DBB1
DI : Struct // -> %DB1.DBX2.0
Inp : Array[0..7] of Bool; // SCATTER of selected %IB
END_STRUCT;
DQ : Struct // -> %DB1.DBX4.0
Out : Array[0..7] of Bool; // SCATTER of selected %QB
END_STRUCT;
Filter_DI : Byte; // 0 All, 1 ON, 2 OFF, 3 NC only, 4 Faults
Filter_DQ : Byte; // 0 All, 1 ON, 2 OFF
Show_DI : Array[0..7] of Bool; // row visibility on HMI
Show_DQ : Array[0..7] of Bool;
DI_Fault : Array[0..7] of Bool; // NC contact open
DI_Changed : Array[0..7] of Bool; // flashes until Clear
DQ_Changed : Array[0..7] of Bool;
DI_Prev : Array[0..7] of Bool;
DQ_Prev : Array[0..7] of Bool;
Prev_Card : Byte;
Prev_Card_DQ : Byte;
Clear_Changed : Bool; // HMI button, PLC resets it
DI_On_Count : USInt;
DI_Fault_Count : USInt;
DQ_On_Count : USInt;
DI_NC_Mask : Array[0..7] of Byte := [16#27, 16#07, 16#07, 16#03, 16#03, 16#03, 16#03, 16#03]; // 1 = NC contact
END_STRUCT;
BEGIN
END_DATA_BLOCK
Stage 4SCATTER ladder for every byte
One network for inputs and one for outputs. Each branch compares Card_No with a constant and, only on its own byte, runs SCATTER from the byte tag into the DB array. Only one branch is true at a time, so the array always holds the byte the operator picked.
false, none of the SCATTER boxes ever runs and the HMI status stays frozen. Delete that contact, or replace it with a real enable bit.Shorter alternative in SCL
The eight branches can be replaced by PEEK, which reads the input byte whose number is in Card_No. Use it when you are comfortable with indirect addressing; the ladder version is easier for maintenance staff to follow online.
// One-line alternative to the 8 branches of Network 1 (SCL network or FC)
// #b : Byte (Temp)
#b := PEEK(area := 16#81, // 16#81 = process image inputs
dbNumber := 0,
byteOffset := "HMI_Status".Card_No);
SCATTER(IN := #b, OUT => "HMI_Status".DI.Inp);
Stage 5Filter, NC fault and change logic
The HMI only shows bits; this FC decides which rows are visible, which NC contacts are open, and which bits changed since the byte was opened. Generate it from source like the DB and call it in OB1 directly after Networks 1 and 2.
| Filter_DI | Button | Row visible when |
|---|---|---|
| 0 | All | every row |
| 1 | ON only | DI.Inp[b] = 1 |
| 2 | OFF only | DI.Inp[b] = 0 |
| 3 | NC only | contact type NC |
| 4 | Faults | NC contact that reads 0 |
FUNCTION "FC_HMI_IO_Status" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_TEMP
i : Int;
card : Int;
on : Bool;
ncBits : Array[0..7] of Bool;
END_VAR
BEGIN
// Call in OB1 AFTER the two SCATTER networks.
// 1. Keep the HMI byte numbers inside the real hardware
IF "HMI_Status".Card_No > 7 THEN
"HMI_Status".Card_No := 7;
END_IF;
IF "HMI_Status".Card_No_DQ > 2 THEN
"HMI_Status".Card_No_DQ := 2;
END_IF;
#card := BYTE_TO_INT("HMI_Status".Card_No);
// 2. NO/NC pattern of the selected DI byte, one Bool per bit
SCATTER(IN := "HMI_Status".DI_NC_Mask[#card],
OUT => #ncBits);
// 3. New byte selected or Clear pressed: forget old changes
IF ("HMI_Status".Card_No <> "HMI_Status".Prev_Card) OR "HMI_Status".Clear_Changed THEN
FOR #i := 0 TO 7 DO
"HMI_Status".DI_Changed[#i] := FALSE;
"HMI_Status".DI_Prev[#i] := "HMI_Status".DI.Inp[#i];
END_FOR;
END_IF;
IF ("HMI_Status".Card_No_DQ <> "HMI_Status".Prev_Card_DQ) OR "HMI_Status".Clear_Changed THEN
FOR #i := 0 TO 7 DO
"HMI_Status".DQ_Changed[#i] := FALSE;
"HMI_Status".DQ_Prev[#i] := "HMI_Status".DQ.Out[#i];
END_FOR;
END_IF;
"HMI_Status".Prev_Card := "HMI_Status".Card_No;
"HMI_Status".Prev_Card_DQ := "HMI_Status".Card_No_DQ;
"HMI_Status".Clear_Changed := FALSE;
// 4. Digital inputs: fault, change, filter, counters
"HMI_Status".DI_On_Count := 0;
"HMI_Status".DI_Fault_Count := 0;
FOR #i := 0 TO 7 DO
#on := "HMI_Status".DI.Inp[#i];
"HMI_Status".DI_Fault[#i] := #ncBits[#i] AND NOT #on;
IF #on <> "HMI_Status".DI_Prev[#i] THEN
"HMI_Status".DI_Changed[#i] := TRUE;
END_IF;
"HMI_Status".DI_Prev[#i] := #on;
CASE BYTE_TO_INT("HMI_Status".Filter_DI) OF
1: "HMI_Status".Show_DI[#i] := #on;
2: "HMI_Status".Show_DI[#i] := NOT #on;
3: "HMI_Status".Show_DI[#i] := #ncBits[#i];
4: "HMI_Status".Show_DI[#i] := "HMI_Status".DI_Fault[#i];
ELSE "HMI_Status".Show_DI[#i] := TRUE;
END_CASE;
IF #on THEN
"HMI_Status".DI_On_Count := "HMI_Status".DI_On_Count + 1;
END_IF;
IF "HMI_Status".DI_Fault[#i] THEN
"HMI_Status".DI_Fault_Count := "HMI_Status".DI_Fault_Count + 1;
END_IF;
END_FOR;
// 5. Digital outputs: change, filter, counter
"HMI_Status".DQ_On_Count := 0;
FOR #i := 0 TO 7 DO
#on := "HMI_Status".DQ.Out[#i];
IF #on <> "HMI_Status".DQ_Prev[#i] THEN
"HMI_Status".DQ_Changed[#i] := TRUE;
END_IF;
"HMI_Status".DQ_Prev[#i] := #on;
CASE BYTE_TO_INT("HMI_Status".Filter_DQ) OF
1: "HMI_Status".Show_DQ[#i] := #on;
2: "HMI_Status".Show_DQ[#i] := NOT #on;
ELSE "HMI_Status".Show_DQ[#i] := TRUE;
END_CASE;
IF #on THEN
"HMI_Status".DQ_On_Count := "HMI_Status".DQ_On_Count + 1;
END_IF;
END_FOR;
END_FUNCTION
Stage 6Text and graphics lists (same format as g.xlsx)
The text lists follow the naming of the project export: Input Add b holds the description of bit b for every byte, Input Add C b holds NO or NC, and the value of each entry is the byte number. One new set, Input Address b, shows the address as text so column 1 is a single clean field.
| Text list | Indexed by | Example text | Used in |
|---|---|---|---|
| Input Address 0 … 7 | Card_No | %I3.5 | Column 1 |
| Input Add 0 … 7 | Card_No | FORK BASE UP | Column 2 |
| Input Add C 0 … 7 | Card_No | NO / NC | Column 3 |
| Input Status | DI.Inp[b] | Off / On | Column 4 |
| Output Address / Add / Add C 0 … 7 | Card_No_DQ | same for outputs | DQ screen |
| IO Filter | Filter_DI | All … Faults | Filter caption |
Copy both sheets, paste each into its own sheet of one Excel file with the names TextList and TextListEntry, save, then import in the Text and graphic lists editor of the HMI device.
Name ListRange Comment [en-US] Input Status Decimal <No value> Output Status Decimal <No value> IO Filter Decimal <No value> Input Address 0 Decimal <No value> Input Add 0 Decimal <No value> Input Add C 0 Decimal <No value> Input Address 1 Decimal <No value> … (51 text lists)
Name Parent DefaultEntry Value Text [en-US] FieldInfos Text_list_entry_1 Input Address 0 0 %I0.0 Text_list_entry_2 Input Address 0 1 %I1.0 Text_list_entry_3 Input Address 0 2 %I2.0 Text_list_entry_4 Input Address 0 3 %I3.0 Text_list_entry_1 Input Add 0 0 CHARGE FORK BACKWARD Text_list_entry_2 Input Add 0 1 DISCHARGE FORK BACKWARD Text_list_entry_3 Input Add 0 2 REAR DOOR OPEN LIMIT SWITCH Text_list_entry_4 Input Add 0 3 FRESH CHARGE ENTRY SAFE CP(1) Text_list_entry_1 Input Add C 0 0 NC Text_list_entry_2 Input Add C 0 1 NC Text_list_entry_3 Input Add C 0 2 NC Text_list_entry_4 Input Add C 0 3 NC …
Graphics lists
| Graphics list | Value | Graphic | Meaning |
|---|---|---|---|
| GL_Lamp | 0 | Lamp_Grey | Status column, off |
| GL_Lamp | 1 | Lamp_Green | Status column, on |
| GL_Fault | 0 | (none) | No fault |
| GL_Fault | 1 | Warning_Red | NC contact open |
Take a grey lamp, a green lamp and a red warning symbol from the WinCC graphics collection (or import your own PNGs) and use them in a Graphic I/O field, mode Output, next to the status text.
Problems found in the supplied text lists
These were corrected in the copy-paste data above. Fix them in the project as well so the export and the drawing agree.
| Address | Text in g.xlsx | What to fix |
|---|---|---|
%I0.0 | CHARGE FORK BACK WARD%I0.0 | spelling corrected → CHARGE FORK BACKWARD |
%I0.1 | DISCHARGE FORK BACK WARD%I0.1 | spelling corrected → DISCHARGE FORK BACKWARD |
%I0.5 | DICHARGE FORK FORWARD%I0.5 | spelling corrected → DISCHARGE FORK FORWARD |
%I0.6 | CHARGE FORK H .W BACK%I0.6 | spelling corrected → CHARGE FORK HALF WAY BACK |
%I1.0 | DISCHARGE FORK BACK WARD%I1.0 | spelling corrected → DISCHARGE FORK BACKWARD |
%I2.4 | EMERGENCY STOP FPR REAR PANEL%I2.4 | spelling corrected → EMERGENCY STOP FOR REAR PANEL |
%I3.1 | VESTIBULE OIL COOLING PUMPON(1)%I3.1 | spelling corrected → VESTIBULE OIL COOLING PUMP ON(1) |
%I3.3 | BELL ACCECPT%I3.3 | spelling corrected → BELL ACCEPT |
%I3.6 | HARENING SOAK IN PROGRESS%I3.6 | spelling corrected → HARDENING SOAK IN PROGRESS |
%I4.0 | CHARGE FORK FWD & DISCARGE FORK RVS%I4.0 | spelling corrected → CHARGE FORK FWD & DISCHARGE FORK RVS |
%I4.1 | DISCHARGE FORK FWD & CARGE FORK RVS%I4.1 | spelling corrected → DISCHARGE FORK FWD & CHARGE FORK RVS |
%I5.0 | AUTO OPEN SELECTION IN REAR OPEN PANEL%I5.0 | spelling corrected → AUTO OPER SELECTION IN REAR OPER PANEL |
%I5.1 | MANUAL OPEN SELECTION IN REAR OPEN PANEL%I5.1 | spelling corrected → MANUAL OPER SELECTION IN REAR OPER PANEL |
%I5.2 | REAL DOOR OPEN%I5.2 | spelling corrected → REAR DOOR OPEN |
%I5.3 | ELEVATOR CHAIR DRIVE ON%I5.3 | spelling corrected → ELEVATOR CHAIN DRIVE ON |
%I6.7 | INTERMDIATE DOOR OPEN PUSH BUTTON%I6.7 | spelling corrected → INTERMEDIATE DOOR OPEN PUSH BUTTON |
%Q0.1 | DICHARGE FORK FORWARD CHRGE FORK BACKWARD%Q0.1 | spelling corrected → DISCHARGE FORK FORWARD CHARGE FORK BACKWARD |
%Q1.7 | TRAY IN POSITION ????%Q1.7 | placeholder ??? – confirm signal name |
%I0.1 | DISCHARGE FORK BACKWARD | same description used on another address – check drawing |
%I0.5 | DISCHARGE FORK FORWARD | same description used on another address – check drawing |
%I1.0 | DISCHARGE FORK BACKWARD | same description used on another address – check drawing |
%I6.3 | DISCHARGE FORK FORWARD | same description used on another address – check drawing |
Stage 7HMI screen and animations
Build one row, test it, then copy it seven times and change only the row number b in the text list names and tag indexes. The table lists every object of row b.
| Object | Type and mode | Process tag | Text list / animation |
|---|---|---|---|
| Byte selector | I/O field, mode Input/output, format 9 | "HMI_Status".Card_No | Tag limits 0 … 7; buttons ◄ ► call DecreaseTag / IncreaseTag |
| Column 1 – Address | Symbolic I/O field, mode Output | "HMI_Status".Card_No | Text list Input Address b (b = row 0…7) → shows %I3.5 |
| Column 2 – Description | Symbolic I/O field, mode Output, width 420 px | "HMI_Status".Card_No | Text list Input Add b |
| Column 3 – NO / NC | Symbolic I/O field, mode Output | "HMI_Status".Card_No | Text list Input Add C b; Appearance: text colour red when value shows NC |
| Column 4 – Live status | Symbolic I/O field + Graphic I/O field | "HMI_Status".DI.Inp[b] | Text list Input Status (Off/On); graphics list GL_Lamp; Appearance 0 = grey, 1 = green |
| Row background | Rectangle behind the row | "HMI_Status".DI_Fault[b] | Appearance 1 = light red; second animation on DI_Changed[b] = yellow, Flashing = Yes |
| Row visibility (filter) | Group the 5 objects of the row | "HMI_Status".Show_DI[b] | Visibility animation: visible when 1 |
| Filter buttons | Buttons All / ON / OFF / NC / Faults | "HMI_Status".Filter_DI | Press → SetTag value 0 … 4; Appearance on Filter_DI shows the active button |
| Counters | I/O fields, mode Output | DI_On_Count, DI_Fault_Count | Fault count red when > 0 |
| Clear changes | Button | "HMI_Status".Clear_Changed | Press → SetBit; the PLC resets it |
For outputs, copy the screen and swap Card_No → Card_No_DQ, DI.Inp → DQ.Out and Input → Output in the text list names. Drop the NC filter and the fault animation. Layout rules for fonts and colours are in HMI screen design best practices, and I/O field details in HMI I/O fields and setpoint entry.
Stage 8Live simulator – perform and test
This works like the finished panel. Change the byte, click a status lamp to simulate the field, try every filter, and type an address such as I2.3 to jump straight to it. The dark line under the table shows what the PLC is doing at that moment.
| Address | Description | NO / NC | Live status |
|---|
Test checklist
- Card_No 0 … 7 changes all eight descriptions and addresses together.
- Forcing or bridging an input turns its lamp green and the row flashes yellow until Clear.
- Opening an NC contact turns the row red and raises the fault counter.
- Typing 9 in the byte field is refused by the tag limits; the FC also clamps it to 7.
- Each filter shows only matching rows; All brings every row back.
More animations worth adding
- Analog status page. Same byte idea for channels: Card_No picks an AI card, rows show tag, scaled value, a bar graph and the raw value. Raw 32767 on a 4–20 mA channel means wire break, so colour that row red. Scaling is covered in PLC analog input scaling.
- Byte overview strip. Eight small boxes, one per byte, each showing its ON count and turning red when DI_Fault_Count for that byte is above zero. Touching a box sets Card_No.
- Last change time. Store
RD_SYS_Tin an array when a bit changes and show it in a fifth column; it helps prove intermittent limit switches. - Force indication. Show a yellow banner when the CPU has forced I/O, read from the diagnostic buffer, so nobody leaves forces behind after testing.
- Access level. Let operators view only; give the Clear button and forcing tools to the maintenance user group as in HMI user administration.
Practice notes
I/O status screen – my practice steps
- → no red rows? then go on
- ! no FALSE contact at start of rung
- change b in list name AND tag index!
- done = show trainer ✍
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Status never changes | Rung disabled (FALSE contact) or FC not called | Remove the contact; call the FC after the networks |
| Description shows ### | Text list has no entry for that Card_No | Add the missing value 0 … 7 to the list |
| All rows show the same text | Every row uses Input Add 0 | Change the list to Input Add b for row b |
| NC rows red although wired | DI_NC_Mask does not match field wiring | Correct the mask and the Input Add C list together |
| Wrong bits after download | DB is optimized, absolute DBX2.0 no longer valid | Untick Optimized block access, compile, download |
| Filter leaves gaps | Hidden objects keep their place | Expected in Comfort; use an index list for a compact view |
For hardware faults behind a bad signal, see Siemens PLC diagnostics and troubleshooting.
Frequently asked questions
What does the SCATTER instruction do in TIA Portal?
SCATTER splits a Byte, Word or DWord into individual Bools and writes them to an Array of Bool or a Struct. Here it turns the selected input byte, for example %IB3, into "HMI_Status".DI.Inp[0..7] so the HMI reads only eight bits.
Why use one byte selector instead of 60 rows on the HMI?
One screen with eight rows, a byte number and text lists replaces eight screens. The panel reads about twenty tags instead of more than eighty, which keeps the screen fast and saves tags on Runtime Advanced licences.
How do I show NO and NC contacts correctly?
Keep the contact type in a text list for the NO/NC column and in DI_NC_Mask in the PLC. An NC input that reads Off means the contact is open, so the PLC raises DI_Fault and the HMI shows that row in red.
Which PLCs support SCATTER?
All S7-1500 CPUs and S7-1200 CPUs with firmware 4.2 or newer. On older S7-1200 firmware, move the byte into a Byte tag and read the bits with slice access such as #b.%X0.
Can I import the text lists instead of typing them?
Yes. Paste the two copied sheets into an Excel file with sheet names TextList and TextListEntry, the same layout as an export from the Text and graphic lists editor, then import it into the HMI device.
Does the filter remove rows or only hide them?
In WinCC Comfort and Advanced a hidden object keeps its position, so the row leaves a gap. If you need a compact list, let the PLC build an index of matching rows and show the descriptions through that index.