Plclib Arduino Guide v1pt2
Plclib Arduino Guide v1pt2
Author: W. Ditch
Published: electronics-micros.com
1 Contents
1 Contents ................................................................................................................................................ 2
2 Introduction .......................................................................................................................................... 5
2.1 Software Development Methods.................................................................................................. 5
2.2 Supported Hardware..................................................................................................................... 6
3 Installing the Software .......................................................................................................................... 8
3.1 First Time Installation.................................................................................................................... 8
3.1.1 Loading and Running Your First Application ......................................................................... 8
3.2 Updating to a New Version ........................................................................................................... 9
4 Configuring the Hardware................................................................................................................... 10
5 Getting Started with Ladder Logic ...................................................................................................... 11
5.1 Single Bit Input and Output......................................................................................................... 12
5.2 Performing Boolean Operations ................................................................................................. 13
6 Latching Outputs ................................................................................................................................. 18
6.1 Latch with Discrete Components ................................................................................................ 18
6.2 Using the Latch Command .......................................................................................................... 19
6.3 Using the Set and Reset Commands ........................................................................................... 20
7 Edge Triggered Pulses ......................................................................................................................... 22
7.1 Creating an Edge Triggered Bistable ........................................................................................... 23
8 Inputting from a Keypad ..................................................................................................................... 25
8.1 Hardware Connections ............................................................................................................... 25
8.2 Software ...................................................................................................................................... 26
9 Using Time Delays ............................................................................................................................... 29
9.1 Producing a Turn-on Delay.......................................................................................................... 29
9.2 Switch Debouncing ..................................................................................................................... 30
9.3 Creating a Turn-off Delay ............................................................................................................ 31
9.4 Creating a Fixed Duration Pulse .................................................................................................. 32
10 Producing Repeating Waveforms ................................................................................................... 33
10.1 Manual Pulse Creation ................................................................................................................ 33
10.2 Using the timerCycle() Command ............................................................................................... 34
11 Counting and Counters ................................................................................................................... 36
11.1 Up Counter .................................................................................................................................. 36
11.2 Down Counter ............................................................................................................................. 37
11.3 Up/Down Counter ....................................................................................................................... 38
11.4 Debugging Counter-based Applications...................................................................................... 39
12 Shifting and Rotating Binary Data ................................................................................................... 41
12.1 Creating and Using Shift Registers .............................................................................................. 41
12.2 Rotating Data .............................................................................................................................. 44
13 Working with Analogue Signals ...................................................................................................... 47
13.1 Controlling LED Brightness using PWM ...................................................................................... 47
13.2 Controlling the Speed and Direction of a Motor ........................................................................ 47
14 Position Control Using Servos ......................................................................................................... 50
15 Comparing Analogue Values ........................................................................................................... 51
15.1 Software-based Comparison of Analogue Values....................................................................... 51
15.2 A Simple Comparator Application............................................................................................... 52
16 Instruction List Programming.......................................................................................................... 54
17 Function Block Diagrams................................................................................................................. 55
17.1 Constructing Working Systems ................................................................................................... 55
17.2 Application 1: A Simple Alarm .................................................................................................... 56
17.3 Application 2: Alarm with Flashing 'Armed' LED ......................................................................... 57
17.4 Creating User Defined Function Blocks....................................................................................... 58
18 Sequential Function Charts ............................................................................................................. 60
18.1 Creating Sequences..................................................................................................................... 60
18.2 Branching and Converging .......................................................................................................... 63
19 Developing Timed SFC-based Applications ..................................................................................... 65
19.1 Time-base Transitions ................................................................................................................. 65
19.2 Application 1: Traffic Light Controller Application...................................................................... 67
19.3 Application 2: Running Light Display........................................................................................... 69
20 Structured Text ............................................................................................................................... 74
20.1 Using Program Structures ........................................................................................................... 74
21 Advanced Concepts......................................................................................................................... 76
21.1 How the Software Works ............................................................................................................ 76
21.2 Using Variables in Programs ....................................................................................................... 77
21.2.1 Using the scanValue Variable.............................................................................................. 77
21.3 Working with Custom Variables ................................................................................................. 78
21.4 Using Variables with Complex Logic Circuits .............................................................................. 79
22 Stack-based Storage and Logic........................................................................................................ 81
22.1 Block Logic Operations ................................................................................................................ 82
23 Defining Custom IO Allocations ...................................................................................................... 85
23.1 Preconfigured I/O Allocations ..................................................................................................... 85
23.2 Case Study: Creating a Custom IO Allocation ............................................................................. 85
24 Strengths and Limitations of the Software ..................................................................................... 88
25 Command Reference ...................................................................................................................... 89
25.1 General Configuration................................................................................................................. 89
25.2 Single Bit Digital Input / Output .................................................................................................. 89
25.3 Combinational Logic.................................................................................................................... 90
25.4 Analogue Signal Input / Output .................................................................................................. 90
25.5 Comparing Analogue Signals....................................................................................................... 91
25.6 Latches ........................................................................................................................................ 91
25.7 Timers.......................................................................................................................................... 92
25.8 Edge Triggered Pulses ................................................................................................................. 93
25.9 Counters ...................................................................................................................................... 94
25.10 Shift Registers ......................................................................................................................... 95
25.11 Stack and Block Logic .............................................................................................................. 97
26 Frequently Asked Questions ........................................................................................................... 98
27 Revision History ............................................................................................................................ 100
2 Introduction
The plcLib library allows you to develop 'PLC-style' control-oriented software applications for
the Arduino and compatibles.
Figure 1. Converting a simple electrical circuit into a ladder diagram and then into a simple program.
A wide range of example sketches will also become available once you have installed the library. The
above program – which is probably the simplest that does something useful – will then be available from
the pull down menu of the Arduino IDE by selecting File > Examples > plcLib > InputOutput >
BareMinimum.
The software is supplied as an installable Arduino library, which is included in the normal way at the
start of your program. A range of text-based PLC-style commands then become available for use in your
programs.
Note: Unlike a modern commercial PLC, the software does not currently support graphical program
entry, simulation, or run-time monitoring. Programs must be entered using the standard Arduino IDE.
Diagrams provided in the User Guide are intended to illustrate the design process, and are linked to
example sketches provided with the library.
Software features supported by the current plcLib version include inputs (digital / analogue), outputs
(digital / PWM / servo), Boolean logic operators, latches, timers, and repeating waveforms. Further
details are available in following sections of the User Guide, including download and installation
instructions.
The Arduino Motor shield is supported as standard, allowing speed and direction control of up to two DC
motors.
Modular construction and experimentation systems such as Grove allow a wide range of input and
output devices to be connected, without the need for prototype board wiring or soldering.
Figure 4. A Grove base shield and serial Bluetooth module connected to an Arduino Uno.
Version 1.2 of the software is supplied with a wide range of sample configurations for commonly
available hardware, including Controllino and Industrial Shields Arduino compatible PLCs. Details of
supported hardware is given in the Defining Custom IO Allocations section.
Custom I/O configurations may also be developed for other hardware, not supported as standard. This
process is illustrated later, using the Velleman I/O shield for Arduino as a case study.
Figure 6. The Velleman Input/Output Shield offers a useful range of pre-configured inputs and outputs.
3 Installing the Software
Please follow the appropriate instructions below, depending on whether you are installing the software
for the first time, or upgrading an existing version.
Download: plcLib Version 1.2, released 21st Dec, 2015. (See the Revision History for all published
versions.)
Exact details of the installation process depends on the version of Arduino IDE installed. For Arduino
1.6.4 or later, select the Sketch > Include Library > Add .Zip Library option and browse to the Zip file
downloaded earlier.
If you're using Version 1.0.5 of the Arduino IDE, then select Sketch > Import Library... > Add
Library... from the pull-down menu, browse to find the previously downloaded Zip file.
Connections:
Input - switch connected to input X0 (Arduino pin A0)
Output - LED connected to output Y0 (Arduino pin 3)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
in(X0); // Read Input 0
out(Y0); // Send to Output 0
}
Listing 1. Bare Minimum (Source: File > Examples > plcLib > InputOutput > BareMinimum)
Note: All examples shown are available from the File > Examples section of the Arduino IDE.
The above sketch reads a switch connected to input X0 (pin A0 on the Arduino) and sends the switch
state to output Y0 (pin 3 on the Arduino). To see it working, you can either wire up a prototype board
circuit, or use any of the range of supported hardware, as explained in the Configuring the
Hardware section.
Figure 7. Testing the Bare Minimum program by using a modular experimentation system.
1. Identify the location of the library files on your computer, which will be in a libraries folder beneath
the Arduino Sketchbook location. Exact details may vary but it will typically be something
like [My Documents]/Arduino/libraries, with a plcLib folder existing beneath this if the software has
been previously installed. You can check the path to the Sketchbook folder by selecting File >
Preferences from the Arduino IDE.
2. Close the Arduino IDE, and then delete the plcLib folder identified above. (It is a good idea to make a
backup copy of any existing files before deleting them – just in case you make a mistake.)
The next section introduces the hardware arrangement used by the software.
4 Configuring the Hardware
A basic set of inputs and outputs is enabled by default. This default configuration is selected by firstly
'including' the plc library file (#include <plcLib.h>) and secondly by calling the setupPLC() function from
within the setup() section of your sketch, as was seen in the example sketch of Listing 1.
At a minimum, the software defines four inputs X0, X1, X2 and X3 (analogue inputs A0–A3) and four
outputs Y0, Y1, Y2 and Y3 (pins 3, 5, 6, and 9).
Additional pins are allocated for larger Arduino boards (Mega, Mega 2560 or Due), as shown at the
right, giving 8 inputs and 8 outputs in total.
Arduino pins with duplicate functions have been avoided wherever possible, to minimise hardware
conflicts.
Data directions of inputs and outputs are automatically configured and outputs are initially disabled
(based on the assumption that 0='off' and 1 = 'on')
Note: Most of the supplied example files make use of the standard I/O configuration.
If this default arrangement proves unsuitable, then a number of alternative custom hardware setups are
available – or you may prefer to create your own. Please see the Defining Custom IO Allocations section
for more details.
The next section introduces the use of a ladder diagram to describe the arrangement and operation of a
simple system, and its conversion into ladder logic based program. Ladder logic concepts are further
developed in subsequent sections of the plcLib User Guide.
5 Getting Started with Ladder Logic
The PLC design method often starts with an electrical circuit, or block diagram, which is then redrawn as
a ladder diagram, and then converted into an Arduino sketch before being compiled and downloaded in
the normal way. The figure below illustrates the process.
Figure 9. Converting an electrical circuit into a ladder diagram and then into a ladder logic program.
The name 'ladder diagram' comes from the superficial resemblance to a physical ladder, with vertical
power rails at each side, and horizontal circuit branches called rungs connected between the rails. More
complex ladder diagrams have a series of rungs, each of which represents a separate circuit.
Ladder diagrams are an adaptation of an earlier technology called relay logic, in which switches and
relays are used to control industrial circuits. A simple relay logic circuit is shown below.
Notice the positive power rail at the left, and negative at the right. Switches SW1 and SW2 are push-to-
make and push-to-break types, causing their associated lamps to be lit when the switches are pressed or
released, respectively. Switch SW3 is connected to relay coil RL1 and the changeover relay contacts are
then linked to lamps BL3 and BL4. The relay contacts are arranged so that only one lamp is lit at any
time.
Any program which make use of the plcLib software library must be entered as a standard Arduino text-
based sketch, which PLC programmers may refer to as instruction list programming. With practice, the
process of converting a ladder diagram into an Arduino sketch becomes relatively straightforward. A
number of alternatives to the ladder logic design approach are available, including function block
programming, sequential function charts and structured text, each of which is discussed separately.
Note: These five programming methods (ladder diagram, instruction list, function block, sequential
function chart and structured text) are defined by the Part 3 of the IEC 61131 standard (IEC 61131-3, also
known in the UK as BS EN 61131-3), which deals with programming languages for programmable
controllers.
Figure 11. A ladder diagram showing methods of reading inputs and controlling outputs.
The ladder diagram may be easily converted to a text-based sketch, as shown below.
#include <plcLib.h>
Digital Input / Output - Single bit I/O in normal and inverted forms
Connections:
Input - switch connected to input X0 (Arduino pin A0)
Input - switch connected to input X1 (Arduino pin A1)
Input - switch connected to input X2 (Arduino pin A2)
Input - switch connected to input X3 (Arduino pin A3)
Output - LED connected to output Y0 (Arduino pin 3)
Output - LED connected to output Y1 (Arduino pin 5)
Output - LED connected to output Y2 (Arduino pin 6)
Output - LED connected to output Y3 (Arduino pin 9)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
in(X0); // Read Input 0
out(Y0); // Send to Output 0
The PLC software repeatedly calculates each rung of the ladder diagram in sequence – from left to right
and top to bottom – by 'scanning' the inputs, performing calculations, and outputting the results; a
process known as the scan cycle. Each rung of the ladder diagram is effectively a separate task, and the
computer shares its processing power between these tasks in a repeating sequence. The high processing
speed makes it appear that the PLC is performing several activities at the same time.
Inputs may be connected in series or parallel to create simple Boolean Logic (combinational logic)
functions, as discussed in the next section.
The basic Boolean logic functions AND, OR, XOR and NOT may be represented in ladder diagram form by
using series / parallel combinations of input switches and output contacts, as shown below.
Figure 13. Boolean logic ladder logic functions and their equivalent logic functions.
This ladder diagram arrangement may be easily coded, as shown in the following sketch.
#include <plcLib.h>
Connections:
Input - switch connected to input X0 (Arduino pin A0)
Input - switch connected to input X1 (Arduino pin A1)
Output - ANDed Output - LED connected to output Y0 (Arduino pin 3)
Output - ORed Output - LED connected to output Y1 (Arduino pin 5)
Output - XORed Output - LED connected to output Y2 (Arduino pin 6)
Output - Inverted Output - LED connected to output Y3 (Arduino pin 9)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
in(X0); // Read Input 0
andBit(X1); // AND with Input 1
out(Y0); // Send result to Output 0
If active-low outputs are required then NAND, NOR and XNOR equivalent functions may be created in
ladder logic.
Figure 14. NAND, NOR and XNOR ladder logic circuits and their equivalent logic functions.
Coding of these functions is achieved by replacing the out() instructions of the previous example with
the negative logic outNot() equivalent, as shown below.
#include <plcLib.h>
NAND, NOR, and XNOR - Boolean Logic functions with inverted outputs
Connections:
Input - switch connected to input X0 (Arduino pin A0)
Input - switch connected to input X1 (Arduino pin A1)
Output - NAND Output - LED connected to output Y0 (Arduino pin 3)
Output - NOR Output - LED connected to output Y1 (Arduino pin 5)
Output - XNOR Output - LED connected to output Y2 (Arduino pin 6)
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
// NAND
in(X0); // Read Input 0
andBit(X1); // AND with Input 1
outNot(Y0); // Send result to Output 0 (inverted)
// NOR
in(X0); // Read Input 0
orBit(X1); // OR with Input 1
outNot(Y1); // Send result to Output 1 (inverted)
// XNOR
in(X0); // Read Input 0
xorBit(X1); // XOR with Input 1
outNot(Y2); // Send result to Output 2 (inverted)
}
Listing 4. NAND, NOR, and XNOR functions. (Source: File > Examples > plcLib > Logic >
NandNorXnor)
Logical operations may also be performed with one or more of the inputs inverted, as seen here.
Connections:
Input - switch connected to input X0 (Arduino pin A0)
Input - switch connected to input X1 (Arduino pin A1)
Output - ANDed output - LED connected to output Y0 (Arduino pin 3)
Output - ORed output - LED connected to output Y1 (Arduino pin 5)
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
in(X0); // Read Input 0
andNotBit(X1); // AND with Input 1 (inverted)
out(Y0); // Send result to Output 0
Figure 16. Discrete components have been used here to create a self-latching circuit.
Examining the circuit at the left, firstly notice that the two switches are wired in parallel, which is of
course a logical OR arrangement. However, to begin with, current does not flow through either path!
The upper branch is off, as the push-to-make switch is not pressed. The lower switch is a push-to-break
type, but this path is also off, being blocked by the relay contacts which are in the off position (down).
A momentary press of the Set input switch allows power to reach the relay coil which activates, moving
the relay contacts to their On position (up). Current now flows through the lower branch, so the relay
remains enabled, even when the Set input is released. The relay remains active until the Reset input
switch is pressed, hence disconnecting the relay coil and returning the relay contacts to their Off
position.
Note: Set Reset latches often have normal and inverted outputs. This function may easily be added, if
required, by wiring a second lamp via the unused set of switch contacts, but with opposite polarity to the
main output.
Latch using Discrete Components - Self latching circuit with Q and Not Q outputs
Connections:
Input - Set - switch connected to input X0 (Arduino pin A0)
Input - Reset - switch connected to input X1 (Arduino pin A1)
Output - Q - LED connected to output Y0 (Arduino pin 3)
Output - NotQ - LED connected to output Y1 (Arduino pin 5)
Software and Documentation:
http://www.electronics-micros.com/software-hardware/plclib-arduino/
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
in(X0); // Read switch connected to Input 0 (Set)
orBit(Y0); // Self latch using Output 0 (Q)
andNotBit(X1); // Reset latch using Input 1 (Reset)
out(Y0); // Output to Output 0 (Q)
The above self-latching circuit works well, but is rather verbose. A simplified version is shown in the next
section.
Figure 17. Set reset latch symbols, shown both with and without an inverted output.
The following sketch shows a latch with both normal and inverted outputs, although the latter two lines
used to generate the inverted output are optional.
#include <plcLib.h>
Latch Command - Set Reset latch with Q and NotQ outputs, based on the 'latch' command
Connections:
Input - Set - switch connected to input X0 (Arduino pin A0)
Input - Reset - switch connected to input X1 (Arduino pin A1)
Output - Q - LED connected to output Y0 (Arduino pin 3)
Output - NotQ - LED connected to output Y1 (Arduino pin 5)
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
in(X0); // Read switch connected to Input 0 (Set input)
latch(Y0, X1); // Latch, Q = Output 0, Reset = Input 1
Notice that the Set input to the latch is taken from the preceding value from the same 'rung' of the
ladder diagram (reading input X0 in this case). The command takes two arguments which are
the Q output and the Reset input respectively.
Connections:
Input - Set - switch connected to input X0 (Arduino pin A0)
Input - Reset - switch connected to input X1 (Arduino pin A1)
Output - Q - LED connected to output Y0 (Arduino pin 3)
Output - NotQ - LED connected to output Y1 (Arduino pin 5)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
in(X0); // Read switch connected to Input 0 (Set input)
set(Y0); // Set Y0 to 1 if X0 = 1, leave Y0 unaltered otherwise
The set() and reset() commands are available in Version 0.7 or later of the plcLib library.
A letter is added to the standard output symbol indicating whether the output is a 'set' or 'reset' type, as
shown in the equivalent ladder diagram.
Figure 18. A latch implemented using Set and Reset outputs.
This method allows separate logic to control the enabling and disabling of a latched output, which is
often convenient. A sequential function chart is a typical application, in which these commands may be
used to control the transitions between steps in a sequence.
7 Edge Triggered Pulses
Version 1.1 of the plcLib software introduces the ability to generate edge triggered pulses, the output of
which are active for a single scan cycle only.
This can be useful in a range of scenarios, such as triggering an output once only, ensuring an output
lasts for a shorter duration than an input, or preventing a latch-based system from being locked in one
position due to a faulty external switch.
Figure 19. Brief output pulses may be generated from the rising or falling edges of an input waveform.
This may be represented as shown in the following ladder diagram, with rising or falling edges on
input X0 being used to momentarily set outputs Y0 and Y1, respectively.
Figure 20. Output pulses on Y0 and Y1 are generated by rising or falling edges of input waveform X0.
Connections:
Clock input - switch connected to input X0 (Arduino pin A0)
Rising-edge output - LED connected to output Y0 (Arduino pin 3)
Falling-edge output - LED connected to output Y1 (Arduino pin 5)
*/
void loop() {
in(X0); // Read switch connected to Input 0 and
pulse1.inClock(); // connect it to the clock input
Examining the above listing, a pulse object called 'pulse1' is first created. External input X0 is then
connected to the clock input of the previously created pulse. Finally, rising and falling edge signals are
used to drive outputs Y0 and Y1 respectively.
Output pulses last for a single scan cycle only, so a 50 millisecond time delay has been added to the
above sketch to 'stretch' the output pulses long enough to be visible when connected to LEDs. This delay
should be removed after testing to avoid slowing down the scan cycle.
These potential issues may to a large extent be overcome by using edge triggered signals to drive the
latch inputs, as shown in the following ladder diagram.
Connections:
Set input - switch connected to input X0 (Arduino pin A0)
Reset input - switch connected to input X1 (Arduino pin A1)
Latched output - LED connected to output Y0 (Arduino pin 3)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
in(X0); // Read switch connected to Input 0 and
setPulse.inClock(); // connect it to the set pulse clock input
Figure 22. A test circuit and sketch, with keypad inputs and latched LED outputs.
Note: Before trying the examples, you'll need to download and install the Arduino Keypad library. The
keyboard example files are available with Version 0.6 or later of the plcLib software.
Figure 23. IO allocation for the Arduino Uno and membrane keypad.
A possible prototype board wiring arrangement is shown below (drawn using Fritzing).
Figure 25. Keypad and LED connections (left), prototype board wiring detail (right).
8.2 Software
The following listing takes a fairly standard keypad input program, and uses a custom latchKey()
function to enable or disable an output bit based on momentary presses of the allocated Set and Reset
keys.
/* Programmable Logic Controller Library for the Arduino and Compatibles
*/
char keyPress = 0; // Holds the currently pressed key value (if any)
const byte ROWS = 4; // Keypad has four rows
const byte COLS = 3; // Keypad has three columns
void setup() {
setupPLC(); // Define input / output pins
}
void loop()
{
keyPress = kpd.getKey(); // Read key pressed (if any)
The overall effect of the four latchKey() commands in the above sketch is to activate LEDs connected to
outputs Y0, Y1, Y2 or Y3 when keys '1', '3', '5' or '7' are pressed, with keys '2', '4', '6' and '8' turning the
corresponding outputs off again.
A slight change to the switch allocations allows a single input key to act as a master reset, as shown in
the following extract.
void loop()
{
keyPress = kpd.getKey(); // Read key pressed (if any)
It is also possible to store the latch output bit in a user defined variable, rather than sending it directly to
an output pin. An example based on this approach is given in the LedVariable example sketch, while the
underlying approach is discussed in the Using Variables in Programs section.
9 Using Time Delays
The plcLib software has commands to produce time delays based on the activation or deactivation of an
input signal (the timerOn() and timerOff() commands), and can also produce an output pulse of fixed
duration (the timerPulse() command). All commands accept two parameters which are firstly the name
of the elapsed timer variable and secondly the required time delay in milliseconds.
Avoid using the Arduino's own delay() command wherever possible, as this halts the PLC scan cycle for
the duration of the delay, and only supports a single delay being active at any time. See the Advanced
Concepts section for more details.
A timer-based system may be be conveniently represented using a block diagram or function block
diagram, as shown in the following example.
Figure 27. A pair of on-delay timers produce separate delays, controlled by two different inputs.
The two on-delay timers provide independent activation time delays of 2 seconds and 4 seconds on
Outputs 0 and 1, respectively. Output 0 becomes active after a signal connected to Input 0 has been
active for 2 seconds, while Output 1 requires Input 1 to have been active for a period of 4 seconds. The
equivalent sketch is shown below.
#include <plcLib.h>
Connections:
Input - switch connected to input X0 (Arduino pin A0)
Input - switch connected to input X1 (Arduino pin A1)
Output with 2 s delay - LED connected to output Y0 (Arduino pin 3)
Output with 4 s delay - LED connected to output Y1 (Arduino pin 5)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
in(X0); // Read Input 0
timerOn(TIMER0, 2000); // 2 second delay
out(Y0); // Output to Output 0
Notice that each timer makes internal use of an elapsed timer variable of type 'unsigned long', which
must be declared at the start of the program.
Connections:
Input - switch connected to input X0 (Arduino pin A0)
Output - debounced output - LED connected to output Y0 (Arduino pin 3)
*/
unsigned long TIMER0 = 0; // Define variable used to hold timer 0 elapsed time
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
in(X0); // Read Input 0
timerOn(TIMER0, 10); // 10 ms delay
out(Y0); // Output to Output 0
}
Listing 14. Switch Debounce (Source: File > Examples > plcLib > TimeDelays > SwitchDebounce)
Figure 28. An off-delay causes an output to remain active for a fixed duration after the input is removed.
An application of the turn-off delay is 'pulse stretching' in which a brief input signal is expanded to have
a minimum pulse width. The following function block diagram shows an off-delay timer with a 2 second
turn-off delay.
Connections:
Input - switch connected to input X0 (Arduino pin A0)
Output - LED connected to output Y0 (Arduino pin 3)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
in(X0); // Read Input 0
timerOff(TIMER0, 2000); // 2 second turn-off delay
out(Y0); // Output to Output 0
}
Listing 15. Turn-off Delay (Source: File > Examples > plcLib > TimeDelays > DelayOff)
9.4 Creating a Fixed Duration Pulse
The timerPulse() command (available with Version 1.0 or later) creates a fixed width output pulse when
triggered by a brief input pulse. This is equivalent to an electronic monostable circuit.
Fixed Pulse - Activates an output for a fixed period after a momentary input is applie
d
Connections:
Input - switch connected to input X0 (Arduino pin A0)
Output with 2 s pulse - LED connected to output Y0 (Arduino pin 3)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
in(X0); // Read Input 0
timerPulse(TIMER0, 2000); // 2 second pulse
out(Y0); // Output to Output 0
}
Listing 16. Fixed width pulse (Source location: File > Examples > plcLib > TimeDelays > FixedPulse)
Note: In Version 1.1 or later, operation of the timerPulse command is modified to be edge triggered
rather than level triggered. Hence the timer is re-triggered by the first low to high transition of the
trigger input after the previous pulse has ended. (This now agrees with the standard behaviour in IEC
standard 61131-3.)
The next section extends the time delay concepts introduced here to create continuously repeating
waveforms.
10 Producing Repeating Waveforms
A repeating pulse may be defined using the duration of the low and high components of the waveform.
Figure 31. A repeating pulse may be defined in terms of the durations of the low and high sections.
The time taken for one complete cycle is called the periodic time (or period), which is obtained by adding
the durations of the low and high components (a duration of 1 second in the above example).
Repeating pulses may either be created manually, from simpler components, or by using a dedicated
command.
Connections:
Input - switch connected to input X0 (Arduino pin A0)
Output - LED connected to output Y0 (Arduino pin 3)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
in(X0); // Read Input 0 (enable)
andNotBit(Y0); // And with inverted output
timerOn(TIMER0, 900); // 900 ms (0.9 s) delay
set(Y0); // Set Output 0 on time-out
With the program running, it will be seen that continuously pressing the enable input (X0) causes the
output (Y0) to turn on for 0.1 s, then off for 0.9 s in a repeating sequence.
The program makes use of a pair of on-delay timers, plus a set-reset latch based around output Y0. The
first timer is initially enabled, assuming output Y0 is zero, and the enable input is also on. The first timer
output goes high after 900 ms, which in turn sets output Y0 to 1. At this point, the second on-delay
timer is enabled and begins to count. After a further 100 ms, the second timer output becomes set,
which causes output Y0 to be cleared, and the whole cycle begins again.
This is an example of a very simple Finite State Machine (FSM), which is the basis of sequential function
charts.
Don't worry if the above example seems rather complex, as this same functionality is provided by
the timerCycle() command, discussed next.
Figure 32. A cycle timer produces a repeating pulse waveform, when enabled.
The command requires four parameters to be specified for each waveform. Parameters 1 and 3 must be
specified as variables (of type unsigned long) and are used internally by the plcLib software to measure
the elapsed time for the low and high sections of the waveform respectively. Associated low and high
pulse widths are defined in the 2nd and 4th parameters. The following example illustrates the process.
#include <plcLib.h>
Connections:
Input - Enable input connected to input X0 (Arduino pin A0)
Output - Pulse Waveform on LED connected to output Y0 (Arduino pin 3)
*/
// Variables:
unsigned long AUX0 = 0; // Pulse low timer variable
unsigned long AUX1 = 0; // Pulse high timer variable
void setup() {
setupPLC(); // Define inputs and outputs
}
void loop() {
in (X0); // Read Enable input (1 = enable)
timerCycle(AUX0, 900, AUX1, 100); // Repeating pulse, low = 0.9 s, high = 0.1 s
// (hence period = 1 second)
out(Y0); // Send pulse waveform to Output 0
}
Listing 18. Pulsed Output - Creating a repeating pulse using the timerCycle command (Source: File
> Examples > plcLib > Waveforms > PulsedOutput)
Note: A typical application is the creation of a repeating 'alarm armed' flashing pulse, as demonstrated
in the File > Examples > plcLib > Applications > AlarmWithArmedStatus example sketch.
11 Counting and Counters
Version 0.8 of the software introduces counters, which can activate an output once a predetermined
number of events have occurred. A counter 'object' may be configured to count up, down, or a
combination of both.
Figure 33. A counter object may be configured to count up, down, or both.
Each counter has four inputs, and four outputs, shown at the left and right of above diagram,
respectively. In practice, only a subset of these may be required, depending on the type of counter
required.
11.1 Up Counter
At its simplest, an up counter counts pulses received on its countUp input, activating the 'finished'
or upperQ output when the required number of input pulses have been detected. To illustrate the
process, the following example creates an up counter which counts from 0 to 10, driven by switch
presses applied to input X0.
#include <plcLib.h>
Connections:
Count input - switch connected to input X0 (Arduino pin A0)
Clear input - switch connected to input X1 (Arduino pin A1)
Preset input - switch connected to input X2 (Arduino pin A2)
Lower Q output - LED connected to output Y0 (Arduino pin 3)
Upper Q output - LED connected to output Y1 (Arduino pin 5)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
in(X0); // Read Input 0
timerOn(TIMER0, 10); // 10 ms switch debounce delay
ctr.countUp(); // Count up
Examining the above listing, the first step is to use the Counter command to create a counter object ctr,
at the same time setting the final value to 10, which is equivalent to the presetValue property of the
counter. The counter defaults to being an up counter, so the internal count value is initially zero, causing
the lowerQ output to be activated. Pulses applied to the X0 input are linked to the countUp input,
causing the internal count value to be incremented by each 0 to 1 transition. After 10 pulses,
the count becomes equal to the upper limit or preset value, causing the upperQ output to be enabled.
A commonly encountered problem with counter circuits is switch bounce, where the switch contacts
'bounce' several times (over a period of a few milliseconds) before settling. This in turn may cause a
single switch press to update the counter several times in rapid succession. To avoid this effect, notice
that a 10 millisecond on-delay timer has been linked in series with the X0 switch connected to
the countUp input.
It may also be necessary to manually force the counter to go back to the start, which is achieved in the
above example by connecting switch input X1 to the clear input of the counter. The preset input
(connected to switch input X2) performs a similar function, but this time setting the internal count to the
final or preset value. Hence pressing the switches connected to inputs X1 or X2 will cause
the lowerQ or upperQ outputs to be immediately activated, respectively.
Connections:
Count input - switch connected to input X0 (Arduino pin A0)
Clear input - switch connected to input X1 (Arduino pin A1)
Preset input - switch connected to input X2 (Arduino pin A2)
Lower Q output - LED connected to output Y0 (Arduino pin 3)
Upper Q output - LED connected to output Y1 (Arduino pin 5)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
in(X0); // Read Input 0
timerOn(TIMER0, 10); // 10 ms switch debounce delay
ctr.countDown(); // Count down
The first difference is in the creation of the Counter object ctr, using the Counter ctr(5, 1); command. As
well setting the preset value to 5, the optional second parameter has a value of 1, causing the initial
count value to be set equal to the upper limit, which is suitable for a down counter. (Omitting the
second parameter, or setting it to zero inialises the count to zero). Input X0 is then connected to
the countDown input, while output Y0 is driven by lowerQ. Hence Y0 will go high after 5 pulses have
been received on input X0.
Connections:
Count up input - switch connected to input X0 (Arduino pin A0)
Count down input - switch connected to input X1 (Arduino pin A1)
Clear input - switch connected to input X2 (Arduino pin A2)
Preset input - switch connected to input X3 (Arduino pin A3)
Lower Q output - LED connected to output Y0 (Arduino pin 3)
Upper Q output - LED connected to output Y1 (Arduino pin 5)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
in(X0); // Read Input 0
timerOn(TIMER0, 10); // 10 ms switch debounce delay
ctr.countUp(); // Count up
The above counter has separate count-up and count-down inputs linked to input
switches X0 and X1 respectively, and each counter input has its own debounced switch input.
Connections:
Count up input - switch connected to input X0 (Arduino pin A0)
Count down input - switch connected to input X1 (Arduino pin A1)
Clear input - switch connected to input X2 (Arduino pin A2)
Preset input - switch connected to input X3 (Arduino pin A3)
Lower Q output - LED connected to output Y0 (Arduino pin 3)
Upper Q output - LED connected to output Y1 (Arduino pin 5)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
Serial.begin(9600); // Open serial connection over USB
}
void loop() {
in(X0); // Read Input 0
timerOn(TIMER0, 10); // 10 ms switch debounce delay
ctr.countUp(); // Count up
To debug the application, simply open the Serial Monitor while the sketch is running. This will repeatedly
display the internal count value, with the repetition interval controlled by the delay command towards
the end of the listing. (However, don't forget to remove the debugging code, once your application is
working as intended.)
12 Shifting and Rotating Binary Data
Version 0.9 of the software introduces shift registers which may be used to shift binary data to the left
or right, by one bit position at a time.
Figure 34. A simple shift register moves data one place to the right on each rising edge of the Clock.
The above example shows a simple 8-bit shift register, which shifts data one position to the right on
each rising edge of the Clock input. New data is shifted in at the left side, while data is discarded as it
leaves at the right. The content of individual bits may be read from output connections at the top.
Considering the numerical content of the shift register, shifting data to the right is equivalent to division
by two, since the most significant bit is at the left. Conversely, shifting to the left would be equivalent to
multiplication by two.
Several other configuration tasks are also required, including definition of the serial data input, clock
input (shifting data to the right in this case), reset input and any parallel output connections, as
illustrated by the following function block symbol.
The actual coding of the shift register is given by the following sketch.
#include <plcLib.h>
Connections:
Serial Input - switch connected to input X0 (Arduino pin A0)
Clock Input - switch connected to input X1 (Arduino pin A1)
Reset Input - switch connected to input X2 (Arduino pin A2 )
Output - LED connected to output Y0 (Arduino pin 3)
Output - LED connected to output Y1 (Arduino pin 5)
Output - LED connected to output Y2 (Arduino pin 6)
Output - LED connected to output Y3 (Arduino pin 9)
*/
Shift shift1(0x8888); // Create a 16 bit shift register with initial value 0x8888
// Bit 1 1 1 1 1 1
// Positions 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// | | | | | | | | | | | | | | | |
// X0 -> -> -> -> 1 0 0 0 -> 1 0 0 0 -> 1 0 0 0 -> 1 0 0 0 ->
// | | | |
// X1 -> Clock | | | |
// | | | |
// X2 -> Reset | | | |
//
// Y Y Y Y
// Outputs 3 2 1 0
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
Data is shifted right by the rising edge of the clock input taken from a switch connected to input X1, with
new data shifted-in at the left taken from input switch X0. (Notice that the potential problem of contact
bounce on the clock input is avoided by the use of a 10 ms switch debounce delay.) Input
swicth X2 provides a reset input, clearing the shift register to zero when pressed. Parallel outputs are
taken from bits 15–12, allowing any newly inputted serial data to be immediately visible on the outputs.
It is straightforward to modify the above sketch to shift data to the left, as shown below.
#include <plcLib.h>
Connections:
Serial Input - switch connected to input X0 (Arduino pin A0)
Clock Input - switch connected to input X1 (Arduino pin A1)
Reset Input - switch connected to input X2 (Arduino pin A2)
Output - LED connected to output Y0 (Arduino pin 3)
Output - LED connected to output Y1 (Arduino pin 5)
Output - LED connected to output Y2 (Arduino pin 6)
Output - LED connected to output Y3 (Arduino pin 9)
*/
Shift shift1(0x1111); // Create a 16 bit shift register with initial value 0x1111
// Bit 1 1 1 1 1 1
// Positions 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// | | | | | | | | | | | | | | | |
// <- 0 0 0 1 <- 0 0 0 1 <- 0 0 0 1 <- 0 0 0 1 <-
X0
// | | | |
// X1 -> Clock | | | |
// | | | |
// X2 -> Reset | | | |
//
// Y Y Y Y
// Outputs 3 2 1 0
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
Figure 36. Adding a feedback connection causes data to be rotated right or left in a continuous loop.
In fact, the feedback connection may be taken from any convenient output bit, hence creating a
circulating bit pattern of any desired width. As an example, the following sketch uses shift register bit 12
as the feedback connection to the serial input (i.e. the 4th bit from the left), to rotate a 4-bit data word
to the right.
#include <plcLib.h>
Connections:
Clock Input - switch connected to input X0 (Arduino pin A0)
Reset Input - switch connected to input X1 (Arduino pin A1)
Output - LED connected to output Y0 (Arduino pin 3)
Output - LED connected to output Y1 (Arduino pin 5)
Output - LED connected to output Y2 (Arduino pin 6)
Output - LED connected to output Y3 (Arduino pin 9)
*/
// Outputs Y Y Y Y
// 3 2 1 0
//
// Bit 1 1 1 1
// Positions 5 4 3 2
// | | | |
// -> 1 0 0 0 ->
// | |
// | |
// X0 -> Clock -<--<--<--<--
//
// X1 -> Reset
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
An equivalent sketch to rotate a 4-bit data word to the left would use bit 3 (the 4th bit from the right) as
the feedback connection, as shown in the following example.
#include <plcLib.h>
Connections:
Clock Input - switch connected to input X0 (Arduino pin A0)
Reset Input - switch connected to input X1 (Arduino pin A1)
Output - LED connected to output Y0 (Arduino pin 3)
Output - LED connected to output Y1 (Arduino pin 5)
Output - LED connected to output Y2 (Arduino pin 6)
Output - LED connected to output Y3 (Arduino pin 9)
*/
// Outputs Y Y Y Y
// 3 2 1 0
// Bit
// Positions 3 2 1 0
// | | | |
// <- 0 0 0 1 <-
// | |
// | |
// X0 -> Clock ->-->-->-->--
//
// X1 -> Reset
void loop() {
The scanValue global variable holds the inputted value, which is in the range 0-1023 for an analogue
input. This is automatically scaled in the range 0-255 or 0-179 when used to control a PWM or servo
output, respectively.
Connections:
Input - potentiometer connected to input X0 (Arduino pin A0)
Output - LED connected to output Y0 (Arduino pin 3)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
inAnalog(X0); // Read Analogue Input 0
outPWM(Y0); // Send to Output 0 as PWM waveform
}
Listing 27. Analogue control of a PWM output (Source: File > Examples > plcLib > InputOutput >
PWM)
Two motor channels are available – Channel A and Channel B – and the shield also supports a small
number of Tinkerkit compatible input and output connectors (plus two TWI / I2C interfaces not
considered here). The above image shows a linear potentiometer connected to pin X2 (A2), used to
control the motor speed via PWM, and a tilt switch controlling the motor direction, linked to pin X3 (A3).
The following example controls the speed and direction of a motor connected to Channel A.
#include <plcLib.h>
Connections:
Input - Speed - potentiometer connected to input X2 (Arduino pin A2)
Input - Direction - switch connected to input X3 (Arduino pin A3)
Output - Channel A Direction (DIRA) - Arduino pin 12
Output - Channel A PWM (PWMA) - Arduino pin 3
Output - Channel A Brake (BRAKEA) - Arduino pin 9
*/
// Variables
unsigned int RUN = 0; // Disable brake
void setup() {
setupPLC(); // Setup inputs and outputs
void loop() {
// Control direction of motor
in(X3); // Read switch connected to Input 3
out(DIRA); // Output to DIRA (motor direction)
Notice that a number of predefined variables are available to simplify the coding of motor control
software as far as possible, as summarised below:
BRAKEA and BRAKEB enable or disable the brake on each channel (0 = brake off).
DIRA and DIRB set the forward or reverse direction of each motor.
PWMA and PWMB control the motor speed of their related channels.
14 Position Control Using Servos
Controlling a servo is slightly more complex, due to the need to work with the Servo library which is
supplied as a standard part of the Arduino environment. The outServo() replaces
the outPWM() command used previously, and is defined locally, as shown below.
#include <Servo.h>
#include <plcLib.h>
Connections:
Input - potentiometer connected to input X0 (Arduino pin A0)
Output - servo connected to output Y0 (Arduino pin 3)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
servo1.attach(Y0); // Attaches Servo 1 to Output 0
}
void loop() {
inAnalog(X0); // Read potentiometer connected to input 0
outServo(servo1); // Output to Servo 1 (connected to Output 0)
}
Note: See the InputOutput section of the example files for a dual servo control sketch.
15 Comparing Analogue Values
Analogue comparison commands provide equivalent functionality to an electronic comparator circuit,
giving a true / false result based on which of the two tested analogue signals is the larger.
Figure 38. A comparator 'tests' the relative magnitude of two analogue inputs.
The circuit symbol for an electronic comparator is triangular, with two analogue inputs at the left and a
single digital output at the left. A high output is produced if the voltage applied to the upper V+, input
terminal is greater than that connected to the lower, V– input (called the non-inverting input and
the inverting input, respectively). Otherwise, a low output is produced.
The two available variations of the comparison operation are compareGT() and compareLT() which test
whether an input is either greater than or less than a reference value, respectively.
The following example tests whether the analogue voltage on input X0 is greater than that on input X1,
setting output Y0 if this is true.
#include <plcLib.h>
Connections:
Analogue Input - potentiometer connected to input X0 (Arduino pin A0)
Analogue Input - potentiometer connected to input X1 (Arduino pin A1)
Digital Output - LED connected to output Y0 (Arduino pin 3)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
inAnalog(X0); // Read Analogue Input 0
compareGT(X1); // X0 > X1 ?
out(Y0); // Y0 = 1 if X0 > X1, Y0 = 0 otherwise
}
Listing 30. Greater than test between two input pins using a comparator (Source: File > Examples >
plcLib > AnalogCompare > GreaterThan)
It is also possible to compare an analogue input against a fixed reference, as shown in the following
example.
#include <plcLib.h>
Connections:
Analogue Input - potentiometer connected to input X0 (Arduino pin A0)
Digital Output - LED connected to output Y0 (Arduino pin 3)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
inAnalog(X0); // Read Analogue Input 0
compareLT(threshold); // X0 < 500?
out(Y0); // Y0 = 1 if X0 < 500, Y0 = 0 otherwise
}
Listing 31. Less than comparator test between an input and a fixed threshold (Source: File >
Examples > plcLib > AnalogCompare > LessThanThreshold)
Figure 39. A dual-threshold comparator indicates if the input is above or below an allowed 'window'.
The upper comparator causes its associated LED to light if the input voltage, V1 is greater than a fixed
threshold of 3.5 V. Conversely, the lower comparator gives an output if its input voltage is less than its
threshold voltage of 1.5 V. (Carefully note the polarity of each comparator input connection to
understand how 'greater than' or 'less than' tests are achieved.)
An equivalent sketch is given below, which makes use of both forms of comparator command, together
with calculated threshold values based on a 5 V power supply.
#include <plcLib.h>
Connections:
Analogue Input - potentiometer connected to input X0 (Arduino pin A0)
Digital Output - 'High' LED connected to output Y0 (Arduino pin 3)
Digital Output - 'Low' LED connected to output Y1 (Arduino pin 5)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
inAnalog(X0); // Read Analogue Input 0
compareGT(highLimit); // X0 > upper threshold?
out(Y0); // Y0 = 1 if X0 > 717, Y0 = 0 otherwise
Following sections introduce the range of commonly used PLC programming techniques, starting
with Instruction List programming.
16 Instruction List Programming
Instruction list programming is a text based language, used to describe PLC programs, and is one of five
methods specified by international standard IEC 61131-3, with the others being ladder diagram, function
block diagram, sequential function chart and structured text.
Examples of instruction list commands include reading inputs, performing logical operations and
controlling outputs, although details of command syntax tend to vary between manufacturers. A close
relationship exists between instruction list and graphical design methods, including ladder diagrams and
function block diagrams, as shown by the following illustration.
Figure 40. A close equivalence exists between instruction list and graphical design methods.
Instruction list is sometimes claimed to be a 'low level language', reminiscent of assembly language, but
'slightly lower level' (than a graphical method) might be more accurate.
Note: Instruction list is not directly related to the microprocessor running the program, unlike assembly
language or its close relative machine code (both of which are true ‘low level’ languages), and is likely to
have been implemented using a high level language such as C or C++.
Instruction list may be used as a program entry method in its own right, although this is less common in
modern, commercially available PLCs.
17 Function Block Diagrams
A function block diagram allows an electronic system to be represented as a block diagram, which may
then be translated into a text-based Arduino sketch in the usual way.
Figure 41. A block diagram can represent many types of electronic system.
Function block diagrams are typically made up of a series of boxes (often rectangular in shape), having
inputs at the left and outputs at the right. External inputs are normally shown at the left side of the
diagram and outputs at the right. Interconnections between these elements allow signals to progress
generally from left to right, although in some cases, feedback signals, may also be present, returning
signals back to an earlier stage for further processing.
A variety of function types are supported, including logic gates, comparators, latches, time
delays and waveform generators.
A good understanding of how the software 'solves the circuit' is required, to write an equivalent text-
based sketch. The Advanced Concepts section explains how the software uses the scanValue variable to
solve each rung of a ladder diagram, progressing from left to right across each rung, and from top to
bottom in a repeating sequence called the scan cycle. In effect, the output of each command is
temporarily stored in the scanValue variable and then reused as the first input to the next command.
This works fine for simple networks, but it may be necessary to store temporary results for later reuse in
more complex circuits.
The process of solving a system represented in block diagram form is similar to a ladder diagram. In
summary, aim to work from left to right and from top to bottom. Try to allow the scanValue variable to
automatically transfer signals between system blocks, wherever possible. You can use multiple left to
right 'passes' – just like the 'rungs' of a ladder diagram – and temporary results may be stored and later
retrieved, if necessary. The following two examples demonstrate the application of this design approach
with some relatively simple circuits.
Figure 43. A simple alarm circuit with 3 input sensors, a latched alarm output and a reset input.
The alarm has three sensors, which are connected to a 3-input OR gate. If one or more of the sensors
becomes active, this causes the output of the logic gate to go high, which in turn sets the latch and
activates the alarm output (Q). The alarm will remain active due to the latch, even when the original
alarm input is removed, but may be manually cancelled by activating the Reset input.
Simple Alarm - A 3-input alarm circuit with a latched output and manual Reset input
Connections:
Input - Sensor 0 - switch connected to input X0 (Arduino pin A0)
Input - Sensor 1 - switch connected to input X1 (Arduino pin A1)
Input - Sensor 3 - switch connected to input X2 (Arduino pin A2)
Input - Reset Alarm - switch connected to input X3 (Arduino pin A3)
Output - Alarm Output - LED connected to output Y0 (Arduino pin 3)
Software and Documentation:
http://www.electronics-micros.com/software-hardware/plclib-arduino/
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
in(X0); // Read Sensor 0 (Input 0)
orBit(X1); // OR with Sensor 1 (Input 1)
orBit(X2); // OR with Sensor 2 (Input 2)
Figure 44. An improved alarm produces a pulse on Y1 when the alarm is armed but not triggered.
Operation of the OR gate and Set Reset latch is the same as the basic alarm described previously. The
pulse generator (or cycle timer) is enabled when the Reset input is inactive (using the Not gate
connected to input X3) and is configured to produce a brief pulse of 0.1 seconds duration every 2
seconds. The Q output of the cycle timer is connected to the Armed output (Y1) via an AND gate, which
will disable the Armed output if the main alarm has been triggered. The equivalent software listing is
shown below.
#include <plcLib.h>
Alarm with Armed Status LED - 3 input alarm controller with flashing Armed LED
Connections:
Input - Sensor 0 - switch connected to input X0 (Arduino pin A0)
Input - Sensor 1 - switch connected to input X1 (Arduino pin A1)
Input - Sensor 3 - switch connected to input X2 (Arduino pin A2)
Input - Reset Alarm - switch connected to input X3 (Arduino pin A3)
Output - Alarm Output - LED connected to output Y0 (Arduino pin 3)
Output - Armed Output - LED connected to output Y1 (Arduino pin 5)
Software and Documentation:
http://www.electronics-micros.com/software-hardware/plclib-arduino/
*/
// Timer Variables
unsigned long AUX0 = 0; // Pulse low timer variable
unsigned long AUX1 = 0; // Pulse high timer variable
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
Note: To create your own custom commands you will need to be reasonably confident with C / C++
programming, and have a basic knowledge of Arduino functions. You will also need to be familiar with
the Advanced Concepts and Using Variables in Programs sections of the User Guide.
The following example calls a user defined function to calculate the average value of two different
analogue inputs, using the result to control the brightness of an LED.
#include <plcLib.h>
Average - Create a custom function to calculate the mean of two analogue inputs
Connections:
Input - Potentiometer connected to analogue input X0 (Arduino pin A0)
Input - Potentiometer connected to analogue input X1 (Arduino pin A1)
Output - LED connected to output Y0 (Arduino pin 3)
*/
void loop() {
reading1 = inAnalog(X0); // Read analogue Input 0
reading2 = inAnalog(X1); // Read analogue Input 1
scanValue = average(reading1, reading2); // Set scanValue to average reading
outPWM(Y0); // Send to Output 0
}
The above sketch repeatedly reads the two analogue inputs, storing these values in two user defined
variables, reading1 and reading2. These are 'passed' to the average() function, which finds the mean
of reading1 and reading2, returning the result to the main program. This returned result is stored in
the scanValue variable, which automatically makes the value available as an input to the next command
in the scan cycle. The actual function definition is found towards the end of the listing.
Note: The scanCycle variable must be initially defined as an external variable, as it is used internally by
the plcLib library software.
18 Sequential Function Charts
A Sequential Function Chart (SFC), allows a PLC to move through a series of steps under program control.
The transition from one step to another occurs if the transition condition(s) are met, and each step may
optionally produce one or more outputs. As the name suggests, SFCs are normally represented in
diagrammatic form, as shown in the following example.
Figure 45. A simple three step program represented as a sequential function chart.
In the above case, the system automatically begins in the Start-up step. Progression to Step 1 occurs
when input X0 is pressed, causing output Y0 to be displayed. With Y0 displayed, pressing input X1 causes
the system to progress to Step 2, activating output Y1.
Connections:
Input - switch connected to input X0 (Arduino pin A0)
Input - switch connected to input X1 (Arduino pin A1)
Output - LED connected to output Y0 (Arduino pin 3)
Output - LED connected to output Y1 (Arduino pin 5)
|=========|
| START |
|=========|
|
-|-- X0
|
|----|----| |------|
| STEP1 |----| Y0 |
|---------| |------|
|
-|-- X1
|
|----|----| |------|
| STEP2 |----| Y1 |
|---------| |------|
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
// Do state transitions
in(STEP1);
out(Y0); // Send to Output 0
in(STEP2);
out(Y1); // Send to Output 1
}
Listing 36. A Simple Sequence (Source: File > Examples > plcLib > SequentialFunctionChart >
SimpleSwitchSequence)
A step is active if its associated variable is equal to 1, and inactive when zero. Hence, initial conditions at
power-up or reset are defined based on the above allocated variable values.
2: Steps are activated in a predefined sequence, as each transition condition occurs.
// Do state transitions
Notice that transition conditions are ANDed with the current state, which ensures a transition input is
only accepted when its associated step is active. The program should also cancel the previous step when
the next step is activated, and this is achieved using the set() and reset() latch commands, in the above
extract.
in(STEP1);
out(Y0); // Send to Output 0
in(STEP2);
out(Y1); // Send to Output 1
Note: This simple program has a single unique output for each step. A more complex system, such as a
traffic light controller (see later), may require a custom 'mapping' between steps and outputs – typically
implemented with Boolean OR functions.
The above example may easily be extended to create a repeating sequence, as shown below.
Figure 46. A simple repeating sequence (Source: File > Examples > plcLib > SequentialFunctionChart >
RepeatingSwitchSequence)
The system powers up in the start-up step with output Y0 active. Pressing X0 activates Step 1, then
inputs X1, X2 and X3 cause a repeating progression through Steps 1 – 3, with outputs Y1 – Y3 activated,
respectively.
Note: Program listings have been omitted in the remainder of this section in the interests of brevity, but
are available from the Examples section in the Arduino IDE, with plcLib installed.
Figure 47. Activating several steps simultaneously with a parallel branch (Source: File > Examples > plcLib
> SequentialFunctionChart > ParallelSwitchBranch)
The Start step is initially active with output Y0 enabled. Pressing input X0 simultaneously activates
Steps 1 – 3, displaying outputs Y1 – Y3.
Figure 48. A simultaneous convergence following a parallel branch (Source: File > Examples > plcLib >
SequentialFunctionChart > ParallelSwitchBranchConverge)
A selective branch allows a multiple choice decision to be made in which a single step is activated from a
range of possible options, as shown below.
Figure 49. A selective branch activates a single step from a range of options (Source: File > Examples >
plcLib > SequentialFunctionChart > SelectiveSwitchBranch)
The next section discusses the use of delays to produce time-based sequences, and the development of
simple SFC-based applications.
19 Developing Timed SFC-based Applications
The previous section introduced basic concepts related to Sequential Function Charts (SFCs), but with
transitions between steps initiated by switch presses. This section introduces the use of on-delay
timers to produce timed transitions between steps, and then develops some simple SFC-based
applications.
An existing switch-based transition may be converted to a time-based equivalent simply by replacing the
switch transition with an on-delay timer, as shown in the following program extract.
in(START); // Read Start-up state
timerOn(DELAY0, 2000); // 2 second delay
set(STEP1); // Activate Step 1
reset(START); // Cancel Start-up state
In this case, the Start-up state is automatically set to 1 after the computer is switched-on or reset. This
enables the timer, which begins counting (using the DELAY0 user variable). After 2 seconds the timer
output changes to a 1, causing the next step in the sequence to be activated, and the previous step
cancelled.
Connections:
|=========| |------|
| START |----| Y0 |
|=========| |------|
|
-|-- DELAY0 = 2000 (ms)
|
|----|----| |------|
| STEP1 |----| Y1 |
|---------| |------|
|
-|-- DELAY1 = 4000 (ms)
|
|----|----| |------|
| STEP2 |----| Y2 |
|---------| |------|
The Start step is active when the system is switched-on or reset, displaying Y0
Step 1 becomes active after 2 seconds, displaying Y1
After a further 4 seconds Step 2 becomes active, displaying Y2
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
// Do state transitions
in(STEP1);
out(Y1); // Send to Output 1
in(STEP2);
out(Y2); // Send to Output 2
}
Listing 37. A Simple Timed Sequence (Source: File > Examples > plcLib > SequentialFunctionChart >
SimpleTimedSequence)
Having covered the main elements of sequential function charts, following sections develop some
simple SFC-based applications.
Figure 53. A (UK) traffic light sequence for a single set of lights.
Connections:
Output - Red LED connected to output Y0 (Arduino pin 3)
Output - Amber LED connected to output Y1 (Arduino pin 5)
Output - Green LED connected to output Y2 (Arduino pin 6)
Output - Blue LED connected to output Y3 (Arduino pin 9)
|=========| |---------------|
| START |----| -- -- -- Y3 | (Blue)
|=========| |---------------|
|
-|-- DELAY0 = 2000 (ms)
|
|------>------|
| |
| |----|----| |---------------|
| | STEP1 |----| Y0 -- -- -- | (Red)
| |---------| |---------------|
| |
| -|-- DELAY1 = 2000 (ms)
| |
| |----|----| |---------------|
| | STEP2 |----| Y0 Y1 -- -- | (Red + Amber)
| |---------| |---------------|
| |
| -|-- DELAY2 = 2000 (ms)
| |
| |----|----| |---------------|
| | STEP3 |----| -- -- Y2 -- | (Green)
| |---------| |---------------|
| |
| -|-- DELAY3 = 5000 (ms)
| |
| |----|----| |---------------|
| | STEP4 |----| -- Y1 -- -- | (Amber)
| |---------| |---------------|
| |
| -|-- DELAY4 = 2000 (ms)
| |
|------<------|
The system begins in the start-up state, proceeding to Red after 2 seconds
Red is displayed for 2 seconds
Red and Amber are displayed for 2 seconds
Green is displayed for 5 seconds
Amber is displayed for 2 seconds , after which operation resumes at the Red step
Step (Variable) Red (Y0) Amber (Y1) Green (Y2) Blue (Y3) Duration (Variable)
0 (START) - - - X 2000 ms (DELAY0)
1 (STEP1) X - - - 2000 ms (DELAY1)
2 (STEP2) X X - - 2000 ms (DELAY2)
3 (STEP3) - - X - 5000 ms (DELAY3)
4 (STEP4) - X - - 2000 ms (DELAY4)
1
2 etc.
*/
// Define step names
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
// Do timed step transitions
}
Listing 38. UK Traffic Lights (Source location: File > Examples > plcLib > Applications>
SingleTrafficLight)
Notice the use of combinational logic instructions toward the end of the above listing, to create a
'mapping' between sequence steps and the outputs generated. Hence the Red LED is displayed if Step 1
or 2 is active, Amber is shown during Steps 2 or 4, and so on. This same technique is used in the next
example.
Connections:
Output - Red LED connected to output Y0 (Arduino pin 3)
Output - Amber LED connected to output Y1 (Arduino pin 5)
Output - Green LED connected to output Y2 (Arduino pin 6)
Output - Blue LED connected to output Y3 (Arduino pin 9)
|=========| |---------------|
| START |----| -- -- -- -- |
|=========| |---------------|
|
-|-- DELAY0 = 200 (ms)
|
|------>------|
| |
| |----|----| |---------------|
| | STEP1 |----| Y0 -- -- -- |
| |---------| |---------------|
| |
| -|-- DELAY1 = 200 (ms)
| |
| |----|----| |---------------|
| | STEP2 |----| Y0 Y1 -- -- |
| |---------| |---------------|
| |
| -|-- DELAY2 = 200 (ms)
| |
| |----|----| |---------------|
| | STEP3 |----| -- Y1 Y2 -- |
| |---------| |---------------|
| |
| -|-- DELAY3 = 200 (ms)
| |
| |----|----| |---------------|
| | STEP4 |----| -- -- Y2 Y3 |
| |---------| |---------------|
| |
| -|-- DELAY4 = 200 (ms)
| |
| |----|----| |---------------|
| | STEP5 |----| -- -- -- Y3 |
| |---------| |---------------|
| |
| -|-- DELAY5 = 200 (ms)
| |
| |----|----| |---------------|
| | STEP6 |----| -- -- -- -- |
| |---------| |---------------|
| |
| -|-- DELAY6 = 1000 (ms)
| |
| |----|----| |---------------|
| | STEP7 |----| -- -- -- Y3 |
| |---------| |---------------|
| |
| -|-- DELAY7 = 200 (ms)
| |
| |----|----| |---------------|
| | STEP8 |----| -- -- Y2 Y3 |
| |---------| |---------------|
| |
| -|-- DELAY8 = 200 (ms)
| |
| |----|----| |---------------|
| | STEP9 |----| -- Y1 Y2 -- |
| |---------| |---------------|
| |
| -|-- DELAY9 = 200 (ms)
| |
| |----|----| |---------------|
| | STEP10 |----| Y0 Y1 -- -- |
| |---------| |---------------|
| |
| -|-- DELAY10 = 200 (ms)
| |
| |----|----| |---------------|
| | STEP11 |----| Y0 -- -- -- |
| |---------| |---------------|
| |
| -|-- DELAY11 = 200 (ms)
| |
| |----|----| |---------------|
| | STEP12 |----| -- -- -- -- |
| |---------| |---------------|
| |
| -|-- DELAY12 = 1000 (ms)
| |
|------<------|
The system begins in the Start-up state, proceeding to Step 1 after 0.2 seconds
Steps 1 - 12 are executed in a repeating sequence with delay controlled transitions
Outputs Y0 - Y3 are displayed according to the following table
*/
// Define step names for Sequential Function Chart program
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
// Do timed step transitions
// Display Y0 if step = 1, 2, 10 or 11
in(STEP1); // Read Step 1
orBit(STEP2); // OR with Step 2
orBit(STEP10); // OR with Step 10
orBit(STEP11); // OR with Step 11
out(Y0); // Send to Output 0 (Red)
// Display Y1 if step = 2, 3, 9 or 10
in(STEP2); // Read Step 2
orBit(STEP3); // OR with Step 3
orBit(STEP9); // OR with Step 9
orBit(STEP10); // OR with Step 10
out(Y1); // Send to Output 1 (Amber)
// Display Y2 if step = 3, 4, 8 or 9
in(STEP3); // Read Step 3
orBit(STEP4); // OR with Step 4
orBit(STEP8); // OR with Step 8
orBit(STEP9); // OR with Step 9
out(Y2); // Send to Output 2 (Green)
// Display Y3 if step = 4, 5, 7 or 8
in(STEP4); // Read Step 4
orBit(STEP5); // OR with Step 5
orBit(STEP7); // OR with Step 7
orBit(STEP8); // OR with Step 8
out(Y3); // Send to Output 3 (Blue)
}
Listing 39. Running Light Display (Source: File > Examples > plcLib > Applications >
RunningLightDisplay)
20 Structured Text
Software developed to use the PLC library may incorporate a wide range of standard program
statements, such as variable assignments, calculations and user defined functions, plus a variety of
program structures, including decisions and loops.
Possibilities for coding are largely limited by your imagination – and knowledge of C / C++ programming
of course. There are a few caveats however, so a good understanding of the internal operation of the
plcLib software, and its use of variables, is recommended before attempting to develop your
own structured text programs.
Note: Lots of information related to Arduino programming is available online, including the Arduino
Reference and Examples pages.
if ... else – conditional execution of a main section or an alternative, based on a tested logical
condition
do ... while – repeat a section while a condition is true. (The test is at the end, so this type of
loop always runs at least once, even if the test condition is initially false.)
while – repeat a section while a condition is true. (The test is at the start, so this type of loop
may not run at all if the test is initially false.)
for – repeat a section a fixed number of times, with the loop variable progressing through a
predetermined series of values.
As an example, the following sketch first reads digital input X0. It then uses an if statement, based on
the state of the digital input, to conditionally read an analogue input, using this result to control the
brightness of an LED.
#include <plcLib.h>
LED brightness may be varied using the potentiometer, but only when X0 is pressed.
Previous PWM output is displayed otherwise.
Connections:
Input - switch connected to input X0 (Arduino pin A0)
Input - potentiometer connected to input X1 (Arduino pin A1)
Output - LED connected to output Y0 (Arduino pin 3)
Software and Documentation:
http://www.electronics-micros.com/software-hardware/plclib-arduino/
*/
unsigned int myVar = 0; // Create a user defined variable and set initial value
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
myVar = in(X0); // Read digital Input 0, storing result in user variable
The above sketch allows the brightness of the LED to be varied, but only when the switch is pressed. At
other times, the previously set PWM value is used, in effect acting as a 'programmable' light dimmer.
A range of other examples are available from the same directory as the above example, with each one
illustrating a different control structure.
Note: The C / C++ programming language used by the Arduino (and hence in the examples) is similar, but
not identical, to the Pascal-style programming language described by the appropriate standard (IEC
61131-3).
21 Advanced Concepts
This section explains the internal operation of the plcLib software. An understanding of these concepts is
not necessary for basic programming, but may be useful when developing more advanced applications,
or for understanding why things aren't quite working as you expected.
Figure 54. Each row is scanned in a repeating process as part of the scan cycle.
Each rung of the ladder may be thought of as a parallel process, which receives its own share of the
processor time as the scan cycle repeatedly executes. Hence PLC-based applications demonstrate simple
parallel processing capabilities, but without the need to resort to advanced programming techniques.
For basic operation, the PLC software uses a single variable called scanValue to hold its running
calculation result as each branch is solved. Consider the following code snippet to see how this works for
single bit values:
void loop() {
in(X0); // Read Input 0
out(Y0); // Send to Output 0
}
The single bit input command in(X0) reads digital input pin X0 and stores its result in
the scanValue variable as 1 or 0. A subsequent bit output command out(Y0) simply reads
the scanValue variable and sends this value to digital output pin Y0. This process repeats as each rung of
the ladder diagram is calculated, with scanValue repeatedly initialised, updated and then discarded as
the ladder logic program executes.
The process is similar for an analogue input, which is read from an analogue to digital converter as a 10-
bit value in the range 0-1023 using the inAnalog() command – as illustrated by the following code
snippet.
void loop() {
inAnalog(X0); // Read Analogue Input 0
outPWM(Y0); // Send to Output 0 as PWM waveform
}
The same scanValue variable is used to hold this analogue value, which is not a problem as the variable
is actually an unsigned integer variable type. The plcLib software automatically handles the scaling of
any 'analogue' outputs, so an outPWM() command is scaled to be in the range 0-255 (8-bit binary),
while an outServo() command would use a value scaled in the range 0-179 (representing 180° of
rotation).
The next section explains how the above mentioned scanValue variable may be used, and discusses
possible applications of user-created variables in sketches.
Connections:
Input - potentiometer connected to input X0 (Arduino pin A0)
Output - servo connected to output Y0 (Arduino pin 3)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
servo1.attach(Y0); // Attaches Servo 1 to Output 0
}
void loop() {
inAnalog(X0); // Read potentiometer connected to input 0
outServo(servo1); // Output to Servo 1 (connected to Output 0)
}
As an alternative to the above approach, plcLib instructions may optionally return the
current scanValue value to a previously defined user variable (which is only accurate at that specific
point in the scan cycle). The content of a user defined variable may also be used as an 'input' to a plcLib
command, in place of direct input or output from a named pin. The following example illustrates some
of the possibilities.
#include <plcLib.h>
Latch Command with Variables - Latch command using variables to hold temporary values
Connections:
Input - Set - switch connected to input X0 (Arduino pin A0)
Input - Reset - Switch connected to input X1 (Arduino pin A1)
Output - Q Output - LED connected to output Y0 (Arduino pin 3)
*/
// Temporary Variables:
unsigned int AUX0; // Latch output variable
unsigned int AUX1; // Latch reset variable
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
AUX1 = in(X1); // AUX1 (Reset) controlled by input X1
Things to notice above are the saving of the scanValue variable in a user defined variable (AUX1 =
in(X1);), and also the use of variable names in place of pin names in other plcLib commands.
Just remember to specify your user defined integer-type variables as either unsigned integer (16-bit)
or unsigned long (32-bit) to avoid confusion between user variables and pin names.
Connections:
Input - switch connected to input X0 (Arduino pin A0)
Input - switch connected to input X1 (Arduino pin A1)
Input - switch connected to input X2 (Arduino pin A2)
Input - switch connected to input X3 (Arduino pin A3)
Output - LED connected to output Y0 (Arduino pin 3)
*/
unsigned int AUX0; // AUX0 variable holds top rung temporary result
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
// Solve first branch
in(X0); // Read Input 0
andNotBit(X1); // AND with inverted Input 1
out(AUX0); // Use auxiliary variable AUX0 to store first branch result
An alternative to the 'user variable' approach discussed above is the application of block
logic commands, which is discussed in the next section.
22 Stack-based Storage and Logic
Version 1.0 of the plcLib software adds the ability to create and use a software-based stack for
temporary storage and retrieval of single-bit values. This capability may be combined with block
logic commands, to simplify the solution of complex networks based on Boolean algebra – but without
the need to create individual user variables for temporary storage, as discussed previously.
A stack is a special area of memory which may be used for temporary data storage and retrieval.
Information is stored by being pushed onto the stack and is later retrieved by popping from the stack.
The most recently stored information is always the first to be removed, so the stack acts as a last-in,
first-out store.
A useful analogy to aid understanding of stack-based data storage and retrieval is a pile of plates, where
each plate represents a single piece of information. Storing data is equivalent to adding a new plate to
the top of the pile, which causes the 'stack' of plates to grow higher. Conversely, information is retrieved
by removing a plate. The most recently added plate will always be at the top, and the oldest at the
bottom.
The first step when writing a stack-based sketch is to use the Stack command to create a stack object.
(For example, the command Stack stack1; creates a stack called stack1, capable of holding up to 32
single-bit numbers.) Values may be added or removed from the stack by using
the push() or pop() methods of the previously created stack object. The following sketch demonstrates
the use of the stack to store and subsequently retrieve a series of single bit values.
#include <plcLib.h>
Connections:
Input - switch connected to input X0 (Arduino pin A0)
Input - switch connected to input X1 (Arduino pin A1)
Input - switch connected to input X2 (Arduino pin A2)
Input - switch connected to input X3 (Arduino pin A3)
Output - LED connected to output Y0 (Arduino pin 3)
Output - LED connected to output Y1 (Arduino pin 5)
Output - LED connected to output Y2 (Arduino pin 6)
Output - LED connected to output Y3 (Arduino pin 9)
*/
Stack stack1; // Create a single-bit stack with 32 levels
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
The ability to store temporary calculation results on the stack may be used to simplify the solution of
complex logic networks. Options are available to combine parallel or series branches by using block-
based logical AND and OR operations, as discussed in the next section.
X0 X1
----| |--------| |----
| | Y0
----- -----( )-----
| X2 X3 |
----| |--------| |----
Connections:
Input - switch connected to input X0 (Arduino pin A0)
Input - switch connected to input X1 (Arduino pin A1)
Input - switch connected to input X2 (Arduino pin A2)
Input - switch connected to input X3 (Arduino pin A3)
Output - LED connected to output Y0 (Arduino pin 3)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
}
Listing 45. Performing a logical OR of two parallel switch branches using Block OR instruction
(Source: File > Examples > plcLib > Stack > OrBlock)
A similar technique may be applied with series connections of switch groups, which may be combined
using an AND Block.
Figure 57. A Block-AND may be used to solve a complex network consisting of series elements.
The following example first calculates the result of the switch group at the left, which is stored as an
intermediate result on the stack. The right hand block is then solved and combined with the earlier
result by using the andBlock() method of the stack object.
#include <plcLib.h>
Logical AND of two series switch groups using Block AND instruction
X0 X2
----| |---- ----| |----
| | | | Y0
----- ------------- -----( )-----
| X1 | | X3 |
----| |---- ----| |----
Connections:
Input - switch connected to input X0 (Arduino pin A0)
Input - switch connected to input X1 (Arduino pin A1)
Input - switch connected to input X2 (Arduino pin A2)
Input - switch connected to input X3 (Arduino pin A3)
Output - LED connected to output Y0 (Arduino pin 3)
*/
void setup() {
setupPLC(); // Setup inputs and outputs
}
void loop() {
}
Listing 46. Logical AND of two series switch groups using Block AND instruction (Source: File >
Examples > plcLib > Stack > AndBlock)
The next section discusses methods of creating custom input/output allocations, should the standard
configuration be unsuitable.
23 Defining Custom IO Allocations
In some cases, the default input output configuration may not be suitable. A custom I/O allocation may
be appropriate if additional inputs or outputs are needed, custom hardware is being used, or if a
different pin naming convention is preferred.
Arduino Uno and Mega with default pin configurations (Uno, Mega)
Use of custom pin names and user defined variable names (CustomIO)
If the supplied configurations are unsuitable, then you may need to create your own from scratch, as
discussed next.
Figure 58. The Velleman Input/Output Shield for Arduino offers a useful range of inputs an outputs.
The module provides a total of eighteen IO connections, arranged as six analogue inputs, six digital
inputs, and six relay-based digital outputs. Further details of connection and internal wiring details are
available in the manual and datasheet.
The first task is to choose a suitable naming convention for inputs and outputs, and identify the
associated pin connections.
Digital inputs will be allocated names D0–D5, linked to Arduino pins 2, 3, 4, 5, 6 and 7.
Relay outputs will be called R0–R5, using pins 8, 9, 10, 11, 12 and 13.
The following sketch begins by disabling the definition of default pin names (X0, X1, ..., Y0, Y1, ...) using
the command #define noPinDefs, and then specifies the required pin names as a series of integer
constants.
#define noPinDefs // Disable default pin definitions (X0, X1, ..., Y0, Y1, ...)
#include <plcLib.h> // Load the PLC library
Connections:
6 digital inputs D0-D5 (Arduino pins 2, 3, 4, 5, 6 and 7)
6 analogue inputs A0-A5 (connected to the same Arduino pins)
6 relay outputs R0-R5 (Arduino pins 8, 9, 10,11, 12 and 13)
Note: outPWM() and outServo() commands should not be used with this
board due to the use of mechanical switch-based relay outputs.
*/
void setup() {
customIO(); // Setup inputs and outputs for Velleman IO Shield
} // (See IO tab for details)
The customIO() function is used (in place of the standard setupPLC() function) to define data directions
for all inputs and outputs as shown in the following program extract (available by clicking the IO tab of
the sketch).
void customIO (){
pinMode(A0, INPUT);
pinMode(A1, INPUT);
pinMode(A2, INPUT);
pinMode(A3, INPUT);
pinMode(A4, INPUT);
pinMode(A5, INPUT);
Names for the digital inputs and relay outputs must be defined globally, by defining them
outside of the setup() { ... } and loop() { ... } sections, hence making them available for use
anywhere within the sketch.
Pin names and allocations will not change so are defined as constants rather than variables.
The plcLib software requires pin names to be defined of signed integer type (i.e. 'int' rather than
'unsigned int'), for reasons discussed earlier, in the Using Variables in Programs section
24 Strengths and Limitations of the Software
The plcLib software is freely available, and allows simple PLC-style programs to be developed on low
cost Arduino compatible hardware. As such it offers an affordable entry point for those wishing to
develop control-oriented software applications, or to use the Arduino for related educational purposes.
Commands are written as extensions to the C/C++ programming language, and hence make use of a
C/C++ compatible command syntax. Programs may be designed using ladder diagram, function block
diagram, sequential function chart, or structured text, but must be entered into the Arduino IDE in a
text-only format, commonly known as instruction list. However, this process becomes easier with
practice, and is aided by the availability of examples.
While the command syntax is not identical to any particular manufacturer, it should be straightforward
to transfer existing knowledge between systems, or to compare operation of a given feature against the
appropriate standard (IEC 61131).
The following points may be useful when deciding whether or not to use a plcLib-based solution in a
particular situation.
The ladder logic approach is particularly effective when implementing systems which can easily
be represented using a ladder diagram, block diagram, or sequence-based system. These
systems often involve performing a significant number of tasks in parallel, which is a particular
strength. For other systems most easily represented using a flowchart, or similar, then a
traditional programming approach may be more effective. In some cases it may be possible to
use a combination of these approaches, perhaps making use of structured text.
The scan cycle will inevitably slow down as more parallel tasks are added. Care should always be
taken to ensure that the system response time is adequate for the system being controlled.
The system may in some circumstance require several passes of the scan cycle to complete
complex calculations, and intermediate results or 'glitches' may briefly occur at this time. In
addition, outputs are updated at each step in the scan cycle (not just at the end). You should
test programs carefully to ensure that any intermediate results will not affect the correct
operation of the system.
In general, you should avoid using the delay() command in ladder logic programs, as this halts
the scan cycle for the duration of the time delay (software debugging is an exception, where the
aim may be to deliberately slow down the scan cycle). If time-based operation is required then
consider using a timer command such as timerOn(), timerOff(), timerPulse() or timerCycle(), as
these use an interrupt driven approach which does not affect the scan cycle.
25 Command Reference
This page lists all commands supported by the plcLib software.
Notes
1. setupPLC() is an optional command which configures data directions for the default set of inputs
and outputs, together with initial output values, as discussed in the Configuring the
Hardware section. This command is typically omitted if a custom input/output allocation is being
used, as discussed in the Defining Custom IO Allocations section.
2. The #define noPinDefs option, which is available with Version 1.2 or later, prevents creation and
configuration of standard inputs and outputs (X0, X1, X2, ..., Y0, Y1, Y2, ...). If used, this setting
must appear before the inclusion of the PLC library.
in(X0);
Performing Boolean
andBit(input); Logical AND with a digital input. andBit(X1);
Operations
out(Y0);
in(X0);
Performing Boolean
orBit(input); Logical OR with a digital input. orBit(X1);
Operations
out(Y0);
in(X0);
Performing Boolean
xorBit(input); Logical XOR with a digital input. xorBit(X1);
Operations
out(Y0);
in(X0);
Logical AND with an inverted digital Performing Boolean
andNotBit(input); andNotBit(X1);
input. Operations
out(Y0);
in(X0);
Logical OR with an inverted digital Performing Boolean
orNotBit(input); orNotBit(X1);
input. Operations
out(Y0);
Notes:
1. To create a NAND or NOR function, start with the appropriate AND / OR example above,
replacing the out() command with outNot().
2. AND- and OR-based examples may be extended to have more than two inputs, if required.
3. Methods of solving complex (multiple branch) logic circuits are discussed in the Using Variables
in Programs and Stack-based Storage and Logic sections.
Notes
1. Analogue input values are in the range 0–1023 (based on a standard 10-bit A–D converter).
Output values are automatically scaled to match the output type (0–255 for PWM or 0–180° for
a servo.)
2. The outServo() command requires the Arduino Servo library. The associated function must be
locally defined, as explained in the Working with Analogue Signals section.
Notes
1. To compare an analogue input with a fixed threshold, replace the input parameter of the
compare command with a user specified variable of type 'unsigned int', and assigned a value in
the range
0–1023.
25.6 Latches
Command Description Example Section
in(X0);
latch(latch_output, Latches the previous digital input Latching
latch(Y0, X1);
reset_input); value. Outputs
latchKey(set_key, reset_key, Latches a digital output based on latchKey('1', '2', Inputting from a
output); keypad entry. Y0); Keypad
in(X0);
Latches (sets) a digital output if the Latching
set(latch_output); set(Y0);
previous value is true. Outputs
in(X0);
Clears (unsets) a latched output if Latching
reset(latch_output); reset(Y0);
the previous value is true. Outputs
Notes
1. The latchKey() command requires the Keypad library. The associated function must be locally
defined, as explained in the Inputting from a Keypad section.
25.7 Timers
Command Description Example Section
in(X0);
Produces a delayed timerOn(TIMER0, 2000); Using Time
timerOn(timer_variable,
output after an input is
delay_ms); out(Y0); Delays
enabled.
in(X0);
in(X0);
Notes
1. Elapsed timer variables should be defined of type unsigned long (e.g. unsigned long TIMER0 =
0;).
2. The timerPulse() command is available with Version 1.0 or later of the plcLib software.
3. The timerPulse() command is modified in Version 1.1 to be edge triggered, rather than level
triggered. This prevents the timer from being automatically re-triggered if the trigger input is
still high when the fixed width pulse finishes.
in(X0);
Connects an input signal to the pulse Edge Triggered
pulse_name.inClock(); pulse1.inClock();
object. Pulses
pulse1.rising();
Edge Triggered
pulse_name.rising(); Read rising edge of pulse waveform1. out(Y0);
Pulses
pulse1.falling();
pulse_name.falling(); Edge Triggered
Read falling edge of pulse waveform1. out(Y1);
Pulses
Notes
1. Pulses generated by rising or falling edges are active for a single scan cycle only.
25.9 Counters
Command Description Example Section
counter_name(preset_value Counting
Creates and configures a Counter ctr1(5);
and
[, direction]); counter object1. Counter ctr2(10,1);
Counters
Counting
Counts up, if count is in(X0);
counter_name.countUp(); 2, 3 and
less than preset value . ctr1.countUp();
Counters
Counting
Counts down, if count is in(X0);
counter_name.countDown(); and
greater than zero2, 3. ctr1.countDown();
Counters
Counting
Returns the preset
counter_name.presetValue(); Serial.println(ctr1.presetValue()); and
value.
Counters
Notes
1. A newly created counter object is configured with a preset value (upper count limit) specified by
the first parameter. If a single parameter is supplied, or the optional second parameter is 0, then
the initial count value is set to 0, which is suitable for an up counter. A non-zero second
parameter value causes the internal count value to be set to the preset value, which is
effectively the start position for a down counter.
2. A debounced switch input, provided by an on-delay timer, may be used to prevent multiple
triggering when connecting a switch to a counter input.
3. The countUp, countDown, preset, and clear counter methods are conditionally enabled by the
result of the previous instruction, which will often be produced by reading a switch.
4. Counter commands are available with Version 0.8 or later of the plcLib software.
Shifting
Creates and and
Shift shift1();
Shift register_name([start_value]); configures a shift Rotating
Shift shift2(0x8888);
register object1. Binary
Data
Shifting
Sets the serial input and
in(X0);
register_name.inputBit(); bit based on the Rotating
shift1.inputBit();
previous input. Binary
Data
in(X1); Shifting
register_name.shiftLeft(); Shifts data one
and
place to the left, on shift1.shiftLeft();
Rotating
the rising edge of Binary
the previous input. Data
Shifting
Returns the value of
and
the shift register bit shift1.bitValue(0);
register_name.bitValue(bit_position); Rotating
at the specified out(Y0);
Binary
position.
Data
Shifting
Returns the value of
and
the shift register as Serial.println(shift1.value());
register_name.value(); Rotating
an unsigned delay(200);
Binary
integer2.
Data
Notes
1. Shift registers have a fixed data width of 16 bits. A newly created shift register object has a
default value of 0x0000 if no parameter is specified, or a start value specified by the first
parameter in the range 0X0000–0XFFFF.
2. The ability to read the shift register value is useful when debugging shift register applications.
3. Shift register commands are available with Version 0.9 or later of the plcLib software.
25.11 Stack and Block Logic
Command Description Example Section
Stack-based
Stack stack_name; Creates a single-bit, 32-level stack. Stack stack1; Storage and
Logic
Stack-based
Pushes the scanValue, expressed as a
stack_name.push(); stack1.push(); Storage and
single-bit number, onto the stack.
Logic
Stack-based
Updates the scanValue with a single-
stack_name.pop(); stack1.pop(); Storage and
bit value removed from the stack.
Logic
Notes
1. Stack-based commands are available with Version 1.0 or later of the plcLib software.
26 Frequently Asked Questions
Q1. I've installed the software. What next?.
A1. If you have successfully installed the plcLib library then a set of example programs should be
available by selecting File > Examples > plcLib > ... from the pull-down menu of the Arduino IDE.
Examples are arranged into folders which are related to the different sections of the User Guide. (If
these are not found, then see the Installing the Software section of the User Guide.)
Figure 60. GUI-based modelling of a latch circuit with normal and inverted outputs.
A useful approach is to logically separate or ‘decouple’ the testing of hardware and software. One way
to do this is to test your hardware connections using the simplest possible test application (something
like the plcLib version of the BareMinimum sketch works well). Once you know the hardware is working,
then proceed to testing and debugging the software.
As a rule, it is better to start with a simple working system, and progressively add to it, testing as you go,
rather than 'dive straight in' with a complex combination of software and hardware.
27 Revision History
Brief details of all published versions is given below.
Version 1.2: Published 21st Dec, 2015. Added improved ability to define custom pin names and
optionally disable the default pin configuration through the “#define noPinDefs” setting.
Provided a range of custom input/output configurations in the File > Examples > CustomIO
menu area. Supported hardware now includes Industrial Shields Ardbox and M-Duino PLCs (10
variants), Controllino PLCs (3 variants), Seeedstudio Grove shields (Uno and Mega), Arduino
(Uno and Mega), Tinkerkit shields (Uno and Mega) and the Velleman IO shield. Modified
operation of TimerOn, TimerPulse, TimerOff, and TimerCycle commands to operate correctly
during millis() command rollover, which occurs every 49.7 days after power-on or reset. (Test
sketches for each command are given in the File > Examples >TimeDelays > TimerRolloverTest
menu section.) Updated user documentation.
Version 1.1: Published 16th May, 2015. Added single shot (edge triggered) pulse inputs triggered
by low to high and high to low transitions of an input waveform. Modified the timerPulse
command to wait for the input to go low before being re-triggered. (This now agrees with the
standard behaviour in IEC standard 61131-3.). Updated the library format to be compatible with
Arduino IDE 1.5+ (while remaining compatible with earlier versions).
Version 1.0: Published 26th December, 2014. Added stack-oriented commands (push, pop,
andBlock, orBlock). Added a pulse generator command (timerPulse). Added support
for unsigned long user variables in addition to unsigned int.
Version 0.7: Published 31st August, 2014. Added set() and reset() latch commands. Added
analogue comparison commands. Added sequential function charts. Renamed timerPulse()
command as timerCycle() to better reflect its operation as a cycle timer. Updated user
documentation and added several new sections.
Version 0.51: Published 23rd June, 2013. Minor corrections (mostly typos).
Notes:
1. The most recent version of the plcLib software is always available from the Installing the
Software section of the User Guide.
2. Incremental versions, 0.1, 0.2, 0.3, etc. add new functionality, while minor bug fixes and
enhancements are indicated using an extra digit,such as 0.11, 0.12, 0.13
3. Pre-release versions of the software may be available from the author's GitHub page.