Полный мануал по использованию LDMicro

Перевод на русский язык оригинального руководства <manyal.txt> Jonathan Westhues: http://cq.cx/ladder.pl

Введение
========

LDmicro генерирует машинный код для некоторых микроконтроллеров (далее MCU)
Microchip PIC16 и Atmel AVR. Обычно программное обеспечение для этих MCU написано
на таких языках программирования, как ассемблер, C, или BASIC. Программы для этих
языков программирования состоят из списка команд. Эти мощный инструментарий и хорошо
подходит для архитектуры MCU.

ПЛК, с другой стороны, часто программируются в диаграммах 'лестничной логики'
(ЛЛ далее). Простая программа может выглядеть следующим образом:

|| ||
|| 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 - таймер с задержкой на ВКЛ., TOF - таймер с задержкой на ВЫКЛ..
Выражение --] [-- - вход, который мы можем представить в приближении
контактом реле (контакт далее). Выражение --( )-- - выход, представляем
его как катушку реле (реле далее). Много хороших материалов по лестничной
логике доступны в Интернете и в соответствующей литературе. Детали специфики
реализации лестничной логики в программе LDmicro описаны ниже.

Отличия ЛЛ от обычного языка программирование очевидны:

* Программа представлена в графическом формате, а не как текст
со списком выражений программирования. Большинство люди проще
понимают графику.

* В целом, программа выглядят как электрическая схема с
контактами (входы) и реле (выходы). Это интуитивно
понятно людям со знанием теории электрических цепей (электрикам,
электронщикам, энергетикам и тд.).

* Компилятор ЛЛ сам позаботится о том, что как и где нужно считать.
Вам не нужно писать код, чтобы определить, когда выходы
должны изменить свое состояние на основании изменения входов или
событий таймера, и вам не придется указывать порядок, в котором
эти расчеты должны иметь место; ПЛК инструментарий будет делать это
за Вас.

LDmicro компилирует ЛЛ в код для PIC16 и AVR. Следующие MCU поддерживаются:
*PIC16F877
*PIC16F628
*PIC16F876 (неиспытан)
*PIC16F88 (неиспытан)
*PIC16F819 (неиспытан)
*PIC16F887 (неиспытан)
*PIC16F886 (неиспытан)
*ATmega128
*ATmega64
*ATmega162 (неиспытан)
*ATmega32 (неиспытан)
*ATmega16 (неиспытан)
*ATmega8 (неиспытан)

Неиспытан, те. "не обкатан" в железе лично автором программы, но как правило
успешно эксплуатируется простыми пользователями программы (прим. переводчика).

Достаточно легко включить большее кол.-во представителей семейств MCU AVR или PIC16,
но я не могу лично проверить их сам (незабываем что программа GNU GPL 3 т.е. open source,
автор занимается пока этим проектом на "голом" энтузиазме. прим. переводчика). Если Вы
хотите добавить какой-либо чип, то свяжитесь со мной и я посмотрю, что можно сделать.


Используя LDmicro Вы рисуете алгоритм ЛЛ в графическом виде.
Затем вы можете протестировать программу, моделируя ее в режиме
реального времени. После того как программа отлажена в режиме
симуляции, можно связать пины микроконтроллера с входами и выходами
релейной схемы и генерировать PIC или AVR код. На выходе Компилятора мы получаем
'.hex' файл, который Вы можете запрограммировать в ваш микроконтроллер с помощью
имеющегося у Вас PIC / AVR программатора.

LDmicro разработан, так чтобы быть в чем-то похожим на коммерческие ПЛК
систем программирования. Есть некоторые исключения, и многие аспекты не являются
стандартными в отрасли так или иначе. Внимательно прочитайте описание
каждой инструкции, даже если это кажется знакомым. Этот документ предполагает,
базовые знания в области релейной логики и структуры программного обеспечения ПЛК
(выполнение цикла: чтение входов, вычисление, запись выходов).

Дополнения
==========

Кроме того, можно генерировать C код из лестничных диаграмм. Вы можете
использовать его на любом процессоре, для которого
у вас есть компилятор C. Но вы ответственны за поддержку ран-тайм.
Это значит, что LDmicro просто генерирует код функции PlcCycle().
Вы отвечаете за вызов данной функции PlcCycle() во время основого цикла
программы, и Вы реализуете весь I/O (чтение/запись цифровых входов, и т.д.)
который вызывается через вызовы PlcCycle(). См. комментарии в генерируемом
исходнике для дальнейших пояснений.

В конечном итоге LDmicro может даже генерировать процессоро-независимый байт-код,
для виртуальной машины (далее VM) предназначенной для исполения кода ЛЛ. Я написал пример
интерпретатора/(VM), на хорошо портируемом С (см. исходники проекта файл ldinterpret.c
прим. переводчика). Таким образом ЛЛ будет работать НА ЛЮБОЙ платформе, на которой вы
запустите VM. Это может показаться полезным если вы хотите использовать ЛЛ в качестве
'скриптового языка' для крупных программ. См. комментарии в примере интерпретатора для
дальнейших пояснений (ldinterpret.c).

Опции Командной строки
=======================

Ldmicro.exe обычно запускается без ключей командной строки. Это значит
что вы можете просто сделать ярлык программы или сохранить ее на
рабочем столе и дважды щелкните по значку, чтобы запустить программу, и тогда вы может делать
все, из графического интерфейса.

Если LDmicro передано имя файла через командную строку,
(например 'ldmicro.exe asd.ld'), тогда LDmicro попытается открыть `asd.ld',
если он существует. Появится сообщение об ошибке если 'asd.ld' не существует.
Т.е. Вы можете ассоциировать ldmicro.exe с файлами '.ld', и они запустятся автоматически
при двойном клике на '.ld' файле.

Если LDmicro будет передан аргумент командной строки вида
'ldmicro.exe /c src.ld dest.hex', тогда будет скомпилирован 'src.ld',
и результат сохранен в 'dest.hex'. LDmicro прервет свою работу после
компиляции, независимо от результата работы. Все сообщения компилятора
при этом будут выведены на консоль. Этот режим возможен только при запуске
LDmicro из консоли.


Основы
======

Запуск LDmicro без аргументов запустит пустую программу с одной пустой ступенью.
LDmicro использует свой внутренний формат для схем ЛЛ, при этом не импортируются
ЛЛ из других программных пакетов.

Вы можете добавлять инструкции, например
Вы можете добавить контакт (Инструкции -> Вставить Контакт) названный
`Xnew'. Префикс 'X' означает, что контакт будет привязан к входу MCU.
Привязать пин можно позднее, после выбора типа MCU и переименования
контактов. Первая буква имени показывает тип обьекта. Например:

* Xname -- привязка к вводу MCU
* Yname -- привязка к выводу MCU
* Rname -- 'внутреннее реле: бит в памяти
* Tname -- таймер; с задержкой на ВКЛ, с задержкой на ВЫКЛ, с памятью
* Cname -- счетчик, или инкремент (+) или декремент (-)
* Aname -- целочисленное (integer 16bit) чтение из АЦП
* name -- переменная общего назначения (integer 16bit)

Назначайте оставшуюся часть имени объекта осмысленно,
чтобы оно было уникально для программы. Совпадающие имена указывают на один
и тот же объект в программе. Например, будет ошибкой назвать таймер (TON) -
'Tdelay' и таймер (TOF) - 'Tdelay' в одной программе (оба таймеры задержки),
так как каждый из них выделяет свою память для счета. С другой стороны, правильно
назвать Сохраняемый таймер (RTO) - 'Tdelay' и сбрасывать его командой (RES сброс
RTO/Cчетчика) связанной с - 'Tdelay', так как обе команды работают с одним
таймером.

Имена переменных могут состоять из букв, цифр и символов подчеркивания ' _ '.
Имя переменной не должно начинаться с цифры. Имена переменных регистро-зависимы
(как в С прим. переводчика).

Команды (MOV, ADD, EQU и т.д.) могут работать с любыми переменными.
Это означает, что они могут получить доступ к таймерам и Счетчикам.
Иногда это может быть полезно, например, Вы можете проверить,
что таймер находится в определенном временном диапазоне.

Переменные всегда 16 битные числа. Это означает, что они могут быть
от -32768 до 32767. Переменные всегда рассматриваются как знаковое.
Вы можете указать литералы как обычные десятичные числа (0, 1234, -56).
Вы также можете указать их как символы ASCII ('A', 'z'), заключив символ
в одиночные кавычки. Вы можете использовать ASCII код символов в
большинстве случаев, в которых используются десятичные числа.

В нижней части экрана вы видите список всех объектов программы.
Этот список автоматически генерируется из программы;
нет необходимости его модифицировать без надобности. Большинство объектов не
требуют никакой конфигурации. 'XName','Yname' и 'Aname' необходимо
тем не менее привязать к пинам MCU. Сначала выберите микроконтроллер который
Вы используете (Установки -> микроконтроллер). Затем необходимо назначить
ваши порты ввода / вывода (I/O), дважды щелкнув их в списке.

Вы можете изменить программу путем вставки или удаления инструкций.
Курсор в программе мигает показывая выбранную инструкцию и текущее
положение курсора. Если он не мигает, то нажмите или кликнете на
инструкции. Теперь Вы можете удалить текущую инструкцию, или Вы можете
вставить новую инструкцию с права или с лева (при последовательном соединении)
или выше или ниже (при параллельном соединении), от выбранной инструкции.
Некоторые операции не допускаются. Например, не позволяется вставка справа от
реле.

Программа состоит минимум из одной ступени (rung). Вы можете добавить больше
ступеней, выбрав "Редактировать -> Вставить Ступень До / После" в меню.
Вы можете получить тот же эффект путем размещения множества параллельных ветвей
в одной ступени. Но более удобно использовать несколько ступеней.

После того как вы написали программу, вы можете протестировать ее в режиме симуляции,
а затем Вы можете скомпилировать ее в HEX файл для целевого микроконтроллера.

СИМУЛЯЦИЯ
==========

Чтобы войти в режим симуляции, выберите "Симуляция -> Режим Симуляции" или нажмите
. Программа выглядит по-другому в режиме симуляции. Курсора больше нет.
Инструкции, которые выполняются (TRUE) подсвечиваются ярким красным, инструкции,
которые не выполняются (FALSE) подсвечены серым. Нажмите <Пробел>, чтобы
запустить один цикл ПЛК. Для непрерывной симуляции в режиме реального времени, выберите
"Симуляция -> Старт Ран-Тайм Симуляции", или нажмите .Состояние программы будет
обновляться в режиме реального времени, анимируя состояние схемы.

Вы можете установить состояние входов в программе, дважды щелкнув
их в списке в нижней части экрана, либо с помощью двойного щелчка
по контакту инструкции 'XName" в программе. При изменении состояния
входа изменения не будут анимированы пока программа не завершит цикл ПЛК.Это произойдет
автоматически, если вы запустите симуляцию в режиме реального времени, или при нажатии
клавиши пробела (выполнение одного цикла).

Компиляция в Нативный Код
=========================

В конечном итоге пора создать '.HEX' файл, который можно запрограммировать
в ваш MCU. Сначала Вы должны выбрать тип MCU, в меню "Установки ->
Микроконтроллер". После этого Вам необходимо назначить ввода / вывода для
каждого объекта 'XName' и 'Yname'. Для этого дважды щелкните имя объекта
в списке в нижней части экрана. Появится диалоговое окно, где можно выбрать
пин из списка нераспределенных выводов.

Затем Вы должны выбрать время цикла, с которым будет работать программа, и
Вы должны сообщить компилятору, какова будет тактовая частота MCU. Эти настройки
устанавливаются в меню "Установки -> Параметры Процессора...". Как правило, Вы
не должны изменять время цикла; 10 мс является хорошим значением для большинства
приложений. Введите частоту кристалла (или керамического резонатора и т.д.),
который вы будете использовать с микроконтроллером и нажмите кнопку "ОК".

Теперь вы можете сгенерировать код для Вашей программы. Выберите "Компиляция ->
Компилировать", или "Компиляция -> Компилировать как...". Если нет ошибок, то
LDmicro cгенерирует файл Intel IHEX готовый для программирования в Ваш чип.

Используйте соответствующий софт и программатор, для загрузки "HEX" файла в MCU.
Не забудьте установить биты конфигурации (фьюзы)! Для процессоров PIC16, биты
конфигурации включены в "HEX" файл, и большинство программаторов "прошьет" их
автоматически. Для AVR процессоров необходимо установить биты конфигурации вручную.

Справочник Команд
=================

КОНТАКТ,НОРМАЛЬНО ОТКРЫТЫЙ Xname Rname Yname
---] [---- ----] [---- ----] [----

Контакт Открытый.
(Очевидная по электрике вещь прим. переводчика)



КОНТАКТ,НОРМАЛЬНО ЗАКРЫТЫЙ Xname Rname Yname
----]/[---- ----]/[---- ----]/[----

Контакт Закрытый.
Эта команда инверсна по отношению к "КОНТАКТ,НОРМАЛЬНО ОТКРЫТЫЙ"


РЕЛЕ, НОРМА Rname Yname
----( )---- ----( )----

Реле Нормальное.
Команда должна быть крайней справа в ступени (завершающей)

РЕЛЕ, Инверсн. Rname Yname
----(/)---- ----(/)----

Реле Инверсное. Инверсно по отношению к "Реле Нормальное"
Команда должна быть крайней справа в ступени (завершающей)


РЕЛЕ, ТОЛЬКО УСТАНОВ Rname Yname
----(S)---- ----(S)----

Проще представить как триггер со входом SET.
Обычно используется в паре с "РЕЛЕ, ТОЛЬКО СБРОС"
Команда должна быть крайней справа в ступени (завершающей)


РЕЛЕ, ТОЛЬКО СБРОС Rname Yname
----(R)---- ----(R)----

Проще представить как триггер со входом RESET.
Обычно используется в паре с "РЕЛЕ, ТОЛЬКО УСТАНОВ"
Команда должна быть крайней справа в ступени (завершающей)


Таймер задержки ВКЛ Tdon
-[TON 1.000 s]-

При нарастающем фронте входного сигнала 0->1 выход в состоянии "0" на
1 сек. а затем переходит в состояние "1". При спадающем фронте 1->0
выход переходит в "0" немедленно. Таймер сбрасывается каждый раз, при
входном уровне "0". Задержка в 1 сек. настраиваемая (дискрета настройки
привязана к интервалу цикла ПЛК, т.е. если цикл. - 10 ms можно изменять
интервал задержки с шагом 10 ms прим. переводчика и тд.).

Переменная 'Tname' считает в "+" от 0 до значения TON. Возможно принудительно
устанавливать 'Tname', например командой 'MOV'.
Подходит для реализации входа с защитой от дребезга например, и как реле
времени (прим. переводчика).


Таймер задержки ВЫКЛ Tdoff
-[TOF 1.000 s]-

При спадающем фронте входного сигнала 1->0 выход в состоянии "1" на
1 сек. а затем переходит в состояние "0". При нарастающем фронте 0->1
выход переходит в "1" немедленно. Таймер сбрасывается каждый раз, при
входном уровне "1". Задержка в 1 сек. настраиваемая (дискрета настройки
привязана к интервалу цикла ПЛК, т.е. если цикл. - 10 ms можно изменять
интервал задержки с шагом 10 ms прим. переводчика и тд.).

Переменная 'Tname' считает в "+" от 0 до значения TOF. Возможно принудительно
устанавливать 'Tname', например командой 'MOV'.



Сохраняемый Таймер Trto
-[RTO 1.000 s]-

Эта команда запоминает длительность сигнала "1". Если длительность
"1" не менее 1 сек., выход переходит в "1". Заметьте что сигнал
может прерываться, т.е. вход "1" - 0.6сек, затем "0" - 2сек, а затем
"1" - 0.4сек, только тогда выход переходит в "1" (т.е. происходит накопление
длительности состояния входа "1" прим. переводчика). После этого
независимо от состояния входного сигнала, выход в "1", до тех пор,
пока он не будет сброшен командой RES (Сброс RTO/Счетчика).

Переменная 'Tname' считает в "+" от 0 до значения RTO. Возможно принудительно
устанавливать 'Tname', например командой 'MOV'.



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

Эта инструкция сбрасывает таймер или счетчик. Для таймеров задержки
ВКЛ/ВЫКЛ - эта команда не нужна. Для сохраняемого Таймера и Счетчиков
обязательна, они сбрасываются только этой инструкцией. При входе
"1" происходит сброс, "0" не оказывает влияние на привязанный Таймер
или Счетчик. Команда должна быть крайней справа в ступени (завершающей).


Одновибратор по Нарастанию _
--[OSR_/ ]--

Для электронщиков коротко: это одновибратор по нарастающему фронту.
Для остальных: Обычное состояние выхода "0". Если в текущем шаге
ПЛК вход "1", а в предыдущем шаге вход был "0" выход переходит
в состояние "1", тем самым на длительность цикла ПЛК формируется
положительный импульс на выходе. Этот инструкцию удобно использовать,
как триггер нарастающего фронта сигнала.

Одновибратор по Спаду _
--[OSF \_]--

Для электронщиков коротко: это одновибратор по спадающему фронту.
Для остальных: Обычное состояние выхода "0". Если в текущем шаге
ПЛК вход "0", а в предыдущем шаге вход был "1" выход переходит
в состояние "1", тем самым на длительность цикла ПЛК формируется
положительный импульс на выходе. Этот инструкцию удобно использовать,
как триггер спадающего фронта сигнала.


Перемычка, Разрыв
----+----+---- ----+ +----

Все очевидно из названия, в основном применяется при отладке.

МАСТЕР-РЕЛЕ
-{MASTER RLY}-

По умолчанию все ступени выполняются на каждом цикле ПЛК. Если
на входе МАСТЕР-РЕЛЕ "0", то на входах всех последующих ступеней
"0" (расположенных ниже по схеме прим. переводчика). Инструкции
по управлению МАСТЕР-РЕЛЕ должны идти в паре: одна на его выключение
(возможно по условию), вторая на включение.


Перемещение {destvar := } {Tret := }
-{ 123 MOV}- -{ srcvar MOV}-

Когда на входе команды "1" происходит перемещение в destvar
значения (123) или переменной (srcvar). При входе "0" ничего не
происходит. В качестве destvar (цели) могут использоваться таймеры и
счетчики. Загружая в них 0 мы их сбрасываем. Команда должна быть крайней
справа в ступени (завершающей).


АРИФМЕТИЧЕСКИЕ ОПЕРАЦИИ {ADD kay :=} {SUB Ccnt :=}
-{ 'a' + 10 }- -{ Ccnt - 10 }-

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

Когда на входе команды "1", над целью производится соответсвующая
арифметическая операция. Операнд может быть или переменной (включая
таймеры и счетчики) или константой. Инструкции signed 16 bit.
Помните, что если на входе 'висит' "1" - выражение вычисляется
при каждом цикле ПЛК. Если вы хотите, чтобы выражение вычислялось
один раз, поставьте последовательно с этим операндом одновибратор
по нарастанию или спаду. При Делении частное обрезается, например
8 / 3 = 2.Команда должна быть крайней справа в ступени (завершающей).

Компаратор [var ==] [var >] [1 >=]
-[ var2 ]- -[ 1 ]- -[ Ton]-

[var /=] [-4 < ] [1 <=]
-[ var2 ]- -[ vartwo]- -[ Cup]-
Если на входе команды "0" то выход "0". Если на входе команды "1" то
на выходе "1", но только тогда когда условие сравнения выполняется.
Эта инструкция может быть использована для сравнения (равно,
больше, больше или равно, не равно, меньше, меньше или равно)
переменной с переменной, или сравнения переменной с 16-битовой константой.

Счетчик Cname Cname
--[CTU >=5]-- --[CTD >=5]--

Счетчик инкрементирует (CTU, +) или декрементирует (CTD, -) переменную
Cname по каждому положительному фронту входной ступени (т.е. 0->1).
Выход "1" при значении CTU(CTD) >= 5, и "0" в противном случае.
Можно назначать пару счетчиков CTU и CTD на одну переменную Cname.
Один будет увеличивать переменную, второй уменьшать. Сбросить
счетчик можно операцией RESET, или операций MOVE Cname->0 например.
Интервал счета от -32768 до 32768, значение по умолчанию 0.

Циклический Счетчик Cname
--{CTC 0:7}--

Круговой счетчик работает как обычный счетчик CTU, за исключением того,
что после достижения верхнего предела, он сбрасывает свое значение
обратно в 0. Например, счетчик показанный выше будет считать: 0, 1,
2, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 2,.... Это полезно в
сочетании с компаратором "==" по переменной 'CNAME '. Вы можете использовать
эту конструкцию, как конечный автомат. Счетчик инкрементирует переменную
Cname по каждому положительному фронту входной ступени (т.е. 0->1).
Команда должна быть крайней справа в ступени (завершающей).


Сдвиговый Регистр {SHIFT REG }
-{ reg0..3 }-

Регистр сдвига связан с массивом переменных (правильно его считать чем-то
наподобие FIFO-очереди прим. переводчика).
Например,этот регистр сдвига связан с переменными 'reg0', 'reg1', 'reg2'и
'reg3'.Входное число помещается в 'reg0' (командой MOV например
прим. переводчика). на каждый положительный фронт входа ступени '0->1',
регистр сдвига будет сдвигать свое содержимое вправо. Это означает, что
присвоение данных происходит так: 'reg3: = reg2','reg2: = reg1' и 'reg1: = reg0'.
'reg0" остается без изменений. Большой массив очереди сдвига может легко занять
много памяти. Команда должна быть крайней справа в ступени (завершающей).

Таблица Просмотра {dest := }
-{ LUT[i] }-

Справочная таблица представляет собой массив 16-ти битных значений.
Когда вход ступени "1" , В Переменную 'Dest' записывается значение из таблицы
LUT[i].Индекс начинается с нуля, поэтому "i" в интервале между 0 и (n-1).
Поведение этой инструкции не предсказуемо, если индекс находится за пределами
этого диапазона. Команда должна быть крайней справа в ступени (завершающей).

Таблица Аппроксимации {yvar := }
-{ PWL[xvar] }-

Это хороший способ аппроксимировать сложные функции или кривую. Она могла бы,
например, быть полезной, если вы пытаетесь применить калибровочную кривую
для преобразования входного напряжения от датчика в более удобные единицы.
Предположим, что вы пытаетесь аппроксимировать функцию, которая преобразует
входную переменную "х", к выходной переменной "у". Вы определяете функцию
в нескольких точках, например, вы знаете, что:

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

Другими словами точки

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

лежат на этой кривой. Вы можете ввести эти 4 точки в таблицу
аппроксимации. Соообразно значению "xvar" будет установлено значение
"yvar". Например, если вы установите xvar = 10, то yvar = 50.

Но если значение xvar получает значение, что лежит между двумя
значениями в таблице аппроксимации, то значение yvar будет вычислено
значением на прямой линии, соединяющей эти две точки в таблице. Например,
xvar = 55 дает выход yvar = 75. (Две точки в таблице - (10, 50) и (100, 100).
55 между 10 и 100, и 75 находится между 50 и 100, так что (55, 75) лежит на
линии, которая соединяет эти две точки.)

Точки должны быть указаны в порядке возрастания координаты "х". Иногда
может оказаться невозможным для выполнения математических операций, значений
в справочной таблице с использованием 16-битной целочисленной арифметики, тогда
LDmicro выдаст предупреждение. Например, эта таблица будет выдавать ошибку:

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

Вы можете избежать эти ошибки, делая расстояние между точками в таблице
меньше. Например, эта таблица соответствует приведенной выше, и она
не производит ошибок:

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

Вряд-ли оправдано использование более чем пяти или шести точек в таблице.
Добавление большего кол.-ва элементов таблицы, увеличивает ваш код в размере
и замедляет программу. Поведение, таблицы если вы передадите значение 'xvar'
больше наибольшей координаты "x" в таблице или меньше, чем наименьшее "х"
в таблице не предсказуемо. Команда должна быть крайней справа в ступени
(завершающей).

Чтение из АЦП Aname
--{READ ADC}--

LDmicro может генерировать код для использования АЦП встроенного в
некоторые MCU. Если входное условие "1", то производится выборка из
АЦП которая сохраняется в переменной 'Aname'. Эта переменная
впоследствии может быть подвергнута арифметической обработке или
сравнению. Пин АЦП должен быть привязан к выводу MCU как и цифровой вход.
Если входное условие ступени ложно, то переменная 'Aname' остается без
изменений.

Для всех поддерживаемых устройств, 0 вольт входного напряжения соотв.
чтению из АЦП "0", и вход равный Vdd (напряжение питания) соответствует
чтению из АЦП "1023". Если вы используете AVR, то подключайте AREF к Vdd.
Вы можете использовать арифметические операции для масштабирования
результата вычисления, но помните, что вы используете целочисленную математику.
Не все выводы будут доступны для использования с преобразователем АЦП .
Программа не позволит вам связать не -АЦП входы с командой "Чтение из АЦП".
Команда должна быть крайней справа в ступени (завершающей).

PWM Выход duty_cycle
-{PWM 32.8 kHz}-

LDmicro может генерировать код для использования ШИМ-выхода встроенного в
некоторые MCU. Если входное условие "1", то выход PWM выдает частоту со
скважностью переменной duty_cycle. Скважность должна быть числом
от 0 до 100. 0 соответствует минимальному уровню выхода, а 100 соответствует
максимальному уровню выхода.

Вы можете указать целевую частоту ШИМ, в Гц. Частота, которую Вы определили,
не может быть в точности достижима, в зависимости от того, как она соотносится
к тактовой частоте микроконтроллера. LDmicro выберет ближайшую достижимую
частоту. Если ошибка большая, то он предупредит Вас. Более высокая скорость
соответствует меньшему разрешению.

Команда должна быть крайней справа в ступени (завершающей).
Ран-Тайм Алгоритм ПЛК забирает ресурсы одного таймера для измерения временного
интервала рабочего цикла. Поэтому PWM доступен на MCU не менее чем с 2-мя
походящими таймерами. PWM использует пин CCP2 (НЕ CCP1) в PIC16 и OC2 (НЕ OC1A)
в AVR.

Запоминаемая Переменная saved_var
--{PERSIST}--

Если на входе команды "1" то соответсвующая переменная "saved_var" автоматически
сохраняется в EEPROM. Что означает, что "saved_var" сохранится, даже если MCU
будет обесточен. Переменная будет перезаписываться только при изменении ее
значения. "saved_var" восстановит свое значение при подаче питания. Не следует
сохранять в Запоминаемую Переменную значение которое изменяется очень часто,
поскольку кол.-во допустимых циклов перезаписи яйчейки EEPROM ~ 100000.
Команда должна быть крайней справа в ступени (завершающей).

Получить из UART var
--{UART RECV}--

LDmicro может генерировать код для использования UART встроенного в MCU.
У AVR с несколькими портами UART поддерживается только UART1 (не UART0).
Настройте скорость передачи используя "Установки -> Параметры Процессора".
Некоторые скорости передачи данных не могут быть достигнуты с определенными
частотами кварца. LDmicro предупредит Вас, в этом случае об ошибке.

Если на входе команды "0" то ничего не происходит. Если на входе команды
"1" то оператор пытается получить одиночный символ из UART.
Если не удается прочитать символ, выходное условие - "false". Если символ
прочитан, тогда ASCII значение сохраняется в 'var' и выходное условие
оператора - "true" до конца одного рабочего цикла ПЛК.

Послать в UART var
--{UART SEND}--

LDmicro может генерировать код для использования UART встроенного в MCU.
У AVR с несколькими портами UART поддерживается только UART1 (не UART0).
Настройте скорость передачи используя "Установки -> Параметры Процессора".
Некоторые скорости передачи данных не могут быть достигнуты с определенными
частотами кварца. LDmicro предупредит Вас, в этом случае об ошибке.

Если на входе команды "0", то ничего не происходит. Если на входе команды
"1", то оператор записывает одиночный символ в UART. ASCII значение символа
должно быть предварительно сохранено в 'var'. Выходное условие
оператора - "true" пока UART занят (передает символ прим. переводчика), и
наоборот как символ будет передан через UART передатчика - перейдет в
состояние"false".

Помните, что символу потребуется некоторое время для передачи. Проверьте
выход состояния этой инструкции, чтобы убедиться что символ передан перед
тем, как отправить следующий, или используйте таймер, чтобы вставить
гарантированную задержку между символами. Вы должны передавать символ
(выставлять на вход команды "true"), только если выход оператора "false",
т.е. передатчик UART не занят.

Изучите инструкцию Передачи Форматированных Строк (ниже), прежде чем
использовать эту инструкцию. Передача Форматированных Строк гораздо
проще в использовании, и почти наверняка способна сделать Все то, что Вы
хотите.

Форматированная Cтрока через UART var
-{"Pressure: \3\r\n"}-

LDmicro может генерировать код для использования UART встроенного в MCU.
У AVR с несколькими портами UART поддерживается только UART1 (не UART0).
Настройте скорость передачи используя "Установки -> Параметры Процессора".
Некоторые скорости передачи данных не могут быть достигнуты с определенными
частотами кварца. LDmicro предупредит Вас, в этом случае об ошибке.

По положительному фронту входной ступени (т.е. 0->1). начинается передача
символьной строки через UART. Если в строке содержится кодовая
последовательность '\3' (или \1.. \5.. \10 и т.д. прим. переводчика), она
заменяется на значение переменной "var", которое автоматически
конвертируется в символьный вид. В данном случае манипулятор ('\3') будет
сконвертирован ровно в 3 символа, например: 'var' = 35, тогда передаваемая
через UART строка будет точно - 'Pressure: 35\r\n' (обратите внимание на
добавленный символ пробела перед 35). Если 'var' = 1432, содержимое
выводимой строки непредсказуемо, поскольку в числе 1432 более 3-х цифр.
В данном случае необходимо использовать манипулятор '\4'.


Если переменная отрицательна, используйте манипулятор '\-3d' (или `\-4d'
и т.д.). Это заставит LDmicro печатать дополнительный пробел перед
положительным числом, и знак '-' перед отрицательным.

Если одновременно (т.е. параллельно) передаются несколько форматированных
строк (или начинается передача следующей строки, пока не передана текущая)
или одновременно начинается передача командой "Послать в UART", содержимое
выводимой строки непредсказуемо.

Также возможно передавать этой командой обычные текстовые строки, без
каких- либо манипуляторов с числами. Просто не включайте в таком случае
манипулятор '\xx' в передаваемую строку.

Используйте манипулятор '\\' для передачи символа "\". Также возможно
передавать следующие управляющие символы в строке:
* \r -- carriage return (возврат каретки)
* \n -- newline (переход строки)
* \f -- formfeed (перевод страницы)
* \b -- backspace (забой)
* \xAB -- символ ASCII c числовым значение 0xAB (hex)

Выход инструкции "1" во время передачи данных, в противном случае "0".
Эта команда занимает большой обьем памяти программы (незабываем,
что архитектура процессоров AVR и PIC16 - Гарвардская прим. переводчика).
Поэтому используйте данную инструкцию с осторожностью.
Текущая реализация этой команды не оптимизирована, но лучшая реализация
потребует полной модификации ядра программы.


Замечания по использованию Арифметики
=====================================

Помните, что LDmicro выполняет вычисления только над 16-bit числами.
Это означает, что конечный результат любого вычисления, которое Вы
выполняете должнен быть числом от -32768 до 32767. Это также означает,
что промежуточные результаты Ваших расчетов всегда должны быть в
пределах этого диапазона.

Например, скажем, что Вы хотите вычислить у = (1 / х) * 1200,
где "х" в интервале между 1 и 20. Тогда "у" будет между 1200 и 60 -
результат вписывается в 16-разрядное целое число, так что теоретически
возможно выполнить вычисления. Есть два способа, которыми Вы можете
вычислить выражение. Вы можете поделить, а затем умножить:

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

Или выполнить деление сразу, одним шагом:

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

Математически, оба выражения эквивалентны, но первое даст неправильный
результат: y = 0. Потому, что переменная 'temp' меньше единицы.
Например, когда x = 3, то (1 / x) = 0.333, но это не целое; округление
даст temp = 0. Поэтому y = temp * 1200 = 0. Во втором случае нет
промежуточного результата , и все будет OK.

Если у Вас появится ошибка в вычислениях, проверьте промежуточный результат
на предмет ошибки округления до 0 (см. выше прим. переводчика), или переполнения
которое "завернет" число, например: 32767 + 1 = -32768. Если возможно, выбирайте
числа в диапазоне от -100 до 100 (ограничьтесь диапазоном signed char
прим. переводчика).

Когда Вам необходимо смасштабировать переменную на некоторую величину,
используйте умножение и деление. Например, чтобы получить масштаб у = 1.8*x,
примените выражение y = (9/5)*x (что эквивалентно, так как 1.8 = 9/5), и
запрограммируйте его как y = (9*x)/5, первым вычисляя произведение:

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

Этот код будет работать правильно при x < (32767 / 9) или x < 3640. Для больших
значений 'x', переменная 'temp' будет переполнена. Аналогично ограничен нижний
предел x (надо считать допустимую погрешность округления при малых значениях х,
прим. переводчика).


Стиль программирования
======================


Я позволяю использовать несколько реле параллельно в одной ступени.
Это означает, что Вы можете сделать что-то вроде этого:

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

Вместо этого:

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


Это означает, что теоретически можно написать любую программу как одну
гигантскую ступень, и можно не использовать несколько ступеней вообще.
На практике это является плохой идеей, потому что, если ступени становятся
все более сложными, то их труднее редактировать без удаления и перерисовки
множества логики.

Тем не менее, часто является хорошей идеей, чтобы сгруппировать связанную
логику вместе, как единую ступень. Это создает почти идиентичный код, как если
бы Вы сделали отдельные ступени. Но он показывает, что Ступени связаны, когда Вы
смотрите на них на лестничной диаграмме.

* * *

В целом, считается плохим тоном писать программу таким образом, что
результат вычислений зависит от порядка ступеней. Например, этот код
работает не очень хорошо, если оба входа 'Xa' и 'Xb' будут замкнуты
(результат входа Xb будет "перекрывать" Xa, что должен учитывать программист
прим. переводчика):

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

Я тем не менее нарушаю это правило, если при этом я могу сделать кусок кода
значительно более компактным. Например, вот как я преобразую 4-разрядное
двоичное число из входов 'XB3:0' в целое число 'v':

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


Если команда MOV будет перемещена вниз программы вместо верхнего
положения, тогда 'v' если она будет читаться где-либо в программе будет
всегда 0. Надо учитывать что реальное выполнение ступеней по шагам идет
сверху вниз.

ОШИБКИ
======

LDmicro не генерирует очень эффективный код, он медленен и не оптимально
расходует флэш-память и оперативую память. Несмотря на это, среднего класса
PIC или AVR может делать все, что небольшие ПЛК , так что это не беспокоит
меня сильно.

Максимальная длина имен переменных весьма ограничена. Иначе они плохо
помещаются на лестничной диаграмме, пока я не вижу хорошего решения
этой проблемы (давайте компактные имена переменным прим. переводчика).

Если ваша программа является слишком большой по времени исполнения,
величине памяти программ или памяти данных для того MCU, которое Вы выбрали,
то Вы, вероятно, не получите сообщение об ошибке. Программма просто где-то
будет работать неправильно.

Нерегулярное сохранения в файл сохранения/загрузки програмы ('.ld'), вероятно,
может привести к краху программы или порче файла '.ld' (Чаще сохраняйте
результат работы LDmicro, делайте резерные копии программы прим. переводчика).

Пожалуйста, сообщайте о ошибках и задавайте вопросы автору..

Благодарности:
* 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


Ограничения, и Правовая ответственность
=======================================

НЕ ИСПОЛЬЗУЙТЕ КОД, СГЕНЕРИРОВАННЫЙ LDMICRO В ПРИЛОЖЕНИЯХ, ГДЕ ОТКАЗ
ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ МОЖЕТ ПРИВЕСТИ К ОПАСНОСТИ ДЛЯ ЧЕЛОВЕЧЕСКОЙ ЖИЗНИ
ИЛИ ПОВРЕЖДЕНИЮ ИМУЩЕСТВА. АВТОР НЕ НЕСЕТ ОТВЕТСТВЕННОСТИ ЗА УЩЕРБ В
РЕЗУЛЬТАТЕ ВОЗМОЖНЫХ ПОВРЕЖДЕНИЙ ОТ ИСПОЛЬЗОВАНИЯ LDMICRO ИЛИ КОДА,
СГЕНЕРИРОВАННОГО LDMICRO.

Данная программа является свободным программным обеспечением:
Вы можете распространять и / или изменять ее на условиях
GNU General Public License, опубликованных Free Software Foundation,
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

Эта программа распространяется в надежде, что она будет полезной, но
БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ. Смотрите GNU General Public License для более
подробной информации.

Вы должны получить копию GNU General Public License вместе
с этой программой.



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



Переведено: Ибрагимов М.Р.
Россия Тольятти 06.2011.г.







наверх

Hosted by uCoz