PWM with a user-entered duty cycle (0–99)
Write a PLC program that performs Pulse-Width Modulation (PWM). The user enters a duty-cycle value in the range 0–99 that varies the width of the output pulse (i.e. the ON-time of the output). When the input value is 50, the high and low portions of the PWM waveform have equal duration, giving a square wave with a 50 % duty cycle. When the input value is 0, the ON timer may be replaced with a brief blink pulse to avoid an error condition. Include a sample input value and the corresponding output waveform.
ShowHide worked solution
Strategy
Choose a fixed period Tperiod (here 100 ms). The ON-time is then a simple proportion of the duty input, and the OFF-time is whatever’s left of the period:
Two cascaded TONs form a self-toggling loop: T1 runs while Q is OFF, T2 runs while Q is ON. The presets T_ON and T_OFF are recomputed live from the DUTY register, so changing DUTY on the fly changes the next half-cycle’s width immediately. A guard rung handles the DUTY = 0 case by substituting a tiny 5 ms blink — a TON with PRE = 0 is undefined on many platforms.
Rung 1 — calculate T_ON, with guard for DUTY = 0: |---[ DUTY = 0 ]----(MOV 5, T_ON)----| ← 5-ms blink fall-back |---[ DUTY > 0 ]----(MUL DUTY, 100, T_ON)----| |---[ DUTY > 0 ]----(DIV T_ON, 100, T_ON)----| Rung 2 — calculate T_OFF (period − T_ON): |---[ ALWAYS ]----(SUB 100, T_ON, T_OFF)----| Rung 3 — ON-phase TON (runs while Q is OFF): |---[/Q]----(TON T1, PRE = T_ON)----| Rung 4 — set Q after T1, seal until T2 finishes: |---[ T1.DN ]----+----( Q )----| | | |---[ Q ]---[/T2.DN]------------+ Rung 5 — OFF-phase TON (runs while Q is ON): |---[ Q ]----(TON T2, PRE = T_OFF)----|
When T2.DN fires, the seal in Rung 4 drops, Q clears, T1 restarts — cycle repeats forever.
Sample waveform (DUTY = 30)
With Tperiod = 100 ms and DUTY = 30: T_ON = 30 ms, T_OFF = 70 ms. The output sits high for 30 ms then low for 70 ms, repeating indefinitely:
Setting DUTY = 50 gives a symmetric square wave (50 ms ON, 50 ms OFF). Setting DUTY = 0 falls through to the 5 ms blink guard so the timer chain never sees a zero preset.