summaryrefslogtreecommitdiff
path: root/ldmicro/manual.txt
diff options
context:
space:
mode:
authorakshay-c2019-01-30 12:23:44 +0530
committerakshay-c2019-01-30 12:23:44 +0530
commit4196481f74afb84e5cc59cdf00c06c1ca1becab7 (patch)
treeb531deb0466897691f08f9076b7012592f026664 /ldmicro/manual.txt
downloadLDmicroQt-4196481f74afb84e5cc59cdf00c06c1ca1becab7.tar.gz
LDmicroQt-4196481f74afb84e5cc59cdf00c06c1ca1becab7.tar.bz2
LDmicroQt-4196481f74afb84e5cc59cdf00c06c1ca1becab7.zip
First commit
Diffstat (limited to 'ldmicro/manual.txt')
-rw-r--r--ldmicro/manual.txt969
1 files changed, 969 insertions, 0 deletions
diff --git a/ldmicro/manual.txt b/ldmicro/manual.txt
new file mode 100644
index 0000000..6d7d5e7
--- /dev/null
+++ b/ldmicro/manual.txt
@@ -0,0 +1,969 @@
+
+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 (untested)
+ * PIC16F88 (untested)
+ * PIC16F819 (untested)
+ * PIC16F887 (untested)
+ * PIC16F886 (untested)
+ * ATmega128
+ * ATmega64
+ * ATmega162 (untested)
+ * ATmega32 (untested)
+ * ATmega16 (untested)
+ * ATmega8 (untested)
+
+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).
+
+
+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.
+
+
+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
+ * name -- a general-purpose (integer) variable
+
+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. You can
+specify literals as normal decimal numbers (0, 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.
+
+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.
+
+
+INSTRUCTIONS REFERENCE
+======================
+
+> 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.
+
+
+> 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.
+
+
+> 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.
+
+
+> 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.
+
+
+> 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.
+
+
+> 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.
+
+
+> 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.
+
+
+> RETENTIVE TIMER Trto
+ -[RTO 1.000 s]-
+
+ This instruction keeps track of how long its input has been true. 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.
+
+
+> 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. 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.
+
+
+> ONE-SHOT RISING _
+ --[OSR_/ ]--
+
+ 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. This instruction is
+ useful if you want to trigger events off the rising edge of a signal.
+
+
+> ONE-SHOT FALLING _
+ --[OSF \_]--
+
+ 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. This instruction is
+ useful if you want to trigger events off the falling edge of a signal.
+
+
+> 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.
+
+
+> 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.
+
+
+> MOVE {destvar := } {Tret := }
+ -{ 123 MOV}- -{ srcvar MOV}-
+
+ 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; 8 / 3 = 2. This instruction must be
+ the rightmost instruction in its rung.
+
+
+> 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.
+
+
+> 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 is greater than or equal to 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
+ --{CTC 0:7}--
+
+ 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, 2,.... 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. This instruction must
+ be the rightmost instruction in its rung.
+
+
+> 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.
+
+
+> 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.
+
+
+> SET PWM DUTY CYCLE duty_cycle
+ -{PWM 32.8 kHz}-
+
+ LDmicro can generate code to use the PWM peripheral built in to
+ 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. The duty cycle must be a number
+ between 0 and 100; 0 corresponds to always low, and 100 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 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 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 OC2 (not OC1A) on AVRs.
+
+
+> 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.
+
+
+> 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. Check the output
+ condition of this instruction to ensure that the first character has
+ been transmitted before trying to send a second character, or use
+ a timer to insert a delay between characters. You must only bring
+ the input condition true (try to send a character) when the output
+ condition is false (UART is not busy).
+
+ 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.
+
+
+> 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.
+
+ Use `\\' for a literal backslash. In addition to the escape sequence
+ for interpolating an integer variable, the following control
+ characters are available:
+ * \r -- carriage return
+ * \n -- newline
+ * \f -- formfeed
+ * \b -- backspace
+ * \xAB -- character with ASCII value 0xAB (hex)
+
+ 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.
+
+
+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.
+
+
+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
+
+