Skip to Content

Creating external variables in OpenPLC to interact with an Arduino extension

Share BOOL, UINT and STRING values between Ladder and C++
January 8, 2025 by
Boot & Work Corp. S.L, Arnau Tena

Complete guide: OpenPLC with industrial PLCs

An external variable in OpenPLC is a variable that the Ladder diagram and the C++ code of an Arduino extension share. Declare it in the Ladder variables table with the class External, declare a variable with the same name and type in the Arduino extension with an initial value, and then read or write it by name in sketch_loop(). BOOL and UINT values are assigned directly; a STRING needs its length and its characters.

Arduino extensions let you add C++ to an OpenPLC project for what Ladder cannot do: an HTTP request, a library function, a sensor protocol. External variables are the bridge between both parts. This guide shows the three common types on an M-Duino 42+, with code that compiles against the OpenPLC types, and how to read a PLC input directly from the extension.

Before you start

Editor version. Arduino extensions and the screenshots below come from the classic OpenPLC Editor, the one the Industrial Shields mod was made for in 2024. OpenPLC Editor v4 is a new application: check that your PLC model and the Arduino extension are available in it before you start a project.

How to declare an external variable

  1. In the Ladder variables table, add a variable and set its class to External.
OpenPLC variables table with a BOOL variable named extVar whose class is External
  1. Create an Arduino extension: click the grey + icon of the project tree and select Arduino extension.
OpenPLC Editor project tree with the grey plus menu open and Arduino extension selected
  1. In the variables table of the extension, declare the same variable, with the same name and type, and give it an initial value.
Variables table of the Arduino extension with extVar declared as BOOL with the initial value false

The variable is now available in both places. In the extension you use it by its name: the Editor generates a #define that points the name to the PLC variable, so extVar = true; writes the same memory that the Ladder diagram reads.

When the extension code runs

The extension has two functions. sketch_setup() runs once at start, after OpenPLC has set up the inputs and outputs. sketch_loop() runs once per scan cycle, after the PLC has read the inputs, solved the Ladder logic and written the outputs. Three things follow from that:

  • A value written by the extension reaches the Ladder logic in the next scan.
  • A delay() or a long wait inside sketch_loop() delays the whole PLC scan. Use millis() to time things instead.
  • Do not write from the extension to an output that also has a located variable in Ladder (for example %QX0.0): OpenPLC writes it again in every scan. Give the value to Ladder through an external variable instead, as in the examples below.

Which C type each OpenPLC type becomes

OpenPLC stores variables as IEC 61131-3 types. In the extension they are plain C types, except STRING, which is a structure.

OpenPLC typeC type in the extensionRange
BOOLuint8_tfalse (0) or true (1)
INTint16_t-32768 to 32767
UINT, WORDuint16_t0 to 65535
DINTint32_t-2147483648 to 2147483647
REALfloat32-bit floating point
STRINGstructure with len and bodyUp to 126 characters

BOOL external variables

BOOL is the simplest case: assign true or false in the extension. In this example the Ladder diagram copies ex_bool to the digital output Q0_0 (%QX0.0), and the extension turns it on.

Ladder variables Q0_0 at %QX0.0 and ex_bool of class External, with ex_bool connected to the Q0_0 coil
// Arduino extension: turn on the output while the extension says so
void sketch_setup()
{

}

void sketch_loop()
{
    ex_bool = true;
}

UINT external variables and analog scaling

UINT values are also assigned directly, but analog values need scaling. OpenPLC uses 0 to 65535 for every analog signal, while analogRead() on an M-Duino returns 0 to 1023. This example reads the analog input I0_7 in the extension, multiplies it by 64 and gives it to the Ladder diagram, which sends it to the analog output A0_5 (%QW0).

Ladder variables A0_5 at %QW0 and ext_uint of class External, with ext_uint connected to A0_5
// Arduino extension: copy analog input I0_7 to the Ladder variable
void sketch_setup()
{
    pinMode(I0_7, INPUT);
}

void sketch_loop()
{
    ext_uint = analogRead(I0_7) * 64;   // 0 to 1023 becomes 0 to 65472
}

Reading the input in the extension is also how you use a pin directly from C++. Here the input has no located variable in Ladder, so the extension is its only reader. Use these factors to convert between the PLC functions and the OpenPLC range:

PLC familyanalogRead() to OpenPLCOpenPLC to analogWrite()
M-Duino and Ardboxmultiply by 64divide by 256
ESP32 PLC (all models except the 14)multiply by 32divide by 16
ESP32 PLC 14multiply by 16divide by 16

For example, to drive an analog output of an M-Duino from a UINT that Ladder writes, use analogWrite(A0_5, ext_uint / 256); in the extension, and do not give that output a location in Ladder.

STRING external variables

A STRING is a structure with two fields: len, the number of characters, and body, an array of up to 126 characters. To write it you copy the characters into body and set len. In this example the extension writes "Hello" and the Ladder diagram turns on Q0_0 when ext_str is equal to 'Hello'.

Ladder diagram with an EQ block comparing the constant 'Hello' with the external STRING ext_str and driving the Q0_0 coil
// Arduino extension: write "Hello" into a STRING variable
void sketch_setup()
{

}

void sketch_loop()
{
    const char *str = "Hello";
    size_t n = strlen(str);
    if (n > STR_MAX_LEN) {
        n = STR_MAX_LEN;               // the body holds 126 characters
    }
    memcpy(ext_str.body, str, n);      // copy the characters
    ext_str.len = n;                   // then set the length
}

Two details matter here. In C a text goes in double quotes ("Hello"); single quotes are for one character, and 'Hello' does not compile as a string. In Ladder it is the other way round: IEC 61131-3 writes strings in single quotes. OpenPLC uses len to know where the text ends, so body does not need a final zero.

Exact match. In the OpenPLC library, EQ on two STRING values compares only as many characters as the shorter one has, so an empty string is equal to 'Hello'. If the match must be exact, also check that LEN(ext_str) is 5.

Common errors

What you seeLikely causeWhat to do
The build fails with an undeclared variableThe variable is External in Ladder but missing from the extension table, or the name is differentDeclare it in the extension with the same name and type
The analog output barely movesThe raw analogRead() value (0 to 1023) was not scaledMultiply by the factor of your PLC family
An output set from the extension switches back offThe output also has a location in Ladder, and OpenPLC rewrites it every scanPass the value through an external variable, or remove the location
The PLC scan becomes slowdelay() inside sketch_loop()Time with millis()
The STRING comparison is true too earlyEQ compares only the shorter stringAlso compare LEN()

Ladder and C++ in real projects

Mixing a PLC program with C++ is common when a project needs a protocol or a library that the PLC language does not have, as in HTTP on M-Duino with OpenPLC. If the C++ part grows, the Arduino IDE with the Industrial Shields boards gives direct access to every library. The OpenPLC guide compares both options, and how to choose an industrial controller helps if you are still picking the hardware.

Watch a PLC run a sequence before you write yours. In the process plant simulator, a PLC starts a turbine or a pump step by step and stops it safely. Change the conditions and see how each step waits for its signals.

Open the process plant simulatorAsk an engineer about your project

FAQ about OpenPLC external variables

What is the difference between a Local, Global and External variable?

A Local variable belongs to one program. A Global variable belongs to the resource and every program can use it. External tells a program that the variable is declared somewhere else, here in the Arduino extension, and that it should use that one.

Can the extension read a variable that Ladder writes?

Yes. The sharing works both ways. The extension sees the value written by Ladder in the same scan, because sketch_loop() runs after the logic.

Can I use REAL or DINT external variables?

Yes. They become float and int32_t in the extension and are assigned directly, like BOOL and UINT.

How long can a STRING be?

Up to 126 characters, the default STR_MAX_LEN of OpenPLC. Limit the copy to that size, as the example does.

Can I use Industrial Shields libraries in the extension?

Yes. With the Industrial Shields mod, the extension is compiled for the PLC model you select, so you can use its pin names and libraries as in the Arduino IDE.

​Search in our Blog

Boot & Work Corp. S.L, Arnau Tena January 8, 2025
Share this post
Tags

Looking for your ideal Programmable Logic Controller?

Take a look at this product comparison with other industrial controllers Arduino-based. 

We are comparing inputs, outputs, communications and other features with the ones of the relevant brands.

PLC Comparison