ladder logic for pic and avr
DESCRIPTION
Programação Ladder para PICTRANSCRIPT
Ladder Logic for PIC and AVR
(also in: Italiano, Deutsch, Português, Русский)
Quick summary: I wrote a compiler that starts with a ladder diagram and
generates native PIC16 or AVR code. Features include:
digital inputs and outputs
timers (TON, TOF, RTO)
counters (CTU, CTD, `circular counters' for use like a sequencer)
analog inputs, analog (PWM) outputs
integer variables and arithmetic instructions
easy-to-use serial communications, to a PC, LCD, or other device
shift registers, look-up tables
EEPROM variables, whose values are not forgotten when you lose power
simulator, to test your program before you generate PIC/AVR code
This program is free software; source code and executables are available for
download.
Introduction
PLCs are often programmed in ladder logic. This is because PLCs originally
replaced relay control systems, and forty years later, we still haven't quite let
go. A PLC, like any microprocessor, executes a list of instructions in
sequence. Ladder logic tools abstract this; you can program the PLC by
wiring up relay contacts and coils on-screen, and the PLC runtime will
simulate the circuit that you've drawn. Some of the relay contacts can be tied
to input signals from the real world; some of the coils can be tied to outputs.
That way you can make your simulated circuit interact with other devices,
and actually control things. That is the point.
Actually it's more general than that, because you can incorporate timers and
counters and arithmetic operations that you couldn't (easily) perform with
just relays. The circuit concept is still useful though, partly just because it's
intuitive, but also because it abstracts the concurrency issues. It looks like
this:
|| Xa Xb Yout ||
1 ||-------] [------+-------] [------+-------( )-------||
|| | | ||
|| | Xc | ||
|| +-------]/[------+ ||
This is a simple piece of combinational logic. There are three input terms, Xa,
Xb, and Xc. There is one output term, Yout. The expression is Yout := Xa and
(Xb or (not Xc)). This makes sense if you think of Xa and Xb as normally
open relay contacts, Xc as normally closed relay contacts, and Yout as a
relay coil. Of course it gets more complicated than that:
|| ||
|| Asetpoint ||
1 ||-------------------------------------{READ ADC}----||
|| ||
|| Atemperature ||
||-------------------------------------{READ ADC}----||
|| ||
|| ||
|| ||
|| ||
|| {SUB min_temp :=} ||
2 ||------------------------{ Asetpoint - 20 }--------||
|| ||
|| {ADD max_temp :=} ||
||------------------------{ Asetpoint + 20 }--------||
|| ||
|| ||
|| ||
|| ||
||[Atemperature >] Yheater ||
3 ||[ max_temp ]+------------------------(R)-------||
|| | ||
|| Xenable | ||
||-------]/[------+ ||
|| ||
||[Atemperature <] Xenable Yheater ||
||[ min_temp ]--------] [--------------(S)-------||
|| ||
|| ||
|| ||
|| ||
|| {SUB check_temp :=} ||
4 ||-----------------------{ Asetpoint - 30 }-------||
|| ||
|| ||
|| ||
|| ||
||[Atemperature >] Yis_hot ||
5 ||[ check_temp ]-------------------------( )-------||
|| ||
|| ||
|| ||
||------[END]----------------------------------------||
|| ||
|| ||
This is for a simple thermostat. There are two analog inputs; one of them is
for the setpoint, so that it might, for example, be connected to a pot that the
user turns to select the desired temperature. The other provides the
temperature measurement; it might be a semiconductor temperature sensor,
or a platinum RTD with suitable interfacing circuitry. There is a digital output,
Yheater. That might control a heating element, through a suitable switch (a
TRIAC, or a relay, or a solid-state relay, or whatever).
We close the loop with a simple hysteretic (bang-bang) controller. We have
selected plus or minus 20 ADC units of hysteresis. That means that when the
temperature falls below (setpoint - 20), we turn on the heater, and when it
climbs above (setpoint + 20), we turn the heater off.
I chose to add a few small frills. First, there is an enable input: the heater is
forced off when Xenable is low. I also added an indicator light, Yis_hot, to
indicate that the temperature is within regulation. This compares against a
threshold slightly colder than (setpoint - 20), so that the light does not flicker
with the normal cycling of the thermostat.
This is a trivial example, but it should be clear that the language is quite
expressive. Ladder logic is not a general-purpose programming language, but
it is Turing-complete, accepted in industry, and, for a limited class of (mostly
control-oriented) problems, surprisingly convenient.
A Ladder Logic Compiler for PIC16 and AVR
Modern sub-3.00 USD microcontrollers probably have about the computing
power of a PLC circa 1975. They therefore provide more than enough MIPS to
run reasonably complex ladder logic with a cycle time of a few milliseconds. I
think PLCs usually have some sort of runtime that's kind of like an interpreter
or a virtual machine, but if we're doing simple logic on a processor without
much memory then a compiler might be a better idea.
So I wrote a compiler. You start with an empty rung. You can add contacts
(inputs) and coils (outputs) and more complicated structures to build up your
program. Timers (TON, TOF, RTO) are supported. The max/min durations
depend on the cycle time of the `PLC,' which is configurable; timers can
count from milliseconds to tens of minutes. There are counters and
arithmetic operations (plus, minus, times, div).
Circuit elements may be added in series or in parallel with existing elements.
An I/O list is built from the ladder logic drawn. You can have internal relays
(Rfoo), for which memory is automatically allocated, or inputs (Xfoo) and
outputs (Yfoo), to which you must assign a pin on the microcontroller. The
selection of pins available depends on the microcontroller. I have tried to
support the most popular PICs and AVRs (see below).
You can edit the program in graphical form:
Then you can test the program by simulating it in real time. The program
appears on screen with the energized (true) branches highlighted, which
makes it easy to debug. The state of all variables is shown at the bottom of
the screen in the I/O list.
Once the program works in simulation you can assign pins to the inputs and
outputs and generate PIC or AVR code. The code generator isn't all that
difficult. If you realize that a parallel circuit is an OR and a series circuit is an
AND, it's a second-year CS assignment, and not a very long one. The editor
is actually much more challenging. It would take some work to make a smart
compiler, though. For the AVR a good register allocator would provide a
major speedup. If you wanted to get very fancy then you could apply
standard logic reduction algorithms, and maybe state reduction too. That
would be much more difficult. The timers screw things up anyways.
Even ignoring all that, my code generator for the AVR is very poor. The AVR
back end still generates PIC code...for example, it does not really take
advantage of the fact that the AVR has more than one register. Some of the
code that it generates is just embarrassingly bad. The PIC back end is better,
but not really great. None of this matters much until you're trying to run
dozens of rungs of logic with fast cycle times.
I support the A/D converter, PWM unit, and UART on those microcontrollers
that provide them. That means that you can write ladder logic that reads
analog inputs, and that sends and receives characters over serial (for
example to a PC, if you add a suitable level-shifter like a MAX232, or to a
character LCD). It is possible to send arbitrary strings over serial, as well as
the values of integer variables, as ASCII text. Finally, I now support
`preserved variables' on devices with EEPROM; you can indicate that a
particular variable should be auto-saved to nonvolatile memory whenever it
changes, so that its value is persistent across power-on resets.
Limitations, and Disclaimer
Of course a microcontroller with this software can't do everything that a PLC
will. Most PLC environments offer more features and predefined blocks than
my tool does. The PLC hardware is better too; usually the inputs and outputs
are designed to withstand incredible electrical abuse. You can get a
PIC16F877 on a carrier board for ten or twenty USD, though, and you'll pay a
fair bit more for a PLC with the same capabilities.
So far I have received very few bug reports compared to the number of
people with questions or feature requests. There is still great possibility for
defects, especially in the targets for microcontrollers that I do not physically
have (and therefore cannot test). Certainly do not use LDmicro for anything
safety-critical, or anything that would break something expensive if it failed.
As noted above, the code that it generates is far from optimal. Also, not all of
the data RAM in PIC16 devices is available to the ladder logic program. This
is because I have not implemented very much support for all the paging
nonsense. I do, however, support the program memory paging, which is
necessary to access program memory locations in the PIC16 beyond 2k.
Download
The software is developed under Windows XP. It's tested under all versions
from Windows 2000 to Windows 7, and unconfirmed reports suggest that it
works under WINE. The download is a .exe file; there are no other files
required, so there is no installation program. Save it somewhere on your
computer and just run it, and it will work. The manual is included in the .exe
file, but you can download it separately if you want.
The compiler generates Intel IHEX files. Most of the programming software
that I have seen expects this. Of course you need some sort of programming
gadget to get the hex file into the chip. For the AVRs, I recommend an
AVRISP mkII, which is available from various distributors. For the PICs, I
recommend Microchip's PICkit 2, which is available from their web store. Both
of these are officially supported, connect over USB, and cost less than 40
USD.
It should generally be possible to use code generated by LDmicro with a
bootloader. Most AVR parts have special fuses (BOOTRST, BOOTSZx) that
will need to be configured for whatever bootloader you are using. The PIC16
parts don't have any specific hardware support for a bootloader, but LDmicro
generates code with the correct format to allow the bootloader to rewrite the
reset vector.
I would appreciate any bug reports. The following chips are supported:
PIC16F628(A)
PIC16F88
PIC16F819
PIC16F877(A)
PIC16F876(A)
PIC16F887
PIC16F886
ATmega128
ATmega64
ATmega162
ATmega32
ATmega16
ATmega8
It is also possible to generate C code from the ladder program. That is less
convenient, but you could use it on any processor for which you have a C
compiler.
LDmicro can generate interpretable byte code. If you are willing to write an
interpreter then you can use this to run your ladder code on any kind of
target. There is not very much documentation on this, but I provide a sample
interpreter in mostly-portable C.
Pre-built executables are available in several languages:
ldmicro.exe (English)
ldmicro-de.exe (Deutsch)
ldmicro-fr.exe (Français)
ldmicro-es.exe (Español)
ldmicro-tr.exe (Türkçe)
ldmicro-it.exe (Italiano)
ldmicro-pt.exe (Português)
The source code, and various other files, are also available for download.
This program may be distributed and modified under the terms of the GPL
Version 3.
ldmicro-rel2.2.zip (source, release 2.2)
ldmicro.txt (manual)
feature / bugfix history
sample: a simplified traffic light
sample: how to drive a seven-segment display
sample: `hello, world;' it prints the string over serial
Older releases are also available:
ldmicro-rel2.1.zip (source, release 2.1)
ldmicro-rel2.0.zip (source, release 2.0)
ldmicro-rel1.9.zip (source, release 1.9)
ldmicro-rel1.8.zip (source, release 1.8)
ldmicro-rel1.7.zip (source, release 1.7)
ldmicro-rel1.6.zip (source, release 1.6)
(right-click to save any of these files)
Please report any defects. This is free software, with no department in
charge of quality control. I do not even have the hardware to test many of
the targets myself. A bug that is not reported is unlikely to ever be fixed.
I have a tutorial, in which I describe how to enter a simple ladder diagram,
simulate it, and then generate an IHEX file and program it into a PIC. That is
probably the easiest way to get started with this software.
If you have questions about LDmicro, then ask them on the forum.
August 2010, New York City; thanks to G. Mariani and A. Pedrazzi for Italian
translations; H. U. Noell for German; D. Corteletti and O. da Rocha for
Portuguese; M. Vaufleury for French; J. Pascual for Spanish; A. Akici for
Turkish.