Привет. Недавно мне прислали ссылку статья , где был показан пример реализации простой и в то же время знаковой игры «Змейка» в контроллере семейства Siemens s7-300. И я подумал: все знают о таких монстрах, как Сименс, АББ и т. д. Но современные отечественные разработки остаются в тени.
В этой статье я покажу, как за полчаса реализовать алгоритм игры «Змейка» на российской АСУ ТП.
«КВИНТ 7» , разработанный в НИИТеплоприборе .
А для большего интереса игра будет полностью реализована на технологичном языке программирования.
ФБД , которому уделяется незаслуженно мало внимания.
Итак, начнем: Наша задача — написать игру «Змейка» за полчаса.
Для реализации идеи нам понадобится:
- Компьютер с установленным ПО КВИНТ 7.
- Контроллер Р-400
- Патч-корд для подключения контроллера к компьютеру
- Лицензия на средства эксплуатации (для игры) и средства проектирования (для написания самой игры) КВИНТА 7
Сам алгоритм игры можно разделить на несколько крупных блоков:
- Генератор (для генерации тактовой частоты)
- Управление (чтобы вы могли играть)
- Голова змеи (стихия, которую мы будем контролировать)
- Змеиный хвост (без него игра теряет смысл, так как цель игры собрать как можно длинный хвост)
- Еда (те клетки, которые змея будет «съедать» и увеличивать длину своего хвоста)
- Дополнительные проверки (позволяют сделать игру более удобной и логичной)
Генератор
Сначала давайте создадим основу змеи.Т.
к.
наша змея непрерывно ползает по полю, то основой всей программы будет генератор, выдающий импульсы с периодом, соответствующим скорости движения змеи.
Начнем со скорости 1 ячейка в секунду.
Организовать такой генератор очень легко.
Все, что вам нужно, это логический алгоритм И, счетчик импульсов, алгоритм сравнения и алгоритм выбора.
Итого за 1 минуту делаем простой генератор.
Принцип работы следующий.
На выходе блока алгоритма " я1 «Каждый цикл логическое значение 1<-> 0 изменений.
Далее по блоку алгоритма» Сложный1 "Идет подсчет количества единиц, которое сравнивается с заданным нами значением (в данном примере 50, поскольку время цикла составляет 10 мс, тогда за 1 секунду счетчик посчитает 50 включений).
Если показания счетчика равны нашему заданному значению, то отматываем наведенное на счетчике значение (алгоритм " Кальк1 ") и выдать тактовый импульс длительностью 10 мс (1 такт контроллера) с выхода алгоритма "=" Сравнить1 ".
Последний алгоритм выбора используется для обнуления счетчика с помощью сигнала сброса.
Для внимательных читателей Внимательный читатель наверняка заметил, что при первом включении счетчик будет считать 50 импульсов не за 1 секунду, а за 980 мс.
потому что мы считаем по передней кромке, а не по задней кромке.
Но при этом все остальные тактовые импульсы он будет выдавать ровно через 1 секунду.
Конечно, исправить эту ситуацию очень просто, но именно для этого вопроса я намеренно оставил именно этот вариант реализации генератора.
После того, как генератор сделан, давайте свернем его в компактный макрос и оставим ждать своего часа.
Контроль
Здесь все предельно просто.У нас уже есть генератор.
Змея непрерывно ползет по полю, меняя лишь направление своего движения.
Само поле представляет собой двумерный массив, каждая ячейка которого задана координатами X и Y. При движении вправо координата X с каждым шагом увеличивается на единицу, но координата Y не меняется.
При движении влево координата X уменьшается, а координата Y остается постоянной.
Для перемещения вверх и вниз то же самое, только координата Y изменится, а координата X будет постоянной.
Поэтому мы устанавливаем два реверсивных счетчика (по одному на каждую координату), которые в зависимости от команды одновременно с приходом нового тактового импульса будут либо прибавлять, либо вычитать единицу из текущей координаты головы змеи.
В результате мы получаем следующую диаграмму.
Небольшое пояснение по поводу резервирования цепей Опять же у внимательных читателей может возникнуть вопрос, почему эта схема реализована не оптимальным образом, а с использованием дополнительных ненужных алгоритмов.
Все очень просто.
Эти пока бесполезные алгоритмы включены в схему заранее и понадобятся на этапе «причесывания» программы.
Чтобы не возвращаться и не редактировать лишний раз исходный дизайн, лучше ввести их заранее.
Зачем они нужны, расскажу в спойлере ниже.
Принцип работы Алгоритм» РухСелектор1 "используется для ввода команд змейки.
Имеет 4 выхода, которые соответствуют четырем направлениям движения (вправо-влево-вверх-вниз).
Далее идет другой алгоритм выбора" РухСелектор2 «Поскольку команды управления могут поступить в любой момент, мы используем его для синхронизации команд управления с тактовыми импульсами.
То есть мы передадим значение с первого селектора на второй только при приходе тактового импульса.
Очевидно, что этот алгоритм избыточен, поскольку мы синхронизируемся с тактовыми импульсами непосредственно на счетчиках (это видно из схемы), однако я оставил этот алгоритм в программе исключительно для целей отладки.
Далее идут 4 алгоритма».
И "для синхронизации счётчиков с тактовыми импульсами, о чём я писал выше.
На основе соответствующего сигнала от алгоритмов" И » выбираем увеличение или уменьшение нужной нам координаты на единицу.
Так как алгоритм выбора работает по схеме «1 из n», следовательно, в каждый момент времени логическая единица будет находиться только на одном из селекторов Это означает, что мы можем просто добавить приращение соответствующей координаты и полученное значение отправить на реверсивный счетчик этой координаты, реализованный как и в случае с генератором с использованием алгоритма суммирования с обратной связью.
На этом схема управления завершена.
Пока мы не будем превращать это в макрос, потому что.
На последнем этапе мы еще немного подправим его.
Голова и хвост змеи
Как говорилось ранее, голова змеи представляет собой ячейку массива с определенными координатами X и Y. Но у нас пока нет этого массива.Кроме того, заглянув немного в будущее (а именно в создание хвоста змеи), становится понятно, что эта ячейка массива должна иметь память.
Простейший логический элемент с памятью — триггер.
Их существует множество разновидностей, каждая из которых используется в своих целях.
В данном примере мы отдадим предпочтение «триггеру RS».
Чтобы добавить красоты игре (например, раскрасить «змею» и «еду» в разные цвета, выделить цветом голову змеи и т. д.), логической ячейки памяти недостаточно, ведь нам придется хранить не 2 , но в нем минимум 4 государства.
Те.
вам придется делать ячейку памяти либо из нескольких триггеров, либо в другом формате — например, хранить в ячейке целое число.
Но это несколько усложнит программу, и одна из целей всего этого действа — выполнить ее за полчаса.
Давайте сделаем для нашей змейки поле 20 на 20. нам понадобится 400 триггеров.
Проблему можно легко решить.
создайте одну ячейку с одним триггером и превратите ее в макрос.
Мы создаем макросы из двадцати ячеек и сворачиваем их в новый, большой макрос.
Устанавливаем двадцать больших макросов и получаем 400 ячеек памяти.
Сам макрос ячейки будет иметь 5 входов и 4 выхода.
Входы:
- Вход (логический признак того, находится ли «голова» змеи в этой ячейке памяти)
- Clock (тактовые импульсы для синхронизации с основным генератором)
- Длина (длина змеиного хвоста)
- Сброс (логический признак нажатия кнопки сброса для начала новой игры)
- Еда (логический признак того, есть ли в этой клетке «пища» для змеи)
Попадание головы змеи на клетку с «едой» — хорошо, а попадание змеи на клетку со змеиным хвостом — поражение и конец игры.
Выходы:
- Вывод (логический признак, закрашивать эту ячейку на поле или нет)
- GameOver (логический признак окончания игры, если змея наступит себе на хвост)
- Ням_ням (логический признак того, что змея наступила на ячейку с едой и для змеи нужно сгенерировать новую еду)
- Another_try (логический признак того, что случайно брошенная клетка с едой оказалась на поле, уже занятом змеей и необходимо перегенерировать координаты новой случайной ячейки)
Как работает клеточный алгоритм На вход поступает сигнал о том, что змея наступила на эту ячейку.
Из него выделяется импульс длительностью 10 мс.
и по алгоритму " И " добавляется к тактовому импульсу.
Если оба условия выполнены, т.е.
за один цикл поступил тактовый импульс и сигнал о том, что в этой ячейке появилась змейка, то срабатывает триггер " РС1 " взведен.
Это основной триггер этой ячейки памяти.
В принципе, для обработки головы змеи достаточно сбросить триггер следующим тактовым сигналом.
Все остальное - обработка хвоста, и различных ситуаций.
1. обработка ситуации «змея наступила себе на хвост».
Здесь все просто, за исключением небольшой тонкости.
С помощью AND мы добавляем входной сигнал и состояние триггера.
Если оба сигнала равны единице, то голова наступила на ячейку, занятую хвостом.
Это нарушение правил и мы выдаем сигнал «GameOver», который завершает игру.
Тонкость в том, что сигнал с триггера нужно брать не из текущего цикла, а из предыдущего цикла.
Для этого здесь используется обратная связь (отображается пунктирной линией).
2. обработка «еды».
Здесь тоже все просто.
Мы получаем сигнал о том, что в этой ячейке должна быть еда.
Мы добавляем его вместе с И с основным триггером.
Если оба сигнала один, то квадрат еды упал на поле, уже занятое змеей.
В этом случае мы выводим сигнал «Еще одна попытка», который дает команду на генерацию новых случайных координат. 3. обработка ситуации «змея съела еду».
Если условие 2 не выполнено, т.е.
если ячейка с едой приземляется на свободное поле, то срабатывает триггер еды" РС2 Далее просто ждем сигнала о том, что змея наступила на эту ячейку.
Как только такой сигнал поступает, мы сбрасываем пищевой триггер (еда съедена) и выдаем сигнал «Ням-ням», согласно для чего увеличиваем длину змеи на единицу и одновременно отправляем команду на генерацию новых координат для еды.
4. «обработка хвоста».
Идея состоит в том, чтобы хранить состояние клетки до тех пор, пока весь хвост змеи не сползет с нее.
Для этого установите счетчик (алгоритм " Сложный1 ") и посчитаем, сколько тактовых импульсов мы получили за время взведения основного триггера.
Сравниваем это значение с длиной змейки и как только они станут равными, сбрасываем триггер.
Для простоты и отладки это не так.
значение счетчика, которое сравнивается с длиной.
Но разница между ними с нулем.
Один из моментов, на который стоит обратить внимание, это то, что после вычитания показаний счетчика к полученной разнице прибавляем единицу.
для компенсации отсчета первого тика, который происходит одновременно с попаданием змеи по ячейке.
"Еда"
Самая большая проблема здесь — получить случайное число.
Потому что у нас нет «случайной» команды.
В Интернете существует множество способов генерации псевдослучайного числа.
Этот пример реализует один из них.
Берется некое большое переменное число — UpTime контроллера в секундах.
А делится он постоянно меняющимся делителем (реализованным на интеграторе).
Берется остаток частного и предполагается, что это случайное число.
На самом деле, конечно, оно вовсе не случайно, и на первый взгляд можно заметить, что вероятность выпадения малых чисел больше, чем больших именно за счет «гуляния» делителя в определенной области, но если мы берем, скажем, не целые числа из остатка, а, скажем, сотые или тысячные доли из остатка.
Доведите их до диапазона 1-20, тогда мы получим число, значение которого уже будет очень похоже на случайную величину.
Соединяем все детали и прочесываем программу
Итак, все части программы у нас готовы.Соединяем их между собой связями.
В первом приближении наша игра уже работает. Остаются последние штрихи.
1. Проверить выход за границы поля.
Все зависит от реализации игры.
Мы помним, что на втором этапе «Управление» у нас был счетчик, в котором находились координаты X и Y головы змеи.
Мы просто сравниваем эти координаты с 0 и 21 (так как наше поле размером 20 на 20 и координаты 1-20).
Если какое-то из условий выполнено, то ставим знак «Конец игры» (который должен быть дополнен ИЛИ с нашим знаком «GameOver»).
Вы можете сделать это, как в игре "Пакмен" чтобы, когда змея вылезет из поля, она появилась бы на другой стороне.
Для этого достаточно сбросить соответствующую координату.
2. Проверка правильности команды.
Наша змея не может мгновенно развернуться на 180 градусов.
Поэтому добавим небольшую проверку, которая не позволит выдавать команды противоположного направления одну за другой.
Принцип работы следующий.
Если приходит команда, то мы проверяем, является ли она противоположностью уже действующей команды.
Если нет, то записываем в память новую команду и отправляем ее на выход. Если да, то запись в память не происходит и на выходе остается старая команда.
При желании вы можете разместить эту функцию на отдельном макровыходе и использовать ее для генерации звукового сигнала.
3. Команды «Пуск» и «Сброс».
Сделано для удобства.
Команда «Пуск» взводит курок, который посылает сигнал на наш генератор.
Команда сброса сбрасывает этот триггер, останавливая генератор.
В то же время сброс сбрасывает всю память и данные во всех счетчиках.
Итоговая программа.
рисунок очень большой
Делаем интерфейс и играем
Осталось пару минут отведенного нам на игру времени, которых как раз хватит на то, чтобы присоединить к игре графический интерфейс.Нарисуйте поле из квадратов 20х20. Каждому квадрату соответствует своя ячейка памяти.
Задаем в свойствах так, что если для соответствующей ячейки памяти значение 0, то квадрат будет серым, а если 1, то зеленым (или любым понравившимся вам цветом).
Поискав картинки в Интернете, находим красивую рамку для поля и какой-то рисунок змеи, соответствующий смыслу.
Размещаем кнопки управления рядом с полем и привязываем управление мышью и клавиатурой к клавишам WASD. Рядом размещаем кнопки «Пуск» и «Сброс».
И большой знак «GameOver», который появится, когда вы проиграете.
Компилируем и загружаем программу в контроллер.
Запускаем пункт оперативного управления и играем.
Вот мнемосхема, которую будет иметь оператор.
Давайте подведем итоги
В этой статье мы немного рассмотрели принципы программирования на языке FBD для контроллеров.ПТК КВИНТ 7 .
Без особых усилий мы реализовали игру «Змейка».
язык FBD ориентирован в основном на технологов, поэтому любой человек, знакомый с элементарной логикой (например, логикой работы алгоритмов И, ИЛИ, триггеров и счетчиков), может понять принципы работы и начать писать свои программы.
Вам не обязательно иметь большой опыт в программировании или схемотехнике.
Этот алгоритм можно реализовать на любой системе, поддерживающей язык программирования FBD, просто заменив представленные на рисунке алгоритмы аналогичными по функционалу, т.к.
используемые здесь алгоритмы являются базовыми и существуют во всех системах.
При написании программы на языке FBD важно следить за порядком выполнения алгоритмов.
Как я уже писал выше, приведенная программа не является оптимальной и оснащена дополнительными алгоритмами, которые нужны только для одной цели — контроля порядка выполнения и синхронизации выполнения всех алгоритмов с тактовым сигналом.
Конечно, с помощью несложных манипуляций можно улучшить программу, например, со временем увеличивая скорость змейки.
Или ввести параметр «голода», согласно которому змея, не получающая новую пищу в течение определенного периода времени, ускоряется.
Кроме того, внимательные читатели могли бы обратить внимание на функцию запоминания длины змеи при ее переходе в новую ячейку (и здесь специально внесена небольшая ошибка, чтобы привлечь внимание) и подумать, что это неверно, т.к.
обычно змея вытягивается из голову, а не хвост. Ты можешь делать что угодно.
Это всего лишь вопрос желания и времени.
Спасибо всем, кто дочитал до конца.
Надеюсь, это было интересно.
Теги: #plc #scada #программирование микроконтроллеров #ненормальное программирование #программирование
-
Место Для... Антенны
19 Oct, 24 -
Орел Или Решка?
19 Oct, 24 -
Когда Это Будет - Анонсы Будущих Событий
19 Oct, 24 -
Эмулятор Playstation 1 Для Iphone
19 Oct, 24