S7-1200 Analog Output Rate Limiter Using TIA Portal V13 Cyclic OB
Field-tested procedure for ramping a SIMATIC S7-1200 analog output toward a commanded setpoint at a fixed rate (200 raw units per second), with working SCL and LAD code in TIA Portal V13 SP1 / STEP 7 Basic V13 SP1. The pattern is generic and applies to any CPU 1211C/1212C/1214C/1215C/1217C.
1. Problem Statement and Requirements
An operator enters a percentage between 0 and 100 on an HMI tag. The PLC must convert that percentage to a raw analog value in the Siemens integer range 0–27648 (the canonical range for 0–10 V or 0/4–20 mA on the onboard analog outputs of the CPU 1214C and on SM analog output modules).
If the operator jumps from 0 % to 100 % in a single step, the raw integer is not allowed to step directly to 27648. The process variable must rise in increments of 200 units per second. Likewise, on a decreasing command it must fall by 200 units per second until it reaches the commanded value. The conversion can be summarized as:
| Symbol | Meaning | Type | Range |
|---|---|---|---|
| Sp_Pct | Operator setpoint | INT (HMI) | 0 – 100 |
| Sp_Raw | Scaled command | INT | 0 – 27648 |
| Out_Raw | Ramped output value | INT | 0 – 27648 |
| StepRate | Allowed change per cycle | INT | 200 (units/s) |
| CycleTime | OB30 phase | TIME | 1000 ms |
| AQ | Analog output word | INT | 0 – 27648 |
The scaling from percentage to raw value uses the standard Siemens linear conversion:
Sp_Raw = (Sp_Pct * 27648) / 100
For a CPU 1214C DC/DC/DC (6ES7214-1AG40-0XB0) the two onboard analog outputs are addressed as %AQ0 and %AQ2 (the two-word alignment is fixed by the analog output channel granularity). For the DC/DC/RLY variant (6ES7214-1BG40-0XB0) you must add an SB 1232 or SM 1232 analog output module – there is no onboard AQ on the relay variant. Refer to the S7-1200 Programmable Controller System Manual, section 6.3 "Analog outputs", for channel address layout.
2. Why CTRL_HSC_EXT Is the Wrong Block
CTRL_HSC_EXT (and its smaller cousin CTRL_HSC) are HSC (High Speed Counter) control blocks from the "Counters and Measurement" technology object family in TIA Portal. They are designed to:
- Configure a hardware counter channel (CU, CD, or incremental encoder).
- Load a comparison value, set a hardware interrupt threshold, and reset the counter.
- Read measured frequency / period / velocity from the HSC hardware.
None of these functions enforce a rate of change on an INT tag. CTRL_HSC_EXT cannot be told "increase this INT by 200 every 1000 ms until it equals Sp_Raw". It operates on a 32-bit counter hardware register, not on user memory, and it does not call a user-defined ramp function. If you wire CTRL_HSC_EXT into the program you will compile successfully but the rate-limit logic will never run.
Discard the HSC path. Use a cyclic interrupt OB instead.
3. Architecture Overview
4. Prerequisites
| Item | Required | Notes |
|---|---|---|
| STEP 7 Basic V13 SP1 (TIA Portal) | V13 SP1 Update 4 or later | Update 5 (released 2015) recommended for stability. |
| CPU 1214C firmware | V4.0 minimum, V4.2+ recommended | Allows OB30–OB38 cyclic interrupts. |
| Hardware | CPU 1214C DC/DC/DC for onboard AQ, or DC/DC/RLY + SM 1232 | See S7-1200 System Manual. |
| User program blocks | OB1 (main), OB30 (cyclic), FB "RampLimiter", DB instance, global tags | DB can be omitted if FB uses multi-instance instead. |
| HMI tag mapping | INT tag "Sp_Pct" 0–100 | Use absolute mode scaling on the HMI for direct INT bound. |
If TIA Portal V13 SP1 is not yet installed, obtain the package from the Siemens Industry Online Support portal. Newer TIA Portal versions (V15, V16, V17) are backward-compatible with the V13 SP1 project but V13 SP1 cannot open projects saved by V14+.
5. Step 1 — Define the Tags
In the PLC tag table, add the following global tags. Right-click PLC tags → Add new tag table, then create:
| Name | Data type | Address | Initial value | Comment |
|---|---|---|---|---|
| Sp_Pct | INT | %MW100 | 0 | Operator command 0–100 % |
| Sp_Raw | INT | %MW102 | 0 | Scaled command 0–27648 |
| Out_Raw | INT | %MW104 | 0 | Ramped output value |
| StepRate | INT | %MW106 | 200 | Units per cycle |
| AQ_Out | INT | %AQ0 | – | Analog output word, channel 0 |
6. Step 2 — Create the Function Block "RampLimiter"
The FB encapsulates the rate-limit math so it can be reused if you later add a second analog channel with a different slew rate. In the project tree, add Program blocks → Add new block → Function Block, name it RampLimiter, language SCL.
6.1 SCL Implementation
FUNCTION_BLOCK "RampLimiter"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_INPUT
Sp_Raw : INT; // commanded value 0..27648
StepRate : INT; // units per OB cycle (default 200)
Enable : BOOL; // 1 = ramp, 0 = hold
END_VAR
VAR_OUTPUT
Out_Raw : INT; // ramped value
Done : BOOL; // 1 when reached setpoint
Error : WORD; // 0 = OK, 16#0001 = invalid range
END_VAR
VAR
Diff : DINT; // signed difference
END_VAR
VAR RETAIN
Out_Raw_R : INT; // internal retained copy
END_VAR
BEGIN
Error := 16#0000;
Done := FALSE;
// ---- 1. Range guard ----
IF (Sp_Raw < 0) OR (Sp_Raw > 27648) OR (StepRate <= 0) THEN
Error := 16#0001;
Out_Raw := Out_Raw_R;
RETURN;
END_IF;
// ---- 2. Initialise retained memory on first call ----
IF NOT Enable THEN
Out_Raw := Out_Raw_R;
RETURN;
END_IF;
// ---- 3. Compute signed difference ----
Diff := INT_TO_DINT(Sp_Raw) - INT_TO_DINT(Out_Raw_R);
// ---- 4. Apply rate-limited step ----
IF ABS(Diff) <= INT_TO_DINT(StepRate) THEN
// Within one step of target — snap to setpoint
Out_Raw_R := Sp_Raw;
Done := TRUE;
ELSIF Diff > 0 THEN
// Ramping up
Out_Raw_R := Out_Raw_R + StepRate;
ELSE
// Ramping down, guard against INT underflow
Out_Raw_R := Out_Raw_R - StepRate;
END_IF;
// ---- 5. Saturate ----
IF Out_Raw_R < 0 THEN Out_Raw_R := 0; END_IF;
IF Out_Raw_R > 27648 THEN Out_Raw_R := 27648; END_IF;
Out_Raw := Out_Raw_R;
END_FUNCTION_BLOCK
Key engineering points:
-
INT + INT can overflow. Two INT values up to 27648 cannot exceed 32767 (max INT), so
Out_Raw_R + StepRateis safe. If you later raise the maximum to 32767 or higher you must convert to DINT before addition. - The "snap-to-target" branch prevents the output from oscillating forever around the setpoint when the residual error is smaller than one step.
-
Retain on
Out_Raw_Rpreserves the ramp position through a CPU restart. If you do not want that behaviour, removeRETAINand the output will reset to 0 on every restart.
6.2 LAD Equivalent (for Engineers Who Prefer Ladder)
If SCL is not available or your site standard mandates LAD, the equivalent is a network of compares, additions, and a SET/RESET flip-flop. The structure is identical; here is a network-by-network summary.
// Network 1 — range guard
A Sp_Raw
L 0
<I
S Error_Flag // on if negative
A Sp_Raw
L 27648
>I
S Error_Flag // on if above max
A Error_Flag
BEC // skip remainder if invalid
// Network 2 — load retained Out_Raw_R into working word
L Out_Raw_R
T Out_Raw
// Network 3 — done / next-step direction
L Sp_Raw
L Out_Raw_R
-I
T Diff
L 0
>I
= RampUp // Diff > 0 → must go up
L Diff
ABS
L StepRate
>=I
= WithinOneStep
// Network 4 — apply step
A WithinOneStep
JCN NO1
L Sp_Raw
T Out_Raw_R
S Done
JU END_STEP
NO1: A RampUp
JCN NO2
L Out_Raw_R
L StepRate
+I
T Out_Raw_R
JU END_STEP
NO2: L Out_Raw_R
L StepRate
-I
T Out_Raw_R
END_STEP: NOP 0
// Network 5 — saturate at 0 and 27648
L Out_Raw_R
L 0
<I
JCN SAT1
L 0
T Out_Raw_R
SAT1: L Out_Raw_R
L 27648
>I
JCN SAT2
L 27648
T Out_Raw_R
SAT2: L Out_Raw_R
T Out_Raw
For a visual representation, the I/O is identical to the SCL version. Network 4 implements the up/down/snap branches with conditional jumps.
7. Step 3 — Create the Cyclic Interrupt OB30
Add Program blocks → Add new block → Organization Block → OB type: Cyclic interrupt. Name it Main_Ramp_Cyclic. After creation, open its properties and set the Cycle time to 1000 ms and the Phase offset to 0 ms (or any value that does not collide with other cyclic OBs).
| OB30 property | Value | Reason |
|---|---|---|
| OB number | 30 | Standard cyclic interrupt, 5 ms default, configurable. |
| Cycle time | 1000 ms | Matches the "200 units per second" rate requirement. |
| Phase offset | 0 ms | Deterministic start of first execution after RUN. |
| Priority | 9 (default) | Lower than OB1 (1) so OB1 I/O stays consistent. |
Inside OB30, call the FB once per firing:
// Main_Ramp_Cyclic — fires every 1000 ms
IF TRUE THEN
"Ramp_DB"( // instance DB for RampLimiter
Sp_Raw := "Sp_Raw",
StepRate := "StepRate",
Enable := TRUE,
Out_Raw => "Out_Raw",
Done => "Done_Tag",
Error => "Err_Tag"
);
// Hand ramped value to physical analog output
%AQ0 := "Out_Raw";
END_IF;
OB30 runs independently of the main scan. Even if OB1 spends 50 ms on a heavy block, OB30 still fires on the configured 1000 ms grid because the cyclic interrupt is dispatched by the S7-1200 firmware scheduler before the next user cycle finishes.
8. Step 4 — Scaling in OB1
OB1 only needs to convert Sp_Pct (0–100) to Sp_Raw (0–27648). Keep this in the main cycle because the operator HMI tag changes asynchronously and 1 ms latency is fine.
// OB1 Segment 1 — percent to raw conversion
"Sp_Raw" := ("Sp_Pct" * 27648) / 100;
If you prefer floating-point and round-trips through REAL, the equivalent is:
// REAL scaling variant
#sp_real := INT_TO_REAL("Sp_Pct") / 100.0;
"Sp_Raw" := REAL_TO_INT(#sp_real * 27648.0);
For the integer variant, watch the rounding direction. Siemens rounds toward zero. For an operator entry of "100" the result is exactly 27648. For "1" the result is 276. For "37" the result is 10229. If your process cannot tolerate this quantisation, use the REAL path and round explicitly with ROUND or CEIL before REAL_TO_INT.
9. Step 5 — Configure the Analog Output
In Devices & Networks, double-click the analog output channel of the CPU 1214C (or SM 1232). Set:
| Parameter | Value | Comment |
|---|---|---|
| Output type | Voltage 0–10 V (or Current 4–20 mA) | Select on the channel's properties. |
| Output range | 0–10 V / 0–20 mA / 4–20 mA | Match the actuator's input card. |
| Diagnostics | Wire-break enable (for 4–20 mA only) | Generates an I/O fault if loop opens. |
| Substitute value | 0 | Value written when CPU is in STOP, prevents actuator bump. |
The CPU writes the integer 0 to 27648 into the analog channel and the firmware converts it to the physical voltage or current. See the S7-1200 System Manual, section "Representation of analog values".
10. Verification and Commissioning
- Download the project to the CPU 1214C and place the CPU in RUN.
- Watch table test: open PLC → Watch & force tables → Add watch table. Add Sp_Pct, Sp_Raw, Out_Raw, %AQ0, Done_Tag.
- Force Sp_Pct = 0 and let Out_Raw settle at 0. Confirm %AQ0 reads 0.
- Force Sp_Pct = 100. Out_Raw should rise by exactly 200 each second: 0, 200, 400, 600, ... up to 27648. The transition takes 138.24 seconds. Confirm monotonic increase in the watch table (force periodic refresh <= 1 s).
- Force Sp_Pct = 50 mid-ramp. Out_Raw should reverse direction within one OB30 cycle, falling at 200 units/s until it hits 13824 (50 % of 27648).
- Force Sp_Pct = 49 (within one step of current value if currently at 13824). Done_Tag should turn on at the next OB30 firing because the snap-to-target branch fires.
- Disconnect the field loop (4–20 mA only). The wire-break diagnostic should trigger an I/O fault. OB30 keeps running and updating Out_Raw, but %AQ0 will not physically drive the field if hardware output is disabled. Always re-evaluate the safety implication of this behaviour in your risk assessment.
- STOP→RUN test: cycle the CPU mode. If Out_Raw_R is RETAIN it resumes at its last value; otherwise it resets to 0 and climbs again.
11. Edge Cases and Field Caveats
11.1 Faster Cycle Time
If you need a finer ramp granularity, drop OB30 cycle to 100 ms and scale StepRate to 20 (still 200 units/s). The S7-1200 minimum cycle time for OB30 is 1 ms, but anything below 5 ms is unsafe in cyclic interrupt OB 30 — use OB35–OB38 (configured 1 ms minimum) if you need sub-millisecond timing. The arithmetic remains identical.
11.2 Multi-Channel
If you need two channels ramping independently, declare two instance DBs ("Ramp_DB_Ch0", "Ramp_DB_Ch1") and call the FB twice inside OB30. The CPU 1214C DC/DC/DC has two onboard outputs (%AQ0 and %AQ2). Add a separate StepRate tag per channel if rates differ.
11.3 HMI Smoothing
If the operator knob on the HMI is also being polled, the HMI may not see a smooth ramp because it reads Sp_Pct (the command), not Out_Raw. Bind the HMI display to Out_Raw via a separate tag (Sp_Display). Otherwise the operator will see the command jump to 100 even though the field value is still ramping up.
11.4 Network Dropout / HMI Disconnect
If the HMI connection fails, Sp_Pct retains its last value because it lives in the PLC tag table. Out_Raw continues to ramp toward the last command. This is the desired behaviour for most processes — a stuck ramp at the last command is safer than a snap to zero — but document the behaviour in your FMEA.
11.5 Saturation Math
If Sp_Raw suddenly flips from 27648 to 0 the ramp falls 200 per second. At that rate it takes 138.24 s to reach 0. Some processes (e.g. pneumatic valves) require a different down-rate than up-rate. Add a StepRate_Dn input to the FB and select inside the down-branch:
// Replace the down-step in the FB with:
ELSIF Diff < 0 THEN
IF StepRate_Dn > 0 THEN
Out_Raw_R := Out_Raw_R - StepRate_Dn;
ELSE
Out_Raw_R := Out_Raw_R - StepRate;
END_IF;
END_IF;
11.6 Skip OB30 on a Slow Scan
If the user program overruns and the cyclic OB misses its scheduled phase, the S7-1200 firmware generates an OB80 (time error) and either calls the OB80 error handler or logs a diagnostic entry. By default the CPU stays in RUN and the late OB30 fires immediately. If your application depends on a precise ramp time you must enable OB80 and count skipped firings.
12. Common Errors and Error Matrix
| Symptom | Likely cause | Fix |
|---|---|---|
| Out_Raw stays at 0, never moves | OB30 not generated or not wired into the call | Verify OB30 → Properties → Cycle time is enabled; confirm DB instance exists. |
| Out_Raw snaps instantly to Sp_Raw | Code placed in OB1 instead of OB30, or OB30 cycle too short (e.g. 1 ms) and step accumulates over many calls | Verify block is called inside OB30 only; check cycle time in OB properties. |
| Out_Raw oscillates around Sp_Raw | Snap-to-target branch missing or StepRate larger than the smallest Sp_Raw delta | Add the within-one-step branch shown in section 6.1. |
| Output signal has high ripple | StepRate is too large and the actuator hunts | Lower StepRate or increase cycle resolution. |
| Output never exceeds 0 or never goes above a value | Saturate branch missing or wrong direction in subtract | Re-verify saturation guards in section 6.1 step 5. |
| Err_Tag = 16#0001 | Sp_Raw out of range, or StepRate <= 0 | Check HMI bounds; PLC accepts negative or >27648 integers without scaling. |
| Ramp resets on every power cycle | RETAIN not set on Out_Raw_R | Open DB instance, mark the tag RETAIN. |
| CPU goes STOP after first ramp step | OB80 time error or analog output diagnostic not handled | Check diagnostic buffer in TIA Portal → Online → Diagnostics. |
| AQ reads a different value than Out_Raw | Another block writes %AQ0 in OB1 | Search for all writes to %AQ0; only OB30 should write the analog output word. |
13. Alternate Implementations
13.1 IEC 61131-3 Standard Timer Block (No Cyclic OB)
If your plant standard disallows cyclic OBs, you can implement the ramp in OB1 using a TP (pulse timer) at 1000 ms triggering a single increment. This works but ties the ramp to the main scan, which can drift under heavy CPU load. Use it only if the rate precision is non-critical.
13.2 S7-1500 Equivalent
On S7-1500 the same logic applies, but use the Runtime OB (OB30) under the new naming convention and enable optimisations in the FB. The IEC timer resolution is higher and you can drop StepRate to 1 with a 10 ms OB30 to get smoother ramps. See the SIMATIC S7-1500 Automation System Manual.
13.3 Using the PLC Web Server
On CPU 1214C firmware V4.0 and above with the Web Server activated, you can read Out_Raw in a browser at http://<plc-ip>/. Useful for sanity checks during commissioning when the HMI is not yet connected.
14. Performance and Resource Budget
| Resource | Used | Available |
|---|---|---|
| User program memory | ~ 600 bytes for RampLimiter FB + 200 bytes OB30 | 50 KB on CPU 1214C for user code (work memory) and 2 MB load memory. |
| Instance DB | ~ 60 bytes | 2048 DBs available (DB1–DB2047), 64 KB DB size limit. |
| OB30 priority class | 9 | Classes 1–26 available. |
| Scan time impact | ≈ 30 µs per OB30 firing on 1214C | Negligible against 1 ms main scan. |
The ramp adds essentially no scan-time load and consumes less than 1 % of the 1214C's user memory budget.
15. Putting It Together — The Full Control Loop
Once the ramp block is in place, the entire process loop is:
- Operator entry — HMI tag Sp_Pct (0–100).
- Scale — OB1 converts Sp_Pct to Sp_Raw (0–27648) using integer math.
- Ramp — OB30 fires every 1000 ms; FB "RampLimiter" walks Out_Raw toward Sp_Raw at 200 units/s, with saturation and snap-to-target.
- Output — OB30 writes Out_Raw to %AQ0; the onboard analog converts it to 0–10 V or 4–20 mA.
- Feedback (optional) — An analog input monitors the field; compare to Out_Raw to detect stuck actuator. This is outside the ramp logic but is the natural place to add process safety.
For further background on Siemens analog value representation and the S7-1200 cyclic interrupt model, refer to the SIMATIC S7-1200 Programmable Controller System Manual, the STEP 7 Basic V13 SP1 Programming and Operating Manual, and Siemens application entry "Cyclic interrupt OBs" in the Industry Online Support knowledge base.
What is the correct block to rate-limit an INT tag on S7-1200?
Use a Cyclic Interrupt OB (OB30–OB38) configured to fire every 1000 ms. Inside the OB, call a user-written FB that compares the setpoint against the current value and adds or subtracts 200 each cycle, saturating at 0 and 27648. The High Speed Counter block CTRL_HSC_EXT is for hardware counters and cannot enforce a rate of change on a tag.
How long does a 0–100 % step take at 200 units per second?
The maximum raw integer is 27648, and the step rate is 200 units/s. The end-to-end ramp time is therefore 27648 / 200 = 138.24 s. For 50 % it is half that (≈ 69 s). Set StepRate = 200 and OB30 cycle time = 1000 ms to match the spec exactly.
Can I use a 100 ms cycle time and a 20-unit step to get the same 200 units/s ramp?
Yes. Change OB30 cycle time to 100 ms and StepRate to 20. The result is identical in average rate, but the per-cycle granularity is finer, so the actuator moves in smaller, more frequent steps. This is useful if the downstream valve or drive is sensitive to step size.
Why does my analog output jump immediately to the setpoint even though OB30 is configured?
Three common causes: (1) the ramp FB is being called inside OB1 instead of OB30, so the main scan executes the math every cycle; (2) another block writes %AQ0 in OB1 and overrides the ramp; (3) OB30 cycle time is set to 1 ms by default and StepRate accumulates many steps per second, hiding the ramp visually. Verify the call site and the OB properties.
How do I make the ramp remember its position after a power cycle?
Declare the internal retained variable Out_Raw_R with the RETAIN keyword in the FB. The S7-1200 firmware preserves RETAIN variables through STOP→RUN, warm restart, and power-off if the CPU has a retentive memory area configured (default is 10 KB on the 1214C). Mark only the variables you need to preserve as RETAIN, otherwise you consume that 10 KB budget quickly.
Does this work on S7-1500 or LOGO! as well?
Yes on S7-1500 — the same FB body works with optimisations enabled and a higher-resolution cyclic OB. On LOGO! the approach is different because LOGO! has no cyclic interrupt OB; the equivalent uses a pulse relay and an analog multiplexer, or the LOGO! Soft Comfort built-in ramp function block (no SCL available). For LOGO! refer to the LOGO! 8 System Manual instead.