------------------------------------
Lavr: Спасибо, Виталий!

с удовольствием, а вовсе не тужась так, чтобы кишки стремились покинуть чрево...

Я немного ускорился в начале лета, чтобы не оставлять недоделанного на отпуск,
а так - после того как я отрисовал схемы в привычном ГОСТ-овском виде, мне уже
стало примерно понятно, как и что работает и чем я буду тот или иной узел заменять.
Так что при "сборке" всё работало сразу или почти сразу, что было весьма приятно.
Вообще все эти симуляторы - замечательная штука, когда хочешь просто посмотреть
работу того или иного гаджета, тогда как сам он в виде вещи тебе совсем и не нужен.
Но когда гаджет и по внешнему виду похож на то, что предполагается смоделировать,
то это уже приятно вдвойне, и поэтому я хочу уделить тут некоторое внимание процессу
создания динамической библиотеки Proteus с анимацией, поскольку
динамические библиотеки устройств мы уже разобрали как писать на примере процессора 580ВМ80,
и, я думаю, моделирование различных передних панелей устройств многим будет интересно,
поскольку позволяет увидеть свой девайс в почти закоченном внешнем виде.
Тем более, что это оказалось не так трудно, как я себе представлял, и я заложил
в свою LEDPANEL.DLL некоторую универсальность, которая может помочь тем, кто хочет
смоделировать свой оригинальный индикатор, но не имеет возможности копаться долго
в хитросплетениях VSM.SDK или же и вовсе не дружит с C/C++...
Посмотрим, как это делается на примере фронтальной панели EDUC-8:
Начать отрисовку передней панели и индикатора лучше всего с вот такого "скелетного"
чертежа, где хорошо видно масштабную сетку, которую желательно выставить равной 100,
чтобы основные габариты были уложены в координаты, кратные 100, поскольку по умолча-
нию Proteus чаще всего начинает работать с такой сеткой = 100, то это позволит будущей
модели избежать возможных проблем с позиционированием.

Ничего особо неприятного не будет, но вот модель с шагом 50 Proteus затруднится точно
поставить на узлы сетки 100, если не будет попадания в 50х50 = 100. Т.е. модель частично
останется за узлами сетки и неизвестно, попадут ли в узлы выводы, а если нет, то разводка
шин от них будет кривая. Можете взглянуть как это выглядит на выводах 7-сегментых индикаторов,
т.к. они расположены кратно 50.
Модель рисуется из примитивов прямоугольник, линия, окружность и текст - выделены в
меню на рисунке красными контурами. Подробннее, как надо рисовать, мы уже разбирали
в старте топика о библиотеках Proteus - Proteus C++ DLL's.
В процессе рисования элементов можно менять сетку на более мелкую. На рисунке видно,
что прямоугольные индикаторы отрисованы в сетке, кратной 50. Главное, к моменту рас-
становки координатных маркеров опять вернуться к сетке, кратной 100.
Эти маленькие прямоугольные индикаторы в проекте отображают состояние клавиш, поскольку
сами клавиши не имеют фиксации и по их виду невозможно судить об их положении.
Эти индикаторы идентичны двухцветным светодиодам: горят красным, горят синим, либо не
горят совсем. Это несколько усложнит нам создание модели, но не сильно...
После того как "скелетный" вид нарисован и удовлетворяет всем собственным предпочтениям,
следует сохранить проект и начать расстановку координатных маркеров. Лучше сохранять
проект на каждом этапе с новым названием, чтобы в случае ошибки вернуться к предыдущему
варианту, а не путаться с правкой. Скажем, сохранили как LEDPANEL_0, а расставляем
маркеры уже в проекте LEDPANEL_1 и т.д.
Маркер расставляется с помощью инструмента-"прицела", выделенного в меню синим контуром.
Первый маркер ставим в левый верхний угол модели, и он определит оси координат на панели
нашей модели. Если на маркер навести курсор мыши и ввести с клавиатуры латинский символ О
(Origin), то в нижней строке статуса Proteus координаты всех элементов будут изображаться
розовым цветом и отсчитываться от этого маркера в указанных осях координат (ось Y - вниз,
действительно имеет отрицательные значения).
Теперь надо расставить маркеры координат возле или на всех отображаемых индикаторах панели.
Эти маркеры нужны нам для "прицеливания" при определении координат индикаторов на панели.
Я не поставил маркеры для круглых "светодидов" по центру, т.к. цвет мешает прицелиться.
А без цвета было несколько затруднительно оценить примерный внешний вид.
Но вот у маленьких прямоугольных двухцветных индикаторов маркеры находятся сверху и по центру,
т.к. маркеры нарисованы в сетке кратной 50, то узел сетки = 100 - аккурат посредине.
Теперь довольно занудная процедура - надо записать все координаты элементов индикации
относительно маркера левого верхнего угла. Для этого активизируем этот маркер, наведя на
него курсор мыши и введя с клавиатуры латинский символ О (Origin - отключается так же: O),
и теперь прицеливаемся курсором мыши в расставленные ранее маркеры координат индикаторов.
Главное, Origin для маркера левого верхнего угла во время этих процедур не отключать, иначе
координаты, которые отображаются в нижней статусной строке Proteus, не будут правильными.
Координаты желательно занести в текстовый документ с какой-либо осмысленной нумерацией,
чтобы в дальнейшем точно знать к какому индикатору они относятся.
Я, например, сделал это следующим образом:
Code: Select all
/--- подсветка нижнего ряда ---
/--- слева-направо (Х, У, Номер гр.символа индикатора (1...5) > LEDPANEL_1_х ... LEDPANEL_5_х)
400,-2000,5
800,-2000,5
1200,-2000,5
1600,-2000,5
2000,-2000,5
2400,-2000,5
2800,-2000,5
3200,-2000,5
4200,-2000,5
4600,-2000,5
5000,-2000,5
6000,-2000,5
6400,-2000,5
6800,-2000,5
7200,-2000,5
7650,-2000,5
/--- подсветка PC
300,-300,1
700,-300,1
1100,-300,1
1500,-300,1
1900,-300,1
2300,-300,1
2700,-300,1
3100,-300,1
/--- подсветка MA
300,-700,3
700,-700,3
1100,-700,3
1500,-700,3
1900,-700,3
2300,-700,3
2700,-700,3
3100,-700,3
/--- подсветка MB
300,-1100,4
700,-1100,4
1100,-1100,4
1500,-1100,4
1900,-1100,4
2300,-1100,4
2700,-1100,4
3100,-1100,4
/--- подсветка AC
300,-1500,2
700,-1500,2
1100,-1500,2
1500,-1500,2
1900,-1500,2
2300,-1500,2
2700,-1500,2
3100,-1500,2
/--- подсветка КОП
4500,-300,1
4500,-700,2
4500,-1100,3
4500,-1500,4
4900,-300,4
4900,-700,3
4900,-1100,2
4900,-1500,1
/--- подсветка РЕЖИМА
7100,-300,1
7100,-700,2
7100,-1100,3
7100,-1500,4
в совсем неожиданном месте!

Теперь из "скелетной" модели сделаем корпус элемента. Сохраним проект с новым названием,
выделим весь рисунок контуром с нажатой правой кнопкой мыши (в Proteus v7.xx - левой
кнопкой мыши) и командой copy, выделенной на следующем рисунке красным контуром в верхнем
меню, получаем копию рисунка на второй половине листа. На этом рисунке выделяем контуром
и копируем ниже рисунка 8 круглых индикаторов ВМЕСТЕ С МАРКЕРАМИ и 3 прямоугольных инди-
катора ВМЕСТЕ С МАРКЕРАМИ - они нам понадобятся позже.

С самогО рисунка удаляем все круглые индикаторы ВМЕСТЕ С МАРКЕРАМИ, оставляем только
маркер левого верхнего угла. Раскрашиваем тело и окна модели в нужные нам цвета.
Этот рисунок будет представлять собой модель в неактивном состоянии - так мы её будем
видеть, когда симуляция не включена, поэтому окна светодиодов - тёмного коричневого
цвета, контуров диодов не видно, маленькие прямоугольные индикаторы - также неактивного
тёмного коричневого цвета. Цвет панели я выбрал серый.
Этот рисунок будет стартовым при анимации модели библиотекой LEDPANEL.DLL поэтому в
Proteus принято группировать графические элементы анимированной модели под общим именем
с индексами. Этот элемент по этому принципу получает название LEDPANEL_C, видимо от
английского "Corpus" - корпус, тело.
Так и обозначим его ниже с помощью текстового скрипта (выделен синим контуром в меню
слева): LEDPANEL_C - это чтобы не забыть самим. В создаваемый под этим именем графичес-
кий символ текстовый скрипт LEDPANEL_C - НЕ ВХОДИТ !!!
Теперь, когда рисунок тела готов, создаем из него графический элемент библиотеки графи-
ческих символов Proteus:

Выделяем весь рисунок вместе с маркером левого верхнего угла НО БЕЗ НИЖНЕГО ТЕКСТОВОГО
СКРИПТА контуром с нажатой правой кнопкой мыши (в Proteus v7.xx - левой кнопкой мыши)
в верхнем меню Edit применяем к рисунку опцию Send to back - "тело" всегда должно быть
позади всего, что на нем нарисуют. И, не снимая выделения с рисунка, в меню Library
выбираем опцию Make Symbol. И вот уже в окне этой опции вписываем название этого графи-
ческого символа: LEDPANEL_C, указываем галочку Graphic и помещаем элемент в библиотеку
пользователя - USERSYM. Подтверждаем 'OK', и элемент LEDPANEL_C сохранён в библиотеке.
Теперь следует подготовить вид включенного "тела". Наш проект анимации относится по типу
к Bitwise, где у элементов подразумевают наличие двух состояний "включено" и "выключено",
или "активно" и "не активно", поэтому все остальные графические элементы модели будут иметь
два индекса у имени. Сейчас создаем вид включенного, но "неактивного" "тела" под именем
LEDPANEL_0_0. Парой ему будет графический элемент включенного и "активного" "тела" под
именем LEDPANEL_0_1. Скажем у LEDPANEL_C - экран неактивный тёмный, включенный он приобре-
тает более яркий цвет, а когда он "активен" цвет экрана совсем светлый, но это всё довольно
условные понятия и всё зависит от того, что и как мы выведем в программе библиотеки DLL.
Эти индексированные имена просто дают конкретную связь между рисунком графического элемента
и командой вывода элемента на экран, а какую связь - рассмотрим чуть позже.
Чаще всего элемент LEDPANEL_0_0 призван стереть или закрасить сразу всё, что происходило на
передней панели. Я изобразил его вот так:

Это - вся передняя панель, кроме самогО корпуса панели. Но в окнах я обозначил контуры потухших
круглых индикаторов, а маленькие прямоугольные индикаторы стали светлее. На анимации это вы-
глядит так, будто панель включилась. А вот элемент LEDPANEL_0_1 я использовал более своеобразно,
поскольку нижние маленькие прямоугольные индикаторы у нас имеют 3 состояния: красный, синий и
"не горит", так вот LEDPANEL_0_1 и будет - "не горит". Модель-то типа Bitwise! Тристабильных
состояний индикатора в ней нет, так что задействуем элемент LEDPANEL_0_1 нетрадиционно.
Опять сохраняем проект с новым именем, чтобы безболезненно вернуться к старому в случае ошибки,
удаляем у рисунка серый корпус, но оставляем на месте маркер левого верхнего угла. Накладываем копией
со "скелетной" модели контуры круглых индикаторов, предварительно удалив их координатные
маркеры и заполнение цветом. Нижние маленькие прямоугольные индикаторы заполняем тёмно-красным
цветом (он светлее тёмно-коричнегого). Кликнув текстовый скрипт - меняем название на:
LEDPANEL_0_0 - опять же это просто для себя, чтобы не путаться, в графический элемент скрипт не
входит.
Снова выделяем весь рисунок вместе с маркером левого верхнего угла НО БЕЗ НИЖНЕГО ТЕКСТОВОГО
СКРИПТА контуром с нажатой правой кнопкой мыши (в Proteus v7.xx - левой кнопкой мыши) и в
верхнем меню Edit применяем к рисунку опцию Send to back - "активное тело" всегда должно
быть позади всего, что на нем нарисуют. И, не снимая выделения с рисунка, в меню Library
снова выбираем опцию Make Symbol. В окне этой опции вписываем название этого графического
символа: LEDPANEL_0_0, указываем галочку Graphic и помещаем элемент в библиотеку пользова-
теля - USERSYM. Подтверждаем 'OK', и элемент LEDPANEL_0_0 сохранён в библиотеке.
Теперь создадим графические символы всех "активных" и "не активных" индикаторов, для чего
раскрасим заливкой цветом их модели, ранее сохраненные ниже. Мне понадобилось 8 + 3 эле-
мента, поскольку мне было необходимо для круглых индикаторов 4-х цветов и прямоугольных
двух цветов в одной позиции, плюс один символ - на погашенный.
Цвета "активных" и "не активных" индикаторов хорошо видны на рисунке, для оранжевого был
выбран цвет "не активный" также тёмно-красный, т.к. тёмно-оранжевый уж больно противный
цвет. Все индикаторы подписаны текстовыми скриптами индексированными именами общей группы
LEDPANEL_x_x. Напоминаю, что текстовые скрипты подписи НЕ ВХОДЯТ в графический символ!!!
Создаем все графические символы индикаторов. Для чего последовательно обводим каждый из
них, как на рисунке, БЕЗ НИЖНЕГО ТЕКСТОВОГО СКРИПТА контуром с нажатой правой кнопкой
мыши (в Proteus v7.xx - левой кнопкой мыши) и в верхнем меню Edit применяем к рисунку
опцию Bring to front: индикаторы всегда должны быть над "телом" панели.
Опять же, не снимая выделения с рисунка, в меню Library снова выбираем опцию Make Symbol.
В окне этой опции вписываем название соответствующее текстовому скрипту каждого графического
символа: LEDPANEL_х_х, указываем галочку Graphic и помещаем элемент в библиотеку пользова-
теля - USERSYM. Подтверждаем 'OK', и элементы LEDPANEL_х_х последовательно сохраняются в
библиотеке USERSYM.
Всё в точности, как мы уже делали ранее для элементов LEDPANEL_C и LEDPANEL_0_0.
После того, как все операции проделаны, убедимся, что у нас есть в наличии все созданные
нами графические элементы и мы нигде не ошиблись. Иначе придется вернуться на пару шагов
назад и снова повторить создание элементов.
С этой целью в меню слева нажимаем пиктограмму S на зеленом фоне ([S]-2D Graphics Symbols
Mode) после чего должен появиться список графических символов модели, где следует их всех
просмотреть, нет ли дублирования и не забыт ли какой-либо элемент.

Также следует убедиться, что все элементы действительно занесены в графическую библиотеку
USERSYM Proteus. Для этого нажимаем выделенную красным контуром на рисунках выше кнопку L
(Library), и в открывшемся окне в библиотеке USERSYM должны находиться все те же названия
графических элементов.

Если всё верно, то графические элементы для анимации модели подготовлены, и следует приступить
к расстановке выводов модели. В этом процессе надо быть очень внимательным, поскольку нуме-
рация выводов во внутреннем представлении Proteus происходит по мере их появления на листе
модели. Эта внутренняя нумерация никак не связана с названием выводов и присвоенным им нами
номерам, так что этот процесс желательно провести безошибочно расставляя номера на выводах
также по мере их появления на листе, чтобы внутренняя нумерация и присвоенные нами номера
сразу совпали. Позже ошибку можно будет выявить только с отладочной версией DLL, и при большом
количестве выводов исправлять ошибку весьма трудно.
Расставлять выводы будем у изображения "тела", которое мы сохраняли как LEDPANEL_C :

Для расстановки выводов выбираем в левом меню Proteus пиктограмму, похожую на изображение
операционного усилителя (треугольник, два зеленых вывода спереди и один - сзади: Device pin.)
Тип вывода - DEFAULT (иногда удобнее SHORT, но он скрывает автоматически подписи имен выводов).
Главная особенность расстановки, как мы видим на рисунке выше, что для нижних индикаторов
необходимо выставить по 2 вывода, но мы их расставляем не подряд. Сначала - выводы 0, 1...59,
для всех индикаторов логический "0" на этих выводах - признак включения и отрисовки яркого
графического элемента. Но для маленьких прямоугольных индикаторов - это отрисовка яркого
красного графического элемента, а вот когда выводы 0, 1...59 расставлены и последовательно
пронумерованы, то снизу расставляем выводы с номерами 60, 61...74.
Логический "0" на выводах 60, 61...74 - отрисовка яркого синего графического элемента.

Немного о том, что является причиной строгости в нумерации: это очень упрощает алгоритм
программы анимации - номер вывода внутри библиотеки сразу будет индексом массива состояний
индикаторов. Это исключает необходимость в структуре case и любой перекодировке.
По номеру вывода устанавливаем в массив true или false и сразу высвечиваем нужное состояние
индикатора в виде соответствующего графического символа.
Кстати - смотрел на картинку и сам увидел вроде как ошибку: после номера вывода 73 у меня
проставлен следующий номер 75, а не 74... но ведь работает верно!

внутренний номер всё равно - 74, не смотря на то, что промаркирован как 75, поскольку вывод
выставлен на лист 74-м по порядку. Порядок здорово всё упрощает!
Мне, правда, говорили на Kazus.ru, что нельзя закладыватся на столь неопределённую и не
описанную в хелпах фичу... я, было, призадумался - но при всех тестах сбоев не наблюдал
в 3-х версиях Windows, 4-х разных Proteus и 4-х разных компьютерах. Так что оставил всё -
как есть, поскольку быстро, просто и надежно работает!
Теперь остается предпоследний шаг перед созданием активной модели - отредактировать её
текстовый скрипт, в котором ранее было написано только LEDPANEL_C. При компиляции модели
ТЕКСТОВЫЙ СКРИПТ ОБЯЗАТЕЛЬНО ДОЛЖЕН БЫТЬ ВЫДЕЛЕН АКТИВНЫМ ВМЕСТЕ В КАРТИНКОЙ И ВЫВОДАМИ!
В начале скрипта идут следующие строки:
Code: Select all
{*DEVICE}
NAME=LEDPANEL
{PREFIX=U}
{ACTIVE=LEDPANEL,6,BITWISE,DLL}
{HELP=DISPLAYS>POPUP,1}
{*PROPDEFS}
{MODDLL="VSM Model",READONLY STRING}
{PRIMITIVE="PRIMITIVE",HIDDEN STRING}
{ALEVEL="ALEVEL",HIDDEN STRING}
{INVERT="INVERT",HIDDEN STRING}
{TTRIGMIN="Trigger Time",HIDDEN STRING}
{BITWISE="BITWISE",HIDDEN STRING}
{NUM="NUM",HIDDEN STRING}
{A0="A0",HIDDEN STRING}
{A1="A1",HIDDEN STRING}
{A2="A2",HIDDEN STRING}
{A3="A3",HIDDEN STRING}
{A4="A4",HIDDEN STRING}
{A5="A5",HIDDEN STRING}
{A6="A6",HIDDEN STRING}
{A7="A7",HIDDEN STRING}
{A8="A8",HIDDEN STRING}
{A9="A9",HIDDEN STRING}
{A10="A10",HIDDEN STRING}
{A11="A11",HIDDEN STRING}
{A12="A12",HIDDEN STRING}
{A13="A13",HIDDEN STRING}
{A14="A14",HIDDEN STRING}
{A15="A15",HIDDEN STRING}
{A16="A16",HIDDEN STRING}
{A17="A17",HIDDEN STRING}
{A18="A18",HIDDEN STRING}
{A19="A19",HIDDEN STRING}
{A20="A20",HIDDEN STRING}
{A21="A21",HIDDEN STRING}
{A22="A22",HIDDEN STRING}
{A23="A23",HIDDEN STRING}
{A24="A24",HIDDEN STRING}
{A25="A25",HIDDEN STRING}
{A26="A26",HIDDEN STRING}
{A27="A27",HIDDEN STRING}
{A28="A28",HIDDEN STRING}
{A29="A29",HIDDEN STRING}
{A30="A30",HIDDEN STRING}
{A31="A31",HIDDEN STRING}
{A32="A32",HIDDEN STRING}
{A33="A33",HIDDEN STRING}
{A34="A34",HIDDEN STRING}
{A35="A35",HIDDEN STRING}
{A36="A36",HIDDEN STRING}
{A37="A37",HIDDEN STRING}
{A38="A38",HIDDEN STRING}
{A39="A39",HIDDEN STRING}
{A40="A40",HIDDEN STRING}
{A41="A41",HIDDEN STRING}
{A42="A42",HIDDEN STRING}
{A43="A43",HIDDEN STRING}
{A44="A44",HIDDEN STRING}
{A45="A45",HIDDEN STRING}
{A46="A46",HIDDEN STRING}
{A47="A47",HIDDEN STRING}
{A48="A48",HIDDEN STRING}
{A49="A49",HIDDEN STRING}
{A50="A50",HIDDEN STRING}
{A51="A51",HIDDEN STRING}
{A52="A52",HIDDEN STRING}
{A53="A53",HIDDEN STRING}
{A54="A54",HIDDEN STRING}
{A55="A55",HIDDEN STRING}
{A56="A56",HIDDEN STRING}
{A57="A57",HIDDEN STRING}
{A58="A58",HIDDEN STRING}
{A59="A59",HIDDEN STRING}
{*INDEX}
{CAT=Optoelectronics}
{SUBCAT=LED Panels Display}
{MFR=ExUSSR}
{DESC=Interactive LED Panel for EDUC-8}
в топике Proteus C++ DLL's
Для использования в других моделях важна строка:
{ACTIVE=LEDPANEL,6,BITWISE,DLL} - у модели 6 пар изображений LEDPANEL_0_х ... LEDPANEL_5_х
группы LEDPANEL, изображения парные. Если у модели их иное число, то 6 надо изменить!
А вот о вновь веденных параметрах специально для этой модели - скажу:
{ALEVEL="ALEVEL",HIDDEN STRING} - параметр ALEVEL (Active LEVEL) "1" или "0" (всегда "0").
{INVERT="INVERT",HIDDEN STRING} - параметр INVERT (pin) надо ли инвертировать значение вывода
этот параметр в модели не учитывается, заложен для дальнейшего развития.
{TTRIGMIN="Trigger Time",HIDDEN STRING} - параметр времени переключения - также в модели не
учитывается, переключение мгновенное, заложен для дальнейшего развития.
{BITWISE="BITWISE",HIDDEN STRING} - параметр двух состояний для индикаторных элементов,
учитывается и важен, так как определяет порядок индексов графических символов.
{NUM="NUM",HIDDEN STRING} - параметр числа выводов и количества индикаторов - не может быть
более 60, т.к. максимальный размер массива состояний в модели заложен 60 (0...59).
{A0="A0",HIDDEN STRING} - параметры через которые вводятся ранее записанные в текстовый
... файл координаты индикаторов и указатели на их графические символы:
{A59="A59",HIDDEN STRING} (1...5) <==> LEDPANEL_1_х ... LEDPANEL_5_х
После того, как переменные определены, заполняем их значениями, ранее сохраненными в текстовом
файле, учитывая соответствие, что активный вход 0 "зажигает" элемент A0, вход 1 "зажигает"
элемент A1, ... и т.д.
Code: Select all
{NUM=60}
{A0=400,-2000,5}
{A1=800,-2000,5}
{A2=1200,-2000,5}
{A3=1600,-2000,5}
{A4=2000,-2000,5}
{A5=2400,-2000,5}
{A6=2800,-2000,5}
{A7=3200,-2000,5}
{A8=4200,-2000,5}
{A9=4600,-2000,5}
{A10=5000,-2000,5}
{A11=6000,-2000,5}
{A12=6400,-2000,5}
{A13=6800,-2000,5}
{A14=7200,-2000,5}
{A15=7650,-2000,5}
{A16=3100,-300,1}
{A17=2700,-300,1}
{A18=2300,-300,1}
{A19=1900,-300,1}
{A20=1500,-300,1}
{A21=1100,-300,1}
{A22=700,-300,1}
{A23=300,-300,1}
{A24=3100,-700,3}
{A25=2700,-700,3}
{A26=2300,-700,3}
{A27=1900,-700,3}
{A28=1500,-700,3}
{A29=1100,-700,3}
{A30=700,-700,3}
{A31=300,-700,3}
{A32=3100,-1100,4}
{A33=2700,-1100,4}
{A34=2300,-1100,4}
{A35=1900,-1100,4}
{A36=1500,-1100,4}
{A37=1100,-1100,4}
{A38=700,-1100,4}
{A39=300,-1100,4}
{A40=3100,-1500,2}
{A41=2700,-1500,2}
{A42=2300,-1500,2}
{A43=1900,-1500,2}
{A44=1500,-1500,2}
{A45=1100,-1500,2}
{A46=700,-1500,2}
{A47=300,-1500,2}
{A48=4500,-300,1}
{A49=4500,-700,2}
{A50=4500,-1100,3}
{A51=4500,-1500,4}
{A52=4900,-1500,1}
{A53=4900,-1100,2}
{A54=4900,-700,3}
{A55=4900,-300,4}
{A56=7100,-300,1}
{A57=7100,-700,2}
{A58=7100,-1100,3}
{A59=7100,-1500,4}
Есть один нобязательный параметр {POWERPIN}, логический "0" или уровень GND на нём - выключает
активную индикацию модели, при остальных вариантах индикация работает.
По умолчанию:
{POWERPIN=76}
поскольку вывод питания модели LEDPANEL действительно 76, но если библиотеку LEDPANEL.DLL
использовать для анимации других моделей, номер вывода питания можно изменить этим параметром.
Текстовый скрипт тщательно подготовлен, и это очень упростит нам последний этап компиляции
модели, поскольку придется нажимать лишь кнопку "Далее".
Выделяем весь рисунок вместе с маркером левого верхнего угла и ВМЕСТЕ С НИЖНИМ ТЕКСТОВЫМ
СКРИПТОМ контуром с нажатой правой кнопкой мыши (в Proteus v7.xx - левой кнопкой мыши)
в верхнем меню Proteus выбираем и нажимаем пиктограмму Make Device.

Порядок окон компиляции модели и назначение опций в них подробно описаны в топике Proteus C++ DLL's
и, как я уже сказал выше, все параметры внесены нами заранее, единственное, что придется
выбрать - это библиотеку Proteus, где будет храниться модель. Выбираем - USERDVC.
Позже можно будет создать любую собственную библиотеку и перенести модель в неё.
Если компиляция прошла успешно - у нас в панели компонентов проекта появится собственный
компонент - LEDPANEL. Можем поместить его на лист, чтобы оценить на вид свою работу.

Тестировать модель лучше в отдельном проекте на чистом листе собрав какую-либо похожую
схему, позволяющую подать логические уровни на выводы компонента LEDPANEL.

После запуска симуляции Proteus выдаст ошибку, что LEDPANEL.DLL не найдена - это верно!

Мы её ещё не написали! И о том, как это сделать, я расскажу далее...
Я ничего не рассказал о модели клавиатуры, поскольку нарисовал её и указал параметры
для её стандартной библиотеки Proteus - KEYPAD.DLL - используя материалы сайта Kazus.ru:
9.6. KEYPAD.DLL - матричные клавиатуры на любой вкус.
------------------------------------
Теперь перейдём к программным изобразительным средствам, предоставляемым VSM.SDK для
анимированных моделей Proteus.
И прежде всего - как будут отображаться приготовленные нами графические символы:

Для этого существуют функции следующего типа:
Code: Select all
component->drawsymbol(-1); //--- Рисует LEDPANEL_C, (-1) - его номер
component->drawsymbol(0); //--- Рисует LEDPANEL_0_0, (0) - его номер
component->drawsymbol(1); //--- Рисует LEDPANEL_0_1, (1) - его номер
в массив 0, 1...59 при инициаллизации модели, выводились на экран вот так:
Code: Select all
component->drawsymbol(dx[j],dy[j],0,0,sp[j]*2+1); //--- "зажигаем" активный индикатор
component->drawsymbol(dx[j],dy[j],0,0,sp[j]*2); //--- "тушим" НЕ активный индикатор
не намерен, а написан он весьма понятно, хотя кратко и примеров маловато.
Я не из вредности это делаю, а просто опыт мне подсказывает, что после чтения разных
чужих пересказов, я всё же внимательно VSMSDK.HLP сам прочитал, и "процесс пошел"...

Кроме вывода наших "спрайтов" на экран, VSM.SDK предоставляет следующие изобразительные
функции:
Code: Select all
Vector drawing services:
HGFXSTYLE ICOMPONENT::creategfxstyle (CHAR *name)
VOID ICOMPONENT::selectgfxstyle (HGFXSTYLE style)
VOID ICOMPONENT::setpenwidth (INT w)
VOID ICOMPONENT::setpencolour (COLOUR c)
VOID ICOMPONENT::setbrushcolour (COLOUR c)
VOID ICOMPONENT::drawline (INT x1, INT y1, INT x2, INT y2)
VOID ICOMPONENT::drawbox (INT x1, INT y1, INT x2, INT y2)
VOID ICOMPONENT::drawbox (BOX &bx)
VOID ICOMPONENT::drawcircle (INT x, INT y, INT radius)
VOID ICOMPONENT::drawbezier (POINT *p, INT numpoints)
VOID ICOMPONENT::drawpolyline (POINT *p, INT numpoints)
VOID ICOMPONENT::drawpolygon (POINT *p, INT numpoints)
VOID ICOMPONENT::drawsymbol (INT symbol)
VOID ICOMPONENT::drawsymbol (INT x, INT y, INT rot, INT mir, INT symbol)
VOID ICOMPONENT::drawstate (ACTIVESTATE state)
VOID ICOMPONENT::getsymbolarea (INT symbol, BOX *area)
BOOL ICOMPONENT::getmarker (CHAR *name, POINT *pos, INT *rot, INT *mir);
Text output services:
HTEXTSTYLE ICOMPONENT::createtextstyle (CHAR *name)
VOID ICOMPONENT::selecttextstyle (HTEXTSTYLE style)
VOID ICOMPONENT::settextfont (CHAR *name)
VOID ICOMPONENT::settextsize (INT h)
VOID ICOMPONENT::setbold (BOOL f)
VOID ICOMPONENT::setitalic (BOOL f)
VOID ICOMPONENT::setunderline (BOOL f)
VOID ICOMPONENT::settextcolour (COLOUR c)
VOID ICOMPONENT::drawtext (INT x, INT y, INT rot, INT jflags, CHAR *text, ...)

Я из всех этих функций использовал только следующие:
Code: Select all
//--- инициаллизация переменных для работы с текстом ------------
// Get origin and style for readout text
BOX textbox; //--- struct BOX { LONG x1, y1, x2, y2; };
// Устанавливаем расположение спрайта -1 или 0 или 1 ...
//
cpt->getsymbolarea(0, &textbox); //--- "0" - LEDPANEL_0_0
// на котором будет отображаться выводимый текст
// textorg - struct POINT { LONG x, y; };
textorg.x = (textbox.left + textbox.right)/10; // ближе к левому краю
textorg.y = (textbox.top + textbox.bottom)/4; // ближе к верху
// Создаем текстовый стиль, в котором будет выводиться текст
//
textstyle = cpt->createtextstyle(NULL); // NULL == "ACTIVE READOUT"
// Initial readout: начальная инициаллизация текстовой переменной readout
strcpy(readout, " Test: ");
// выводим текст
component->drawtext(280, -100, 0, TXJ_LEFT|TXJ_MIDDLE, readout);
// рисуем рамку заполненную серым цветом
component->setpencolour (GREY);
component->drawbox (1100, -1830, 2500, -1950);
// выводим НАДПИСЬ ДЛЯ ПОЛЬЗОВАТЕЛЯ ОБ АНИМАЦИИ
component->setbold (TRUE);
component->settextsize (180);
component->settextcolour (0x0000ff);
// выводим текстовые символы текущего значения at textorg.x, textorg.y,
strcpy(readout, "If you want to force Front Panel animation,");
component->drawtext(280, -300, 0, TXJ_LEFT|TXJ_MIDDLE, readout);
примеров их применения в VSMSDK.HLP нет, а не всё, порой, сразу очевидно...
Но все эти обширные возможности нельзя применять там, где вздумается, а лишь сугубо в двух
конкретных вызовах, отвечающих в структуре DLL за графические возможности.
И первая из них это:
Code: Select all
// ************************************************************
// P L O T
// отвечает за отрисовку раз за кадр, когда экран перерисовывается
// Proteus раз за кадр, при изменении масштаба, при отрисовке после
// выхода из-под другого окна... и т.д.
// ************************************************************
//
VOID LEDPANEL::plot (ACTIVESTATE state)
{
//--- Рисуем компоненты основного изображения
component->drawsymbol(-1);
//--- Рисуем дисплей активным (видны диоды)
component->drawsymbol(0);
//--- Обновляем все элементы индикации
...
}
какими-то внешними событиями и нуждается в восстановлении целиком.
PLOT никогда и ниоткуда не вызывают прямым образом - он активируется сам в нужных
случаях.
Вторая, и это главная функция вывода графики модели:
Code: Select all
// ************************************************************
// A N I M A T E
// отвечает за мгновенную отрисовку - то, что случилось СЕЙЧАС!
// если в свойствах PROTEUS выключена анимация, то этот вызов
// не срабатывает автоматически и его нужно вызвать принудительно.
//
// Но обычно вызов происходит в конце кадра симуляции из ф-ции
// indicate (), если она указала тип данных в ACTIVEDATA и вернула
// в этой структуре данные такого типа, подтвердив вызов animate ()
// возвратом TRUE.
// ************************************************************
//
VOID LEDPANEL::animate (INT element, ACTIVEDATA *data)
{
//--- вот здесь-то и нужно рисовать всю анимацию модели
if (bootstrt)
{//--- если это самый первый вход в анимацию
if (data->type == ADT_PINSTATE)
{//--- с указанием состояния выводов
component->drawsymbol(0); //--- отрисуем LEDPANEL_0_0 "включилось"!
bootstrt = FALSE; //--- и больше её рисовать не будем
}
}
//--- ну и т.д.
...
}
Дело в том, что когда в верхнем меню Proteus 'System' выбрать опцию 'Animated
Circuits Config' и в ней выставить галочку 'Show Logic State of Pins?', то сам
Proteus будет выставлять на выводах нашей модели логические состояния в виде
цветных квадратиков: красных, синих, серых и желтых.
Эти логические состояния определены в Proteus как:
Code: Select all
State Type Keyword Description
-----------------------------------------------------------------------
Power High PHI Logic 1 power rail.
Strong High SHI Logic 1 active output.
Weak High WHI Logic 1 passive output.
Floating FLT Floating output - high-impedance.
Weak Undefined WUD Mid voltage from analogue source.
Contention CON Mid voltage from digital conflict.
Weak Low WLO Logic 0 passive output.
Strong Low SLO Logic 0 active output.
Power Low PLO Logic 0 power rail.
подавая ей на вход номер вывода в своём внутреннем представлении INT element
и его состояние: ACTIVEDATA *data
Остается лишь проверить состояние на низкий логический уровень:
Code: Select all
BOOL LEDPANEL::itactive(INT element, ACTIVEDATA *data)
{
if((data->stateval == WLO)||(data->stateval == PLO)||(data->stateval == SLO))
{
return TRUE;
}
return FALSE;
}
и номера "спрайта" индикатора в массиве 0, 1...59.
Конечно, если 'Show Logic State of Pins?' выключено, то и анимация нашей панели не
работает. В этом случае она выведет предупреждение, что анимацию надо включить, хотя
и без анимации передней панели вся модель EDUC-8 работает совершенно нормально, только
без индикации.