Send every HMI command into an interface data block, never to an output. Use SetBit for commands the PLC clears after one evaluation, SetBitWhileKeyPressed for hold-to-run, SetValue for mode requests. Keep the active mode in the PLC and drive lamps from a status word built from feedback, never from the command bit.
- Commands go from the panel into an interface DB; the PLC decides what to do with them.
- A lamp that follows the command bit lies to the operator; drive it from feedback.
- Mode is a machine state: requested by the HMI, decided and echoed back by the PLC.
The HMI to PLC Command Interface
A panel should never write directly to a physical output. If a button writes to %Q2.0, the machine loses every interlock in the PLC program, and a communication fault can leave the output in an unknown state. Instead, each device gets an interface data block built from one UDT: a Cmd part written by the HMI and a Sts part written by the PLC.
| System function | Behaviour | Use for |
|---|---|---|
SetBit | Sets the bit; the PLC clears it after evaluating | Start, Stop, Reset |
SetBitWhileKeyPressed | Bit true only while the button is held | Jog, inch, hold-to-run |
ResetBit | Sets the bit to false | Clearing a latched request |
InvertBit | Toggles the bit each press | Lamp test, screen options – never machine start |
SetValue | Writes a fixed number | Mode request, speed preset |
Lab Flow: From Field Selector to a Tested Faceplate
Stage 1Field Wiring and PLC Tag Table
| PLC tag | Address | Type | Device |
|---|---|---|---|
S50_Remote | %I5.0 | Bool | Local/remote selector, 1 = REMOTE (HMI control) |
P1_Running | %I5.1 | Bool | Contactor K20 auxiliary, 1 = pulled in |
LSL_Low | %I5.2 | Bool | Low level switch, 1 = level below |
LSH_High | %I5.3 | Bool | High level switch, 1 = level reached |
P1_Overload_OK | %I5.4 | Bool | MPCB auxiliary, NC, 1 = healthy |
K20_P1 | %Q2.0 | Bool | Pump contactor coil |
Stage 2Input Mapping into DB_IO
// FC_InputMapping – pump P1 "DB_IO".S50_Remote := "S50_Remote"; "DB_IO".P1_Running := "P1_Running"; "DB_IO".LSL_Low := "LSL_Low"; "DB_IO".LSH_High := "LSH_High"; "DB_IO".P1_Overload_OK := "P1_Overload_OK";
Stage 3Logic: Interface UDT, Mode and Status Word
// UDT_MotorHMI – one interface per device, reused for every motor
Cmd : Struct // written by the HMI, cleared by the PLC after evaluation
Start, Stop, Reset : Bool;
ModeReq : Int; // 1 = AUTO, 2 = MANUAL, 0 = no request
END_STRUCT;
Sts : Struct // written by the PLC, read by the HMI
ModeActive : Int; // 1 = AUTO, 2 = MANUAL
RunCmd, Running, Faulted, Ready : Bool;
StatusWord : Int; // 0 stopped, 1 running, 2 fault, 3 local, 4 starting
END_STRUCT;
// DB_P1 (DB70) : UDT_MotorHMI
// FB_Pump – instance "IDB_P1"; STAT: tFb : TON_TIME; FaultCode : Int;
IF "DB_IO".S50_Remote THEN // HMI commands only in REMOTE
IF "DB_P1".Cmd.ModeReq <> 0 AND NOT "DB_P1".Sts.RunCmd THEN
"DB_P1".Sts.ModeActive := "DB_P1".Cmd.ModeReq; // mode change only when stopped
END_IF;
IF "DB_P1".Cmd.Reset AND "DB_IO".P1_Overload_OK THEN #FaultCode := 0; END_IF;
IF "DB_P1".Sts.ModeActive = 2 THEN // MANUAL
IF "DB_P1".Cmd.Start AND #FaultCode = 0 THEN "DB_P1".Sts.RunCmd := TRUE; END_IF;
IF "DB_P1".Cmd.Stop THEN "DB_P1".Sts.RunCmd := FALSE; END_IF;
END_IF;
END_IF;
"DB_P1".Cmd.Start := FALSE; "DB_P1".Cmd.Stop := FALSE; // one-shot: PLC clears the commands
"DB_P1".Cmd.Reset := FALSE; "DB_P1".Cmd.ModeReq := 0;
IF "DB_P1".Sts.ModeActive = 1 AND "DB_IO".S50_Remote THEN // AUTO: fill between LSL and LSH
IF "DB_IO".LSL_Low AND #FaultCode = 0 THEN "DB_P1".Sts.RunCmd := TRUE; END_IF;
IF "DB_IO".LSH_High THEN "DB_P1".Sts.RunCmd := FALSE; END_IF;
END_IF;
IF NOT "DB_IO".P1_Overload_OK THEN #FaultCode := 1; END_IF;
#tFb(IN := "DB_P1".Sts.RunCmd AND NOT "DB_IO".P1_Running, PT := T#2S);
IF #tFb.Q THEN #FaultCode := 2; END_IF;
IF #FaultCode <> 0 THEN "DB_P1".Sts.RunCmd := FALSE; END_IF;
// Status for lamps – from FEEDBACK, never from the command
"DB_P1".Sts.Running := "DB_IO".P1_Running;
"DB_P1".Sts.Faulted := #FaultCode <> 0;
"DB_P1".Sts.Ready := NOT "DB_P1".Sts.Faulted AND "DB_IO".S50_Remote;
IF "DB_P1".Sts.Faulted THEN "DB_P1".Sts.StatusWord := 2;
ELSIF "DB_P1".Sts.Running THEN "DB_P1".Sts.StatusWord := 1;
ELSIF "DB_P1".Sts.RunCmd THEN "DB_P1".Sts.StatusWord := 4;
ELSIF NOT "DB_IO".S50_Remote THEN "DB_P1".Sts.StatusWord := 3;
ELSE "DB_P1".Sts.StatusWord := 0;
END_IF;
// FC_OutputMapping
"K20_P1" := "DB_P1".Sts.RunCmd;
The overload fault could also be one bit of the alarm word from HMI alarm configuration, and the start condition can include the permissives from PLC interlocks and permissives.
Stage 4Link DB_P1 to HMI Tags
| HMI tag | PLC member | Used by |
|---|---|---|
DB_P1_Cmd_Start, _Stop, _Reset | "DB_P1".Cmd.* | Buttons ⑤ ⑥ |
DB_P1_Cmd_ModeReq | "DB_P1".Cmd.ModeReq | AUTO / MANUAL buttons ④ |
DB_P1_Sts_StatusWord | "DB_P1".Sts.StatusWord | Lamp ①, status text ② (text list TL_Status) |
DB_P1_Sts_ModeActive | "DB_P1".Sts.ModeActive | Mode field ③, button highlight |
DB_P1_Sts_Ready | "DB_P1".Sts.Ready | Control enable animations |
Stage 5Buttons, Lamps and Animations
| # | Object | Animation / properties | Tag / event |
|---|---|---|---|
| ① | Circle + text field lamp | Appearance, multiple ranges on StatusWord: 0 white STOP, 1 dark RUN, 2 red outline TRIP (flashing), 3 grey LOCAL, 4 white START | DB_P1_Sts_StatusWord |
| ② | Symbolic output field | Text list TL_Status with the five states | DB_P1_Sts_StatusWord |
| ③ | Symbolic output field | Text list AUTO / MANUAL | DB_P1_Sts_ModeActive |
| ④ | Buttons AUTO / MANUAL | Appearance: highlighted when active; Control enable when REMOTE | Click: SetValue ModeReq = 1 / 2 |
| ⑤ | Buttons START / STOP | START enabled only in MANUAL and Ready | Click: SetBit Cmd_Start / Cmd_Stop |
| ⑥ | Button RESET | Authorisation Operator | Click: SetBit Cmd_Reset |
Colour rules for running, stopped and fault states follow HMI screen design best practices: red stays reserved for the fault, running is shown by fill and text.
Stage 6Perform and Test: Animated Pump Faceplate
Pump P1 fills a tank. In AUTO the PLC runs it between the low and high level switches; in MANUAL the operator uses START and STOP. Switch the field selector to LOCAL and the HMI commands are ignored. Trip the overload or make the contactor fail, then compare a lamp driven by the command with a lamp driven by feedback.
Troubleshooting Buttons and Lamps
| Symptom | Likely cause | First check |
|---|---|---|
| Start works once, then never again | PLC does not clear Cmd.Start, or HMI uses InvertBit | One-shot clearing in FB_Pump |
| Lamp shows RUN but pump stands | Lamp linked to the command | Link to StatusWord / feedback |
| Mode jumps back after panel restart | Mode stored on the HMI | ModeActive must live in the PLC |
| Buttons do nothing in the field | Selector in LOCAL | DB_IO.S50_Remote |
| Lamp blank in one state | A range missing in the appearance animation | One range per StatusWord value |
Hands-On Lab: Pump Faceplate with Auto/Manual Mode
Hands-on- TIA Portal with WinCC Comfort and a panel or PLCSIM + HMI simulation
- Selector switch and push buttons on the trainer kit, or simulated inputs
- Estimated time: 75 minutes
Wire the pump signals and map PLC tags
Declare S50_Remote, P1_Running, P1_Overload_OK, LSL_Low and LSH_High as inputs and K20_P1 as output in the PLC tag table.
Map inputs into DB_IO
Copy the five inputs into DB_IO in FC_InputMapping.
Create UDT_MotorHMI, DB_P1 and FB_Pump
Define the command and status structure, then write mode handling, one-shot command evaluation, auto level control, fault latching and the status word.
Link DB_P1 to HMI tags
Drag DB_P1 into the HMI tag table and create the text list for the status word.
Build the faceplate graphics
Add AUTO, MANUAL, START, STOP and RESET buttons with SetValue and SetBit events, a lamp with a multi-range appearance animation on the status word, and Control enable animations.
Perform and test
Run AUTO and MANUAL, switch LOCAL, trip the overload and fail the contactor; confirm the lamp always shows what the pump really does.
Commands only reach the pump through the PLC, mode is decided in the PLC, the lamp always shows what the pump is really doing, and LOCAL disables every HMI command.
Frequently asked questions
Should an HMI button write directly to a PLC output?
No. Write to a command bit in an interface data block and let the PLC program apply interlocks and mode conditions before it drives any output.
What is the difference between SetBit and SetBitWhileKeyPressed?
SetBit sets the bit and leaves it set until something resets it. SetBitWhileKeyPressed holds the bit true only while the operator keeps the button pressed, which suits jog and hold-to-run functions.
Why does my lamp turn on even though the motor did not start?
The animation is almost certainly linked to the command bit. Link it to the running feedback or to a status word the PLC sets after confirming the contactor auxiliary contact.
Where should the auto and manual mode be stored?
In the PLC. The panel sends a request and displays the active mode returned by the controller, so a communication loss or a panel restart cannot leave the machine in an unclear state.
Who clears an HMI command bit?
The PLC, in the same scan in which it evaluates the command. The panel uses SetBit, the PLC acts once and resets the bit, so a command can never stick on after a communication drop.
What does a local/remote selector do for HMI control?
It is a field switch that decides who may command the device. In LOCAL the PLC ignores all HMI commands and the panel disables the buttons; in REMOTE the HMI commands are evaluated.