
INTRODUCTION
============

LDmicro generates native code for certain Microchip PIC16 and Atmel AVR
microcontrollers. Usually software for these microcontrollers is written
in a programming language like assembler, C, or BASIC. A program in one
of these languages comprises a list of statements. These languages are
powerful and well-suited to the architecture of the processor, which
internally executes a list of instructions.

PLCs, on the other hand, are often programmed in `ladder logic.' A simple
program might look like this:

   ||                                                                    ||
   ||    Xbutton1           Tdon           Rchatter           Yred       ||
 1 ||-------]/[---------[TON 1.000 s]-+-------]/[--------------( )-------||
   ||                                 |                                  ||
   ||    Xbutton2           Tdof      |                                  ||
   ||-------]/[---------[TOF 2.000 s]-+                                  ||
   ||                                                                    ||
   ||                                                                    ||
   ||                                                                    ||
   ||    Rchatter            Ton             Tnew           Rchatter     ||
 2 ||-------]/[---------[TON 1.000 s]----[TOF 1.000 s]---------( )-------||
   ||                                                                    ||
   ||                                                                    ||
   ||                                                                    ||
   ||------[END]---------------------------------------------------------||
   ||                                                                    ||
   ||                                                                    ||

(TON is a turn-on delay; TOF is a turn-off delay. The --] [-- statements
are inputs, which behave sort of like the contacts on a relay. The
--( )-- statements are outputs, which behave sort of like the coil of a
relay. Many good references for ladder logic are available on the Internet
and elsewhere; details specific to this implementation are given below.)

A number of differences are apparent:

    * The program is presented in graphical format, not as a textual list
      of statements. Many people will initially find this easier to
      understand.

    * At the most basic level, programs look like circuit diagrams, with
      relay contacts (inputs) and coils (outputs). This is intuitive to
      programmers with knowledge of electric circuit theory.

    * The ladder logic compiler takes care of what gets calculated
      where. You do not have to write code to determine when the outputs
      have to get recalculated based on a change in the inputs or a
      timer event, and you do not have to specify the order in which
      these calculations must take place; the PLC tools do that for you.

LDmicro compiles ladder logic to PIC16 or AVR code. The following
processors are supported:
    * PIC16F877
    * PIC16F628
    * PIC16F876
    * PIC16F88
    * PIC16F819
    * PIC16F887
    * PIC16F886
    * PIC16F72
    * PIC12F675
    * PIC12F683
    * PIC16F1512
    * PIC16F1516
    * PIC16F1527
    * PIC10F202
    * PIC10F200
    * ATmega128
    * ATmega64
    * ATmega162
    * ATmega32
    * ATmega32U4
    * ATmega16
    * ATmega8
    * ESP8266
    * STM32
    * "PASCAL Code" for PC LPT and COM
    * and a lot of...

It would be easy to support more AVR or PIC16 chips, but I do not have
any way to test them. If you need one in particular then contact me and
I will see what I can do.

Using LDmicro, you can draw a ladder diagram for your program. You can
simulate the logic in real time on your PC. Then when you are convinced
that it is correct you can assign pins on the microcontroller to the
program inputs and outputs. Once you have assigned the pins, you can
compile PIC or AVR code for your program. The compiler output is a .hex
file that you can program into your microcontroller using any PIC/AVR
programmer.

LDmicro is designed to be somewhat similar to most commercial PLC
programming systems. There are some exceptions, and a lot of things
aren't standard in industry anyways. Carefully read the description
of each instruction, even if it looks familiar. This document assumes
basic knowledge of ladder logic and of the structure of PLC software
(the execution cycle: read inputs, compute, write outputs).

PLC and safety
    https://github.com/LDmicro/LDmicro/wiki/PLC-and-safety

PLC Cycle Time 0
    https://github.com/LDmicro/LDmicro/wiki/PLC-Cycle-Time-0

ADDITIONAL TARGETS
==================

It is also possible to generate ANSI C code. You could use this with any
processor for which you have a C compiler, but you are responsible for
supplying the runtime. That means that LDmicro just generates source
for a function PlcCycle(). You are responsible for calling PlcCycle
every cycle time, and you are responsible for implementing all the I/O
(read/write digital input, etc.) functions that the PlcCycle() calls. See
the comments in the generated source for more details.

Finally, LDmicro can generate processor-independent bytecode for a
virtual machine designed to run ladder logic code. I have provided a
sample implementation of the interpreter/VM, written in fairly portable
C. This target will work for just about any platform, as long as you
can supply your own VM. This might be useful for applications where you
wish to use ladder logic as a `scripting language' to customize a larger
program. See the comments in the sample interpreter for details.

A new "Controllino Maxi / Ext bytecode" target has been added. It generates
 .xint file interpretable by the LDuino PLC software. Up to now, only
Controllino Maxi PLC is supported. However, as the bytecode is generic, an
adaptation to any other PLC or CPU board could be done. See LDuino source code
for that.

COMMAND LINE OPTIONS
====================

ldmicro.exe is typically run with no command line options. That means
that you can just make a shortcut to the program, or save it to your
desktop and double-click the icon when you want to run it, and then you
can do everything from within the GUI.

If LDmicro is passed a single filename on the command line
(e.g. `ldmicro.exe asd.ld'), then LDmicro will try to open `asd.ld',
if it exists. An error is produced if `asd.ld' does not exist. This
means that you can associate ldmicro.exe with .ld files, so that it runs
automatically when you double-click a .ld file.

If LDmicro is passed command line arguments in the form
`ldmicro.exe /c src.ld dest.hex', then it tries to compile `src.ld',
and save the output as `dest.hex'. LDmicro exits after compiling,
whether the compile was successful or not. Any messages are printed
to the console. This mode is useful only when running LDmicro from the
command line.


BASICS
======

If you run LDmicro with no arguments then it starts with an empty
program. If you run LDmicro with the name of a ladder program (xxx.ld)
on the command line then it will try to load that program at startup.
LDmicro uses its own internal format for the program; it cannot import
logic from any other tool.

If you did not load an existing program then you will be given a program
with one empty rung. You could add an instruction to it; for example
you could add a set of contacts (Instruction -> Insert Contacts) named
`Xnew'. `X' means that the contacts will be tied to an input pin on the
microcontroller. You could assign a pin to it later, after choosing a
microcontroller and renaming the contacts. The first letter of a name
indicates what kind of object it is.  For example:

    * Xname -- tied to an input pin on the microcontroller
    * Yname -- tied to an output pin on the microcontroller
    * Rname -- `internal relay': a bit in memory
    * Tname -- a timer; turn-on delay, turn-off delay, or retentive
    * Cname -- a counter, either count-up or count-down
    * Aname -- an integer read from an A/D converter
    * Pname -- tied to an PWM output pin on the microcontroller
    * Mname -- tied to a MODBUS Coil output
    * Iname -- tied to a MODBUS Discrete input
    * Hname -- tied to a MODBUS Holding register
    * name  -- a general-purpose (integer) variable

    Variable name that begins with symbol '#' like
    #PORTA, #PORTB, #PORTC, ... treated as output hardware port.
    Variable name that begins with symbol '#' like
    #PINA, #PINB, #PINC, ... treated as input hardware port.
    Variable name that begins with symbol '#' like
    #TRISA, #TRISB, #TRISC, ... treated as data direction register of corresponding ports
    #PORTA, #PORTB, #PORTC, ...
    Note: Address PORTn and PINn are equals for PIC's.

    The variable name that begins with a '#' character and subsequent a number
    (commonly a hexadecimal) treated as immediate address of hardware register.
    Value like #0xXXXX is immediate, direct, explicit addressing.
    For example:
    #0x8E treated as the address of the hardware PCON register
      of the microcontroller Microchip PIC16F628.
    #0x136 treated as the address of the hardware UDR3 register
      (USART3 I/O Data Register) of the microcontroller Atmel ATmega2560.

    The variable name that begins with a '#' character and subsequent as
    a general-purpose variable name treated as the indirect address of hardware register.
    Value like #VarName is the indirect address of hardware register (Indirect Address Pointer).
    For example:
      {MOV  portAddr:=}    portAddr is a general-purpose variable containing the value 0x05.
    --{           0x05}--

      {MOV #portAddr:=}    #portAddr treated as the indirect address of the register #0x05 PORTA (Microchip PIC16F887).
    --{           0xF0}--  Output pins PORTA are set to a binary value of 11110000.

      {ADD  portAddr:=}    The general-purpose portAddr variable now has a value of 0x06.
    --{portAddr  +   1}--

      {MOV #portAddr:=}    #portAddr treated as the indirect address of the register #0x06 PORTB (Microchip PIC16F887).
    --{           0x0F}--  Output pins PORTB are set to a binary value of 00001111.
    * Wiki: LDmicro indirect addressing
      https://github.com/LDmicro/LDmicro/wiki/LDmicro-indirect-addressing

    Be careful with writing to the hardware registers by immediate address access.
    See how to access to SPI thru the hardware registers.
    * Wiki: SPI: Serial Peripheral Interface
      https://github.com/LDmicro/LDmicro/wiki/SPI:-Serial-Peripheral-Interface


Choose the rest of the name so that it describes what the object does,
and so that it is unique within the program. The same name always refers
to the same object within the program. For example, it would be an error
to have a turn-on delay (TON) called `Tdelay' and a turn-off delay (TOF)
called `Tdelay' in the same program, since each counter needs its own
memory. On the other hand, it would be correct to have a retentive timer
(RTO) called `Tdelay' and a reset instruction (RES) associated with
`Tdelay', since it that case you want both instructions to work with
the same timer.

Variable names can consist of letters, numbers, and underscores '_'.
A variable name must not start with a number. Variable names are
case-sensitive.

The general variable instructions (MOV, ADD, EQU, etc.) can work on
variables with any name. This means that they can access timer and
counter accumulators. This may sometimes be useful; for example, you
could check if the count of a timer is in a particular range.

Variables are always 16 bit integers. This means that they can go
from -32768 to 32767. Variables are always treated as signed.

UPDATED: Release 4.3.0
Variables can allocate 1,2,3 or 4 bytes. You can change size of variable by
double-clicking the variable name in the list at the bottom of the screen.
Variables are stored and processed in the two's complement form.
See https://en.wikipedia.org/wiki/Two%27s_complement

Bytes    Types       Range from                   to
 1   signed int8   -2^7 =       -128=0x80        2^7 -1=       127=0x7f
 2   signed int16  -2^15=     -32768=0x8000      2^15-1=     32767=0x7fff
 3   signed int24  -2^23=   -8388608=0x800000    2^23-1=   8388607=0x7fFFFF
 4   signed int32  -2^31=-2147483648=0x80000000  2^31-1=2147483647=0x7fffFFFF

The decimal zero value (0) is represented as all zeros bits 00...000
The decimal value (-1) represented as all  11...111

Signed int8 variables are used for make the hex file smaller and faster.
Signed int24 and int32 types are used to upsize range of variables.
Sign extension for variables of different sizes are provided automatically.
Note: MUL, DIV, MOD instructions can't processed int32 variables.

The arithmetic Overflow(underflow) flag is provided as internal relay ROverflowFlagV.
https://en.wikipedia.org/wiki/Overflow_flag
https://www.allaboutcircuits.com/textbook/digital/chpt-2/binary-overflow/
The Overflow flag indicates that the signed two's-complement result would
not fit in the number of bits used for the operation, and signals an error.
For example, if variable int8 dest = 127(0x7f) add 1, we get -128(0x80),
and Overflow flag ROverflowFlagV will be set to 1.
Instead if variable int16 dest = 127(0x007f) add 1, we get 128(0x0080),
and Overflow flag ROverflowFlagV is not affected.
LDmicro resets the ROverflowFlagV to zero during initialization.
Note: CTC generate overfill(carry) impulse when Counter==Max.
      CTR generate overfill(borrow) impulse when Counter==Min.
      Overfill do not set the Overflow flag.

The Overlap flag is provided as the output state of ADD, SUB operations.
The Overlap flag indicates that sign of result has been changed.
For example, Overlap occured when -1(0xf..f) add 1(or sub -1), we get 0(0x0..0),
all ones 1 are changed to all zeros 0.
Also, Overlap occured when 0(0x0..0) sub 1(or add -1), we get -1(0xf..f),
all zeros 0 are changed to all ones 1.
For example, Overlap occured when -10 add 15(or sub -15), we get 5,
negative source are changed to positive result.
Also, Overlap occured when 10 sub 15(or add -15), we get -5,
positive source are changed to negative result.
END UPDATES: Release 4.3.0

You can specify literals as normal decimal numbers (10, 1234, -56).
You can also specify ASCII character values ('A', 'z') by putting
the character in single-quotes. You can use an ASCII character code
in most places that you could use a decimal number.
You can use hexadecimal numbers (0xA, 0x04D2, 0xffc8),
octal numbers (0o12, 0o2322, 0o177710),
binary numbers (0b1010, 0b10011010010, 0b1111111111001000)
in most places that you could use a decimal number.
LDmicro used the C prefixes:
0x__ or 0X__ for hexadecimal numbers with 1234567890ABCDEF digits
0o__ or 0O__ or 0__ octal numbers with 01234567 digits
0b__ or 0B__ for binary numbers with 01 digits.
Hexadecimals, binary notation is more comfortable for bitwise oparetions.

At the bottom of the screen you will see a list of all the objects in
the program. This list is automatically generated from the program;
there is no need to keep it up to date by hand. Most objects do not
need any configuration. `Xname', `Yname', and `Aname' objects must be
assigned to a pin on the microcontroller, however. First choose which
microcontroller you are using (Settings -> Microcontroller). Then assign
your I/O pins by double-clicking them on the list.

You can modify the program by inserting or deleting instructions. The
cursor in the program display blinks to indicate the currently selected
instruction and the current insertion point. If it is not blinking then
press <Tab> or click on an instruction. Now you can delete the current
instruction, or you can insert a new instruction to the right or left
(in series with) or above or below (in parallel with) the selected
instruction. Some operations are not allowed. For example, no instructions
are allowed to the right of a coil.

The program starts with just one rung. You can add more rungs by selecting
Insert Rung Before/After in the Logic menu. You could get the same effect
by placing many complicated subcircuits in parallel within one rung,
but it is more clear to use multiple rungs.

Once you have written a program, you can test it in simulation, and then
you can compile it to a HEX file for the target microcontroller.


SIMULATION
==========

To enter simulation mode, choose Simulate -> Simulation Mode or press
<Ctrl+M>. The program is shown differently in simulation mode. There is
no longer a cursor. The instructions that are energized show up bright
red; the instructions that are not appear greyed. Press the space bar to
run the PLC one cycle. To cycle continuously in real time, choose
Simulate -> Start Real-Time Simulation, or press <Ctrl+R>. The display of
the program will be updated in real time as the program state changes.

You can set the state of the inputs to the program by double-clicking
them in the list at the bottom of the screen, or by double-clicking an
`Xname' contacts instruction in the program. If you change the state of
an input pin then that change will not be reflected in how the program
is displayed until the PLC cycles; this will happen automatically if
you are running a real time simulation, or when you press the space bar.


COMPILING TO NATIVE CODE
========================

Ultimately the point is to generate a .hex file that you can program
into your microcontroller. First you must select the part number of the
microcontroller, under the Settings -> Microcontroller menu. Then you
must assign an I/O pin to each `Xname' or `Yname' object. Do this by
double-clicking the object name in the list at the bottom of the screen.
A dialog will pop up where you can choose an unallocated pin from a list.

Then you must choose the cycle time that you will run with, and you must
tell the compiler what clock speed the micro will be running at. These
are set under the Settings -> MCU Parameters... menu. In general you
should not need to change the cycle time; 10 ms is a good value for most
applications. Type in the frequency of the crystal that you will use
with the microcontroller (or the ceramic resonator, etc.) and click okay.

Now you can generate code from your program. Choose Compile -> Compile,
or Compile -> Compile As... if you have previously compiled this program
and you want to specify a different output file name. If there are no
errors then LDmicro will generate an Intel IHEX file ready for
programming into your chip.

Use whatever programming software and hardware you have to load the hex
file into the microcontroller. Remember to set the configuration bits
(fuses)! For PIC16 processors, the configuration bits are included in the
hex file, and most programming software will look there automatically.
For AVR processors you must set the configuration bits by hand.


PULL UP RESISTORS
=================
Pull up resistors
https://github.com/LDmicro/LDmicro/wiki/Pull-up-resistors

All input pins try to set Pull-up registers by default.
From Release 5.3.0.4 added menu Settings->Set Pull-up input resistors.

Disable Pull up resistors (Obsolete but possible)
https://github.com/LDmicro/LDmicro/wiki/Disable-Pull-up-resistors

Pull down resistors
https://github.com/LDmicro/LDmicro/wiki/Pull-down-resistors


INSTRUCTIONS REFERENCE
======================

    Terminology:
    "Level sensitive" = output(element) controlled by the level of the input.
    "Edge triggered" = output changes only at the point in time
    when the input changes from value to the other. Can be positive
    edge-triggered (0 to 1), or negative edge-triggered (1 to 0).
    Most elements of LDmicro are "Level sensitive", some elements are
    "positive edge-triggered".

> CONTACT, NORMALLY OPEN        Xname           Rname          Yname
                             ----] [----     ----] [----    ----] [----

    If the signal going into the instruction is false, then the output
    signal is false. If the signal going into the instruction is true,
    then the output signal is true if and only if the given input pin,
    output pin, or internal relay is true, else it is false. This
    instruction can examine the state of an input pin, an output pin,
    or an internal relay.


> CONTACT, NORMALLY CLOSED      Xname           Rname          Yname
                             ----]/[----     ----]/[----    ----]/[----

    If the signal going into the instruction is false, then the output
    signal is false. If the signal going into the instruction is true,
    then the output signal is true if and only if the given input pin,
    output pin, or internal relay is false, else it is false. This
    instruction can examine the state of an input pin, an output pin,
    or an internal relay. This is the opposite of a normally open contact.

    HOW TO: The AND, OR, XOR logic operations on CONTACTs inputs
    See https://github.com/LDmicro/LDmicro/wiki/HOW-TO:-The-AND,-OR,-XOR-logic-operations-on-CONTACTs-inputs

> COIL, NORMAL                  Rname           Yname
                             ----( )----     ----( )----

    If the signal going into the instruction is false, then the given
    internal relay or output pin is cleared false. If the signal going
    into this instruction is true, then the given internal relay or output
    pin is set true. It is not meaningful to assign an input variable to a
    coil. This instruction must be the rightmost instruction in its rung.
    Level sensitive.


> COIL, NEGATED                 Rname           Yname
                             ----(/)----     ----(/)----

    If the signal going into the instruction is true, then the given
    internal relay or output pin is cleared false. If the signal going
    into this instruction is false, then the given internal relay or
    output pin is set true. It is not meaningful to assign an input
    variable to a coil.  This is the opposite of a normal coil. This
    instruction must be the rightmost instruction in its rung.
    Level sensitive.


> COIL, SET-ONLY                Rname           Yname
                             ----(S)----     ----(S)----

    If the signal going into the instruction is true, then the given
    internal relay or output pin is set true. Otherwise the internal
    relay or output pin state is not changed. This instruction can only
    change the state of a coil from false to true, so it is typically
    used in combination with a reset-only coil. This instruction must
    be the rightmost instruction in its rung.
    You can simply present as a trigger with the SET level sensitive input.


> COIL, RESET-ONLY              Rname           Yname
                             ----(R)----     ----(R)----

    If the signal going into the instruction is true, then the given
    internal relay or output pin is cleared false. Otherwise the
    internal relay or output pin state is not changed. This instruction
    instruction can only change the state of a coil from true to false,
    so it is typically used in combination with a set-only coil. This
    instruction must be the rightmost instruction in its rung.
    You can simply present as a trigger with the RESET level sensitive input.


> COIL, T-TRIGGER               Rname           Yname
                             ----(T)----     ----(T)----

    A coil T-trigger is edge-triggered flip-flop (toggle, tip-over, turn over).
    A coil flip-flop every rising edge of the input condition (i.e.
    what the input condition goes from false to true).
    If rising edge detected, then if coil state is false it is sets true.
    If next rising edge detected then if coil state is true it is sets to false.
    This instruction must be the rightmost instruction in its rung.
    You can simply present as a T-trigger with the positive
    edge-triggered input.

Note: The several coils with the same 'YName' or 'RName' can be mentally
    represented as one microchip with multiple inputs and one output.
    Normal and inverted input are directly transfers the input state (normal or
    inverted) to the output every time in every PLC cycle.
    R, S, T inputs lock up (latch) the state of output.
    The T input is positive edge triggered. R, S inputs are level sensitive.
    If before R, S insert the "OSR: ONE-SHOT RISING" or
    "OSF: ONE-SHOT FALLING" you get a "positive edge triggered" element.
    If used only the R and S inputs you get classic RS-trigger.
    If add T input you get "newest" RST-trigger. May be several R..R inputs,
    or several S..S inputs. You can use any combination of inputs for one 'YName'
    or 'RName' coil.
    https://github.com/LDmicro/LDmicro/wiki/COIL


> TURN-ON DELAY                 Tdon
                           -[TON 1.000 s]-

    When the signal going into the instruction goes from false to true,
    the output signal stays false for 1.000 s before going true. When the
    signal going into the instruction goes from true to false, the output
    signal goes false immediately. The timer is reset every time the input
    goes false; the input must stay true for 1000 consecutive milliseconds
    before the output will go true. The delay is configurable.

    The `Tname' variable counts up from zero in units of scan times. The
    TON instruction outputs true when the counter variable is greater
    than or equal to the given delay. It is possible to manipulate the
    counter variable elsewhere, for example with a MOV instruction.


              logic
              level
                   ^  The duration of the input pulse
                   |  must be longer than 1s
           TON     |     _________
           input   | ___/         \_______
                   |    |         |
                   |    | 1s      |
                   |    |<-->|    |
                   |         |    |
                   |         v    v
           TON     |          ____
           output  | ________/    \_______
                 --+---------------------------> time,s
                   |


> TURN-OFF DELAY                Tdoff
                           -[TOF 1.000 s]-

    When the signal going into the instruction goes from true to false,
    the output signal stays true for 1.000 s before going false. When
    the signal going into the instruction goes from false to true,
    the output signal goes true immediately. The timer is reset every
    time the input goes false; the input must stay false for 1000
    consecutive milliseconds before the output will go false. The delay
    is configurable.

    The `Tname' variable counts up from zero in units of scan times. The
    TON instruction outputs true when the counter variable is greater
    than or equal to the given delay. It is possible to manipulate the
    counter variable elsewhere, for example with a MOV instruction.


              logic
              level
                   ^  The duration of the input pulse must be
                   |     longer than the PLC cycle
           TOF     |        _
           input   | ______/ \_________
                   |       | |
                   |       | | 1s
                   |       | |<-->|
                   |       |      |
                   |       v      v
           TOF     |        ______
           output  | ______/      \____
                 --+----------------------> time,s
                   |


> TIMER HIGH                    Thi
                           -[THI 1.000 s]-

    When the signal going into the instruction goes from false to true,
    the output signal is true during 1.000 s. The delay is configurable.
    The output signal is reset after 1.000 s, the internal timer counter
    is reset after 1.000 s and if the input is false.


              logic
              level
                   ^  The duration of the input pulse must be
                   |     longer than the PLC cycle
           THI     |     _           ________
           input   | ___/ \_________/        \_______
                   |    |           |
                   |    | 1s        | 1s
                   |    |<-->|      |<-->|
                   |    |    |      |    |
                   |    v    v      v    v
           THI     |     ____        ____
           output  | ___/    \______/    \___________
                 --+------------------------------------> time,s
                   |


> TIMER LOW                     Tlo
                          -o[TLO 1.000 s]-

    When the signal going into the instruction goes from true to false,
    the output signal is false during 1.000 s. The delay is configurable.
    The output signal is set true after 1.000 s, the internal timer counter
    is reset after 1.000 s and if the input is true.


              logic
              level
                   ^  The duration of the input pulse must be
                   |     longer than the PLC cycle
           TLO     | ___   _________          _______
           input   |    \_/         \________/
                   |    |           |
                   |    | 1s        | 1s
                   |    |<-->|      |<-->|
                   |    |    |      |    |
                   |    v    v      v    v
           TLO     | ___      ______      ___________
           output  |    \____/      \____/
                 --+------------------------------------> time,s
                   |

    See https://github.com/LDmicro/LDmicro/wiki/TON,-TOF,-etc.


> RETENTIVE TIMER               Trto
                           -[RTO 1.000 s]-

    This instruction keeps track of how long its input has been true(HI).
    If its input has been true for at least 1.000 s, then the output is
    true. Otherwise the output is false. The input need not have been
    true for 1000 consecutive milliseconds; if the input goes true
    for 0.6 s, then false for 2.0 s, and then true for 0.4 s, then the
    output will go true. After the output goes true it will stay true
    even after the input goes false, as long as the input has been true
    for longer than 1.000 s. This timer must therefore be reset manually,
    using the reset instruction.

    The `Tname' variable counts up from zero in units of scan times. The
    TON instruction outputs true when the counter variable is greater
    than or equal to the given delay. It is possible to manipulate the
    counter variable elsewhere, for example with a MOV instruction.


              logic
              level
                   ^  The total duration of HI input pulses is more than 1s
                   |  t1+t2+..+tn >= 1s
                   |
           RTO     |     __     _    _________
           input   | ___/  \___/ \__/         \________
                   |    |  |   | |  |
                   |    |t1|   | |  |tn                   Trto
                   |    |<>|  >|-|< |<>|                  RESET
                   |           t2      |                  |
                   |                   v                  v
           RTO     |                    __________________
           output  | __________________/                  \___
                 --+-------------------------------------------> time,s
                   |


> RETENTIVE TIMER LOW           Trtl
                          -o[RTL 1.000 s]-

    RTL works like RTO, but catch low level input.
    This instruction keeps track of how long its input has been false(LOW).
    If its input has been false for at least 1.000 s, then the output is
    true. Otherwise the output is false.
    After the output goes true it will stay true even after the input
    goes true. This timer must therefore be reset manually,
    using the reset instruction.


              logic
              level
                   ^  The total duration of LOW input is more than 1s
                   |  t1+t2+..+tn >= 1s
                   |
           RTL     | ___    ___   __           ________
           input   |    \__/   \_/  \_________/
                   |    |  |   | |  |
                   |    |t1|   | |  |tn                   Trtl
                   |    |<>|  >|-|< |<>|                  RESET
                   |           t2      |                  |
                   |                   v                  v
           RTL     |                    __________________
           output  | __________________/                  \___
                 --+-------------------------------------------> time,s
                   |


> CYCLIC TIMER                Tmeander
                           -[TCY 500 ms]-

    If input signal is true, this instruction produce meander with
    period (500ms+500ms) = 1s and frequency 1 Hz. If the signal going into
    the instruction is false, then the output signal is false.

    If Tmeander value = PLC cycle time, the TCY is equal to OSC.


              logic
              level
                   ^  The duration of the input pulse is longer than 1 s
           TCY     |     ______________________
           input   | ___/                      \_______
                   |    |                      |
                   |    |  1s    1s    1s      |
                   |    |<--->|<--->|<--->|    |
                        |     |     |     |    v
           TCY     |    v   __|   __|   __|   _
           output  | ______/  \__/  \__/  \__/ \_______
                 --+----------------------------------------> time,s
                   |


> TON, TOF, THI, TLO, RTO, RTL, TCY timers      Ton
                                           -[TON value]-

    Updated in release 4.4.1.0
    You can use a general variable as timer delay.
    You must calculate the proper(correct) value of the variable according to
    the PLC Cycle Time.
    Timer delay (ms) = Tplc (ms) * Delay value
   ||                                                       ||
   ||                                             Adc       ||
   ||-----------------------------------------{READ ADC}----||
   ||                                                       ||
   ||                                                       ||
   ||       X1               T1                   Y1        ||
   ||-------] [-----------[TON Adc]---------------( )-------||
   ||                                                       ||


> TIME to COUNTER converter         Tconst
                               -[T2CNT 10 ms]-

    The 'TIME to COUNTER converter' instruction gets the constant time in ms,
    converts it to the timers(TON,TOF,...)-specific value and
    saves it in the Tconst variable for use in counters later.
    See https://github.com/LDmicro/LDmicro/wiki/TIME-to-COUNTER-converter


> RESET                        Trto             Citems
                           ----{RES}----     ----{RES}----

    This instruction resets a timer or a counter. TON and TOF timers are
    automatically reset when their input goes false or true, so RES is
    not required for these timers, but possible. RTO timers and
    CTU/CTD counters are not reset automatically, so they must be reset
    by hand using a RES instruction. When the input is true, the counter or
    timer is reset; when the input is false, no action is taken. This
    instruction must  be the rightmost instruction in its rung.
    Note! RES resets only numeric counter inside RTO, CTU/CTD,
    not their outputs!


> RESET                         PWM
                           ----{RES}----

    This instruction disable PWM output and set it to low level.
    Also you can set another PWM base frequency by SET PWM DUTY CYCLE
    after actuation the RESET PWM.

    See SET PWM DUTY CYCLE below.


> DELAY                        1 us
                           ---[DELAY]---

    The DELAY instruction causes a delay in us. DELAY instruction does not
    use any timers/counters. The NOP and JMP(Current Address+1) instructions
    are used to make the delay.
    See https://github.com/LDmicro/LDmicro/wiki/DELAY-us


> TIME to DELAY converter          Tconst
                               -[T2DELAY 10 us]-

    The 'TIME to DELAY converter' instruction gets the constant time in 'us',
    converts it to the DELAY-specific value and saves it in the Tconst variable
    for use as a parameter of the DELAY instruction later.


> ONE-SHOT RISING               _     _
                           --[_/ OSR_/ \_]--

    ONE-SHOT at the output if RISING edge in the input.
    This instruction normally outputs false. If the instruction's input
    is true during this scan and it was false during the previous scan
    then the output is true. It therefore generates a pulse one scan
    wide on each rising edge of its input signal, i.e. univibrator. This
    instruction is useful if you want to trigger events off the rising
    edge of a signal.


> ONE-SHOT FALLING            _       _
                           --[ \_OSF_/ \_]--

    ONE-SHOT at the output if FALLING edge in the input.
    This instruction normally outputs false. If the instruction's input
    is false during this scan and it was true during the previous scan
    then the output is true. It therefore generates a pulse one scan
    wide on each falling edge of its input signal, i.e. univibrator. This
    instruction is useful if you want to trigger events off the falling
    edge of a signal.


                              this is
                              input signal
                              v v
                                _     _
                           --[_/ OSR_/ \_]--
                              _       _
                           --[ \_OSF_/ \_]--
                                _   _   _
                           --[_/ ODR \_/ ]--
                              _     _   _
                           --[ \_ODF \_/ ]--

                                    ^   ^
                                    this is
                                    output signal




                     logic
                     level
                          ^  The duration of the input pulse is five cycles
                  OSR, OSF|     _________
                  input   | ___/         \_______
                          |
                  OSR     |     _
                  output  | ___/ \_______________
                          |
                  OSF     |               _
                  output  | _____________/ \_____
                        --+---------------------------> time
                          |
       PLC cycle time beat N+ 0 1 2 3 4 5 6 7 8




                     logic
                     level
                          ^      Single-cycle input pulse
                  OSR, OSF|     _
                  input   | ___/ \_______
                          |
                  OSR     |     _
                  output  | ___/ \_______
                          |
                  OSF     |       _
                  output  | _____/ \_____
                        --+------------------> time
                          |
       PLC cycle time beat N+ 0 1 2 3 4 5 6



> ONE DROP if RISING            _   _   _
                           --[_/ ODR \_/ ]--

    ONE DROP at the output if RISING edge in the input.
    This instruction normally outputs true. If the instruction's input is
    true during this scan and it was false during the previous scan then the
    output is false during one PLC cycle. It therefore generates a low level pulse one scan wide
    on each falling edge of its input signal, i.e. univibrator. This
    instruction is useful if you want to trigger events off the falling edge
    of a signal.
    The input level of this instruction is the same as OSR and
    the output level is the inverse of the OSR.


                     logic
                     level
                          ^  The duration of the input pulse is five cycles
                  ODR     |     _______
                  input   | ___/       \_________
                          |
                  ODR     | ___   _______________
                  output  |    \_/
                        --+---------------------------> time
                          |
       PLC cycle time beat N+ 0 1 2 3 4 5 6 7 8



                     logic
                     level
                          ^      Single-cycle input pulse
                  ODR     |     _
                  input   | ___/ \_________
                          |
                  ODR     | ___   _________
                  output  |    \_/
                        --+------------------> time
                          |
       PLC cycle time beat N+ 0 1 2 3 4 5 6



> ONE DROP if FALLING         _     _   _
                           --[ \_ODF \_/ ]--

    The previous name is ONE-SHOT LOW LEVEL(renamed in v5.4.1.0).
    ONE DROP at the output if FALLING edge in the input.
    This instruction normally outputs true. If the instruction's input is
    false during this scan and it was true during the previous scan then the
    output is false. It therefore generates a low level pulse one scan wide
    on each falling edge of its input signal, i.e. univibrator. This
    instruction is useful if you want to trigger events off the falling edge
    of a signal.
    The input level of this instruction is the same as OSF and
    the output level is the inverse of the OSF.



                     logic
                     level
                          ^  The duration of the input pulse is five cycles
                  ODF     | ___           _______
                  input   |    \_________/
                          |
                  ODF     | ___   _______________
                  output  |    \_/
                        --+---------------------------> time
                          |
       PLC cycle time beat N+ 0 1 2 3 4 5 6 7 8



                     logic
                     level
                          ^      Single-cycle input pulse
                  ODF     | ___   _______
                  input   |    \_/
                          |
                  ODF     | ___   _______
                  output  |    \_/
                        --+------------------> time
                          |
       PLC cycle time beat N+ 0 1 2 3 4 5 6



> OSCILLATOR                       _   _
                           --[OSC_/ \_/ \_]--

                             F=1/(2*Tcycle)


                     logic
                     level
                          ^  The duration of the input pulse is seven cycles
                  OSC     |     ____________
                  input   | ___/            \_______
                          |
                  OSC     |     _   _   _
                  output  | ___/ \_/ \_/ \_____________
                          |
                        --+---------------------------> time
                          |
       PLC cycle time beat N+ 0 1 2 3 4 5 6 7 8


    If input signal is true, this instruction produce meander with
    period (2*PLC cycle time), i.e. multivibrator. If the signal going into
    the instruction is false, then the output signal is false.


> SHORT CIRCUIT, OPEN CIRCUIT
                           ----+----+----      ----+     +----

    The output condition of a short-circuit is always equal to its
    input condition. The output condition of an open-circuit is always
    false. These are mostly useful for debugging, temporary short the
    circuit or break an electrical circuit.

    See more https://github.com/LDmicro/LDmicro/wiki/OPEN-CIRCUIT,-SHORT-CIRCUIT
    Note: Be aware.
   || ; The side effect demonstration.                                   ||
   ||                                                          Y1        ||
   ||----------------------------------------------------------( )-------||
   || ; Y1 is 1.                                                         ||
   ||                                                                    ||
   ||                                                          Y1        ||
   ||----+      +----------------------------------------------( )-------||
   || ; COIL element always set output according to it input.            ||
   || ; Y1 is 0 now.                                                     ||
   ||                                                                    ||
   ||                                                          Y1        ||
   ||----------------------------------------------------------( )-------||
   || ; Y1 is 1 again.                                                   ||


> MASTER CONTROL RELAY
                           -{MASTER RLY}-

    By default, the rung-in condition of every rung is true. If a master
    control relay instruction is executed with a rung-in condition of
    false, then the rung-in condition for all following rungs becomes
    false. This will continue until the next master control relay
    instruction is reached (regardless of the rung-in condition of that
    instruction). These instructions must therefore be used in pairs:
    one to (maybe conditionally) start the possibly-disabled section,
    and one to end it.
    See https://github.com/LDmicro/LDmicro/wiki/MASTER-CONTROL-RELAY


> MOVE                      {MOV destvar:=}      {MOV  Tret :=}
                           -{          123}-    -{      srcvar}-

    When the input to this instruction is true, it sets the given
    destination variable equal to the given source variable or
    constant. When the input to this instruction is false nothing
    happens. You can assign to any variable with the move instruction;
    this includes timer and counter state variables, which can be
    distinguished by the leading `T' or `C'. For example, an instruction
    moving 0 into `Tretentive' is equivalent to a reset (RES) instruction
    for that timer. This instruction must be the rightmost instruction
    in its rung.


> ARITHMETIC OPERATION       {ADD  kay  :=}       {SUB  Ccnt :=}
                            -{ 'a' + 10   }-     -{ Ccnt - 10  }-

>                            {MUL  dest :=}       {DIV    dv :=}
                            -{ var * -990 }-     -{ dv / -10000}-

    When the input to this instruction is true, it sets the given
    destination variable equal to the given expression. The operands
    can be either variables (including timer and counter variables)
    or constants. These instructions use 16 bit signed math. Remember
    that the result is evaluated every cycle when the input condition
    true. If you are incrementing or decrementing a variable (i.e. if
    the destination variable is also one of the operands) then you
    probably don't want that; typically you would use a one-shot so that
    it is evaluated only on the rising or falling edge of the input
    condition. Divide truncates; 7 / 3 = 2. This instruction must be
    the rightmost instruction in its rung.


> MODULO                   {MOD     dest:=}
                          -{src     %    2}-

    Remainder of the division 7 % 3 = 1
    See https://en.wikipedia.org/wiki/Modulo_operation


> NEGATIVE                 {NEG     dest:=}
                          -{         - src}-

    Negative -{NEG a:= -a}- is the optimized equivalent to -{SUB a:= 0 - a}-


> BITWISE OPERATION          {AND  var1 :=}       {OR   Ccnt :=}
                            -{var2 & var3 }-     -{ Ccnt | 0o07}-

>                            {XOR  dest :=}       {NOT  dv :=  }
                            -{ var ^ 0xAA }-     -{ ~0b11001100}-

    When the input to this instruction is true, it sets the given
    destination variable equal to the given expression. The operands
    can be either variables (including timer and counter variables)
    or constants. Remember that the result is evaluated every cycle
    when the input condition true.
    Please read http://en.wikipedia.org/wiki/Bitwise_operation


> BITWISE SWAP               {      dest:=}
                            -{SWAP     src}-

    This operation swaps the nibbles and the bytes.
    See https://en.wikipedia.org/wiki/Nibble
    When size of variables is
    1 - then bitwise swap the nibbles in a BYTE, i.e. 0x73 -> 0x37

                     MSB       bits       LSB
                      7  6  5  4  3  2  1  0
                      \________/  \________/
                             ^      ^
                             |      |
                             +------+
        Bits changes:
           7 <-> 3
           6 <-> 2
           5 <-> 1
           4 <-> 0

    2 - then bitwise swap the bytes in a WORD, i.e. 0x7733 -> 0x3377

            MSB                  bits                   LSB
             15 14 13 12 11 10 9 8  7  6  5  4  3  2  1  0
             \___________________/  \____________________/
                             ^           ^
                             |           |
                             +-----------+
        Bits changes:
          15 <-> 7
          14 <-> 6
             ...
           9 <-> 1
           8 <-> 0

    3 - then bitwise swap the nibbles of 1 byte and the bytes 2 and 0 in a INT24, i.e. 0x775A33 -> 0x33A577

       MSB                             bits                          LSB
        23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8 7 6 5 4 3 2 1 0
        \_____________________/ \_________/ \_________/ \_____________/
                    ^                ^           ^             ^
                    |                |           |             |
                    |                +-----------+             |
                    +------------------------------------------+
        Bits changes:
          23 <->  7
             ...
          16 <->  0
          15 <-> 11
             ...
          12 <->  8

    4 - then bitwise swap the bytes 3 and 0  and the bytes 2 and 1 in a DWORD, i.e. 0x7755AA33 -> 0x33AA5577

        MSB                                          bits                                  LSB
        31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
        \_____________________/ \_____________________/ \___________________/ \_____________/
                    ^                            ^           ^                     ^
                    |                            |           |                     |
                    |                            +-----------+                     |
                    +--------------------------------------------------------------+
        Bits changes:
          31 <->  7
             ...
          24 <->  0
          23 <-> 15
             ...
          16 <->  8


> BITWISE OPPOSITE           {      dest:=}
                            -{OPPOSITE src}-

    This operation reverses the bits sequence to the opposite.
    The MSB moves to the LSB, and the LSB moves to the MSB and etc.

                     MSB      bits       LSB
                      n n-1 n-2 ... 2  1  0
                      ^  ^   ^      ^  ^  ^
                      |  |   |      |  |  |
                      |  |   +------+  |  |
                      |  +-------------+  |
                      +-------------------+


> ARITHMETIC SHIFT: SHL, SHR.    {SHL  var1 :=}     {SHR   cnt :=}
                                -{var2 << 2   }-   -{  cnt >>  1 }-

    See https://en.wikipedia.org/wiki/Arithmetic_shift

    SHL - arithmetic left shift
        MSB                    LSB
             MSB-1         1    0
    C <- x <- x <- .... <- x <- x <- 0


    SHR - arithmetic right shift
        MSB                    LSB
             MSB-1         1    0
    /--> x -> x -> .... -> x -> x -> C
    \   /
     <--


    Note: MSB = Most Significant Bit, LSB = Least Significant Bit


> LOGICAL SHIFT TO RIGHT SR0.    {SR0  dest :=}
                                -{var  sr0  3 }-

    See https://en.wikipedia.org/wiki/Logical_shift

    SR0 - logical right shift
        MSB                    LSB
             MSB-1         1    0
    0 -> x -> x -> .... -> x -> x -> C


    NOte: Logical shift to left is equivalent to SHL arithmetic shift to left.


> CIRCULAR SHIFT: ROL, ROR.      {ROL  dest :=}     {ROR    dv :=}
                                -{ var rol 4  }-   -{var ror 4   }-

    See https://en.wikipedia.org/wiki/Circular_shift

    ROL - circular shift (bitwise rotation) left
        MSB                    LSB
             MSB-1         1    0
    C <- x <- x <- .... <- x <- x
         v                      ^
         \_________>____________/


    ROR - circular shift (bitwise rotation) right
        MSB                    LSB
             MSB-1         1    0
         x -> x -> .... -> x -> x -> C
         ^                      v
         \_________<____________/

  SHL, SHR, SR0, ROL, ROR:
    When the input to this instruction is true, it sets the given
    destination variable equal to the given expression. The operands
    can be either variables (including timer and counter variables)
    or constants. Remember that the result is evaluated every cycle
    when the input condition true.


> OPERATIONS WITH ONE BIT   {           var}       {           var}
                           -{SET Bit    bit}-     -{CLR Bit    bit}-

    -{SET Bit var, bit}- In variable 'var' set bit number 'bit'.
    -{CLR Bit var, bit}- In variable 'var' clear bit number 'bit'.

    'Bit' means number of bit, not bit mask. For example,
    to set bit number 4 in variable 'var'
                      v
     Bit numbers:  76543210
     'var'      :  xxx1xxxx
                      ^
    you must write    ^
         {          var}               {             var}
        -{SET Bit     4}-        not  -{SET Bit     0x10}-

    and it is equivalent to
         {OR     var :=}
        -{   var | 0x10}-


    To clear bit number 4 in variable 'var'
    you must write
         {          var}               {             var}
        -{CLR Bit     4}-        not  -{CLR Bit     0x10}-

    and it is equivalent to
         {AND    var :=}
        -{   var & 0xEF}-

    var must be a variable, not a literal value.
    The size of var must be from 1 to 4 bytes.
    bit can be a literal number or a variable.
    bit can have a value of 0-7 if sizeof(var) == 1 byte,
                           0-15 if sizeof(var) == 2 bytes,
                           0-23 if sizeof(var) == 3 bytes,
                           0-31 if sizeof(var) == 4 bytes.

    Learn how to use SetBit(), ClrBit() to Disable Pull up resistors
    https://github.com/LDmicro/LDmicro/wiki/Disable-Pull-up-resistors


> COMPARE               [var ==]        [var >]        [1 >=]
                       -[ var2 ]-      -[ 1   ]-      -[ Ton]-

>                       [var !=]       [-4 <   ]       [1 <=]
                       -[ var2 ]-     -[ vartwo]-     -[ Cup]-

    If the input to this instruction is false then the output is false. If
    the input is true then the output is true if and only if the given
    condition is true. This instruction can be used to compare (equals,
    is greater than, is greater than or equal to, does not equal,
    is less than, is less than or equal to) a variable to a variable,
    or to compare a variable to a 16-bit signed constant.


> TEST STATE OF ONE BIT     [             var]       [             var]
                           -[if Bit SET   bit]-     -[if Bit CLR   bit]-

    If the input to this instruction is false then the output is false. If
    the input is true then the output is true if and only if the given
    condition is true. This instruction can be used to check the state only
    one bit of the variable.
    'Bit' means number of bit, not bit mask. See upper the SET Bit operation.

    Operation -{if Bit SET var, 0}- is equivalent condition 'If var is odd'.
    Operation -{if Bit CLR var, 0}- is equivalent condition 'If var is an even'.

    var must be a variable, not a literal value.
    The size of var must be from 1 to 4 bytes.
    bit can be a literal number or a variable.
    bit can have a value of 0-7 if sizeof(var) == 1 byte,
                           0-15 if sizeof(var) == 2 bytes,
                           0-23 if sizeof(var) == 3 bytes,
                           0-31 if sizeof(var) == 4 bytes.


> COUNTER                      Cname          Cname
                           --[CTU >= 5]--  --[CTD > -5]--

    A counter increments (CTU, count up) or decrements (CTD, count
    down) the associated count on every rising edge of the rung input
    condition (i.e. what the rung input condition goes from false to
    true). The output condition from the counter is true if the counter
    variable CTU >= 5 (CTD > -5), and false otherwise. The
    rung output condition may be true even if the input condition is
    false; it only depends on the counter variable. You can have CTU
    and CTD instructions with the same name, in order to increment and
    decrement the same counter. The RES instruction can reset a counter,
    or you can perform general variable operations on the count variable.


> CIRCULAR COUNTER             Cname             Cname
                           --{CTC 0:7}--     --{CTR 7:0}--

    A circular counter works like a normal CTU counter, except that
    after reaching its upper limit, it resets its counter variable
    back to 0. For example, the counter shown above would count 0, 1,
    2, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, ... This is useful in
    combination with conditional statements on the variable `Cname';
    you can use this like a sequencer. CTC counters clock on the rising
    edge of the rung input condition condition.
    Obsolete: This instruction must be the rightmost instruction in its rung.

    CTR is reversive circular counter. It like CTC but with decrement
    counting inside. For example, the counter shown above would count
    7, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 0, 7, ...

    Added 'Start' value in CTU,CTD,CTC,CTR counters.
    CTU,CTC counter start from 'Start' and count up to 'Max' value.
    CTC generate overfill(carry) impulse when Counter==Max.
    For the proper work 'Start' value should be less than 'Max' value.

    CTD,CTR counter start from 'Start' and count down to 'Min' value.
    CTR generate overfill(borrow) impulse when Counter==Min.
    For the proper work 'Start' value should be more than 'Min' value.

   ||   Rnew      Tnew                                    Rnew      ||
   ||----] [----[TON 1 s]----------------------------------(/)------||
   ||                                                               ||
   ||                                                               ||
   ||   Rnew       Css           Cmm          Chh         Cdays     ||
   ||----] [----[CTC 0:59]---[CTC 0:59]---[CTC 0:23]---[CTC 0:364]--||
   ||                                                               ||

    Updated in release 4.4.1.0
    Kind of inputs of ladder elements
    https://github.com/LDmicro/LDmicro/wiki/Kind-of-inputs-of-ladder-elements

   ||                               ||
   ||  X1          CTU1:0      Y1   ||
   ||--] [---+---/[CTU>=10]----( )--|| '/' Dynamic input active on 0 to 1
   ||        |                      || transition for positive logic.
   ||        |     CTU2:0      Y2   ||
   ||        +---\[CTU>=10]----( )--|| '\' Dynamic input active on 1 to 0
   ||        |                      || transition for positive logic.
   ||        |     CTU3:0      Y3   ||
   ||        +----[CTU>=10]----( )--|| '-' Direct static logic input.
   ||        |                      || Active at external 1.
   ||        |     CTU4:0      Y4   ||
   ||        +---o[CTU>=10]----( )--|| 'o' Inverse static logic input.
   ||                               || Logic negation at input.
   ||                               || External 0 produces internal 1.

    Note: Counters of previous versions has the dynamic input "/".
    These two rungs are equivalent in new release.
   ||                                                   ||
   ||       X1               C1                         ||
   ||-------] [----------/[CTC  0:9]---                 ||
   ||                                                   ||
   ||                                                   ||
   ||       X1             _     _            C2        ||
   ||-------] [---------[_/ OSR_/ \_]------[CTC  0:9]---||
   ||                                                   ||

    '-/' is positive edge-triggered (rising edge) input.
    '-\' is negative edge-triggered (falling edge) input.
    '--' is high level active static input.
    '--' is static input, active at a high level.
    '-o' is static input, active at a low level.


> SHIFT REGISTER            {SHIFT REG   }
                           -{ reg0..3    }-

    A shift register is associated with a set of variables. For example,
    this shift register is associated with the variables `reg0', `reg1',
    `reg2', and `reg3'. The input to the shift register is `reg0'. On
    every rising edge of the rung-in condition, the shift register will
    shift right. That means that it assigns `reg3 := reg2', `reg2 :=
    reg1'. and `reg1 := reg0'. `reg0' is left unchanged. A large shift
    register can easily consume a lot of memory. This instruction must
    be the rightmost instruction in its rung.


> LOOK-UP TABLE             {dest :=     }
                           -{ LUT[i]     }-

    A look-up table is an ordered set of n values. When the rung-in
    condition is true, the integer variable `dest' is set equal to the
    entry in the lookup table corresponding to the integer variable
    `i'. The index starts from zero, so `i' must be between 0 and
    (n-1). The behaviour of this instruction is not defined if the
    index is outside this range. This instruction must be the rightmost
    instruction in its rung.

    See https://github.com/LDmicro/LDmicro/wiki/HOW-TO:-Look-Up-Table,-UART-SEND


> PIECEWISE LINEAR TABLE    {yvar :=     }
                           -{ PWL[xvar]  }-

    This is a good way to approximate a complicated function or
    curve. It might, for example, be useful if you are trying to apply
    a calibration curve to convert a raw output voltage from a sensor
    into more convenient units.

    Assume that you are trying to approximate a function that converts
    an integer input variable, x, to an integer output variable, y. You
    know the function at several points; for example, you might know that

        f(0)   = 2
        f(5)   = 10
        f(10)  = 50
        f(100) = 100

    This means that the points

        (x0, y0)   = (  0,   2)
        (x1, y1)   = (  5,  10)
        (x2, y2)   = ( 10,  50)
        (x3, y3)   = (100, 100)

    lie on that curve. You can enter those 4 points into a table
    associated with the piecewise linear instruction. The piecewise linear
    instruction will look at the value of xvar, and set the value of
    yvar. It will set yvar in such a way that the piecewise linear curve
    will pass through all of the points that you give it; for example,
    if you set xvar = 10, then the instruction will set yvar = 50.

    If you give the instruction a value of xvar that lies between two
    of the values of x for which you have given it points, then the
    instruction will set yvar so that (xvar, yvar) lies on the straight
    line connecting those two points in the table.  For example, xvar =
    55 gives an output of yvar = 75. (The two points in the table are
    (10, 50) and (100, 100). 55 is half-way between 10 and 100, and 75
    is half-way between 50 and 100, so (55, 75) lies on the line that
    connects those two points.)

    The points must be specified in ascending order by x coordinate. It
    may not be possible to perform mathematical operations required for
    certain look-up tables using 16-bit integer math; if this is the
    case, then LDmicro will warn you. For example, this look up table
    will produce an error:

        (x0, y0)    = (  0,   0)
        (x1, y1)    = (300, 300)

    You can fix these errors by making the distance between points in
    the table smaller. For example, this table is equivalent to the one
    given above, and it does not produce an error:

        (x0, y0)    = (  0,   0)
        (x1, y1)    = (150, 150)
        (x2, y2)    = (300, 300)

    It should hardly ever be necessary to use more than five or six
    points. Adding more points makes your code larger and slower to
    execute. The behaviour if you pass a value of `xvar' greater than
    the greatest x coordinate in the table or less than the smallest x
    coordinate in the table is undefined. This instruction must be the
    rightmost instruction in its rung.


> A/D CONVERTER READ           Aname
                           --{READ ADC}--

    LDmicro can generate code to use the A/D converters built in to
    certain microcontrollers. If the input condition to this instruction
    is true, then a single sample from the A/D converter is acquired and
    stored in the variable `Aname'. This variable can subsequently be
    manipulated with general variable operations (less than, greater than,
    arithmetic, and so on). Assign a pin to the `Axxx' variable in the
    same way that you would assign a pin to a digital input or output,
    by double-clicking it in the list at the bottom of the screen. If
    the input condition to this rung is false then the variable `Aname'
    is left unchanged.

    For all currently-supported devices, 0 volts input corresponds to
    an ADC reading of 0, and an input equal to Vdd (the supply voltage)
    corresponds to an ADC reading of 1023. If you are using an AVR, then
    connect AREF to Vdd. You can use arithmetic operations to scale the
    reading to more convenient units afterwards, but remember that you
    are using integer math. In general not all pins will be available
    for use with the A/D converter. The software will not allow you to
    assign non-A/D pins to an analog input. This instruction must be
    the rightmost instruction in its rung.

    Updated: ADC Voltage Reference.
    The reference voltage for the ADC (Vref) indicates the conversion
    range for the ADC. Single-ended channels that exceed Vref will result
    in codes close to 0x3FF(1023). Vref can be selected as either AVCC,
    internal 2.56V reference, internal 1.1V reference, or external Aref pin.
    The parameter REFS=0 is backward compatible with the previous LDmicro releases.

    See https://github.com/LDmicro/LDmicro/wiki/ADC-Voltage-Reference
    https://github.com/LDmicro/LDmicro/wiki/How-to-measure-battery-voltage
    https://github.com/LDmicro/LDmicro/wiki/How-to-measure-voltage-(PIC)


> SET PWM DUTY CYCLE        duty_cycle  3.8 kHz
                          -{PWM            PWM1}-

    LDmicro can generate code to use the PWM peripheral built into
    certain microcontrollers. If the input condition to this instruction
    is true, then the duty cycle of the PWM peripheral is set to the
    value of the variable duty_cycle.
    Updated: LDmicro v4.3.5 allow select higher PWM resolution:
      0-100% (maximum resolution 6.7 bits)
      0-256  (maximum resolution 8 bits)
      0-512  (maximum resolution 9 bits)
      0-1024 (maximum resolution 10 bits)
    The duty cycle must be a number between 0 and 100/256/512/1024;
    0 corresponds to always low, and 100/256/512/1024 corresponds to
    always high. (If you are familiar with how the PWM peripheral works,
    then notice that that means that LDmicro automatically scales the
    duty cycle variable from percent(or binary value) to PWM clock periods.)

    You can specify the target PWM frequency, in Hz. The frequency that
    you specify might not be exactly achievable, depending on how it
    divides into the microcontroller's clock frequency. LDmicro will
    choose the closest achievable frequency; if the error is large then
    it will warn you. Faster speeds(PWM frequency) may sacrifice resolution.

    This instruction must be the rightmost instruction in its rung.
    The ladder logic runtime consumes one timer to measure the cycle
    time. That means that PWM is only available on microcontrollers
    with at least two suitable timers. PWM uses pin CCP2 (not CCP1)
    on PIC16 chips and OC1B (not OC1A) on AVRs.

    Updated: LDmicro v4.x.x allow all hardware PWM.
    See https://github.com/LDmicro/LDmicro/wiki/LDmicro-PWM

    You can set another PWM base frequency only after actuation the RESET PWM.
    See RESET PWM above.



> PULSER                   [PULSER counter         Ypulse]->
                         --[      D1 D0 accel_decel      ]--

> PULSER                   [PULSER 10              Ypulse]->
                         --[       1  1 3                ]--

    PULSER is a software generator, hardware PWM MCU units are not used.
    See https://github.com/LDmicro/LDmicro/wiki/PULSER


> MAKE PERSISTENT            saved_var
                           --{PERSIST}--

    When the rung-in condition of this instruction is true, it causes the
    specified integer variable to be automatically saved to EEPROM. That
    means that its value will persist, even when the micro loses
    power. There is no need to explicitly save the variable to EEPROM;
    that will happen automatically, whenever the variable changes. The
    variable is automatically loaded from EEPROM after power-on reset. If
    a variable that changes frequently is made persistent, then the
    EEPROM in your micro may wear out very quickly, because it is only
    good for a limited (~100 000) number of writes. When the rung-in
    condition is false, nothing happens. This instruction must be the
    rightmost instruction in its rung.

    See https://github.com/LDmicro/LDmicro/wiki/MAKE-PERSISTENT-operation


> UART (SERIAL) RECEIVE          var
                           --{UART RECV}--

    LDmicro can generate code to use the UART built in to certain
    microcontrollers. On AVRs with multiple UARTs only UART1 (not
    UART0) is supported. Configure the baud rate using Settings -> MCU
    Parameters. Certain baud rates may not be achievable with certain
    crystal frequencies; LDmicro will warn you if this is the case.

    If the input condition to this instruction is false, then nothing
    happens. If the input condition is true then this instruction tries
    to receive a single character from the UART. If no character is read
    then the output condition is false. If a character is read then its
    ASCII value is stored in `var', and the output condition is true
    for a single PLC cycle.


> UART (SERIAL) SEND             var
                           --{UART SEND}--

    LDmicro can generate code to use the UARTs built in to certain
    microcontrollers. On AVRS with multiple UARTs only UART1 (not
    UART0) is supported. Configure the baud rate using Settings -> MCU
    Parameters. Certain baud rates may not be achievable with certain
    crystal frequencies; LDmicro will warn you if this is the case.

    If the input condition to this instruction is false, then nothing
    happens. If the input condition is true then this instruction writes
    a single character to the UART. The ASCII value of the character to
    send must previously have been stored in `var'. The output condition
    of the rung is true if the UART is busy (currently transmitting a
    character), and false otherwise.

    Remember that characters take some time to transmit. There are several
    ways to organize the transmission:
    1) Use PLC cycle time, which is knowingly greater than UART transmittion
    time.
   ||                                                    ||
   || ; PLC cycle time is 10 ms.                         ||
   || ; UART baud rate is 9600 bps.                      ||
   ||                                                    ||
   || ; In this case, there is a tenfold time reserve.   ||
   || ; Chars sequence will be transmitted without loss. ||
   ||                                                    ||
   || ; 1 2 3 4 5 6 7 8 9 10 11 12 ...                   ||
   ||                                                    ||
   ||                                   {ADD     char:=} ||
   ||-----------------------------------{char    +    1}-||
   ||                                                    ||
   ||      char                                          ||
   ||---{UART SEND}---                                   ||
   ||                                                    ||

    2) Use timers to insert delays between characters. Timer delay must be
    longer than UART transmission time.
   ||                                                                    ||
   || ; PLC cycle time is 1 ms.                                          ||
   || ; UART baud rate is 9600 bps.                                      ||
   ||                                                                    ||
   || ; In this case, there is a fivefold time reserve.                  ||
   || ; Chars sequence will be transmitted without loss.                 ||
   ||                                                                    ||
   || ; char1 char2 char3   char1 char2 char3   char1 char2 char3   ...  ||
   || ; 1     5     10      2     10    20      3     15    30      ...  ||
   ||                                                                    ||
   ||       T0                                               Rstart      ||
   ||---[TCY 15 ms]--------------------------------------------( )-------||
   ||                                                                    ||
   ||                                                                    ||
   ||     Rstart             T1             _     _     {ADD    char1:=} ||
   ||-------] [----------[RTO 5 ms]------[_/ OSR_/ \_]-+{char1    +   1}-||
   ||                                                  |                 ||
   ||                                                  |      char1      ||
   ||                                                  +---{UART SEND}---||
   ||                                                                    ||
   ||                                                                    ||
   ||     Rstart             T2             _     _     {ADD    char2:=} ||
   ||-------] [----------[RTO 10 ms]-----[_/ OSR_/ \_]-+{char2    +   5}-||
   ||                                                  |                 ||
   ||                                                  |      char2      ||
   ||                                                  +---{UART SEND}---||
   ||                                                                    ||
   ||                                                                    ||
   ||     Rstart             T3             _     _     {ADD    char3:=} ||
   ||-------] [----------[RTO 15 ms]-----[_/ OSR_/ \_]-+{char3   +   10}-||
   ||                                                  |                 ||
   ||                                                  |      char3      ||
   ||                                                  +---{UART SEND}---||
   ||                                                  |                 ||
   ||                                                  |       T1        ||
   ||                                                  +------{RES}------||
   ||                                                  |                 ||
   ||                                                  |       T2        ||
   ||                                                  +------{RES}------||
   ||                                                  |                 ||
   ||                                                  |       T3        ||
   ||                                                  +------{RES}------||
   ||                                                                    ||

    3) Check the output condition of this instruction to ensure that the
    previous character has been transmitted before trying to send a next
    character. You must only bring the input condition true (try to send
    a character) when the output condition is false (UART is not busy).
   ||                                                      ||
   || ; PLC cycle time and UART baud rate are independent  ||
   || ; and can be various.                                ||
   ||                                                      ||
   || ; 1 2 3 4 5 6 7 8 9 10 11 12 ...                     ||
   ||                                                      ||
   ||      Rbusy                          {ADD     DATA:=} ||
   ||-------]/[------+--[_/ OSR_/ \_]-----{DATA    +    1}-||
   ||                |                                     ||
   ||                |      DATA                Rbusy      ||
   ||                +---{UART SEND}-------------( )-------||
   ||                                                      ||


   ||                                                                       ||
   || ; DATA1 DATA2   DATA1 DATA2   DATA1 DATA2   ...                       ||
   || ; 1     10      2     20      3     30      ...                       ||
   ||                                                                       ||
   ||   Rbusy        DATA1       _       _        DATA2          Rbusy      ||
   ||----]/[--+---{UART SEND}---[ \_OSF_/ \_]--{UART SEND}--------( )-------||
   ||         |                                                             ||
   ||         |     _     _                                {ADD    DATA1:=} ||
   ||         +--[_/ OSR_/ \_]-+---------------------------{DATA1    +   1}-||
   ||                          |                                            ||
   ||                          |                           {ADD    DATA2:=} ||
   ||                          +---------------------------{DATA2   +   10}-||
   ||                                                                       ||

    4) Use the 'UART SEND: Is ready ?' instruction before UART SEND to checks
    the UART status.
   ||                                                    ||
   || ; 0 1 2 3 4 5 6 7 8 9 10 11 12 ...                 ||
   ||                                                    ||
   ||    Is ready?          DATA                         ||
   ||---[UART SEND]--+---{UART SEND}---------------------||
   ||                |                                   ||
   ||                |                  {ADD     DATA:=} ||
   ||                +------------------{DATA    +    1}-||
   ||                                                    ||
    See: UART communication FAQ
    https://github.com/LDmicro/LDmicro/wiki/UART-communication-FAQ

    Updated: The UART RECEIVE, UART SEND instructions can receive/send a more
    than one-byte length variables. "Number of bytes to transmit:" parameter
    must be less or equal to the size of the used variable. Value 1 byte is
    compatible with the previous LDmicro version.
    The parameter "Wait until all bytes are transmitted:" controls the algorithm
    of the transmission: if 1 - all bytes are transmitted in one package,
    if 0 - one byte per a PLC cycle. When all bytes are has transmitted,
    the output condition is "true" during one PLC cycle. Value 0 is
    compatible with the previous LDmicro version.
    See: UART communication FAQ part 2
    https://github.com/LDmicro/LDmicro/wiki/UART-communication-FAQ-part-2

    Investigate the formatted string instruction (next) before using this
    instruction. The formatted string instruction is much easier to use,
    and it is almost certainly capable of doing what you want.

    See https://github.com/LDmicro/LDmicro/wiki/HOW-TO:-Look-Up-Table,-UART-SEND


> UART (SERIAL) SENDn             var
                           --{UART SENDn}--

    If the input condition to this instruction is false, then nothing
    happens. If the input condition is true then this instruction writes
    a variable to the UART in raw binary format. One byte sends per cycle
    of PLC, like 'FORMATTED STR OVER UART' element. The output condition
    of the rung is true if the UART is busy (currently transmitting a
    variable), and false otherwise.


> UART SEND: Is ready ?       Is ready?
                           --[UART SEND]--

    If the input condition to this instruction is false, then nothing
    happens. If the input condition is true, then  output is true
    when transmit buffer is empty and ready to loading new data,
    and false otherwise.


> UART RECV: Is avail ?       Is avail?
                           --[UART RECV]--

    If the input condition to this instruction is false, then nothing
    happens. If the input condition is true, then  output is true when
    there are unread data in the receive buffer, and false otherwise.


> FORMATTED STRING OVER UART                var
                                   -{"Pressure: \3\r\n"}-

    LDmicro can generate code to use the UARTs built in to certain
    microcontrollers. On AVRS with multiple UARTs only UART1 (not
    UART0) is supported. Configure the baud rate using Settings -> MCU
    Parameters. Certain baud rates may not be achievable with certain
    crystal frequencies; LDmicro will warn you if this is the case.

    When the rung-in condition for this instruction goes from false to
    true, it starts to send an entire string over the serial port. If
    the string contains the special sequence `\3', then that sequence
    will be replaced with the value of `var', which is automatically
    converted into a string. The variable will be formatted to take
    exactly 3 characters; for example, if `var' is equal to 35, then
    the exact string printed will be `Pressure:  35\r\n' (note the extra
    space). If instead `var' were equal to 1432, then the behaviour would
    be undefined, because 1432 has more than three digits. In that case
    it would be necessary to use `\4' instead.

    If the variable might be negative, then use `\-3d' (or `\-4d'
    etc.) instead. That will cause LDmicro to print a leading space for
    positive numbers, and a leading minus sign for negative numbers.

    If multiple formatted string instructions are energized at once
    (or if one is energized before another completes), or if these
    instructions are intermixed with the UART TX instructions, then the
    behaviour is undefined.

    It is also possible to use this instruction to output a fixed string,
    without interpolating an integer variable's value into the text that
    is sent over serial. In that case simply do not include the special
    escape sequence.

    The rung-out condition of this instruction is true while it is
    transmitting data, else false. This instruction consumes a very
    large amount of program memory, so it should be used sparingly. The
    present implementation is not efficient, but a better one will
    require modifications to all the back-ends.

    Use `\\' for a literal backslash. In addition to the escape sequence
    for interpolating an integer variable, the following control
    characters are available:

         Escape      Hex         Character
         sequence    value       represented

         \a          0x07        BEL, Alert (Beep, Bell)
         \b          0x08        BS, Backspace
         \e          0x1B        Escape character
         \f          0x0C        FF, Formfeed
         \n          0x0A        NL, Newline (Line Feed)
         \r          0x0D        CR, Carriage Return
         \t          0x09        HT, TAB, Horizontal Tab
         \v          0x0B        VT, Vertical Tab
         \'          0x27        Single quotation mark
         \"          0x22        Double quotation mark
         \?          0x3F        Question mark
         \\          0x5C        Backslash
         \xhh        any         The byte whose numerical value is given by
                                 hh: interpreted as a hexadecimal number
                                 from the range 0x00..0xFF(hex), 0..255(dec)
         for example
         \xAB is character with ASCII value 0xAB (hex)

      See https://en.m.wikipedia.org/wiki/Escape_sequences_in_C

    ------------------------------ ASCII Control Codes ---------------------------
    |Dec Hex Ctl  Name Control Meaning      |Dec Hex Ctl  Name Control Meaning
    |--- --- ---  ---- -------------------  |--- --- ---  ---- --------------------
    |  0  00  ^@  NUL  null (end string)    | 16  10  ^P  DLE  data line escape
    |  1  01  ^A  SOH  start of heading     | 17  11  ^Q  DC1  dev ctrl 1 (X-ON)
    |  2  02  ^B  STX  start of text        | 18  12  ^R  DC2  device ctrl 2
    |  3  03  ^C  ETX  end of text          | 19  13  ^S  DC3  dev ctrl 3 (X-OFF)
    |  4  04  ^D  EOT  end of transmission  | 20  14  ^T  DC4  device ctrl 4
    |  5  05  ^E  ENQ  enquiry              | 21  15  ^U  NAK  negative acknowledge
    |  6  06  ^F  ACK  acknowledge          | 22  16  ^V  SYN  synchronous idle
    |  7  07  ^G  BEL  bell               \a| 23  17  ^W  ETB  end transmit block
    |  8  08  ^H  BS   backspace          \b| 24  18  ^X  CAN  cancel
    |  9  09  ^I  HT   TAB horizontal tab \t| 25  19  ^Y  EM   end of medium
    | 10  0a  ^J  LF   line feed          \n| 26  1a  ^Z  SUB  substitute
    | 11  0b  ^K  VT   vertical tab       \v| 27  1b  ^[  ESC  escape
    | 12  0c  ^L  FF   form feed          \f| 28  1c  ^\  FS   file separator
    | 13  0d  ^M  CR   carriage return    \r| 29  1d  ^]  GS   group separator
    | 14  0e  ^N  SO   shift out            | 30  1e  ^^  RS   record separator
    | 15  0f  ^O  SI   shift in             | 31  1f  ^_  US   unit separator


> SPI SEND / RECEIVE            {SPI       SPI}
                               -{->recv send->}-

    SPI functions are only available in 'C' mode, that is via C compiling,
    only for 32-bit ARM and AVR of type AtMega. Only one SPI can be used
    in a same ladder, called SPI, or SPI1, SPI2, SPI3 when there are several
    available on the micro. SPI works only in master mode, 8 bits of data, with
    MSB first, and its frequency is set in the configuration panel of the micro
    in ldmicro. SS pin is handled for AVR but not for ARM. One can use external
    pins to activate / deactivate the slaves on SPI bus, and / or SS pin.
    In a SPI, sending and receiving are simultaneous, that's why both operations
    are combined in only one function.


> SPI WRITE                     {SPI_WR     SPI}
                               -{   "Message"->}-

    Write SPI function sends a string via SPI, without care for incoming data.
    String can contain special chars introduced by \\. Don't abuse of this
    function, because SPI can slow down the program and generate cycle timing
    issues !

    NB:
    SPI functions use external C libraries (furnished) which must be compiled
    with the main C program generated by ldmicro when compiling via ldmicro menus
    < Compile Atmel AVR-GCC > or < Compile ARM-GCC >, followed by a < FlashMCU >
    command to build the .hex executable, and, if well configured, load this
    executable into the AVR or ARM target.


> I2C READ                      {I2C_RD    I2C}
                               -{->recv 0x20 0}-

    I2C functions are only available in 'C' mode, that is via C compiling,
    only for 32-bit ARM and AVR of type AtMega. Only one I2C bus can be used
    in a same ladder, called I2C, or I2C1, I2C2, I2C3 when there are several
    available on the micro. I2C works only in master mode, and can access any
    register (0 based) at any address (1-127) on the I2C bus.
    I2C frequency is set in the configuration panel of the micro.
    I2C READ function reads a byte in a register on the slave at given address.


> I2C WRITE                     {I2C_WR    I2C}
                               -{0x20 0 send->}-

    I2C WRITE function writes a byte in a register on the slave at given address.

    NB:
    I2C functions use external C libraries (furnished) which must be compiled
    with the main C program generated by ldmicro when compiling via ldmicro menus
    < Compile Atmel AVR-GCC > or < Compile ARM-GCC >, followed by a < FlashMCU >
    command to build the .hex executable, and, if well configured, load this
    executable into the AVR or ARM target.


> FORMATTED STRING                          dest
                                       -{"string", var}-

    For targets like Netzer with already present printf implementations
    this instruction can be used.

    When the rung-in condition for this instruction goes from false to
    true, it starts to process the string with printf and writes the result
    to the given dest register.

    It completly embeds the given string into the resulting image.

    The given variable can be any register from the program. It is
    used as placeholder for printf. The printf function accesses
    the register if any printf style placeholder (i.e. %d) is found.

    Dest is a register where the result is written to. This should
    be the top entry of a fifo or circular buffer.

    The rung-out condition of this instruction is always true.


> CLRWDT
                           --{CLRWDT}--

    When the rung-in condition of this instruction is true, it causes the
    clear WDT timer. LDmicro executes CLRWDT command every PLC cycle
    automatically (at begin of the cycle), so you need adiitional CLRWDT
    if PLC cycle period more then WDT period if WDT enabled.
    This instruction must be the rightmost instruction in its rung.


> LOCK
                           --{LOCK}--

    When the rung-in condition of this instruction is true, it causes the
    LOCK command. It is an artificial
    situation to provocation the WDT reset (if WDT enabled). LOCK command
    designed as infinite loop. It is deadlock, way to freeze, blockade the
    program.
    LOCK command executes goto to the current address, i.e.
    labelN: goto labelN (label02: rjmp label02), i.e. infinite loop.
    LOCK command executes the infinite loop, but WDT can reset the MCU.
    Only WDT or external reset can unfreeze the program after LOCK command.


> SLEEP
                           --{SLEEP}--

    When the rung-in condition of this instruction is true,
    the SLEEP (Power-down) mode is setted. It used for power saving
    on battery supply.
    PIC: Wake-up from sleep owing to external interrupt on rising edge of RB0/INT pin.
    PIC10xxxx: Wake-up from sleep on pin change GP0, GP1, GP3.
    AVR: Wake-up from sleep owing to external interrupt on rising edge of PD2/INT0, PD3/INT1 pins.
    SLEEP operation don't affect MCU IO pins and others LDmicro operations.
    Note: SLEEP lengthens the PLC cycle time and timers TON, TOF, RTO, CTY.
    This can frustrate the plans, break the flow of work.
    This instruction must be the rightmost instruction in its rung.


>LABEL, GOTO, SUBPROG, RETURN, ENDSUB, GOSUB

    LABEL and GOTO instruction
    https://github.com/LDmicro/LDmicro/wiki/GOTO-instruction

    SUBPROG, RETURN, ENDSUB and GOSUB, LABEL and GOTO instruction. Part 2
    https://github.com/LDmicro/LDmicro/wiki/SUBPROG,-RETURN,-ENDSUB-and-GOSUB,-LABEL-and-GOTO-instruction.-Part-2

    SUBPROG, RETURN, ENDSUB and GOSUB, LABEL and GOTO instruction. Part 3
    https://github.com/LDmicro/LDmicro/wiki/SUBPROG,-RETURN,-ENDSUB-and-GOSUB,-LABEL-and-GOTO-instruction.-Part-3


> RAND                        Rand
                          --{ RAND }--

    The pseudo-random number generator return the number in the full range
    of 'Rand' variable.
    When the input to this instruction is true, it sets the given
    destination variable 'Rand' with the next pseudo-random number calculated
    by a linear congruential generator (LCG). When the input to this
    instruction is false nothing happens.
    See https://en.m.wikipedia.org/wiki/Linear_congruential_generator
    The generator is defined by the recurrence relation:
    X[n+1] = (a * X[n] + c) mod m
    Used constants from the VMS's MTH$RANDOM, old versions of glibc
    a = 69069 ( 0x10DCD )
    c = 1
    m = 2^32
    X = (X * 0x10DCD + 1) % 0x100000000
    RAND return the most significant bytes of X.
    X stored as $seed_Rand 32 bits variable.


> SRAND                     {SRAND     Rand}
                          --{$seed:=newSeed}--

    The pseudo-random number generator is initialized using the argument
    passed as newSeed.  $seed_Rand := newSeed.
    When the input to this instruction is true, it sets the given
    destination variable $seed_Rand equal to the given source variable or
    constant. When the input to this instruction is false nothing
    happens.
    Two different initializations with the same seed will generate the same
    succession of results in subsequent calls to RAND.
    If seed is set to 1, the generator 'Rand' is reinitialized to its initial
    value and produces the same values as before any call to RAND or SRAND.
    Entropy sources can be ADC, timers, previous RAND saved in EEPROM, etc.

    In this example we have two SEPARATE the pseudo-random number generators LCG.
    But if the newSeed1 equal the newSeed2 then RAnd1 and Rand2 are equal
    sequenses of numbers.
   ||     _    _      {SRAND     Rand1}                       ||
 1 ||--[_/ OSR/ \_]---{$seed:=newSeed1}-                      ||
   ||                                                         ||
   ||      Rand1                                              ||
 0 ||-----{RAND}------                                        ||
   ||                                                         ||
   ||                                                         ||
   ||     _    _      {SRAND     Rand2}                       ||
 0 ||--[_/ OSR/ \_]---{$seed:=newSeed2}-                      ||
   ||                                                         ||
   ||      Rand2                                              ||
 0 ||-----{RAND}------                                        ||
   ||                                                         ||


> 7-SEGMENTS FONT CONVERTER    {7SEG    dest:=}
                             --{C          src}--

    The variable 'dest' gets the value 'abcdefgDP', it controls (highlights)
    the font segments.
    You can use direct access port variable '#PORTx' as the variable 'dest'.
    It can be connected to the anodes (cathodes) of the 7-segments LED module
    thru the current-limiting resistors.

    To turn on (highlights) the "a" LED segment, a high level is required
    on the "a" pin and a low level on the common pin, when a module with
    the common cathode LED connection is used.
    When a module with the common anode connection is used, then to turn on
    the "a" LED segment, the low level is required on the "a" pin and
    the high level is required on the common pin. Use the 'A' parameter instead
    of the 'C' to specify which type of common connection is used.

    7 segments display font
         a
        --
     f|    |b
      |  g |
        --
     e|    |c
      |    |
        -- .
         d  DP

    SEGMENT     DP g f e d c b a
    'dest' BIT   7 6 5 4 3 2 1 0
    DP - is dot segment


    a  --|>|-----+-----+ common Cathodes LED connection
                 |     |
    b  --|>|-----+    ---  connect to the ground
    ...          |
    g  --|>|-----+
                 |
    DP --|>|-----+
                      ^  connect to the power Vcc
                      |
    a  --|<|-----+----+ common Anodes LED connection
                 |
    b  --|<|-----+
    ...          |
    g  --|<|-----+
                 |
    DP --|<|-----+    a,b,...g,DP connect to MCU pins(or buffers)


    The variable 'src'(char) must be in the range of 0..128 and usually has a 1-byte size.
    128 characters of ASCII table codes are implemented.
    The first 16 ASCII chars replased to the hex digits from 0 to F.
    The next  16 ASCII chars replased to the hex digits with dot DP segment on.
    The 129th symbol is a symbol of a degree 'o' for use with a temperature value.
ADDRESS=  0               16(0x10)       31(0x1F)
row+colmn |               |              |  from 0 to 15 - hex digits
  0       0123456789ABCDEF0123456789ABCDEF  from 16 to 31 - hex digits with the dot DP
 32(0x20)  !"#$%&'()*+,-./0123456789:;<=>?
 64(0x40) @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
 96(0x60) `abcdefghijklmnopqrstuvwxyz{|}~
128(0x80) o
          ^
          |_ degree char 0xB0

    ' ' - cpace char 0x20 - blank
    DEL char 0x7F - blank

    See  X-segment LED display, font example
    https://github.com/LDmicro/LDmicro/wiki/X-segment-LED-display,-font-example


> 9-SEGMENTS FONT CONVERTER    {9SEG    dest:=}
                             --{C          src}--
         a
        ---j
     f|   / |b
      |  /  |
        ---g
     e|  /  |c
      | /   |
       m---
         d   DP

    SEGMENT   0 0 m j DP g f e d c b a
    BIT           9 8  7 6 5 4 3 2 1 0
    nibbles  ^        ^       ^       ^
    The size of the variable 'dest' must be at least 2 bytes.


> 14-SEGMENTS FONT CONVERTER   {14SEG   dest:=}
                             --{C          src}--
         a
      h --- j
     f|\ |i/|b
      | \|/ |
     g1-- --g2
     e| /|\ |c
      |/ |l\|
      m --- k
         d   DP

    SEGMENT  0 g2  l  k  i  h  m  j DP g1  f  e  d  c  b  a
    BIT        14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
    nibbles ^          ^           ^           ^           ^
    The size of the variable 'dest' must be at least 2 bytes.


> 16-SEGMENTS FONT CONVERTER   {16SEG   dest:=}
                             --{C          src}--
       a1 a2
      h-- --j
     f|\ |i/|b
      | \|/ |
     g1-- --g2
     e| /|\ |c
      |/ |l\|
      m-- --k
       d1 d2 DP

    SEGMENT   0  0  0 a2 d2 g2  l  k  i  h  m  j DP g1  f  e d1  c  b a1
    BIT               16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
    nibbles  ^          ^           ^           ^           ^           ^
    The size of the variable 'dest' must be at least 3 bytes.


> BUS TRACER                  {BUS    dest:=}
                            --{          src}-

    When routing PCBs, it is often convenient to run the conductors in
    parallel(with minimal conductors crossings) from the microcircuit
    to the MCU, and then software swap the MCU port pins.
    7-SEGMENTS FONT CONVERTER provide bit(PORT) mapping:
    SEGMENTS  -   PORT BITS
    DP        -   7
    g         -   6
    f         -   5
    e         -   4
    d         -   3
    c         -   2
    b         -   1
    a         -   0
    But usually, you need something like this:
    SEGMENTS  -   PORT BITS
    DP        -   6
    g         -   7
    f         -   4
    e         -   5
    d         -   0
    c         -   1
    b         -   2
    a         -   3
    BUS TRACER allow replace bits in no particular order.


> BINARY TO BCD CONVERTER     {BIN2BCD dest:=}
                            --{           src}-

    The 'src' is a binary value with 1,2,3,4 bytes length.
    The 'dest' is unpacked BCD value with 3, 5, 8, 10 bytes length.
    Unpacked: Each numeral is encoded into one byte, with four bits
    representing the numeral and the remaining bits having no significance.
    Decimal  99(0x63) will be converted to the 0x00 09 09 value.
    Decimal 100(0x64) will be converted to the 0x01 00 00 value.
    See https://en.wikipedia.org/wiki/Binary-coded_decimal


> QUADRATURE ENCODER        ~~[XqA0 XqB0            YqDir0]-
                            -\[XqZ0   QUAD ENCOD   qCount0]^-

    The QUADRATURE ENCODER instruction takes two quadrature-encoded signals
    (A and B) from an incremental rotary or linear encoder device.
    See https://en.wikipedia.org/wiki/Incremental_encoder

 logic
 levels               move ->             |            <- move
       ^
       | ___         _______         ___________          _______         ___
Input A|    |_______|       |_______|           |________|       |_______|
       |
       | _______         _______         ___         ________         _______
Input B|        |_______|       |_______|   |_______|        |_______|
       |
       |
Counter|  0 |   | 1 |   | 2 |   | 3 |   | 4 |   | 3 |   | 2 |   | 1 |   | 0
       |
 Output| ___________________________________   decrease or CCW or backward
    Dir|    increase or CW or forward       |________________________________
       |
 Output|
  Pulse| _______^_______^_______^_______^_______^_______^_______^_______^____
       |
     --+----------------------------------------------------------------> time
       |
           '^' - is one PLC Cycle time impulse
    Hint: Use the Output Pulse to determine if the Counter was changed,
    not for counting.

    The QUAD ENCOD instruction can contain 3 or 2 inputs and 1 or 0 output.
    Inputs A and B must be located in same MCU PORT.
    For example, RBx and RBx, not RAx, RBx.
    Input Z is optional and can be empty.
    Output Dir is optional and can be empty.
    Output Dir can be Y (pin) or R (internal relay).

   ||                                                                    ||
   ||       R0        ~~[XqA0 XqB0            YqDir0]-         R1        ||
   ||-------] [--------\[XqZ0   QUAD ENCOD   qCount0]^---------( )-------||
   ||                                                                    ||

    When the rung-in condition R0 of the QUAD ENCOD instruction is false,
    inputs A, B, Z are ignored.
    When the rung-in condition R0 of the QUAD ENCOD instruction is true,
    the pulses at the inputs A, B, Z are decoded into the counter value,
    the output signal Dir is high, when the counter increases and
    a low when the counter is decremented, an output pulse R1 occurs.
    The value of the counter changes when both inputs A and B changes.
    This corresponds to the clock multiplier x2. The frequency of the output
    pulses is twice the frequency of the input pulses A (B).
    The frequency of the input pulses A (B) must be less than the frequency of
    the PLC cycle / 4, otherwise will be losses of input pulses.
    A bounce of the input pulses A (B) must be less than the PLC cycle time / 8.

    Input Z can be dynamic (edge triggered) or static.
    If 'Count per revol' parameter is 0 and the Z input is active, then counter sets to 0.
    If 'Count per revol' parameter is greater than 0 and the Z input is active, then
    the counter will be rounded to a multiple of the 'Count per revol' value.
    If 'Count per revol' parameter is less than 0, then input Z is ignored.


 logic
 levels               move ->
       ^
       | ___         _______         _______         _______         ________
Input A|    |_______|       |_______|       |_______|       |_______|
       |
       | _______         _______         _______         _______         ____
Input B|        |_______|       |_______|       |_______|       |_______|
       |
       |
Input Z| _______________________________________________________/\___________
       |
       |
       |                                     'Count per revol' is 0 (reset the counter)
       |
Counter|  0 |   | 1 |   | 2 |   | 3 |   | 4 |   | 5 |   | 6 |   | 0 |   | 1
       |
       |
       | (there are losses of A,B pulses)   'Count per revol' is 10 (recover the counter)
       |
Counter|  0 |   | 1 |   | 2 |   | 3 |   | 4 |   | 5 |   | 6 |   |10 |   | 11
       |
     --+----------------------------------------------------------------> time
       |

    To simulate the A, B, Z inputs - double-clicking the input name in the list
    at the bottom of the screen.

    See for details https://github.com/LDmicro/LDmicro/wiki/Incremental-QUADRATURE-ENCODER
    Incremental QUADRATURE ENCODER controls the brightness of the LED (PWM out)
    https://github.com/LDmicro/LDmicro/wiki/Incremental-QUADRATURE-ENCODER-controls-the-brightness-of-the-LED-(PWM-out)


A NOTE ON USING MATH
====================

Remember that LDmicro performs only 16-bit integer math. That means
that the final result of any calculation that you perform must be an
integer between -32768 and 32767. It also mean that the intermediate
results of your calculation must all be within that range.

For example, let us say that you wanted to calculate y = (1/x)*1200,
where x is between 1 and 20. Then y goes between 1200 and 60, which
fits into a 16-bit integer, so it is at least in theory possible to
perform the calculation. There are two ways that you might code this:
you can perform the reciprocal, and then multiply:

   ||         {DIV  temp  :=}          ||
   ||---------{ 1 / x       }----------||
   ||                                  ||
   ||          {MUL  y  :=  }          ||
   ||----------{ temp * 1200}----------||
   ||                                  ||

Or you could just do the division directly, in a single step:

   ||           {DIV  y  :=}           ||
   ||-----------{ 1200 / x }-----------||

Mathematically, these two are equivalent; but if you try them, then you
will find that the first one gives an incorrect result of y = 0. That
is because the variable `temp' underflows. For example, when x = 3,
(1 / x) = 0.333, but that is not an integer; the division operation
approximates this as temp = 0. Then y = temp * 1200 = 0. In the second
case there is no intermediate result to underflow, so everything works.

If you are seeing problems with your math, then check intermediate
results for underflow (or overflow, which `wraps around'; for example,
32767 + 1 = -32768). When possible, choose units that put values in
a range of -100 to 100.

When you need to scale a variable by some factor, do it using a multiply
and a divide. For example, to scale y = 1.8*x, calculate y = (9/5)*x
(which is the same, since 1.8 = 9/5), and code this as y = (9*x)/5,
performing the multiplication first:

   ||         {MUL  temp  :=}          ||
   ||---------{ x * 9       }----------||
   ||                                  ||
   ||           {DIV  y  :=}           ||
   ||-----------{ temp / 5 }-----------||

This works for all x < (32767 / 9), or x < 3640. For larger values of x,
the variable `temp' would overflow. There is a similar lower limit on x.


CODING STYLE
============

I allow multiple coils in parallel in a single rung. This means that
you can do things like this:

   ||       Xa               Ya        ||
 1 ||-------] [--------------( )-------||
   ||                                  ||
   ||       Xb               Yb        ||
   ||-------] [------+-------( )-------||
   ||                |                 ||
   ||                |       Yc        ||
   ||                +-------( )-------||
   ||                                  ||

Instead of this:

   ||       Xa               Ya        ||
 1 ||-------] [--------------( )-------||
   ||                                  ||
   ||                                  ||
   ||                                  ||
   ||                                  ||
   ||       Xb               Yb        ||
 2 ||-------] [--------------( )-------||
   ||                                  ||
   ||                                  ||
   ||                                  ||
   ||                                  ||
   ||       Xb               Yc        ||
 3 ||-------] [--------------( )-------||
   ||                                  ||

This means that in theory you could write any program as one giant rung,
and there is no need to use multiple rungs at all. In practice that
would be a bad idea, because as rungs become more complex they become
more difficult to edit without deleting and redrawing a lot of logic.

Still, it is often a good idea to group related logic together as a single
rung. This generates nearly identical code to if you made separate rungs,
but it shows that they are related when you look at them on the ladder
diagram.

                  *                 *                  *

In general, it is considered poor form to write code in such a way that
its output depends on the order of the rungs. For example, this code
isn't very good if both Xa and Xb might ever be true:

   ||       Xa         {v  :=       }  ||
 1 ||-------] [--------{ 12      MOV}--||
   ||                                  ||
   ||       Xb         {v  :=       }  ||
   ||-------] [--------{ 23      MOV}--||
   ||                                  ||
   ||                                  ||
   ||                                  ||
   ||                                  ||
   ||      [v >]             Yc        ||
 2 ||------[ 15]-------------( )-------||
   ||                                  ||

I will break this rule if in doing so I can make a piece of code
significantly more compact, though. For example, here is how I would
convert a 4-bit binary quantity on Xb3:0 into an integer:

   ||                                   {v  :=       }  ||
 3 ||-----------------------------------{ 0       MOV}--||
   ||                                                   ||
   ||       Xb0                  {ADD  v  :=}           ||
   ||-------] [------------------{ v + 1    }-----------||
   ||                                                   ||
   ||       Xb1                  {ADD  v  :=}           ||
   ||-------] [------------------{ v + 2    }-----------||
   ||                                                   ||
   ||       Xb2                  {ADD  v  :=}           ||
   ||-------] [------------------{ v + 4    }-----------||
   ||                                                   ||
   ||       Xb3                  {ADD  v  :=}           ||
   ||-------] [------------------{ v + 8    }-----------||
   ||                                                   ||

If the MOV statement were moved to the bottom of the rung instead of the
top, then the value of v when it is read elsewhere in the program would
be 0. The output of this code therefore depends on the order in which
the instructions are evaluated. Considering how cumbersome it would be
to code this any other way, I accept that.

ABBREVIATIONS
=============
PLC - programmable logic controller.
PWM - pulse width modulation.
ADC - analog-to-digital converter.
PCB - printed circuit board

BUGS
====

LDmicro does not generate very efficient code; it is slow to execute, and
wasteful of flash and RAM. In spite of this, a mid-sized PIC or AVR can
do everything that a small PLC can, so this does not bother me very much.

The maximum length of variable names is highly limited. This is so that
they fit nicely onto the ladder diagram, so I don't see a good solution
to that.

If your program is too big for the time, program memory, or data memory
constraints of the device that you have chosen then you probably won't
get an error. It will just screw up somewhere.

Careless programming in the file load/save routines probably makes it
possible to crash or execute arbitrary code given a corrupt or malicious
.ld file.

Please report additional bugs or feature requests to the author.

Thanks to:
    * Marcelo Solano, for reporting a UI bug under Win98
    * Serge V. Polubarjev, for not only noticing that RA3:0 on the
      PIC16F628 didn't work but also telling me how to fix it
    * Maxim Ibragimov, for reporting and diagnosing major problems
      with the till-then-untested ATmega16 and ATmega162 targets
    * Bill Kishonti, for reporting that the simulator crashed when the
      ladder logic program divided by zero
    * Mohamed Tayae, for reporting that persistent variables were broken
      on the PIC16F628
    * David Rothwell, for reporting several user interface bugs and a
      problem with the "Export as Text" function


COPYING, AND DISCLAIMER
=======================

DO NOT USE CODE GENERATED BY LDMICRO IN APPLICATIONS WHERE SOFTWARE
FAILURE COULD RESULT IN DANGER TO HUMAN LIFE OR DAMAGE TO PROPERTY. THE
AUTHOR ASSUMES NO LIABILITY FOR ANY DAMAGES RESULTING FROM THE OPERATION
OF LDMICRO OR CODE GENERATED BY LDMICRO.

This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.


Jonathan Westhues

Rijswijk      -- Dec 2004
Waterloo ON   -- Jun, Jul 2005
Cambridge MA  -- Sep, Dec 2005
                 Feb, Mar 2006
                 Feb 2007
Seattle WA    -- Feb 2009

Email: user jwesthues, at host cq.cx

LDmicro support:
    LDmicro Forum:  http://cq.cx/ladder-forum.pl
    Latest release: https://github.com/LDmicro/LDmicro/releases
    Repository:     https://github.com/LDmicro/LDmicro
    Email:          LDmicro.GitHub@gmail.com
