Создание VSM -моделей электронных компонентов для Proteus.
Часть I. Цифровые модели. |
Главная страница |
Модели для Протеуса | |
Проекты | |
Статьи | |
Обо мне | |
Фотоальбом | |
Ссылки | |
Обратная связь | |
In English |
Proteus фирмы Labcenter Electronics представляет собой симулятор электронных схем, основанный на Berkeley SPICE3F5 с расширениями для симуляции цифровых и аналогово-цифровых схем. В стандартных библиотеках Proteus представлен достаточно широкий диапазон моделей компонентов, но для некоторых схем возникает необходимость создания собственных моделей. В этой статье мы рассмотрим процесс их создания.
Я ориентируюсь на VSM API версии 1.10, реализованную в Proteus 6.3, так как в более поздних версиях из поставки исключен VSM SDK . Версия Proteus , на которой я буду объяснять – Proteus Professional 6.5SP1, так как это последняя имеющаяся у меня версия. Будьте осторожны - могут возникнуть (и возникнут) некоторые сложности в работе с недолеченными нелицензионными версиями.
Также, будет рассмотрено создание только цифровых VSM -моделей. Модели PSPICE , аналоговые, смешанные, активные и другие будут описаны в следующих статьях.
Примечание. Перед прочтением данной статьи желательно иметь опыт по созданию схем в среде Proteus ISIS, а также сам Proteus желательно версии не ниже 6.3, лучше Professional, можно Lite. Demo-версия не подойдет по причине того, что в ней полностью заблокированы функции сохранения результатов работы. Ещё необходим опыт программирования на C++, в том числе знание объектно-ориентированного программирования.
VSM-модель представляет собой библиотеку .DLL, написанную на языке C++. Желательно использовать компилятор Microsoft Visual C++ 7.0 (он доступен для бесплатной загрузки с сайта Microsoft), или другой компилятор C++, например Digital Mars. Delphi не подойдет по причине невозможности вызова членов классов, откомпилированных C++. Я буду писать вариант для Microsoft Visual C++, для других компиляторов переделка будет не очень сложной.
Также, для того, чтобы отображать на экране компонент и взаимодействовать с ним, необходимо внести визуальную модель компонента в библиотеку компонентов Proteus.
При запуске процесса симуляции ISIS анализирует параметры визуальной модели, подгружает соответствующую .DLL, инициализирует её, в результате чего должен создаться объект соответствующего класса, и затем в процессе инициализации и симуляции происходит обмен данными с методами созданного объекта.
Визуальная модель электронного компонента представляет собой его схематическое представление и описание его свойств. Она включает в себя рисунок элемента («корпус» и надписи), выводы с уникальными именами, а также «скрипт», в котором описаны свойства компонента.
«Корпус» элемента создается с помощью 2D-элементов (2D graphics line, 2D graphics box, и так далее). Например, нарисуем простой прямоугольник:
Добавим выводы. Это делается в разделе «Device pin.». Возьмем для примера DEFAULT:
Назовем их Pin1- Pin4:
Установим Origin – точку, с помощью которой компонент будет выравниваться по координатной сетке. Выберем в разделе «Markers for component origin, etc» ORIGIN и установим его на внешний конец вывода Pin1:
Теперь напишем скрипт. Для этого установим (обычно ниже компонента) «Text script». В открывшемся окошке введём следующее:
{*DEVICE} NAME=OURDEVICE {PREFIX=OD} {*PROPDEFS} {MODDLL="VSM Model DLL",HIDDEN STRING} {PRIMITIVE="Primitive Type",HIDDEN STRING} {*COMPONENT} {MODDLL=OURDEV.DLL} {PRIMITIVE=DIGITAL,OURDEVICE}
Теперь объясню, что это означает.
{*...} – имя раздела, далее идут параметры.
{...} – скрытый параметр, то есть он не будет отображаться в свойствах компонента.
В разделе {*DEVICE} указывается имя компонента (NAME), его префикс (PREFIX) при создании экземпляра компонента (в нашем случае это будет OD1, OD2 и т.д.).
В разделе {*PROPDEFS} перечисляются свойства объекта. У нас это MODDLL – указание, что наша модель будет храниться в .DLL, и PRIMITIVE – указание, что у нашей объекта будет имя и тип. Далее в разделе {*COMPONENT} эти свойства заполняются. В нашем случае указано, что модель будет храниться в файле OURDEV.DLL и следующей строчкой PRIMITIVE=DIGITAL,OURDEVICE показываем, что это будет цифровая модель с именем OURDEVICE.
Имеется очень много дополнительных свойств, но для создания простой модели нам хватит того, что мы написали.
Теперь необходимо скомпоновать разрозненные элементы в единое целое – визуальную модель и поместить её в библиотеку. Выделяем все наши компоненты и выбираем меню Library - Make Device или нажимаем на кнопку «Form tagged graphics / pads into device and place in library».
В открывшемся окошке нажимаем Next , так как мы уже задали имя модели и префикс.
В следующем окне нам предлагают выбрать корпус, в котором будет располагаться наш компонент. Пропустим пока это, нажмем на кнопку Next .
В следующих двух окнах тоже нажимаем Next, так как мы задали уже все необходимые свойства модели. В принципе конечно можно задавать всё, что мы написали в скрипте в этих диалогах, но я обычно делаю вручную.
И наконец в последнем окошке выбираем Device Category – Miscellaneous , и библиотеку USERDVC. После нажатия на кнопку OK наш компонент помещается в библиотеку, и его можно устанавливать на принципиальную схему. Так и сделаем.
Вот что у нас должно получиться в итоге:
Но вот беда – при попытке запустить симуляцию схемы у нас выскакивает сообщение об ошибке:
SIMULATION LOG
==============
…
FATAL: [OD1] External model DLL "OURDEV.DLL" not found. GLE=0x00000002.
Simulation FAILED due to fatal simulator errors.
Это означает, что ISIS не смог найти OURDEV.DLL – библиотеку, в которой располагается наша модель. Созданием этой библиотеки мы и займемся в следующей главе.
Для начала создадим пустой проект .DLL -библиотеки Win32. Включим в проект файл заголовков классов VSM SDK (эти файлы лежат в каталоге INCLUDE):
#include "Vsm.hpp"
Добавим две функции:
extern "C" IDSIMMODEL __declspec ( dllexport ) * createdsimmodel (CHAR *device, ILICENCESERVER *ils)
{
ils->authorize(model_key);
return NULL;
}
extern "C" VOID __declspec ( dllexport ) deletedsimmodel (IDSIMMODEL *model) { }
Первая функция передает нашей библиотеке название устройства, для создания которого ISIS вызывает нашу .DLL-ку. Это удобно использовать, если наша библиотека реализует несколько различных моделей. Она должна вызвать функцию ILICENCESERVER::authorize сервера лицензирования и сообщить ему свой ключ, в случае успеха создать объект и вернуть его адрес. В нашем случае мы возвращаем NULL, так как у нас ещё не готово описание модели. Подробнее о ключах лицензирования я расскажу позднее.
Вторая функция должна удалить модель из памяти. У нас её ещё нет, поэтому можно ничего не делать.
Откомпилируем нашу модель и посмотрим, что получится. Кстати, можно добавить путь к нашей .DLL в окне System - Set Paths…
Теперь симулятор у нас ругается слегка другим сообщением:
ERROR: [OD1] OURDEV.DLL failed to create DSIM model for primitive type 'OURDEVICE'.
Ну и правильно, мы же не создаем никакого объекта.
Теперь небольшое замечание. Все цифровые VSM -модели наследуются от абстрактного класса IDSIMMODEL. Создадим и мы класс DSOURDEVICE как наследника IDSIMMODEL:
class DSOURDEVICE : public IDSIMMODEL
{
public:
INT isdigital (CHAR *pinname);
VOID setup (IINSTANCE *inst, IDSIMCKT *dsim);
VOID runctrl (RUNMODES mode);
VOID actuate (REALTIME time, ACTIVESTATE newstate);
BOOL indicate (REALTIME time, ACTIVEDATA *data);
VOID simulate (ABSTIME time, DSIMMODES mode);
VOID callback (ABSTIME time, EVENTID eventid);
private:
IINSTANCE *instance;
IDSIMCKT *ckt;
IDSIMPIN *Pin1;
IDSIMPIN *Pin2;
IDSIMPIN *Pin3;
IDSIMPIN *Pin4;
};
В разделе public мы перекрываем абстрактные методы класса, а в разделе private у нас будут храниться ссылки на различные внутренние структуры.
Затем добавим реализацию методов:
INT DSOURDEVICE::isdigital (CHAR *pinname)
{
return 1;
}
VOID DSOURDEVICE::setup (IINSTANCE *instance, IDSIMCKT *dsimckt)
{
inst = instance;
ckt = dsimckt;
Pin1 = inst->getdsimpin("Pin1", true );
Pin2 = inst->getdsimpin("Pin2", true );
Pin3 = inst->getdsimpin("Pin3", true );
Pin4 = inst->getdsimpin("Pin4", true );
}
VOID DSOURDEVICE::runctrl (RUNMODES mode)
{
}
VOID DSOURDEVICE::actuate (REALTIME time, ACTIVESTATE newstate)
{
}
BOOL DSOURDEVICE::indicate (REALTIME time, ACTIVEDATA *data)
{
return FALSE;
}
VOID DSOURDEVICE::simulate (ABSTIME time, DSIMMODES mode)
{
}
VOID DSOURDEVICE::callback (ABSTIME time, EVENTID eventid)
{
}
Также, изменим функции createdsimmodel и deletedsimmodel, так как у нас уже готово описание модели:
extern "C" IDSIMMODEL __declspec ( dllexport ) * createdsimmodel (CHAR *device, ILICENCESERVER *ils)
{
if (ils->authorize(model_key)
return new DSOURDEVICE;
else
return NULL;
}
extern "C" VOID __declspec ( dllexport ) deletedsimmodel (IDSIMMODEL *model)
{
delete (DSOURDEVICE *)model;
}
Откомпилируем модель и попробуем запустить симуляцию в ISIS. Ура! Заработала! Одно но - никаких результатов работы не видно:
Во-первых определимся, что Pin1 и Pin2 у нас будут входы, а Pin3 и Pin4 – выходы.
Установим начальное состояние выходов в «1». Для этого добавим следующие строки в конец функции setup:
Pin3->setstate(SHI);
Pin4->setstate(SHI);
Перекомпилируем и запустим симуляцию. Видно, что изменилось начальное состояние наших выходов – они установлены в «1»:
Сделаем из нашей модели генератор. Для этого добавим в конец функции setup строчку
ckt->setcallback(1000000000000, this , 0x25);
Этим мы задаем, что через 1 секунду (время задается в пикосекундах) после запуска будет вызвана функция callback с кодом события 0x25.
Также, добавим в функцию callback:
VOID DSOURDEVICE::callback (ABSTIME time, EVENTID eventid)
{
if (eventid == 0x25)
{
if (ishigh(Pin3->istate()))
Pin3->setstate(time, 1, SLO);
else
Pin3->setstate(time, 1, SHI);
ckt->setcallback(time + 1000000000000, this , 0x25);
}
}
То есть, если вызвано наше событие, то изменяем состояние выхода на противоположное, и запускаем таймер снова на 1 секунду, после чего снова вызовется функция callback.
Откомпилируем и запустим симуляцию. Так и есть – модель изменяет состояние ножки Pin3 каждую секунду.
Теперь попробуем заставить нашу модель читать состояние входов и отображать их на выходы. Договоримся, что Pin3 будет отображать состояние Pin1, а Pin4 – состояние Pin2.
Для начала приведем функции setup и callback в первоначальный вид. Затем добавим две строчки в функцию simulate:
Pin3->setstate(time, 1, Pin1->istate());
Pin4->setstate(time, 1, Pin2->istate());
То есть мы читаем значение состояния со входов Pin1 и Pin2, и через 1 значение тактовой частоты (1 пикосекунда) относительно текущего времени (time) устанавливаем состояние выходов. Конечно, в реальности не бывает таких быстрых устройств, так что необходимо задавать большие значения задержек. Лучше, если эти значения будут заданы через константу. Ещё лучше, если они будут передаваться как параметры модели (об этом позже).
И приделаем на наши входы два цифровых генератора. Что мы видим – выходы отображают состояние входов:
Теперь Вы научились создавать цифровые модели.
Приложение. Исходные тексты к статье
27 октября – 2 ноября 2004 года.