Как запрограммировать приоритет сигнала fbd
Перейти к содержимому

Как запрограммировать приоритет сигнала fbd

  • автор:

Пишем задачки на FBD. Пятнашки и Симпсон

В этой статье будет показано, как на языке программирования FBD написать простую программу, которая, тем не менее, будет делать что-то полезное. В нашем примере это будет игра в Пятнашки.

Для начала напомню правила игры: игра в «15», «Пятнашки», «Такен» — популярная головоломка, придуманная в 1878 году Ноем Чепмэном. Представляет собой набор одинаковых квадратных костяшек с нанесёнными числами, заключённых в квадратную коробку. Длина стороны коробки в четыре раза больше длины стороны костяшек для набора из 15 элементов, соответственно в коробке остаётся незаполненным одно квадратное поле. Цель игры — перемещая костяшки по коробке, добиться упорядочивания их по номерам, желательно сделав как можно меньше перемещений.

Как мы видим, правила предельно простые. И реализация будет простой и займет минут 15 без графической части и полчаса со всеми картинками. При этом хочу обратить ваше внимание на то, что вопросы оптимизации алгоритмов и логики остаются за рамками этой статьи т.к. эти вопросы уже не такие простые и потребуют куда больше времени.

Вот что получилось в итоге:

Описание программы, комментарии и картинки под катом.

Основа программы

Как видно из описания игры, у нас есть поле из 16 элементов. Таким образом основой программы будет элемент «Клетка пятнашек».
Сформулируем требования к этому элементу:

— Наша «клетка пятнашек» должна принимать внешние команды, когда игрок говорит, что хочет передвинуть ее на соседнее пустое место.
— Клетка должна знать о соседях по вертикали и горизонтали, чтобы понять, есть ли рядом пустая клетка, с которой можно поменяться местами.
— Клетка должна на старте игры установить начальное значение.
— На выход Клетка должна передать значение, установленное в ней на данный момент.
— Если игрок подал команду Клетке переместиться на соседнее пустое поле, то Клетка должна передать команду соседней пустой Клетке о том, что они сейчас будут меняться местами.

Исходя из этих требований получаем набор входных и выходных сигналов.

  • УпрКоманда — команда управления от игрока, соседних клеток или начальной установки значения
  • Сверху — значение соседней сверху клетки
  • Снизу — значение соседней снизу клетки
  • Слева — значение соседней слева клетки
  • справа — значение соседней справа клетки
  • УстЗначение — значение, которое должно быть установлено в клетку при старте игры
  • Значение — значение клетки
  • Поехали — команда соседу, что мы хотим «поменяться с ним местами»

В итоге получается вот такой макрос:

Поставим таких макросов в нашу задачу 16 штук и свяжем их между собой. В итоге получаем:

Все очень просто. Поставили в задачу шестнадцать макросов «Клетка пятнашки» и связали каждую клетку с соседями по вертикали и горизонтали. Если каких-то соседей у клетки нет (например в клетке_1_1 нет соседа сверху и слева), ставим на соответствующем входе «-1».

Набивка основы

На прошлом шаге мы заложили основу программы. Но т.к. сам элемент «Клетка пятнашки» пока у нас пустой, то ничего хорошего наша программа делать не умеет. Пора это исправить, наполнив логикой макрос «Клетка пятнашки».

Это готовая реализация нашего макроса. Кратко принцип работы:

1. Получаем на вход управляющую команду и распаковываем ее. Выделяем отдельно сигнал длительностью один цикл — признак, что поступила команда, и параметр команды. В нашем случае параметр команды это набор целых чисел от 1 до 6, где числа 1 — 4 это команда поменяться значениями с одним из соседей, число 5 означает команду установить начальное значение в ячейку, а число 6 — что игрок кликнул мышкой по данной клетке и хочет «передвинуть» ее на возможно находящееся по соседству пустое поле.

2. Проверяем всех соседей на нулевое значение (числом 0 у нас обозначается пустое поле).

3. Дальше смотрим на текущее значение данной клетки и команду. Если значение клетки равно нулю (клетка пустая) и одновременно пришла команда поменяться значениями с соседом (команды 1-4), то перезаписываем в клетку значение соседней клетки.

4. Если нам пришла команда 5 (установить начальное значение), то просто записываем в память значение со входа «УстЗначение».

5. Если нам пришла команда 6 (игрок кликнул мышкой по данной клетке) и значение одной из соседних клеток равно нулю, то записываем в данную клетку нулевое значение и отправляем команду «Поехали» на соседние клетки с указанием, с каким именно соседом мы хотим поменяться.

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

— мы получили команду от игрока «передвинуть» эту клетку на пустое место.
— проверили, действительно рядом есть пустое место.
— записали в клетку «0» и передали соседу, что хотим поменяться с ним значениями.
— сосед (при этом нужно понимать, что отрабатывает все тот же макрос «Клетка пятнашки», просто другой его экземпляр) видит, что ему пришла команда поменяться местами с другой клеткой.
— сосед проверяет что в нем самом записан «0» т.е. он сейчас пустая клетка и записывает себе значение первой клетки, от которой пришла команда поменяться местами.

Но секундочку! Ведь одновременно с тем, как отправить команду соседу мы в нашу первую клетку записали «0», следовательно сосед тоже запишет себе ноль и у нас получатся две пустые клетки, а одно значение (из ряда 1-15) пропадет. И так пока все игровое поле не станет пустым. Чтобы этого не произошло, задерживаем в первой клетке перезапись нулем. Таким образом пустая соседняя клетка успеет себе записать правильное значение.

Несколько слов про оптимизацию

Как несложно заметить, сам макрос «Клетка пятнашки» достаточно прост. Однако его можно еще упростить, выкинув оттуда часть блоков. Идея простая. Сейчас мы проверяем команду и соседние клетки перед выполнением перестановок. Однако, как было сказано выше, при любой перестановки отрабатывает два экземпляра одного и того же макроса. И в первом экземпляре мы проводим проверку перед отправкой команды, а во втором экземпляре проводим ту же самую проверку при получении команды. Таким образом одну из проверок можно смело выкидывать. Это первое, что сразу бросается в глаза. Второй момент — лишняя задержка на значении. Ведь значение хранится в блоке «Память», куда перезаписывается только по команде. Следовательно достаточно задержать только команду перезаписи значения, а само значение подавать как есть.

Победа или поражение

Собственно основа нашей программы готова и уже прекрасно работает. Можно играть. Все дальнейшие действия нужны только для внедрения вспомогательных функций.

Начнем с автоматической проверки победы или проигрыша игрока.

В игре «пятнашки» есть забавный момент заключающийся в том, что из всех возможных начальных раскладов плиток половина раскладов нельзя собрать если плитки с номерами «14» и «15» стоят не в том порядке.

Исходя из этого сформируем два условия:
— условие 1: значение, записанное в каждую клетку соответствует ее порядковому номеру. Т.е. игрок победил.
— условие 2: значения, записанные в клетки соответствуют их порядковому номеру за исключением клеток «14» и «15», которые поменяны местами. Т.е. немного не повезло с раскладом.

Ставим 18 алгоритмов сравнения, и собираем по И два набора по шестнадцать равенств. По ИЛИ формируем признак, что мы пришли к одному из концов расклада.

18 алгоритмов потому, что мы проверяем соответствие 16 ячеек для первого случая и дополнительно перестановку ячеек «14» и «15» для второго случая. Кстати т.к. у нас массив данных заранее определенный, то достаточно пятнадцати проверок для всего поля, т.к. последняя ячейка проверяется автоматом.

Начальная расстановка

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

Сначала делаем генератор случайных целых чисел 0 — 15. Пойдем старым проверенном способом. Это вполне допустимый вариант т.к. получившаяся последовательность случайных чисел зависит от момента времени, когда была нажата кнопка «Новая игра». А т.к. этот момент времени случает и никогда не повторяется, то в итоге мы получаем довольно простой и хороший генератор случайных чисел.

На выходе алгоритма Действительное-в-Целое (ДвЦ) получаем случайное целое значение 0 — 15.

Теперь стоит задача сформировать ряд неповторяющихся значений, и записать каждое значение в свою ячейку.

Как я уже сказал, конкретно для языка FBD более или менее хорошее решение этой задачи сделать сложно. Или может просто я не вижу очевидное для остальных красивое и простое решение. Конечно всегда есть вариант сделать вставку на ST, но цель сделать задачу именно целиком на языке FBD.

Решение задачи «в лоб» заключается в следующем:

— ставим управляющие элемент.
— при подаче команды забиваем начальный массив «-1» (можно было и любыми числами вне диапазона [0..15]).
— обнуляем счетчик.
— далее генерируем случайное число от 0 до 15 и проверяем, есть ли такое в нашем массиве. Если есть — продолжаем генерацию случайных чисел.
— если такого числа нет — увеличиваем счетчик на единицу и записываем в соответствующую ячейку памяти наше значение.
— повторяем эти действия еще 15 раз.
— проверяем, если мы дошли до шестнадцатого шага, то формируем импульс, по которому отправляем команду на запись этих значений во все ячейки.

Главным недостатком данного алгоритма является многократный перебор выкинутых ранее значений. В теории время генерации такой случайной последовательности может быть бесконечным. В реальности при десятках прогонов программы оно не было больше чем полсекунды. В любом случае на время генерации (раз оно не мгновенное) ставим блокировку на действия игрока.

Вот что в итоге получилось:

Приделываем графику

Теперь, когда задача у нас полностью готова, самое время приделать UI.

Для этого выбираем в интернете любые понравившиеся картинки с пятнашками. Одновременно выбираем картинки для удачного сбора расклада и неудачного. Я решил поместить туда Гомера Симпсона.

Ставим 16 картинок и приделываем к ним анимацию чтобы они показывали число, соответствующее числу в ячейке. А в ячейке с нулем плитка должна быть невидимой. Ставим на каждую плитку формирование команды «6». Снизу располагаем кнопку «Новая игра» по которой будем запускать алгоритм генерации случайной начальной расстановки. Одновременно не забываем поставить блокировку на все плитки во время генерации. Поверх всего этого дела помещаем Гомера. Все. Графика готова, можно играть.

Нарисованный вариант. Можно заметить что изначально все плитки у нас с единицей.

Начальная позиция.

Неудачный расклад.

И победа!

Что осталось нереализованным

На самом деле не так уж и много:

— можно приделать счетчик ходов. Делается это элементарно. В макросе «Клетка пятнашки» есть команда «6» — команда игрока. Достаточно взять от нее логический сигнал длительностью в один цикл. Вывести этот сигнал наружу. Собрать все шестнадцать сигналов по ИЛИ и завести на алгоритм сложения, охваченный обратной связью. Т.е. всего три дополнительный алгоритма и пара минут работы.

— статистика. Можно сделать счетчик выигранных и неудачных игр. Добавляется два алгоритма сложения и пару алгоритмов обвязки. Тоже пара минут работы.

— отбор раскладов. Как уже говорилось, половина раскладов не сходится изначально из-за невозможности поменять местами плитки «14» и «15». Можно при старте проверять «неудачный расклад» и сразу менять эти две плитки местами.

Сделать все это не сложно, поэтому оставлю такую возможность всем желающим.

Выводы

В этот раз за полчаса на языке FBD была реализована простенькая игрушка «Пятнашки». При этом все используемые алгоритмы простые и понятные. Вся логика обработки сигналов очевидная. Разобраться в такой программе не составит труда любому человеку, знакомому с азами логики и основами языков программирования МЭК 61131.

Для проверки накидал примерно то же самое на С. Вот что получилось:

Текст программы на С

Т.к. программированием на языке С/С++ я не владею, то скорее всего программа ужасна. Более того я сразу вижу несколько «сомнительных» мест. Однако она работает и работает без ошибок.

Главная идея состоит в том, что одна и та же программа, написанная на языке С и на языке FBD имеет разную сложность понимания человеком «со стороны». И если с языком функциональных блоков разобраться не представляет никакого труда, то с реализацией на С придется повозиться.

И хотя программа на FBD состоит из 153 блоков (и мы помним, что там еще есть 16 макросов, каждый из которых состоит из 32 блоков), но на написание ее ушло гораздо меньше времени, чем на написание 50 строчек кода на С.

#include #include "cstdlib" #include #include #include #include #include #include #include #include #include using namespace std; int main(void) < int MyPyatn[16] = ; int i = 0, x = 0, y = 0, MyRand = 0, MyBuffer = 0, MyButton = 0; bool MyGameover = false, MyChange = false; setlocale(LC_ALL, "ru-RU"); srand(time(NULL)); cout for (i=0;i <16;i++) < if ((i %4) == 0) < cout << "\n"; cout << "\n"; >if ((MyPyatn[i] <10) || (MyPyatn[i] == 16)) cout << " "; else cout << " "; if (MyPyatn[i] == 16) < cout << "_"; x = i %4 + 1; y = int (i/4) + 1; >else cout cout while(!kbhit ()); MyButton = getch(); if ((MyButton == 48) || (MyButton == 72) || (MyButton == 75) || (MyButton == 77) || (MyButton == 80)) < if (MyButton == 48) return 0; if ((MyButton == 72) && (y >1)) < MyBuffer = MyPyatn[(y-1)*4 + x - 1]; MyPyatn[(y-1)*4 + x - 1] = MyPyatn[(y-2)*4 + x - 1]; MyPyatn[(y-2)*4 + x - 1] = MyBuffer; y = y - 1; MyChange = true; >if ((MyButton == 80) && (y < 4)) < MyBuffer = MyPyatn[(y-1)*4 + x - 1]; MyPyatn[(y-1)*4 + x - 1] = MyPyatn[y*4 + x - 1]; MyPyatn[y*4 + x - 1] = MyBuffer; y = y + 1; MyChange = true; >if ((MyButton == 75) && (x > 1)) < MyBuffer = MyPyatn[(y-1)*4 + x - 1]; MyPyatn[(y-1)*4 + x - 1] = MyPyatn[(y-1)*4 + x - 2]; MyPyatn[(y-1)*4 + x - 2] = MyBuffer; x = x - 1; MyChange = true; >if ((MyButton == 77) && (x < 4)) < MyBuffer = MyPyatn[(y-1)*4 + x - 1]; MyPyatn[(y-1)*4 + x - 1] = MyPyatn[(y-1)*4 + x]; MyPyatn[(y-1)*4 + x] = MyBuffer; x = x + 1; MyChange = true; >> if (MyChange) < std::system("cls"); cout if ((MyPyatn[i] <10) || (MyPyatn[i] == 16)) cout << " "; else cout << " "; if (MyPyatn[i] == 16) cout << "_"; else cout cout > while(!MyGameover); std::system("cls"); cout

Другими словами язык FBD это простой и понятный язык, предназначенный для далеких от программирования людей. Программировать простые задачки на нем легко. И разобраться в принципах работы программы, написанной другим человеком тоже обычно не составляет большой проблемы.

На этом все. Надеюсь было интересно.

Язык функциональных блоковых диаграмм (FBD) и его применение

Одним из популярных языков программирования ПЛК — программируемых логических контроллеров, является графический язык функциональных блоковых диаграмм FBD — Function Block Diagram. Этот язык, наряду с другими языками стандарта МЭК 61131-3, такими как например язык лестничной логики (LD), использует в своей архитектуре подобие электронной схемы.

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

Язык функциональных блоковых диаграмм (FBD)

Таким образом, программа, написанная на графическом языке FBD, представляет собой набор связанных друг с другом функциональных блоков, выходы и входы которых соединены линиями связи. Линии связи отражают определенные программные переменные, через которые происходит обмен данными от блока — к блоку.

Отдельный блок несет на себе конкретную функцию (логическое «и», «не», счетчик и т. д.), при этом один блок может иметь несколько выходов и входов. Изначально значения переменных задаются константами или со специальных входов, а выходы их связываются дальше с другими переменными программы или с выходами ПЛК.

На рисунке приведен пример программы, написанной на языке функциональных блоковых диаграмм FBD. Как видите, такое изображение программы очень наглядно отражает алгоритм, что и делает данный язык довольно простым и удобным для разработки ПО для ПЛК.

В процессе программирования на языке FBD применяются как стандартные блоки из библиотек, так и блоки, сами написанные на FBD или на иных языках стандарта МЭК 61131-3. Блок представляет собой элемент программы, своего рода подпрограмму, функциональный блок или функцию (логическое «НЕ», «ИЛИ», «И», таймер, счетчик, триггер, математическая операция, обработка аналогового сигнала и т. д.).

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

Функциональные блоки

Рассмотрим кусочек программы, написанной на языке FBD: В умножить на 4, затем поделить на А, и записать результат в переменную result. В псевдокоде это будет выглядеть так: result := B*4/A. Возможно также добавление к блокам специальных управляющих входов EN и выходов ENO, для управления вызовами отдельных блоков: логический ноль, поданный на вход EN, запретит вызов данного блока, а выход ENO в случае ошибки сообщит о ней, и прервет тем самым выполнение цепи до конца.

Как видите, язык FBD до крайности нагляден, удобен, и потому прост в освоении даже специалистами — прикладниками, не имеющими специальной подготовки по информатике. Код выполняется последовательно, структура команд внутри кода проста, поэтому программа транслируется очень быстро и задача выполняется надежно. Используя FBD, можно решать очень сложные задачи на ПЛК.

Язык программирования FBD

Есть различные модификации языка программирования FBD, отличающиеся наличием тех или иных ограничений или расширений.

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

Или модификация CFC (Continuous Function Chart), позволяющая установить порядок выполнения диаграмм не просто последовательной цепочкой, а по усмотрению разработчика ПО. С CFC разработчик получает больше свободы, хотя код получается более длинным.

Пример языка FBD в STEP 7:

Пример языка FBD в STEP 7

Язык функциональных блок-схем FBD, использующий графический стиль потока данных, является наиболее широко используемым языком программирования ПЛК.

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

По результатам опроса язык FBD напбрал 52,14%, а его разновидность СFC — 10,71%, в сумме два языка набрали 62,85%, что значительно больше, чем другие языки программирования ПЛК. У ближайшего конкурента языка LD — 35%.

Самые популярные языки программирования ПЛК

Преимущество языка FBD перед языком релейных диаграмм LD возрастает с увеличением сложности алгоритма управления. Алгоритм управления написанный в FBD, позволяет легче, чем в LD, отслеживать изменения в программе и искать возможные ошибки во время отладки.

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

Смотрите также по этой теме:

Structured Text

Представляем книгу по Structured Text (ST) МЭК 61131-3. Автор — Сергей Романов

Книга «Изучаем Structured Text МЭК 61131-3»: Ссылка на книгу

  • Язык релейных диаграмм LD (Ladder diagram) и его применение
  • Какой датчик температуры лучше, критерии выбора датчика
  • Что такое ПИД-регулятор

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

Подпишитесь на наш канал в Телеграм «Автоматика и робототехника» (современные технологиии, инновации и будущее автоматизации). Нажмите на ссылку ниже и будьте в центре событий в мире автоматики: Автоматика и робототехника

Поделитесь этой статьей с друзьями:

Как запрограммировать приоритет сигнала fbd

Группа «Мультиплексоры и дешифраторы»

MUX (bool), MUX (int), MUX (long), MUX (real)

Описание. Мультиплексор. Мультиплексор — это блок, имеющий несколько сигнальных входов ( in0 , in1 , in2 и т.д.), один управляющий вход ( addr ) и один выход ( Out ). Мультиплексор позволяет передать сигнал с одного из входов на выход. При этом выбор желаемого входа осуществляется заданием его номера на входе addr .

Количество входов изменяется. Способ изменения описан тут.

Особенностью работы мультиплексоров является тот факт, что если выбрать несуществующий вход (например, addr=4242 ), то значение на выходе мультиплексора «застынет» и будет сохраняться до тех пор, пока не будет выбран один из существующих входов

Часто требуется входы логическим сигналом, выходящим, например, с компаратора.

Для реализации такой задачи собирается следующая схема:

Лучше всего оформить её в виде макроса или взять готовый макрос из библиотеки.

Описание. Демультиплексор. Демультиплексор — это блок, предназначенный для переключения сигнала с одного информационного входа на один из информационных выходов. Таким образом, демультиплексор в функциональном отношении противоположен мультиплексору.

Логический демультиплексор стоит несколько особняком от остальных демультиплексоров. Основное отличие в объединении информационного входа и входа разрешения работы блока, т.к. в случае логического демультиплексора они выполняют идентичные функции.

Блок имеет вход разрешения работы en . При нулевом значении на этом входе блок отключен, на его выходах сохраняются нули.

Количество выходов изменяется. Способ изменения описан тут.

Особенностью работы демультиплексоров является тот факт, что если выбрать несуществующий выход , то будет выбран выход, оставшийся от деления по модулю от общего количества выходов. Например, при задании addr=4242 в нижепривёденном примере будет выбран выход 4242-((4242 mod 5) * 5) = Out2

Программирование FBD

Иногда нужно, чтобы система управления тем или иным оборудованием была автоматизированной, и тогда на помощь приходят программируемые интеллектуальные реле. Они позволяют значительно упростить схемы управления электрооборудованием, повысить их надежность и гибкость. Как правило, для программирования интеллектуального реле используется специализированное ПО: LD, FBD и др. В этом уроке мы подробно разберем программирование FBD.

Для успешного освоения материала рекомендуем вам изучить следующие понятия:
Аппарат защиты

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

Булева алгебра

Раздел математики, изучающий логические значения высказываний (истинность или ложность) и логические операции над ними

Микропроцессор
Устройство обработки цифровой и аналоговой информации
Таблица истинности
Таблица, описывающая значения логической функции при всех возможных значениях ее аргументов
Видеолекция
Области применения интеллектуального реле

Программируемые, или интеллектуальные, реле — программный логический контроллер (ПЛК) простого типа. Устройство используется при создании систем управления с логической обработкой информации.

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

  • управления транспортерами,
  • управления насосами,
  • приточно-вытяжной вентиляции,
  • подготовки пара и сбора конденсата,
  • распределения электроэнергии и управления освещением,
  • сбора и предварительной обработки сигналов,
  • управления компрессорами.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *