To generate a square wave of a specific frequency and duty cycle in Siemens S7-SCL, calculate the high (on) and low (off) pulse durations in milliseconds from the target frequency (Hz) and duty cycle percentage, convert those values into the TIME data type, and feed them into two cross-coupled IEC timers. The cross-coupled timers toggle an output flag continuously whenever the block is called in a cyclic execution task.
Table of Contents
- Technical Cause: Why Standard Clock Memory Bits Are Limited
- Prerequisites
- Implementation Workflow in S7-SCL
- Full S7-SCL Source Code
- Verification
- Limitations and Operational Cautions
- Engineer FAQ
- Related Articles
- Related Tags
Technical Cause: Why Standard Clock Memory Bits Are Limited
Siemens SIMATIC S7 controllers provide built-in CPU clock memory byte bits, but these are fixed to predetermined frequencies (e.g., 0.5 Hz, 1 Hz, 10 Hz) with an unchangeable 50% duty cycle. Process applications such as pulse-width modulated (PWM) dosing pumps, periodic sampling triggers, strobe controls, or flashing diagnostic indicators frequently require custom frequencies and asymmetrical duty cycles (e.g., 20% on, 80% off).
Using standard CPU clock bits forces engineers to add complex counter logic to achieve custom timing. Implementing a dedicated Function Block (FB) using internal IEC timer instances allows precise mathematical derivation of high and low states dynamically within S7-SCL.
Prerequisites
Before deploying the square wave generator function block, ensure the following requirements are met:
- Development Environment: Siemens TIA Portal or STEP 7 supporting S7-SCL (Structured Control Language).
- Target Controller: SIMATIC S7-300, S7-400, S7-1200, or S7-1500 PLC.
- Execution Task: Calling organization block (OB1 for standard main execution, or a cyclic interrupt OB such as OB35/OB30 for enhanced timing precision).
Implementation Workflow in S7-SCL
The custom signal generator operates by converting standard engineering units (frequency in Hertz and duty cycle in percent) into discrete timing durations.
Mathematical Conversion Flow
- Calculate Total Period (T):
T=frequency1
2. Calculate On-Time (Ton) and Off-Time (Toff):
Ton=T×(100.0dutyCycle)Toff=T−Ton
3. Convert Seconds to Milliseconds:
Multiply the REAL time results by 1000.0 to yield milliseconds, then cast through DINT to TIME.
4. Cross-Couple Timers:
Pass NOT #out to the input of the ON-timer and #out to the input of the OFF-timer. When the ON-timer elapses, set the output high. When the OFF-timer elapses, set the output low, resetting the loop.
Full S7-SCL Source Code
The following code demonstrates the complete S7-SCL implementation. Define this structure inside a Function Block (FB) to ensure timer instance states are preserved across scan cycles.
Structured Text
FUNCTION_BLOCK "SquareWaveGenerator"
TITLE = Custom Square Wave Generator
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : AutomationEngineers
FAMILY : SignalGen
VAR_INPUT
frequency : REAL; // Target frequency in Hz (e.g., 2.0 for 2 Hz)
dutyCycle : REAL; // Target duty cycle in % (e.g., 50.0 for 50%, 25.0 for 25%)
END_VAR
VAR_OUTPUT
squareWave : BOOL; // Output square wave clock signal
END_VAR
VAR
onTimer : TON_TIME; // IEC On-Delay timer for high pulse duration
offTimer : TON_TIME; // IEC On-Delay timer for low pulse duration
out : BOOL; // Internal state tracking bit
END_VAR
VAR_TEMP
period : REAL;
real_OnTime : REAL;
real_OffTime : REAL;
dint_OnTime : DINT;
dint_OffTime : DINT;
time_OnTime : TIME;
time_OffTime : TIME;
onTimerOutput : BOOL;
offTimerOutput : BOOL;
END_VAR
BEGIN
// Prevent division by zero if frequency input is invalid
IF #frequency <= 0.0 THEN
#squareWave := FALSE;
#out := FALSE;
RETURN;
END_IF;
// Calculate total period (seconds) and split by duty cycle
#period := 1.0 / #frequency;
#real_OnTime := (#dutyCycle / 100.0) * #period;
#real_OffTime := #period - #real_OnTime;
// Convert seconds to milliseconds (DINT)
#dint_OnTime := REAL_TO_DINT(1000.0 * #real_OnTime);
#dint_OffTime := REAL_TO_DINT(1000.0 * #real_OffTime);
// Convert integer milliseconds to PLC TIME data type
#time_OnTime := DINT_TO_TIME(#dint_OnTime);
#time_OffTime := DINT_TO_TIME(#dint_OffTime);
// Evaluate IEC timers using cross-coupled logic
#onTimer(IN := NOT #out, PT := #time_OnTime, Q => #onTimerOutput);
#offTimer(IN := #out, PT := #time_OffTime, Q => #offTimerOutput);
// Toggle internal output state based on timer completions
IF #onTimerOutput THEN
#out := TRUE;
END_IF;
IF #offTimerOutput THEN
#out := FALSE;
END_IF;
// Assign internal state to block output
#squareWave := #out;
END_FUNCTION_BLOCK
Verification
To verify correct signal generation:
- Instantiate
"SquareWaveGenerator"in OB1 or a Cyclic Interrupt OB. - Supply a known configuration, such as
frequency := 1.0(1 Hz) anddutyCycle := 25.0(25%). - Open a Watch Table or Trace view in TIA Portal and monitor
#squareWave. - Confirm that the signal stays high for 250 ms and low for 750 ms continuously during execution.
Limitations and Operational Cautions
- PLC Scan Time Dependency: When executed inside OB1 (Main Program Sweep), the precision of the generated frequency is bounded by the PLC scan cycle time. High frequencies (e.g., above 20 Hz) will experience timing jitter if the PLC scan time approaches or exceeds the required pulse duration.
- High-Precision Applications: For high-speed PWM or exact pulse generation exceeding PLC scan resolution, use dedicated technology objects, high-speed digital output cards (TM PTO/PWM modules), or call the logic within a fast cyclic interrupt OB (e.g., OB35 at 1 ms intervals).
- Division by Zero Protection: Always ensure input parameter validation (
#frequency > 0.0) is enforced prior to calculating the reciprocal period length.
Engineer FAQ
Can I run this square wave generator inside a Function (FC) instead of a Function Block (FB)?
No. The cross-coupled timer logic relies on preserving internal timer states (TON_TIME) and output status (out) across multiple execution scans. Functions (FC) do not possess persistent static memory (VAR), whereas Function Blocks (FB) retain memory within their associated Instance Data Block.
How do I achieve higher frequency accuracy under varying CPU scan loads?
To eliminate scan time jitter, call the square wave generator function block inside a Cyclic Interrupt OB (such as OB35 or OB30) set to a fixed execution interval (e.g., 1 ms or 2 ms), rather than calling it in the main cyclic loop (OB1).
What happens if I set the duty cycle input to 0% or 100%?
Setting the duty cycle to 0.0 results in #time_OnTime evaluating to T#0ms, forcing #squareWave to remain perpetually FALSE. Setting it to 100.0 results in #time_OffTime evaluating to T#0ms, causing #squareWave to remain continuously TRUE.
Related Articles
- How to Implement Pulse-Width Modulation (PWM) in Siemens S7-1200
- Understanding Siemens S7-SCL IEC Timer Functions TON and TOF
- Optimizing PLC Execution Times using Cyclic Interrupt OBs in TIA Portal
Related Tags
Code: C243