Siemens S7-300 FC105 Temperature Hysteresis Valve Ladder Program

David Krause15 min read
S7-300SiemensTutorial / 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

Problem Statement and Operating Envelope

A hot-water solenoid valve must be driven by a Siemens S7-300 PLC. The control intent is unambiguous: open the valve when the measured temperature falls below a low setpoint (26 °C) and close it once the temperature climbs to a high setpoint (32 °C). Between 26 °C and 32 °C the valve must hold its last state. This is a textbook hysteresis (dead-band) controller, not a proportional controller. The dead-band eliminates relay chattering near the setpoint, prevents valve coil wear, and gives the thermal mass of the load time to respond before the next corrective action.

This reference implements that behavior in STEP 7 Classic (LAD/STL/SCL) on an S7-300 CPU, using the standard FC105 "SCALE" library function to normalize the analog input, comparator blocks to evaluate the limits, and a Set/Reset latching coil to drive the digital output. The same logic ports unchanged to S7-1500 in TIA Portal, with the small syntactic differences noted at the end of this article.

Prerequisites

  • STEP 7 V5.5 or STEP 7 Professional (TIA Portal V13 or later) loaded with the S7-300 / S7-1500 hardware support package.
  • SIMATIC S7-300 station, e.g. CPU 315-2 PN/DP (6ES7 315-2EH14-0AB0) or CPU 312C with integrated AI.
  • Analog input module for temperature, e.g. SM 331 AI8x12 bit (6ES7 331-1KF02-0AB0) for 4–20 mA, or SM 331 AI8xRTD (6ES7 331-7PF01-0AB0) for direct PT100/PT1000 connection. See the SM 331 manual for the channel assignment table.
  • Digital output module, e.g. SM 322 DO8 (6ES7 322-1BF01-0AA0) for 24 VDC valve drive, or DO16 on the CPU 312C.
  • Temperature sensor or transmitter. PT100 RTD, or 4–20 mA head-mounted transmitter scaled to the desired range (e.g. -50 to +200 °C = 4 to 20 mA).
  • 24 VDC solenoid valve; coil current typically 0.3 to 1.5 A. Add an interposing relay if coil inrush exceeds the SM 322 rating (8 A per common on the referenced DO8).
  • Step 7 Standard Library "Standard Library / TI-S7 Converting Blocks" containing FC105 (or the equivalent IEC block NORM_X / SCALE_X in TIA Portal).
Safety: Hard-wire a thermal cut-out and a manual service bypass in series with the solenoid coil. The PLC latches the logical state, but the field device still needs a way to be electrically isolated during commissioning. Never rely on software interlocks alone for a process that can scald personnel or damage equipment.

Hysteresis Control Theory

A two-position controller with hysteresis compares the process variable (PV) against two thresholds: a low limit (T_LOW) and a high limit (T_HIGH). The output latches into one of two stable states.

Condition Valve action Latching behavior
PV < T_LOW (e.g. < 26 °C) Open (energize coil) Set M100.0 = 1
T_LOW ≤ PV < T_HIGH Hold last state No change to M100.0
PV ≥ T_HIGH (e.g. ≥ 32 °C) Close (de-energize) Reset M100.0 = 0

The width of the dead-band (T_HIGH - T_LOW) is the design knob. A 6 °C band on a slow thermal load is conservative; on a fast-reacting exchanger you may need to widen it to 8–10 °C to avoid cycling faster than the valve mechanical life rating (typically 1×10^6 cycles for a quality solenoid).

Why not just use a single comparator and let it chatter near the setpoint? Because every transition of the output contact arcs the contacts and consumes a current pulse in the coil. With a 0.5 s scan and a sensor with even ±0.2 °C noise, you would get hundreds of switching events per hour at the setpoint. The dead-band solves this physically, not algorithmically.

Hardware Topology and Wiring

The reference topology is shown below. A PT100 RTD is wired in 3-wire mode to the first channel of the SM 331 AI8xRTD. The solenoid valve is driven from a SM 322 DO8 output. A freewheeling diode (1N4007 across the coil, cathode to +24 V) suppresses the inductive kick.

Wiring: PT100 (3-wire) to SM 331; 24 VDC valve to SM 322 PT100 RTD IC1+ -----+ IC1 -----+-- channel 0 IC1- -----+ SM 331 AI8xRTD Ch0 (PIW 288) Type: RTD, 3-wire Range: -200..+850 °C SM 322 DO8 (Q0.0) +24V -- coil+ Q0.0 -- coil- Diode 1N4007 reverse Solenoid 24 VDC scale+scale

For 4–20 mA transmitters (head-mounted or DIN-rail), connect to a voltage-input channel with a 250 Ω precision resistor to convert to 1–5 V. The same FC105 call then uses LO_LIM = -50.0 and HI_LIM = +200.0 (or whatever the transmitter range is).

FC105 SCALE Function: Parameter Map and Error Codes

FC105 (called from the standard library path "Standard Library → TI-S7 Converting Blocks") converts the raw 16-bit analog input to a real engineering value. Its formal interface is:

Parameter Type Description
EN BOOL Rising edge enables execution.
IN INT Raw analog value from PIW, e.g. PIW 288.
HI_LIM REAL Engineering value at the high end of the analog range.
LO_LIM REAL Engineering value at the low end of the analog range.
BIPOLAR BOOL TRUE = -27648 to 27648; FALSE = 0 to 27648.
RET_VAL WORD Error code; W#16#0000 = no error.
OUT REAL Scaled result. Must be a memory double-word (MDxx) or DBDxx.

The block evaluates OUT = ( (IN - 0) / 27648.0 ) * (HI_LIM - LO_LIM) + LO_LIM for unipolar, with the equivalent offset for bipolar. For a 4–20 mA input on a -50 to +200 °C transmitter, configure LO_LIM = -50.0, HI_LIM = +200.0, BIPOLAR = FALSE, and remember that FC105 treats 4 mA as the 0% point (about 0 raw counts if the transmitter is ranged correctly). The FC105 function reference documents the corner cases.

FC105 writes an error to RET_VAL when something is misconfigured. These are the codes you will see in your VAT watch table when the scaled temperature reads garbage:

RET_VAL (hex) Meaning Recovery
W#16#0000 No error None required.
W#16#0007 HI_LIM ≤ LO_LIM Swap or re-enter the limits.
W#16#0008 IN > 27648 or IN < -27648 (overflow) Check sensor wiring and AI module range setting (open thermocouple gives 32767 / 7FFF hex; shorted gives -32768 / 8000 hex).
W#16#0006 Output would exceed REAL range Reduce LO_LIM/HI_LIM span; check for integer overflow at IN.

Symbol Table and Tag Database

Define the symbols once in the S7 program / Symbol Editor so that the FB/FC code reads naturally. The M-flag used here is a non-retentive marker bit, which is what you want for a latched control: a warm restart (OB100) will reset it to a known safe state.

Symbol Address Type Comment
AI_TEMP_RAW PIW 288 INT Raw analog input from channel 0 of SM 331.
FC105_RET MW 20 WORD FC105 return value; 0 = OK.
TEMP_ACT MD 0 REAL Scaled process temperature in °C.
T_LOW_LIM MD 4 REAL Valve opens below this. 26.0 °C.
T_HIGH_LIM MD 8 REAL Valve closes above this. 32.0 °C.
VALVE_CTRL M 100.0 BOOL Latched valve command bit.
VALVE_OUT Q 0.0 BOOL 24 VDC output to solenoid driver.
FAULT_AI M 100.1 BOOL Latched sensor/FC105 fault.

Ladder Logic Implementation

The whole control fits in three networks inside OB1 "Main". Initialize the limits once in OB100 (warm restart) so a download or a power cycle does not leave the constants at zero.

OB100 – Initialize limits and clear faults on restart

// Network 1: Load temperature setpoints
      L     2.600000e+001     // 26.0 °C
      T     MD    4            // T_LOW_LIM
      L     3.200000e+001     // 32.0 °C
      T     MD    8            // T_HIGH_LIM

// Network 2: Force valve closed on restart (fail-safe on cold start)
      CLR
      S     M    100.0         // reset VALVE_CTRL
      R     M    100.1         // clear AI fault

OB1 – Main cyclic logic

// Network 1: Scale raw AI to engineering units (°C)
      CALL  FC   105
        IN   :=PIW288          // raw input
        HI_LIM:=MD8            // 32.0
        LO_LIM:=MD4            // 26.0   (NOTE: FC105 supports negative LO_LIM)
        BIPOLAR:=FALSE         // 0..27648 unipolar
        RET_VAL:=MW20
        OUT   :=MD0            // TEMP_ACT
      NOP   0
Range tip: The LO_LIM/HI_LIM in FC105 define the engineering span, not the trip setpoints. If you set LO_LIM = 26.0 and HI_LIM = 32.0 the analog signal is "compressed" into that 6 °C window and the comparator will misbehave. Use the sensor's full calibrated range for FC105 (e.g. -50.0 / +200.0 for a typical PT100 input) and keep T_LOW_LIM/T_HIGH_LIM as separate constants for the comparator.
// Network 2: Latch the valve on (open) when temperature falls below the low limit
      L     MD    0            // TEMP_ACT
      L     MD    4            // T_LOW_LIM  (26.0)
      <R                         // REAL less-than: MD0 < MD4
      S     M    100.0         // VALVE_CTRL := 1 (open valve)
// Network 3: Latch the valve off (close) when temperature reaches the high limit
      L     MD    0
      L     MD    8            // T_HIGH_LIM (32.0)
      >=R                        // REAL greater-or-equal
      R     M    100.0         // VALVE_CTRL := 0 (close valve)
// Network 4: Drive the physical output and watch the fault
      A     M    100.0
      =     Q     0.0          // VALVE_OUT

// Network 5: Latch a fault if the AI scaling failed
      L     MW   20            // FC105_RET
      L     W#16#0
      <>I                       // any non-zero return = fault
      S     M    100.1         // FAULT_AI

The reason the S and R are split across two networks is to make the dead-band explicit. In the gap 26.0 ≤ TEMP_ACT < 32.0 neither comparator is true, so neither S nor R fires, and M100.0 holds its previous value. That is the hysteresis you want.

STL and SCL Equivalents

For teams that maintain code in Structured Text, the entire valve controller collapses to one IF block. Place this in OB1 as a single SCL network (FC1 with SCL source) or paste it into a FB in TIA Portal.

// SCL equivalent for TIA Portal / SCL-enabled CPUs
#temp_actual := NORM_X(INV := INT_TO_REAL(%IW288),
                       MIN := 0.0, MAX := 27648.0);
#temp_actual := SCALE_X(IN  := #temp_actual,
                        MIN := -50.0, MAX := 200.0);

IF #temp_actual < #t_low_lim THEN
    #valve_ctrl := TRUE;                 // open
END_IF;

IF #temp_actual >= #t_high_lim THEN
    #valve_ctrl := FALSE;                // close
END_IF;

%Q0.0 := #valve_ctrl;

Note that TIA Portal exposes the same operation as two blocks (NORM_X and SCALE_X). NORM_X normalizes a real input to 0.0..1.0; SCALE_X scales that to the engineering range. The legacy FC105 folds both steps into one call. See the FC105 / SCALE function description for the equivalent call in TIA Portal.

Step 7 Classic vs. TIA Portal Considerations

Aspect STEP 7 V5.5 / S7-300 TIA Portal / S7-1500
Scale function FC105 from "Standard Library → TI-S7 Converting Blocks" NORM_X + SCALE_X in "Standard → Converting operations"
Compare <R, >=R, ==R in STL; or <R, >=R boxes in LAD Same <R / >=R; LAD boxes auto-typed.
Bit latch S/R coils or S/R box SR / RS flip-flop box, or SR/RS instance in LAD
AI module SM 331 (6ES7 331-1KF02 / 7PF01) SM 1231 / SM 1531 for S7-1200/1500. Address exposed as %IW.
PIW access PIW 288 process-image word %IW288 or symbolic tag from device configuration
Cycle OB1 scan; OB35 if using cyclic interrupt (recommended for stable FC105 reads) OB1; OB30 (cyclic 100 ms) for time-decoupled sampling
Firmware CPU 315-2 PN/DP firmware V3.3 or later recommended for STEP 7 V5.5 SP4 S7-1500 firmware V2.0+ for current TIA Portal releases

On the S7-1500 the behavior is identical but cleaner. The SR/RS flip-flop box in TIA Portal shows the same priority: setting the "S" input forces the bit on; setting the "R" input forces it off; with the standard version, "S" wins on simultaneous assertion, which is the correct choice for a temperature-low override (open valve = heating).

Setpoint Selection, Tuning, and Energy Balance

The 26 / 32 °C thresholds given in the requirement are typical for a hot-water loop serving a 28 °C nominal setpoint. The 3 °C offset above and below center gives a 6 °C dead-band. To size that band from first principles:

Pick a band that gives you at most 6–10 valve cycles per hour. If your thermal load responds at a time constant τ (the time for the sensor reading to traverse 63 % of the dead-band), the period of the limit cycle is roughly 2τ (one heating half-cycle, one cooling half-cycle). With τ = 30 s, the natural cycle is 60 s — much faster than the mechanical life of the valve. Widen the band to about 6 °C, giving a 4τ cycle of 120 s on the rising side and 120 s on the falling side, or roughly 15 cycles per hour, which is acceptable for general-purpose valves.

For a process with a fast τ (e.g. < 10 s, like a small chiller), use PID with a pulse-width-modulated output on the same Q0.0 and skip the on/off logic entirely. The FC105 reading and the comparator structure above stay useful as the PV input to the PID block.

Edge Cases, Faults, and Field-Proven Caveats

Symptom Likely cause Fix
Temperature reads -32768 (8000 hex) Sensor wire break, RTD open, transmitter unpowered Check sensor wiring and AI channel range setting. Use a watchdog that closes the valve on break detection.
Temperature reads +32767 (7FFF hex) Out of configured range; common with PT100 connected to a 4–20 mA input Configure channel to RTD mode, or move to a transmitter-based channel.
Valve chatters at 26 °C Sensor noise riding through the comparator; hysteresis too narrow Widen T_LOW_LIM ↔ T_HIGH_LIM band, or apply a median filter (block FB "Median" or use a moving average over 5–10 samples).
FC105 RET_VAL = W#16#0007 HI_LIM ≤ LO_LIM entered by mistake Verify constants in OB100; remember LO_LIM/HI_LIM are the sensor range, not the trip setpoints.
FC105 RET_VAL = W#16#0008 AI value outside ±27648, typically because the channel is misconfigured for the sensor type Re-check SM 331 channel type (voltage vs. RTD vs. TC) in HW Config.
Output never changes despite correct FC105 reading OB1 not being executed; program downloaded to wrong CPU; M100.0 in retentive area being preserved at an unexpected value Watch M100.0 in VAT. Force the Set and Reset networks one at a time. Verify OB1 is the active cyclic OB.
Valve stays open on power-up Forgetting OB100 to reset M100.0 Add the OB100 latching clear shown above; or make M100.0 non-retentive in the system data.
Scaled value oscillates by 2 °C at steady state AI module set to 50 Hz interference, supply is 60 Hz Reconfigure integration time to 60 Hz (16.67 ms) for typical North American mains.
Retentive bits are the silent killer. If you let the PLC assign M100.0 to a retentive MB by default, the valve will keep its last state across a power cycle. For a heating valve this is usually acceptable, but for safety-critical loads you want OB100 to force the valve to its safe state on every warm restart and then let OB1 run it back to the right state on the next scan.

Verification and Commissioning Checklist

  1. Open the FC105 call in OB1. Force PIW 288 = 0 and verify MD 0 = LO_LIM (e.g. -50.0). Force PIW 288 = 27648 and verify MD 0 = HI_LIM (e.g. 200.0). This confirms the scale is correct end to end.
  2. Force PIW 288 to a value that maps to 24.0 °C (about PIW = 27648 * (24-(-50)) / (200-(-50)) = 9836 decimal, 26C0 hex). Verify M100.0 latches ON. Inspect Q0.0 in VAT; it must read 1.
  3. Force PIW 288 to 32.0 °C (PIW = 27648 * (32-(-50)) / 250 = 9074 decimal, 2372 hex). Verify M100.0 latches OFF and Q0.0 reads 0.
  4. Force PIW 288 to 28.0 °C (between setpoints). Verify M100.0 holds its last value: toggle it manually with the VAT and confirm neither the <R nor the >=R block fires.
  5. Disconnect the sensor. Verify FC105 RET_VAL goes non-zero and M100.1 (FAULT_AI) latches. Decide on a fault policy: usually, fail "valve closed" by AND'ing the output with NOT FAULT_AI.
  6. Run a thermal step test: chill the sensor to 20 °C (ice bath), confirm valve opens. Heat to 40 °C (warm water), confirm valve closes. Plot M100.0 and Q0.0 in a trend to see the dead-band.
  7. Document the wiring, sensor range, and the FC105 LO_LIM/HI_LIM values on a card inside the panel so that the next maintainer does not have to reverse-engineer the constants.

Frequently Asked Questions

Why am I getting a negative temperature after the cold-junction check on a PT100, and FC105 reports W#16#0008?

W#16#0008 means the raw integer overflowed the ±27648 FC105 limit. For a PT100 input this is almost always a wiring error or a wrong channel-type selection (RTD channel configured as voltage, or vice versa). Re-check the SM 331 hardware configuration and confirm the PT100 lead compensation is enabled for 3-wire connections.

Can I use a single comparator instead of the S/R latch pair?

No — a single comparator will chatter the output every scan in the dead-band. The S/R latch pair is what gives you hysteresis. If you only have a single output rung ("A M100.0 = Q0.0") and you use one comparator to set and a second to reset, you get a clean two-state controller with no chatter.

How do I make the setpoints adjustable from an HMI without changing the program?

Move T_LOW_LIM and T_HIGH_LIM out of MD 4 / MD 8 and into a data block (e.g. DB10.DBD0 and DB10.DBD4). Wire the HMI tag to those DB addresses. Make sure the operator cannot enter a T_HIGH_LIM that is less than T_LOW_LIM; add a value check in the HMI screen or in OB100.

Should I run the FC105 in OB1 or in a cyclic interrupt OB like OB35?

For most HVAC and slow thermal loops, OB1 is fine. If the AI channel updates faster than the OB1 cycle (some SM 331 channels do internal averaging that takes 50/60 Hz integration time), call FC105 in OB35 at 100 ms. The comparator and S/R logic must still run in OB1 to be consistent with the rest of the program, so only move the scale call, not the latch.

Will this exact code work on an S7-1200 or S7-1500?

The control logic — comparator + S/R latch + output rung — ports directly. Replace FC105 with the NORM_X + SCALE_X pair (TIA Portal) and use %IW / %Q addresses. On the S7-1200, an integrated AI on the CPU uses %IW96 for the first channel; on the S7-1500 it depends on the slot and the AI module ordering in the device configuration. Consult the SCALE function reference for the exact TIA Portal block call.

Back to blog