🔍
v1.3.8

Edge Detection

Edge detection function blocks let you respond to transitions rather than states. Instead of asking “is the ignition on?” you can ask “did the ignition just turn on?” The output is TRUE for exactly one program scan cycle when the transition occurs, making these blocks ideal for one-shot actions: incrementing counters, toggling states, sending a single CAN frame, or triggering an initialization sequence.

R_TRIG - Rising Edge Detector

R_TRIG detects the rising edge - the moment when CLK transitions from FALSE to TRUE. The output Q is TRUE for exactly one scan cycle, then returns to FALSE regardless of whether CLK remains TRUE.

Parameters

Parameter Type Direction Description
CLK BOOL Input Input signal to monitor
Q BOOL Output TRUE for one scan on rising edge (FALSE → TRUE)

Timing Behavior

CLK: _____|‾‾‾‾‾‾‾‾‾‾‾‾‾|_______|‾‾‾‾‾‾|______
Q:   _____|‾|_____________|_______|‾|______|______
           ^                       ^
           one scan                one scan

Basic Example: Ignition Just Turned On

VAR
    R_TRIG_IGN : R_TRIG;
    SIGNAL_TANDNING : BOOL;
    ignJustOn : BOOL;
END_VAR;

R_TRIG_IGN(CLK := SIGNAL_TANDNING);
// Q is TRUE for one scan cycle when ignition transitions FALSE → TRUE
ignJustOn := R_TRIG_IGN.Q;

Example: Send CAN Frame Once on Ignition

VAR
    R_TRIG_IGN : R_TRIG;
    CANSEND : CAN_TX;
    SENDDATA : ARRAY[0..7] OF BYTE;
    SIGNAL_TANDNING : BOOL;
END_VAR;

R_TRIG_IGN(CLK := SIGNAL_TANDNING);
IF R_TRIG_IGN.Q THEN
    // Send a wake-up DID request exactly once when ignition turns on
    SENDDATA[0] := 0x02;
    SENDDATA[1] := 0x10;    // Diagnostic Session Control
    SENDDATA[2] := 0x01;    // Default Session
    CANSEND(ENABLE := TRUE, ID := 0x7E0, EXT := FALSE, DATALENGTH := 8, DATA := SENDDATA);
END_IF;

F_TRIG - Falling Edge Detector

F_TRIG detects the falling edge - the moment when CLK transitions from TRUE to FALSE. Like R_TRIG, the output Q is TRUE for exactly one scan cycle.

Parameters

Parameter Type Direction Description
CLK BOOL Input Input signal to monitor
Q BOOL Output TRUE for one scan on falling edge (TRUE → FALSE)

Timing Behavior

CLK: ‾‾‾‾‾|_______________|‾‾‾‾‾‾‾|______|‾‾‾‾‾‾
Q:   ______|‾|_______________|‾‾‾‾‾‾‾|‾|____|‾‾‾‾‾‾
            ^                         ^
            one scan                  one scan

Basic Example: Ignition Just Turned Off

VAR
    F_TRIG_IGN : F_TRIG;
    SIGNAL_TANDNING : BOOL;
    COUNTER : INT := 0;
END_VAR;

F_TRIG_IGN(CLK := SIGNAL_TANDNING);
IF F_TRIG_IGN.Q THEN
    // Ignition was just turned off - executes ONCE
    COUNTER := COUNTER + 1;
END_IF;

Example: Save State on Shutdown

VAR
    F_TRIG_IGN : F_TRIG;
    SIGNAL_TANDNING : BOOL;
    shutdownSequence : BOOL := FALSE;
END_VAR;

F_TRIG_IGN(CLK := SIGNAL_TANDNING);
IF F_TRIG_IGN.Q THEN
    // Ignition just turned off - begin shutdown sequence
    shutdownSequence := TRUE;
END_IF;

Common Edge Detection Patterns

Toggle on Button Press

Use a rising edge detector to toggle a boolean value each time a signal transitions:

VAR
    R_TRIG_BTN : R_TRIG;
    SIGNAL_KNAPP : BOOL;
    lampActive : BOOL := FALSE;
END_VAR;

R_TRIG_BTN(CLK := SIGNAL_KNAPP);
IF R_TRIG_BTN.Q THEN
    lampActive := NOT lampActive;
END_IF;

Count Transitions

Count how many times a signal has toggled. Useful for diagnostics and monitoring:

VAR
    R_TRIG_SIGNAL : R_TRIG;
    F_TRIG_SIGNAL : F_TRIG;
    SIGNAL_DORR : BOOL;
    openCount : INT := 0;
    closeCount : INT := 0;
END_VAR;

R_TRIG_SIGNAL(CLK := SIGNAL_DORR);
IF R_TRIG_SIGNAL.Q THEN
    openCount := openCount + 1;    // Door opened
END_IF;

F_TRIG_SIGNAL(CLK := SIGNAL_DORR);
IF F_TRIG_SIGNAL.Q THEN
    closeCount := closeCount + 1;  // Door closed
END_IF;

Detect Signal Value Changes

Detect when a multi-value signal changes by comparing the current value to the previous:

VAR
    currentGear : INT;
    previousGear : INT := -1;
    gearChanged : BOOL;
END_VAR;

gearChanged := (currentGear <> previousGear);
IF gearChanged THEN
    // Gear just changed - take action
    previousGear := currentGear;
END_IF;

High Beam Latch Pattern

A common recipe pattern: use R_TRIG to latch the high beam signal for instant response, rather than waiting for a debounce period:

VAR
    R_TRIG_HELLJUS : R_TRIG;
    SIGNAL_HELLJUS : BOOL;
    helljusLatched : BOOL := FALSE;
END_VAR;

R_TRIG_HELLJUS(CLK := SIGNAL_HELLJUS);

// Latch on rising edge (instant response)
IF R_TRIG_HELLJUS.Q THEN
    helljusLatched := TRUE;
END_IF;

// Clear when signal goes away
IF NOT SIGNAL_HELLJUS THEN
    helljusLatched := FALSE;
END_IF;

HW.BUTTON - Already Edge-Triggered

Warning: HW.BUTTON is already edge-triggered!
The hardware button input (HW.BUTTON) returns its value for only one program cycle. It is inherently a one-shot signal - you do not need to wrap it with R_TRIG. Just check the value directly.
VAR_SIGNAL
    HW : HARDWARE;
END_VAR;

HW();
// CORRECT - no edge detector needed
IF HW.BUTTON = BUTTON_CLICK THEN
    // Single click detected (one cycle only)
END_IF;

IF HW.BUTTON = BUTTON_LONGCLICK THEN
    // Long press detected (one cycle only)
END_IF;
VAR_SIGNAL
    HW : HARDWARE;
END_VAR;

HW();
// UNNECESSARY - R_TRIG on an already-edge-triggered signal
// This works but wastes a function block instance for no benefit
VAR
    RT : R_TRIG;
END_VAR;
RT(CLK := (HW.BUTTON = BUTTON_CLICK));  // Redundant!
IF RT.Q THEN
    // ...
END_IF;
Tip: Use R_TRIG and F_TRIG for signals that represent a continuous state (ignition on/off, door open/closed, CAN signal present/absent). For signals that are already transient one-shot events (button presses, CAN frame received), direct comparison is sufficient.

Summary

Block Detects Q Duration Typical Use
R_TRIG Rising edge (FALSE → TRUE) One scan cycle Initialization, toggle, count activations
F_TRIG Falling edge (TRUE → FALSE) One scan cycle Shutdown actions, count deactivations