РУКОВОДСТВО ПО LDMCIRO

ВВЕДЕНИЕ

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

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

   ||                                                        ||
   ||  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 компилирует лестничную логику в код PIC16 или AVR. Поддерживаются следующие процессоры:

Было бы легко поддерживать больше чипов AVR или PIC16, но у меня нет возможности протестировать их. Если вам нужен какой-то конкретный, свяжитесь со мной, и я посмотрю, что можно сделать.

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

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

 ~

ПРИМЕЧАНИЕ ПО ИСПОЛЬЗОВАНИЮ МАТЕМАТИКИ

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

Например, допустим, вы хотите вычислить y = (1/x)*1200, где x находится в диапазоне от 1 до 20. Тогда y находится в диапазоне от 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. Во втором случае нет промежуточного результата недополнения, поэтому все работает.

Если у вас возникают проблемы с математикой, проверьте промежуточные результаты на переполнение (или переполнение, которое "обертывается вокруг"; например, 32767 + 1 = -32768). Когда это возможно, выбирайте единицы измерения, которые помещают значения в диапазон от -100 до 100.

Когда вам нужно масштабировать переменную на некоторый коэффициент, делайте это с помощью умножения и деления. Например, чтобы масштабировать y = 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 могут быть истинными:

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

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

   ||                                   {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 может делать все, что может маленький ПЛК, так что это меня не очень беспокоит.

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

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

Небрежное программирование в процедурах загрузки/сохранения файлов, вероятно, делает возможным аварийное завершение работы или выполнение произвольного кода при наличии поврежденного или вредоносного файла .ld.

Пожалуйста, сообщайте автору о дополнительных ошибках или пожеланиях по функциям.

Спасибо:

 ~

ДОПОЛНИТЕЛЬНЫЕ ЦЕЛИ

Также можно генерировать ANSI C код. Вы можете использовать его с любым процессором, для которого у вас есть компилятор C, но вы несете ответственность за обеспечение среды выполнения. Это означает, что LDmicro просто генерирует исходный текст для функции PlcCycle(). Вы отвечаете за вызов PlcCycle каждый цикл, и вы отвечаете за реализацию всех функций ввода/вывода (чтение/запись цифрового ввода и т.д.), которые вызывает PlcCycle(). Более подробную информацию смотрите в комментариях к сгенерированному исходному коду.

Наконец, LDmicro может генерировать процессорно-независимый байткод для виртуальной машины, предназначенной для выполнения кода лестничной логики. Я привел пример реализации интерпретатора/VM, написанный на достаточно переносимом языке 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 из командной строки.

 ~

BASICS

Если вы запускаете LDmicro без аргументов, то он запускается с пустой программой. Если вы запустите LDmicro с именем лестничной программы (xxx.ld) в командной строке, то он попытается загрузить эту программу при запуске. LDmicro использует свой собственный внутренний формат для программы; он не может импортировать логику из какого-либо другого инструмента.

Если вы не загрузили существующую программу, то вам будет предоставлена программа с одной пустой строкой. Вы можете добавить в нее инструкцию; например, вы можете добавить набор контактов (Инструкция -> Вставить контакты) с именем Xnew. X означает, что контакты будут привязаны к входному контакту микроконтроллера. Вы можете назначить контакт позже, после выбора микроконтроллера и переименования контактов. Первая буква имени указывает, что это за объект. Например:

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

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

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

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

В нижней части экрана вы увидите список всех объектов программы. Этот список автоматически генерируется программой; нет необходимости обновлять его вручную. Большинство объектов не нуждаются в настройке. Однако объекты Xname, Yname и Aname должны быть назначены на вывод микроконтроллера. Сначала выберите, какой микроконтроллер вы используете (Settings -> Microcontroller). Затем назначьте контакты ввода/вывода, дважды щелкнув по ним в списке.

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

Программа начинается с одной шпалы. Вы можете добавить дополнительные шпалы, выбрав команду Insert Rung Before/After в меню Logic. Вы можете добиться того же эффекта, разместив множество сложных подсхем параллельно в пределах одной шпалы, но более понятно использовать несколько шпал.

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

 ~

СИМУЛЯЦИЯ

Чтобы войти в режим симуляции, выберите Simulate -> Simulation Mode или нажмите <Ctrl+M>. В режиме симуляции программа отображается по-другому. Курсор больше не отображается. Инструкции, на которые подается напряжение, отображаются ярко-красным цветом; инструкции, на которые напряжение не подается, отображаются серым цветом. Нажмите пробел, чтобы запустить ПЛК на один цикл. Для непрерывного цикла в реальном времени выберите Simulate -> Start Real-Time Simulation, или нажмите <Ctrl+R>. Дисплей программы будет обновляться в реальном времени по мере изменения состояния программы.

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

 ~

КОМПИЛЯЦИЯ В РОДНОЙ КОД

В конечном счете, цель заключается в создании .hex-файла, который можно запрограммировать в микроконтроллер. Сначала необходимо выбрать номер детали микроконтроллера в меню Settings -> Microcontroller. Затем необходимо назначить вывод ввода/вывода для каждого объекта Xname или Yname. Для этого дважды щелкните по имени объекта в списке в нижней части экрана. Появится диалог, в котором вы можете выбрать нераспределенный вывод из списка.

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

Теперь вы можете сгенерировать код из вашей программы. Выберите Compile -> Compile, или Compile -> Compile As.., если вы ранее компилировали эту программу и хотите указать другое имя выходного файла. Если ошибок нет, LDmicro сгенерирует файл Intel IHEX, готовый для программирования в вашем чипе.

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

 ~

СПРАВОЧНИК ИНСТРУКЦИЙ

Джонатан Вестхьюз

Рейсвейк -- декабрь 2004 г.
Waterloo ON -- Jun, Jul 2005
Кембридж Массачусетс -- сентябрь, декабрь 2005 г.
                 февраль, март 2006
                 февраль 2007
Сиэтл WA -- февраль 2009 г.

Электронная почта: пользователь jwesthues, at host cq.cx

Translated: https://www.deepl.com/translator
Manually postprocessed.