Skip to content

start stop

Xaeian edited this page Oct 23, 2026 · 2 revisions

Start-Stop in ST, LAD and C

Start-stop is the classic first program in automation: start turns the motor on, stop turns it off, the motor keeps running after start is released, and stop wins when both are pressed. Let's compare it in ST, LAD (ladder logic) and ANSI C using the OpenCPLC libraries, considering two mapping styles in C: variable mapping and pointer mapping. If C code feels most readable and natural to you, you're probably on the right path.

Signal ST and LAD C
Start button %IX0.0 DI1
Stop button %IX0.1 DI2
Motor %QX0.0 RO1

Start-stop in ST

PROGRAM main

VAR
  start_button: BOOL := FALSE;
  stop_button: BOOL := FALSE;
  motor_running: BOOL := FALSE;
END_VAR

start_button := %IX0.0;
stop_button := %IX0.1;

IF stop_button THEN
  motor_running := FALSE;
ELSIF start_button THEN
  motor_running := TRUE;
END_IF;

%QX0.0 := motor_running;

END_PROGRAM

Start-stop in LAD

Start-stop in LAD

In every PLC cycle a coil takes the result of its rung, so without an extra contact motor_running would drop as soon as start is released. The motor_running contact under start_button is the self-holding contact: once the coil is on, it keeps rung 3 closed until stop_button breaks the rung. ST and C need no such contact, as a variable keeps its value until it is written again.

Start-stop in LAD with S and R coils

Start-stop in LAD with S and R coils

A coil S (set) turns motor_running on, and it stays on until a coil R (reset) turns it off. With both buttons pressed, stop breaks rung 3 and rung 4 resets motor_running, so stop wins.

Start-stop in C with variable mapping

The program is the loop thread of a new project, made with opencplc -n myapp -b Uno for example. Every pass of its while(1) is one cycle, as in a PLC: inputs are copied into variables at its start and the output is written from one at its end, like the first two rungs and the last one of each ladder. let() ends the pass and hands the processor over to the other threads.

bool start_button = false;
bool stop_button = false;
bool motor_running = false;

void loop(void)
{
  while(1) {
    start_button = DIN_State(&DI1);
    stop_button = DIN_State(&DI2);
    if(stop_button) {
      motor_running = false;
    }
    else if(start_button) {
      motor_running = true;
    }
    DOUT_Preset(&RO1, motor_running);
    let();
  }
}

Start-stop in C with pointer mapping

Pointers name the inputs and the output in one place, and the code works on them directly: DOUT_Set and DOUT_Rst act like the coils S and R. Both buttons are read by their state, as in the ladders: read by its edge with DIN_Rise, stop would act only at the moment it is pressed, and a stop held down would not keep the motor from starting.

DIN_t *start_button = &DI1;
DIN_t *stop_button = &DI2;
DOUT_t *motor_running = &RO1;

void loop(void)
{
  while(1) {
    if(DIN_State(stop_button)) {
      DOUT_Rst(motor_running);
    }
    else if(DIN_State(start_button)) {
      DOUT_Set(motor_running);
    }
    let();
  }
}

Clone this wiki locally