Overview
The "press-and-hold increment/decrement" pattern is a routine requirement on Siemens HMI panels: an operator holds a button and the value of a setpoint, counter, recipe index, or tag ramps upward or downward at a controlled rate until the button is released. On Siemens platforms (S7-1200/S7-1500 with TIA Portal, or legacy S7-300/S7-400 with STEP 7 + WinCC flexible) the function is not a single built-in tag property - it is a combination of:
- An HMI button configured to set a bit while pressed and reset it on release.
- A PLC program block that ANDs the press-bit with a periodic clock bit (CPU clock memory or a user-generated flasher) and adds or subtracts 1 from a tag on each rising edge of the resulting pulse.
- Tag scaling (limits, wrap, saturation) to prevent the value from drifting outside its valid range.
This article documents three field-proven implementations - the clock-bit ramp, the IEC timer + counter ramp, and the edge-tracked accumulator - with full TIA Portal SCL/ST code, WinCC button wiring, parameter tables, and a verification checklist.
Prerequisites
- Controller: SIMATIC S7-1200 (firmware V4.2 or later) or S7-1500 (firmware V2.0 or later). Logic also runs on S7-300/400 with minor adaptation.
- Engineering tool: TIA Portal V16, V17, or V18 with installed HSP for the CPU and HMI. Legacy users can use STEP 7 V5.5 + WinCC flexible 2008 SP5.
- HMI: Comfort Panel (TP/MTP/KTP), or WinCC Runtime Advanced/Professional on a PC. Pattern is identical for Basic panels using the "Set value while button pressed" event.
- PLC tag type: INT (range -32768 to +32767) or DINT (-2147483648 to +2147483647). Real (floating point) requires integer scaling.
- CPU clock memory byte: Must be enabled in the CPU device properties under Properties > System and clock memory. The default bit assignments in TIA Portal are shown in the table below.
Architecture and Signal Flow
The signal flow has three segments: the HMI input, the PLC logic core, and the tag output that the HMI displays back. The PLC is the only "smart" element - the HMI merely sets/clears two boolean bits.
State machine summary:
- Idle: Both press bits are FALSE. No pulse generated. Tag holds its value.
-
Pressed-INC: HMI sets
bIncPressTRUE. The AND ofbIncPressand the clock bit produces a 0.5 s (or 1.0 s, depending on selection) periodic TRUE pulse. Each rising edge adds +1 (or +N) to the tag. -
Pressed-DEC: HMI sets
bDecPressTRUE. Periodic pulse subtracts -1 (or -N). - Released: Press bit clears. No further pulses. Tag is latched in the last-written value.
Step 1 - Enable CPU Clock Memory Byte
Open the PLC device in TIA Portal. Navigate to Properties > System and clock memory. Tick Enable the use of clock memory byte and assign an unused input byte, for example MB100. The bit assignments are fixed:
| Bit | Period (s) | Frequency (Hz) | Typical Use |
|---|---|---|---|
| MB100.0 | 10.0 | 0.1 | Slow integrator, watchdog |
| MB100.1 | 5.0 | 0.2 | Slow blink |
| MB100.2 | 2.0 | 0.5 | Heartbeat |
| MB100.3 | 1.0 | 1.0 | 1 Hz ramp (1 step/s) |
| MB100.4 | 0.5 | 2.0 | 2 Hz ramp (2 step/s) |
| MB100.5 | 0.2 | 5.0 | Fast ramp (5 step/s) |
| MB100.6 | 0.1 | 10.0 | High-speed ramp |
| MB100.7 | 0.05 | 20.0 | Very fast - rarely used for operator setpoints |
For most operator setpoint ramps, MB100.5 (0.2 s) or MB100.4 (0.5 s) gives the best feel. MB100.3 (1 s) feels coarse; MB100.6 and faster feel jittery on a touchscreen.
Step 2 - Declare the PLC Tags
Create the following tags in the default tag table or in a dedicated UDT_RampCtrl user data type for reuse across multiple setpoints:
| Tag | Data Type | Initial Value | Description |
|---|---|---|---|
| bIncPress | Bool | FALSE | TRUE while HMI "+" button is held |
| bDecPress | Bool | FALSE | TRUE while HMI "-" button is held |
| iSetpoint | INT | 0 | The operator-ramped value (HMI-visible) |
| iSetpointHi | INT | 100 | Upper saturation limit |
| iSetpointLo | INT | 0 | Lower saturation limit |
| iStepInc | INT | 1 | Step size when ramping up (can be 5, 10, etc.) |
| iStepDec | INT | 1 | Step size when ramping down |
| clk02s | Bool | FALSE | = %MB100.5 (clock memory, 0.2 s) |
| clkEdgeOld | Bool | FALSE | Edge-memory bit for rising-edge detection |
| bAccelActive | Bool | FALSE | TRUE if button held > 2 s - enables fast ramp |
| tAccel | TON_TIME | - | Acceleration timer, PT = T#2S |
Step 3 - PLC Logic Block (SCL Implementation)
Create an FB or FC named FB_RampSetpoint. The example below is written in SCL and is valid for S7-1200/S7-1500. The same logic translates to LAD with an --(P)-- edge detector and an ADD/SUB block.
Block interface (IN/OUT/STAT/TEMP)
FUNCTION_BLOCK "FB_RampSetpoint"
VERSION : 0.1
VAR_INPUT
iIncPress : Bool; // HMI press bit, +
iDecPress : Bool; // HMI press bit, -
iHiLim : Int; // Upper limit
iLoLim : Int; // Lower limit
iStepInc : Int; // Step size up
iStepDec : Int; // Step size down
iFastFactor : Int := 5; // Acceleration multiplier after 2 s hold
iClkBit : Bool; // Clock memory bit (e.g. %MB100.5)
END_VAR
VAR_OUTPUT
qValue : Int; // Ramped setpoint
qAtHiLim : Bool; // TRUE when value has reached upper limit
qAtLoLim : Bool; // TRUE when value has reached lower limit
END_VAR
VAR
sClkOld : Bool;
sAccelTmr : TON_TIME;
sAccelActive: Bool;
sIncPulse : Bool;
sDecPulse : Bool;
END_VAR
Code body
BEGIN
// 1. Generate one-shot pulse on rising edge of clock bit
sIncPulse := iClkBit AND NOT sClkOld;
sClkOld := iClkBit;
// 2. Acceleration: after 2 s of continuous press, multiply step
sAccelTmr(IN := (iIncPress OR iDecPress), PT := T#2S);
sAccelActive := sAccelTmr.Q;
IF sAccelActive THEN
iStepInc := iStepInc * iFastFactor; // local copy used below
iStepDec := iStepDec * iFastFactor;
END_IF;
// 3. Increment path (only if not at high limit)
IF (iIncPress AND sIncPulse) AND (qValue < iHiLim) THEN
qValue := qValue + iStepInc;
IF qValue > iHiLim THEN qValue := iHiLim; END_IF;
END_IF;
// 4. Decrement path (only if not at low limit)
IF (iDecPress AND sIncPulse) AND (qValue > iLoLim) THEN
qValue := qValue - iStepDec;
IF qValue < iLoLim THEN qValue := iLoLim; END_IF;
END_IF;
// 5. Mutual exclusion - both buttons pressed = no change
// (Already handled because INC and DEC are independent branches)
// 6. Limit status flags
qAtHiLim := (qValue >= iHiLim);
qAtLoLim := (qValue <= iLoLim);
END_FUNCTION_BLOCK
Ladder equivalent (drop-in for STEP 7 V5.x or S7-300)
For S7-300 with STEP 7 V5.5 and WinCC flexible, the same logic is built from the following network chain in OB1 or a dedicated FC:
-
Network 1:
--[ MB100.5 ]--[P]--(positive edge detector) -> coilM_ClockPulse. -
Network 2:
--[ HMI_IncBit ]--[ M_ClockPulse ]--[AW< iHiLim ]---> ADDDB_Setpoint + 1-> store inDB_Setpoint. -
Network 3: Same as Network 2 but with
HMI_DecBit,SUB 1, andAW> iLoLim. -
Network 4: Limit-clamp with
--[ >= iHiLim ]--resettingDB_SetpointtoiHiLim. - Network 5: Lower clamp.
Step 4 - Alternative: Counter-Based Ramp
The legacy technique quoted in the source thread - "on/off timer feeding an up/down counter" - is still useful on older firmware that lacks comfortable edge detection, or on controllers that do not have the clock memory byte enabled. The pattern is:
- Start a 0.2 s on/off timer (blinker) when the press bit is set.
- Feed the timer's "1" output into a CTU counter (count-up) or CTD counter (count-down).
- Move the counter's CV to the setpoint tag.
- Reset the counter on release.
The drawback is the additional scan-cycle latency: the timer's output is updated in OB1 and the counter increments only when the timer's output transitions FALSE -> TRUE. With the S7 default OB1 scan of 5-10 ms, the perceived ramp is still very close to the clock-bit method. Use the counter method when you need an explicit "number of pulses" count for audit or recipe logging.
Step 5 - Configure the HMI Buttons (TIA Portal / WinCC)
On the Comfort Panel screen, drop two buttons ("+" and "-") and configure the events exactly as listed. The tag HMI_IncBit and HMI_DecBit are the same tags as the PLC's bIncPress and bDecPress - they are the HMI-side names of the same HMI tag in the connection.
"+" button (Button_1)
| Event | Action | Tag | Value |
|---|---|---|---|
| Press | Set bit | HMI_IncBit | 1 |
| Release | Reset bit | HMI_IncBit | 0 |
"-" button (Button_2)
| Event | Action | Tag | Value |
|---|---|---|---|
| Press | Set bit | HMI_DecBit | 1 |
| Release | Reset bit | HMI_DecBit | 0 |
Output field
Place an I/O field bound to qValue (or to the shared HMI tag pointing at iSetpoint in the DB) with display format DEC +/- and a length of 5-6 characters. Set the field to output mode if the operator cannot type a value, or to input/output mode if they can also key in a value directly.
Step 6 - Edge Cases and Field-Proven Caveats
-
Wrap-around: If you allow the setpoint to increment past INT_MAX (32767) on an S7-1200 with default INT arithmetic, the value wraps to -32768. Always include the saturation
IF qValue > iHiLim THEN qValue := iHiLim;clause shown above. - Both buttons pressed: A user can hold both buttons simultaneously. The mutually exclusive branches above net to zero net change, which is the correct behaviour. If you want the most-recent-pressed to win, add a priority resolver.
- Network jitter: On a 100 ms PROFINET update, the press bit can bounce 1-2 cycles. The 0.2 s clock period masks this completely. If you switch to MB100.6 (0.1 s), bouncing can skip pulses - increase the integrator debounce or use the 0.2 s bit.
-
Power cycle: On S7-1200, retainable tags (set with the "Retain" attribute) preserve
iSetpointacross power-off. Mark the DB or the tag as retainable if the operator expects the value to persist. - HMI tag area conflict: On legacy WinCC flexible, the HMI tag for the press bit must be in a region the HMI can write to (default: DB or M area). It cannot be the same tag as the output if you are using point-to-point without a PC station.
Step 7 - Verification
- Go online with the PLC. Add
iSetpoint,bIncPress,bDecPress, andclk02sto a watch table. SetiSetpointto 50 andiSetpointHi/iSetpointLoto 100/0. - Force
bIncPress := TRUEfrom the watch table (simulates the HMI button). Confirm thatiSetpointincreases by 1 every 0.2 s. At 0.2 s/bit, the value should reach 100 in (100-50) * 0.2 = 10 s. - Release (
bIncPress := FALSE). The value should stop incrementing immediately on the next clock edge. - Force
bDecPress := TRUEand verify decrement. Verify that atiSetpoint := 0the value clamps and does not go negative. - Force both bits TRUE simultaneously and confirm the value does not change.
- Hold the button for >2 s. Verify the acceleration multiplier kicks in: step size jumps from 1 to 5 (default
iFastFactor). - On the HMI, simulate the same scenario with a finger press on a TP700 Comfort. Confirm tactile response matches the 0.2 s cadence.
Troubleshooting Matrix
| Symptom | Likely Cause | Fix |
|---|---|---|
| Button does nothing when pressed | Event "Press" not configured as SetBit, or HMI tag is read-only | Re-check button event in WinCC; confirm HMI tag has write access from HMI |
| Value jumps by large numbers (e.g. 5, 10) per click | Acceleration timer active because CPU clock period is 1 s, not 0.2 s | Verify MB100.5 is selected; check the assignment in CPU properties |
| Value changes only while button is held but never reaches the limit | Saturation block missing or wrong comparison direction | Insert IF qValue > iHiLim THEN qValue := iHiLim; |
| Value goes negative or wraps around | Subtracting without lower-bound check on INT/DINT | Add IF qValue < iLoLim THEN qValue := iLoLim; |
| Value changes on press but does not stop on release | Release event not configured as ResetBit, or wrong tag wired to release | Re-add the Release event with ResetBit on the same tag |
| Value does not persist after power cycle | Setpoint tag is not marked as retainable | In the DB or tag properties, tick "Retain" for the setpoint tag |
| Value increments twice per clock pulse | OB1 calls FB twice (e.g. cyclic interrupt + main), or edge detector placed in both networks | Place FB in a single call point; use a single edge bit per clock |
| Clock memory bit always FALSE | Clock memory byte not enabled in CPU properties | Open CPU properties > System and clock memory > enable |
Performance and Scan-Time Notes
The added scan-time cost on an S7-1511 is approximately 0.005-0.010 ms per FB instance. A typical machine HMI has 5-15 setpoint ramp blocks; the aggregate cost is below 0.2 ms and is irrelevant on a 1 ms OB1. On S7-1200 with firmware V4.4 and one FB instance, the cost is approximately 0.04 ms. Reference the S7-1500 System Manual, section "Program execution", for cycle-time accounting.
The clock memory byte is updated by the priority class "cyclic interrupt" OB30-OB38 if configured, but on most projects the default background update is sufficient. The default S7-1500 OB1 priority is 1; clock memory is generated at priority 1 and is therefore phase-locked with OB1.
Quick-Reference Parameter Table
| Parameter | Default | Recommended | Effect |
|---|---|---|---|
| Clock period | 1.0 s (MB100.3) | 0.2 s (MB100.5) | Smaller = faster ramp, more network traffic |
| Step size (slow) | 1 | 1 (INT setpoint 0-100) | 100 distinct steps for full range |
| Step size (fast) | n/a | 5 or 10 | Skips for fast traverse over wide range |
| Acceleration delay | n/a | 2 s | Time to engage fast mode |
| Acceleration factor | 5 | 5-10 | Multiplier on step size |
| Upper limit | 100 | Application-specific | Saturation clamp |
| Lower limit | 0 | Application-specific | Saturation clamp |
Field Commissioning Checklist
- CPU clock memory byte enabled, address recorded in the project documentation.
- Press bits configured on HMI as SetBit (Press) and ResetBit (Release) - not as "Set value while pressed".
- Edge detector single instance per clock bit; no duplicates in other networks.
- Setpoint tag type matches the HMI I/O field format.
- Upper and lower limits set to valid engineering range.
- Setpoint tag marked Retain if the process requires persistence.
- Acceleration timer
PTparameter set and tested with a 5-second hold. - Final ramp rate tested on the actual HMI panel, not the simulator.
Why does my WinCC flexible button increment a tag directly without PLC logic, and why is that not recommended?
WinCC flexible and TIA Portal WinCC have a "Set value while pressed" event that increments a tag on the HMI side, but it bypasses the PLC's clock memory and runs on the HMI panel's task cycle (typically 100-500 ms). This can drift, double-increment, or fail to stop exactly on release. Always run the ramp logic in the PLC and let the HMI only set/reset a single boolean for "inc press" and "dec press".
Which clock memory bit should I use for the ramp rate?
For operator setpoints use MB100.5 (0.2 s, 5 Hz) by default. It gives a balance between tactile responsiveness and avoidance of network-induced jitter. Use MB100.4 (0.5 s) for very large values (e.g. recipe index 0-1000) where you do not want to traverse the whole range too fast, and MB100.6 (0.1 s) only for short ranges (0-20) on a fast PROFINET network.
How do I prevent the setpoint from going negative on a signed INT?
Add a saturation block in the decrement branch: IF qValue > iLoLim THEN qValue := qValue - iStepDec; END_IF; followed by IF qValue < iLoLim THEN qValue := iLoLim; END_IF;. Without this, subtraction at the lower limit will wrap an INT from 0 to -1, then to -32768, which can corrupt any downstream calculation that expects non-negative input.
Can the operator hold both the + and - buttons at the same time?
Yes, the implementation above treats INC and DEC as independent branches and the value will not change while both are pressed (the branches cancel). If your application requires "most-recent-pressed wins", add a small arbitration block that detects which bit was set first and ignores the other until release.
Do I need to enable clock memory in the CPU properties?
Yes - clock memory is opt-in on every S7-1200/S7-1500 CPU. Open the PLC device in TIA Portal, go to Properties > System and clock memory, tick Enable the use of clock memory byte, and assign an unused input byte (commonly MB100). Without this step, all eight bits remain FALSE and the ramp will not advance.