| Timer | Behavior | When done bit (Q) goes high |
|---|---|---|
| TON (on-delay) | Accumulator counts up while EN is true | When ACC ≥ PT (preset time) |
| TOF (off-delay) | Accumulator counts up while EN is false (after EN goes true→false) | While timing — drops when ACC ≥ PT |
| TP (pulse) | Fixed-duration pulse triggered by EN rising edge | For exactly PT seconds, regardless of EN |
| Retentive (RTO) | Holds ACC across EN drops, only resets on RES | When ACC ≥ PT (across multiple enables) |
EN ────┐ ┌────────
│ │
└─────────┘
ACC ────/┐ /┐──────
/│ /│
PT - - -/-│- - - -/-│- - -
/ │ / │
Q ──────┐ ┌────────
│ │
└───────┘
(high once ACC reaches PT)
| Counter | Increment trigger | Reset |
|---|---|---|
| CTU | Rising edge of CU input | When RES is true |
| CTD | Rising edge of CD input | When LD (load preset) is true |
| CTUD | Up on CU↑, down on CD↑ | RES or LD |
Done bit (Q): high when ACC ≥ PV.
Tracks bits moving through a sequence — perfect for parts on a conveyor.
Bit slot: 7 6 5 4 3 2 1 0
Initial: 0 0 0 0 0 0 0 0
After SHL: 0 0 0 0 0 0 0 ←IN
After SHL: 0 0 0 0 0 0 IN ←IN
...
Each shift, every bit moves one position; the new bit-in enters at one end, the old bit-out drops off the other.
Use case: photoelectric sensor at start of conveyor sets bit 0 when a part passes; each conveyor index pulse shifts the register; reject solenoid fires when the right slot reaches the inspection station.
| Instruction | Effect |
|---|---|
JMP label |
Skip to a label later in the program |
LBL label |
Marks the jump destination |
JSR routine |
Call a subroutine |
RET |
Return from subroutine |
Hazard: if a jump skips past a coil, that coil keeps its previous state. This is the classic “stuck output after fault” bug. Always put outputs outside of jumps unless you really know what you’re doing.
| Instruction | Purpose |
|---|---|
MOV src, dst |
Copy value |
ADD a, b, dst |
Addition |
SUB a, b, dst |
Subtraction |
MUL, DIV, MOD |
Math |
EQ, NE, GT, LT, GE, LE |
Comparisons |
LIM lo, val, hi |
True if lo ≤ val ≤ hi |
BCD_TO_INT, INT_TO_BCD |
Conversions |
SCL |
Linear scaling (raw counts → engineering units) |
For a 4–20 mA signal mapped to 0–100% in a 16-bit raw word (0–32767 counts for 4–20 mA on Siemens):
percent = (raw - raw_min) * (eng_max - eng_min) / (raw_max - raw_min) + eng_min
In ST:
Percent := REAL_TO_INT((Raw - 0) * 100 / 32767);
One-shot rising edge (rising-edge detector):
Pulse := Input AND NOT Last_Input;
Last_Input := Input;
Toggle (on/off button):
IF Button AND NOT Last_Button THEN
Output := NOT Output;
END_IF;
Last_Button := Button;
Watchdog timer:
Heartbeat_Timer(IN := NOT Heartbeat_Timer.Q, PT := T#1s);
IF Heartbeat_Timer.Q THEN
Heartbeat := NOT Heartbeat;
END_IF;