Chapter 6 / 36

Remember with intent

Use latches and edges deliberately, with explicit reset and restart behaviour.

Decision tree selecting direct conditions, a remembered fact or a sequence according to how much history the machine needs
Choose memory for a reason. A lamp following a sensor needs no remembered request. A transfer surviving button release does. A clamp-extend-retract operation benefits from named phases.

Before naming a latch, find two histories that demand different answers. In the first, a carton is between the sensors because a transfer was accepted. In the second, someone placed it there while the machine was idle. The present photoeye values can be identical. The machine should not treat the two situations as the same accepted job. Write the distinguishing fact in plain words before creating the variable.

Some facts belong to this scan; others belong to the story

A carton sensor tells you what is observed now. An accepted Start request tells you something that happened earlier and still matters. Those are different kinds of information. If you use only present inputs, releasing a momentary Start button stops the request. If you retain everything indiscriminately, yesterday's request may reappear when it is no longer appropriate.

Memory should have a purpose, an owner, and a clearing rule. Ask four questions for every stored Boolean: what sets it, what clears it, what wins when both happen, and what should it contain after initialization? If you cannot answer those questions, you have not finished designing the memory.

A latch is a decision about persistence

Consider a teaching fan with momentary Start and Stop buttons. Once Start is accepted, a run request should remain until Stop. The following complete small program demonstrates stop-dominant working memory. It is illustrative IEC-style Structured Text; the target environment supplies I/O mapping and task configuration.

PROGRAM FanRequestExample
VAR
    StartButton : BOOL;
    StopButton : BOOL;
    RunRequest : BOOL := FALSE;
    FanCmd : BOOL;
END_VAR

IF StopButton THEN
    RunRequest := FALSE;
ELSIF StartButton THEN
    RunRequest := TRUE;
END_IF;

FanCmd := RunRequest;
END_PROGRAM

When neither button is active, no assignment changes RunRequest, so the program's working state persists between calls. Stop wins if both inputs are true because the first branch is selected and the second is skipped.

This example intentionally does not solve restart inhibition, equipment faults, or safety. In fact, if Start remains held while Stop is released, the request becomes true again. That may violate the real contract. A simple latch is a useful mechanism, not a complete motor-control specification.

An edge is an observed change

If a command must be new, detect a transition from false to true. A rising-edge detector remembers the previous sample and compares it with the current sample. Its output is a one-invocation event, assuming you call it consistently in the relevant task.

(* Excerpt: PreviousStart is persistent program state. *)
StartEdge := StartButton AND NOT PreviousStart;
PreviousStart := StartButton;

Calculate the edge before updating the previous sample. Reversing the two lines destroys the evidence, as we saw in the scan chapter. A standard function block encapsulates the same kind of state. For example, Beckhoff's R_TRIG exposes CLK and a one-cycle Q indication on a detected rising edge. Its documented interface is a concrete library reference, not a promise that every vendor spells every parameter identically. Beckhoff R_TRIG documentation.

An edge detector only detects transitions that reach its calls. It cannot recover a pulse missed by the input system, and it cannot decide whether a transition was an intentional human request or electrical bounce.

Require release before accepting a new Start

Suppose the contract requires a released button to be observed before a Start can be accepted. This also prevents an already-held button from starting the teaching model at initialization. Use an arming state, initialized false.

(* Excerpt; StartArmed and RunRequest initialize FALSE. *)
StartEvent := FALSE;

IF NOT StartButton THEN
    StartArmed := TRUE;
ELSIF StartArmed THEN
    StartEvent := TRUE;
    StartArmed := FALSE;
END_IF;

IF StopButton OR OperationalFault THEN
    RunRequest := FALSE;
ELSIF StartEvent AND Ready THEN
    RunRequest := TRUE;
END_IF;

The event is consumed even if readiness is false. Holding Start while the station later becomes ready does not create another event. That is deliberate: a rejected request is not stored for future surprise execution.

Trace the awkward case. Start and Stop are pressed together after Start was released. StartEvent appears, but Stop wins and the event is consumed. Releasing Stop while keeping Start held does not restart. The operator must release Start and press it again.

For a full application, decide whether losing readiness also clears StartArmed, and how mode changes and initialization affect it. Those choices should come from the behaviour contract. Do not add retention to this variable by habit.

Operational faults need a lifecycle too

A fault condition and a latched fault record are different. ArrivalTimedOut may become false when the sequence leaves its seeking state. If the alarm disappears immediately with it, the operator loses the reason the machine stopped.

Store the fault until its reset conditions are satisfied. Separately display whether the underlying condition is still active. Reset should acknowledge or clear an eligible record; it should not secretly request a new production cycle.

Avoid one global reset assignment scattered across dozens of routines. Give each fault owner responsibility for its clearing conditions, and expose whether reset succeeded. Some faults can clear immediately, while others require a physical check or recovery procedure. A universal reset button can be a shared request without being a universal promise.

Working memory is not automatically power-loss memory

A variable surviving from one scan to the next is not the same as a variable surviving controller restart. Retention, persistence, initialization, downloads, and memory reset depend on the runtime and configuration. Check those rules on the target, then test the actual restart cases.

Retaining a completed production count may be useful. Retaining a run request may cause an inappropriate restart. Retaining a state number does not prove that the physical mechanism stayed in that state while power was absent. Choose retained data by meaning, not by convenience.

There is also a distinction between retaining history and trusting it. A stored “last carton was partly filled” record can guide recovery while commands remain off. It need not authorize resuming the dispenser.

Try it

An alarm latch is set by JamDetected and cleared by ResetButton. The current code has two independent IF statements: the first sets the latch, and the second clears it. Predict the final value when both inputs are true. Then rewrite the logic so an active jam cannot be cleared, and explain why a reset should not start the conveyor.

Work through the answer

With the described order, the second assignment wins and the alarm ends false, even though the jam is still detected. A reader may see both instructions and assume fault detection has priority, but execution order says otherwise.

IF JamDetected THEN
    JamLatched := TRUE;
ELSIF ResetEvent THEN
    JamLatched := FALSE;
END_IF;

This version gives the active fault priority. ResetEvent should follow the project's request rules rather than relying on a permanently held reset input. The conveyor's run state remains a separate owner with a separate Start requirement. Clearing the alarm means the fault record is eligible to clear; it says nothing about carton position or whether the operator intends motion.

The next chapter translates these ideas into ladder diagrams, where memory can look deceptively like electrical wiring even though execution still follows program rules.

Now make the decision yourself

Use the chapter’s model on a fresh question, then compare your reasoning with the worked decision.

How this becomes a program

What should survive the release of the button?

A 100 ms Start press begins a two-second move. Holding the button after delivery must not request another carton.

Start buttonStart pulseAccepted cycletime →

The edge lasts one scan. The accepted cycle lasts until completion or interruption, even after the button is released.

Your first artifact

Write the lifetime of each value: button is a level, pulse is one evaluation, accepted cycle lasts until completion or interruption. Give every remembered value a clearing rule.

Open the worked decision
StartPulse := StartButton AND NOT StartWasDown;
StartWasDown := StartButton;
IF State = 0 AND StartPulse AND CanStart THEN
  State := 10;
END_IF;

Why this line belongs here

The edge detector runs even when a start cannot be accepted. Otherwise a button held through a fault can become a false new event when the state changes. CanStart is a derived permissive defined by the machine contract.

Change the task

Start is pressed while the drive is not ready and stays held. Readiness later returns. Decide whether that old press should be accepted, then write the corresponding test.